diff --git a/server_python/app.py b/server_python/app.py index 715d70f..d4c06b6 100644 --- a/server_python/app.py +++ b/server_python/app.py @@ -140,6 +140,8 @@ async def chat_endpoint(request: Request): temperature=temperature ) + full_content = "" # 用于累计完整内容 + for idx, response in enumerate(responses): if response.status_code == 200: # 检查响应是否包含预期的内容 @@ -156,6 +158,29 @@ async def chat_endpoint(request: Request): 'content' in response.output.choices[0]['message']): content = response.output.choices[0]['message']['content'] + + # 只有当内容发生变化时才发送增量 + if len(content) > len(full_content): + delta_content = content[len(full_content):] + full_content = content + + if delta_content.strip(): # 只有当有非空白新内容时才发送 + # 构建 SSE 数据块 + data = { + "id": f"chatcmpl-{uuid.uuid4()}", + "object": "chat.completion.chunk", + "created": int(datetime.utcnow().timestamp()), + "model": model, + "choices": [ + { + "index": 0, + "delta": {"content": delta_content}, + "finish_reason": None + } + ] + } + + yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n" # 否则尝试从 output.text 获取内容(DashScope特定格式) elif (hasattr(response, 'output') and response.output and @@ -163,26 +188,28 @@ async def chat_endpoint(request: Request): content = response.output.get('text') - if content: - # 构建 SSE 数据块 - data = { - "id": f"chatcmpl-{uuid.uuid4()}", - "object": "chat.completion.chunk", - "created": int(datetime.utcnow().timestamp()), - "model": model, - "choices": [ - { - "index": 0, - "delta": {"content": content} if content else {}, - "finish_reason": None - } - ] - } + # 只有当内容发生变化时才发送增量 + if len(content) > len(full_content): + delta_content = content[len(full_content):] + full_content = content - yield f"data: {json.dumps(data)}\n\n" - else: - # 如果响应中没有内容,跳过 - continue + if delta_content.strip(): # 只有当有非空白新内容时才发送 + # 构建 SSE 数据块 + data = { + "id": f"chatcmpl-{uuid.uuid4()}", + "object": "chat.completion.chunk", + "created": int(datetime.utcnow().timestamp()), + "model": model, + "choices": [ + { + "index": 0, + "delta": {"content": delta_content}, + "finish_reason": None + } + ] + } + + yield f"data: {json.dumps(data, ensure_ascii=False)}\n\n" else: # 错误处理 error_data = { @@ -193,7 +220,7 @@ async def chat_endpoint(request: Request): "code": response.code } } - yield f"data: {json.dumps(error_data)}\n\n" + yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n" break # 发送结束信号 @@ -210,9 +237,8 @@ async def chat_endpoint(request: Request): } ] } - yield f"data: {json.dumps(finish_data)}\n\n" + yield f"data: {json.dumps(finish_data, ensure_ascii=False)}\n\n" yield "data: [DONE]\n\n" - except Exception as e: error_data = { "error": { @@ -220,7 +246,7 @@ async def chat_endpoint(request: Request): "type": "server_error" } } - yield f"data: {json.dumps(error_data)}\n\n" + yield f"data: {json.dumps(error_data, ensure_ascii=False)}\n\n" return StreamingResponse(event_generator(), media_type="text/event-stream") else: @@ -272,7 +298,7 @@ async def chat_endpoint(request: Request): "totalTokens": response.usage.total_tokens } - return JSONResponse(content=chat_response) + return JSONResponse(content=chat_response, ensure_ascii=False) else: raise HTTPException( status_code=500, diff --git a/src/services/api.ts b/src/services/api.ts index 2751df1..7c63954 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -164,6 +164,12 @@ class ChatApi { if (match) { try { const data = JSON.parse(match[1]); + // 检查是否有完成原因,如果是完成则跳出 + const finishReason = data.choices?.[0]?.finish_reason; + if (finishReason && finishReason !== "null") { + break; + } + const content = data.choices?.[0]?.delta?.content; if (content) { yield content;