debug: 修复流式传输语句重复的问题
This commit is contained in:
parent
485b07c12f
commit
a8f631a034
|
|
@ -140,6 +140,8 @@ async def chat_endpoint(request: Request):
|
||||||
temperature=temperature
|
temperature=temperature
|
||||||
)
|
)
|
||||||
|
|
||||||
|
full_content = "" # 用于累计完整内容
|
||||||
|
|
||||||
for idx, response in enumerate(responses):
|
for idx, response in enumerate(responses):
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
# 检查响应是否包含预期的内容
|
# 检查响应是否包含预期的内容
|
||||||
|
|
@ -156,6 +158,29 @@ async def chat_endpoint(request: Request):
|
||||||
'content' in response.output.choices[0]['message']):
|
'content' in response.output.choices[0]['message']):
|
||||||
|
|
||||||
content = response.output.choices[0]['message']['content']
|
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特定格式)
|
# 否则尝试从 output.text 获取内容(DashScope特定格式)
|
||||||
elif (hasattr(response, 'output') and
|
elif (hasattr(response, 'output') and
|
||||||
response.output and
|
response.output and
|
||||||
|
|
@ -163,26 +188,28 @@ async def chat_endpoint(request: Request):
|
||||||
|
|
||||||
content = response.output.get('text')
|
content = response.output.get('text')
|
||||||
|
|
||||||
if content:
|
# 只有当内容发生变化时才发送增量
|
||||||
# 构建 SSE 数据块
|
if len(content) > len(full_content):
|
||||||
data = {
|
delta_content = content[len(full_content):]
|
||||||
"id": f"chatcmpl-{uuid.uuid4()}",
|
full_content = content
|
||||||
"object": "chat.completion.chunk",
|
|
||||||
"created": int(datetime.utcnow().timestamp()),
|
|
||||||
"model": model,
|
|
||||||
"choices": [
|
|
||||||
{
|
|
||||||
"index": 0,
|
|
||||||
"delta": {"content": content} if content else {},
|
|
||||||
"finish_reason": None
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
yield f"data: {json.dumps(data)}\n\n"
|
if delta_content.strip(): # 只有当有非空白新内容时才发送
|
||||||
else:
|
# 构建 SSE 数据块
|
||||||
# 如果响应中没有内容,跳过
|
data = {
|
||||||
continue
|
"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:
|
else:
|
||||||
# 错误处理
|
# 错误处理
|
||||||
error_data = {
|
error_data = {
|
||||||
|
|
@ -193,7 +220,7 @@ async def chat_endpoint(request: Request):
|
||||||
"code": response.code
|
"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
|
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"
|
yield "data: [DONE]\n\n"
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_data = {
|
error_data = {
|
||||||
"error": {
|
"error": {
|
||||||
|
|
@ -220,7 +246,7 @@ async def chat_endpoint(request: Request):
|
||||||
"type": "server_error"
|
"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")
|
return StreamingResponse(event_generator(), media_type="text/event-stream")
|
||||||
else:
|
else:
|
||||||
|
|
@ -272,7 +298,7 @@ async def chat_endpoint(request: Request):
|
||||||
"totalTokens": response.usage.total_tokens
|
"totalTokens": response.usage.total_tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSONResponse(content=chat_response)
|
return JSONResponse(content=chat_response, ensure_ascii=False)
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
|
|
|
||||||
|
|
@ -164,6 +164,12 @@ class ChatApi {
|
||||||
if (match) {
|
if (match) {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(match[1]);
|
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;
|
const content = data.choices?.[0]?.delta?.content;
|
||||||
if (content) {
|
if (content) {
|
||||||
yield content;
|
yield content;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue