diff --git a/adapter/volcano/response.go b/adapter/volcano/response.go index a75418f..90e53c8 100644 --- a/adapter/volcano/response.go +++ b/adapter/volcano/response.go @@ -10,6 +10,7 @@ import ( "log" "time" + "github.com/volcano-tts/tts-api/common" "github.com/volcano-tts/tts-api/dto" ) @@ -40,7 +41,9 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) { } var resp dto.V3TTSResponse if err := json.Unmarshal(line, &resp); err != nil { - log.Printf("volcano: 解析响应行失败: %v, line=%q", err, truncateForLog(line, 200)) + if common.DebugLog { + log.Printf("volcano: 解析响应行失败: %v, line=%q", err, truncateForLog(line, 200)) + } continue } @@ -56,7 +59,9 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) { if resp.Usage != nil { out.TextWords = resp.Usage.TextWords out.HasUsage = true - log.Printf("TTS 合成结束, usage: text_words=%d", out.TextWords) + if common.DebugLog { + log.Printf("TTS 合成结束, usage: text_words=%d", out.TextWords) + } } for scanner.Scan() { } @@ -66,9 +71,13 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) { // 事件分发:显式匹配已知事件,绝不把未知事件当作音频。 switch resp.Event { case "TTSSentenceStart": - log.Printf("Sentence start: sequence=%d, sentence=%s", resp.Sequence, resp.Sentence) + if common.DebugLog { + log.Printf("Sentence start: sequence=%d, sentence=%s", resp.Sequence, resp.Sentence) + } case "TTSSentenceEnd": - log.Printf("Sentence end: sequence=%d", resp.Sequence) + if common.DebugLog { + log.Printf("Sentence end: sequence=%d", resp.Sequence) + } case "TTSSubtitle": if resp.Data != "" { out.Subtitles = append(out.Subtitles, dto.SubtitleEntry{ @@ -98,7 +107,9 @@ func ParseStream(body io.Reader, started time.Time) (*ParsedStream, error) { case "": // 传输帧,跳过 default: - log.Printf("volcano: 忽略未识别事件 event=%q sequence=%d", resp.Event, resp.Sequence) + if common.DebugLog { + log.Printf("volcano: 忽略未识别事件 event=%q sequence=%d", resp.Event, resp.Sequence) + } } } diff --git a/adapter/volcano/synthesis.go b/adapter/volcano/synthesis.go index 6093e97..07ccbaa 100644 --- a/adapter/volcano/synthesis.go +++ b/adapter/volcano/synthesis.go @@ -8,6 +8,7 @@ import ( "log" "time" + "github.com/volcano-tts/tts-api/common" "github.com/volcano-tts/tts-api/dto" ) @@ -79,8 +80,10 @@ func Synthesis( "X-Control-Require-Usage-Tokens-Return": "*", } - log.Printf("TTS upstream: resource_id=%s speaker=%s model=%q format=%s sample_rate=%d speech_rate=%d additions=%q", - opts.ResourceID, opts.Speaker, opts.Model, opts.Format, opts.SampleRate, opts.SpeechRate, extractAdditionsForLog(body)) + if common.DebugLog { + log.Printf("TTS upstream: resource_id=%s speaker=%s model=%q format=%s sample_rate=%d speech_rate=%d additions=%q", + opts.ResourceID, opts.Speaker, opts.Model, opts.Format, opts.SampleRate, opts.SpeechRate, extractAdditionsForLog(body)) + } resp, err := client.PostStream(ctx, "https://openspeech.bytedance.com/api/v3/tts/unidirectional", headers, body) if err != nil { @@ -129,6 +132,9 @@ func Synthesis( } mtr.UpstreamFinished(opts.Speaker, opts.Model, opts.Format, "ok", duration, parsed.FirstChunk, parsed.Chunks, len(finalData), 0) + log.Printf("TTS 合成成功 - 音色=%s 格式=%s 文本=%d字 音频=%d字节 分片=%d 耗时=%v", + opts.Speaker, clientFormat, len(text), len(finalData), parsed.Chunks, duration) + return &dto.SynthesisResult{ AudioData: finalData, Format: finalFormat, diff --git a/common/constants.go b/common/constants.go index 778804c..2e95ea6 100644 --- a/common/constants.go +++ b/common/constants.go @@ -2,6 +2,9 @@ package common import "time" +// DebugLog 控制非必要日志输出;由 setting 包在启动时通过 BYTEDANCE_TTS_DEBUG 环境变量设置。 +var DebugLog bool + const ( DefaultPort = "8080" DefaultTimeout = 30 * time.Second diff --git a/controller/tts.go b/controller/tts.go index 645478c..f9e869e 100644 --- a/controller/tts.go +++ b/controller/tts.go @@ -162,7 +162,7 @@ func OpenaiTTSHandler(w http.ResponseWriter, r *http.Request) { metrics.RequestDuration.Observe(duration.Seconds(), telemetry.Labels{"status": finalLabels["status"], "format": clientFormat}) log.Printf("警告: TTS 合成失败 - 路径=%s 客户端=%s 文本长度=%d 耗时=%v 错误=%v", r.URL.Path, middleware.GetClientIP(r), len(req.Input), duration, err) - http.Error(w, "TTS synthesis failed", http.StatusInternalServerError) + middleware.SendJSONError(w, http.StatusInternalServerError, "TTS synthesis failed.", "server_error", "synthesis_failed") return } diff --git a/middleware/cors.go b/middleware/cors.go index 746e94e..79ba784 100644 --- a/middleware/cors.go +++ b/middleware/cors.go @@ -5,6 +5,7 @@ import ( "net/http" "strings" + "github.com/volcano-tts/tts-api/common" "github.com/volcano-tts/tts-api/setting" ) @@ -70,8 +71,10 @@ func CORS(next http.Handler) http.Handler { if !matched { // Origin 不在白名单:拒绝请求(预检和非预检均拒绝), // 防止不匹配的请求穿透到后端浪费 TTS 资源 - log.Printf("CORS拦截: 来源=%q 路径=%s 方法=%s 客户端=%s", - origin, r.URL.Path, r.Method, GetClientIP(r)) + if common.DebugLog { + log.Printf("CORS拦截: 来源=%q 路径=%s 方法=%s 客户端=%s", + origin, r.URL.Path, r.Method, GetClientIP(r)) + } w.WriteHeader(http.StatusForbidden) return } diff --git a/middleware/security.go b/middleware/security.go index a525481..c3a2ff7 100644 --- a/middleware/security.go +++ b/middleware/security.go @@ -12,7 +12,7 @@ func SecurityHeaders(next http.Handler) http.Handler { w.Header().Set("X-XSS-Protection", "1; mode=block") w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin") - if strings.HasPrefix(r.URL.Path, "/v1/") || r.URL.Path == "/health" { + if strings.HasPrefix(r.URL.Path, "/v1/") || r.URL.Path == "/health" || r.URL.Path == "/dashboard" || r.URL.Path == "/metrics" { w.Header().Set("Cache-Control", "no-store") } diff --git a/setting/config.go b/setting/config.go index d1f5ea1..c48b3b3 100644 --- a/setting/config.go +++ b/setting/config.go @@ -153,6 +153,11 @@ func InitTTSConfig() error { } } + common.DebugLog = getEnvBool("BYTEDANCE_TTS_DEBUG", false) + if common.DebugLog { + log.Println("调试日志已启用 BYTEDANCE_TTS_DEBUG") + } + TTSOptions = volcano.Options{ APIKey: apiKey, ResourceID: resourceId,