fix: 兼容上游 sentence 字段为对象/字符串两种形态,加 debug 打印无 event 元数据行
This commit is contained in:
@@ -72,7 +72,7 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) {
|
|||||||
switch resp.Event {
|
switch resp.Event {
|
||||||
case "TTSSentenceStart":
|
case "TTSSentenceStart":
|
||||||
if common.DebugLog {
|
if common.DebugLog {
|
||||||
log.Printf("Sentence start: sequence=%d, sentence=%s", resp.Sequence, resp.Sentence)
|
log.Printf("Sentence start: sequence=%d, sentence=%s", resp.Sequence, resp.SentenceText())
|
||||||
}
|
}
|
||||||
case "TTSSentenceEnd":
|
case "TTSSentenceEnd":
|
||||||
if common.DebugLog {
|
if common.DebugLog {
|
||||||
@@ -81,7 +81,7 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) {
|
|||||||
case "TTSSubtitle":
|
case "TTSSubtitle":
|
||||||
if resp.Data != "" {
|
if resp.Data != "" {
|
||||||
out.Subtitles = append(out.Subtitles, dto.SubtitleEntry{
|
out.Subtitles = append(out.Subtitles, dto.SubtitleEntry{
|
||||||
Text: resp.Sentence,
|
Text: resp.SentenceText(),
|
||||||
Sequence: resp.Sequence,
|
Sequence: resp.Sequence,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -105,10 +105,15 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) {
|
|||||||
gotFirstChunk = true
|
gotFirstChunk = true
|
||||||
}
|
}
|
||||||
case "":
|
case "":
|
||||||
// 传输帧,跳过
|
// 无 event 字段的元数据行(上游 TTSSentenceStart 偶发省略 event),
|
||||||
|
// debug 模式打印便于排查;正常情况静默跳过。
|
||||||
|
if common.DebugLog && resp.Code == 0 {
|
||||||
|
log.Printf("volcano: 无 event 字段 code=%d sequence=%d sentence=%s data_len=%d", resp.Code, resp.Sequence, resp.SentenceText(), len(resp.Data))
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if common.DebugLog {
|
if common.DebugLog {
|
||||||
log.Printf("volcano: 忽略未识别事件 event=%q sequence=%d", resp.Event, resp.Sequence)
|
log.Printf("volcano: 忽略未识别事件 event=%q sequence=%d sentence=%s data_len=%d", resp.Event, resp.Sequence, resp.SentenceText(), len(resp.Data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-10
@@ -1,6 +1,9 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// OpenAITTSRequest 是 /v1/audio/speech 接收的请求体。
|
// OpenAITTSRequest 是 /v1/audio/speech 接收的请求体。
|
||||||
// 仅 input / speed / response_format 实际影响火山侧;
|
// 仅 input / speed / response_format 实际影响火山侧;
|
||||||
@@ -14,16 +17,40 @@ type OpenAITTSRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// V3TTSResponse 是火山 v3 HTTP Chunked 流式响应中每一行的 JSON 结构。
|
// V3TTSResponse 是火山 v3 HTTP Chunked 流式响应中每一行的 JSON 结构。
|
||||||
|
// Sentence 字段上游有时返回字符串(TTSSentenceStart 里的句文本),有时返回对象
|
||||||
|
// ({"phonemes":[...],"text":"...","words":[...]}),用 json.RawMessage 兼容两种形态,
|
||||||
|
// 避免任意一种上游变更都导致整行解析失败。
|
||||||
type V3TTSResponse struct {
|
type V3TTSResponse struct {
|
||||||
ReqID string `json:"reqid"`
|
ReqID string `json:"reqid"`
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
Sequence int `json:"sequence"`
|
Sequence int `json:"sequence"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Sentence string `json:"sentence,omitempty"`
|
Sentence json.RawMessage `json:"sentence,omitempty"`
|
||||||
IsFinal bool `json:"is_final"`
|
IsFinal bool `json:"is_final"`
|
||||||
Usage *V3Usage `json:"usage,omitempty"`
|
Usage *V3Usage `json:"usage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SentenceText 从 Sentence 提取可读文本:
|
||||||
|
// - 字符串直接返回
|
||||||
|
// - 对象尝试取 .text 字段
|
||||||
|
// - 其它情况返回原始 JSON
|
||||||
|
func (r *V3TTSResponse) SentenceText() string {
|
||||||
|
if len(r.Sentence) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
var s string
|
||||||
|
if err := json.Unmarshal(r.Sentence, &s); err == nil {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
var obj struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(r.Sentence, &obj); err == nil && obj.Text != "" {
|
||||||
|
return obj.Text
|
||||||
|
}
|
||||||
|
return string(r.Sentence)
|
||||||
}
|
}
|
||||||
|
|
||||||
// V3Usage 由 X-Control-Require-Usage-Tokens-Return 触发,包含计费字符数。
|
// V3Usage 由 X-Control-Require-Usage-Tokens-Return 触发,包含计费字符数。
|
||||||
|
|||||||
Reference in New Issue
Block a user