From b0a7ce885e3659b1d75ce378dd4a08d77e21103a Mon Sep 17 00:00:00 2001 From: hhs <386998068@qq.com> Date: Sat, 13 Jun 2026 21:09:56 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=BB=99=E5=89=8D=E7=AB=AF=E7=9A=84=20totalTokens=20=E4=B8=BA0?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=E5=B9=B6=E6=8F=90=E4=BE=9B=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=20.env?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - backend/.env | 17 +++++++++++ backend/.gitignore | 1 - backend/internal/orchestrator/pipeline.go | 36 ++++++++++++++++------- 4 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 backend/.env diff --git a/.gitignore b/.gitignore index 4c77b4c..d7a0342 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ backend/bin/ backend/server # ---- 环境变量 ---- -.env .env.local .env.*.local diff --git a/backend/.env b/backend/.env new file mode 100644 index 0000000..48b24a0 --- /dev/null +++ b/backend/.env @@ -0,0 +1,17 @@ +# ---- AI 服务 API Key ---- +CAMTALK_AI_LLM_API_KEY=sk-ws-H.REHELLY.C4s3.MEUCIQCRee37XWEKp2szaxVLFDtR1rxNNsf372zMvCR0Xl6UvQIgZgvhRTvaa1FmhbCQJgaHu4Jny29AQkn01-3hX9CWBOg +CAMTALK_AI_STT_API_KEY=tp-c9e7scwfx94qvqyhpnahnw8uaiya01za2qzvg4xe24rp3xiv +CAMTALK_AI_TTS_API_KEY=tp-c9e7scwfx94qvqyhpnahnw8uaiya01za2qzvg4xe24rp3xiv + +# ---- 可选覆盖(默认值见 config.yaml)---- +# CAMTALK_AI_LLM_MODEL=qwen3-vl-plus +# CAMTALK_AI_LLM_ENDPOINT=https://api.openai.com/v1 +# CAMTALK_AI_LLM_TIMEOUT=10 +# CAMTALK_AI_STT_ENDPOINT=wss://api.deepgram.com/v1/listen +# CAMTALK_AI_TTS_ENDPOINT=https://api.openai.com/v1 +# CAMTALK_AI_TTS_VOICE=alloy +# CAMTALK_AI_TTS_SPEED=1.0 +# CAMTALK_AI_TTS_TIMEOUT=5 + +# ---- 应用 ---- +# APP_ENV=dev diff --git a/backend/.gitignore b/backend/.gitignore index 8304260..ac13b7b 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -3,7 +3,6 @@ bin/ # 环境配置 -.env config.dev.yaml config.prod.yaml diff --git a/backend/internal/orchestrator/pipeline.go b/backend/internal/orchestrator/pipeline.go index 0186108..d8d2823 100644 --- a/backend/internal/orchestrator/pipeline.go +++ b/backend/internal/orchestrator/pipeline.go @@ -166,11 +166,12 @@ func (p *Pipeline) ProcessQuery( var ttsErr error // goroutine 1: 消费 LLM token + 句子切分 + var tokenUsage *llm.TokenUsage wg.Add(1) go func() { defer wg.Done() defer close(sentenceCh) - fullText = p.consumeLLMStream(ctx, llmStream, req.RequestID, sender, splitter) + fullText, tokenUsage = p.consumeLLMStream(ctx, llmStream, req.RequestID, sender, splitter) }() // goroutine 2: TTS 合成(如果启用) @@ -205,13 +206,25 @@ func (p *Pipeline) ProcessQuery( // 发送 llm_done latency := time.Since(startTime).Milliseconds() - if err := sender.SendLLMDone(models.WsLLMDone{ + done := models.WsLLMDone{ Type: "llm_done", RequestID: req.RequestID, FullText: fullText, Model: p.model, LatencyMs: latency, - }); err != nil { + } + if tokenUsage != nil { + done.TokensUsed = struct { + Prompt int `json:"prompt"` + Completion int `json:"completion"` + Total int `json:"total"` + }{ + Prompt: tokenUsage.Prompt, + Completion: tokenUsage.Completion, + Total: tokenUsage.Total, + } + } + if err := sender.SendLLMDone(done); err != nil { log.Errorw("发送 llm_done 失败", "error", err) } @@ -225,33 +238,36 @@ func (p *Pipeline) ProcessQuery( } // consumeLLMStream 消费 LLM 流式输出,发送 llm_chunk 并进行句子切分。 +// 返回完整文本和 token 用量。 func (p *Pipeline) consumeLLMStream( ctx context.Context, stream <-chan llm.Chunk, requestID string, sender Sender, splitter *Splitter, -) string { +) (string, *llm.TokenUsage) { log := logger.Log var fullText strings.Builder + var tokenUsage *llm.TokenUsage for chunk := range stream { // 检查上下文是否已取消 select { case <-ctx.Done(): log.Infow("LLM 流被中断", "request_id", requestID) - return fullText.String() + return fullText.String(), tokenUsage default: } if chunk.Done { - // 流结束 + // 流结束,记录 token 用量 if chunk.TokensUsed != nil { + tokenUsage = chunk.TokensUsed log.Infow("LLM 用量统计", "request_id", requestID, - "prompt_tokens", chunk.TokensUsed.Prompt, - "completion_tokens", chunk.TokensUsed.Completion, - "total_tokens", chunk.TokensUsed.Total, + "prompt_tokens", tokenUsage.Prompt, + "completion_tokens", tokenUsage.Completion, + "total_tokens", tokenUsage.Total, ) } break @@ -277,7 +293,7 @@ func (p *Pipeline) consumeLLMStream( // 刷新切分器中的剩余文本 splitter.Flush() - return fullText.String() + return fullText.String(), tokenUsage } // synthesizeTTS 从句子 channel 读取文本,进行 TTS 合成并发送音频。 -- 2.49.1