mirror of
https://github.com/CJackHwang/ds2api.git
synced 2026-05-16 22:25:15 +08:00
Merge pull request #16 from CJackHwang/codex/analyze-non-streaming-model-output
Unify non-stream parsing with SSE parser
This commit is contained in:
161
routes/openai.py
161
routes/openai.py
@@ -453,107 +453,84 @@ IMPORTANT: If calling tools, output ONLY the JSON. The response must start with
|
|||||||
|
|
||||||
def collect_data():
|
def collect_data():
|
||||||
nonlocal result
|
nonlocal result
|
||||||
ptype = "text"
|
current_fragment_type = "thinking" if thinking_enabled else "text"
|
||||||
try:
|
try:
|
||||||
for raw_line in deepseek_resp.iter_lines():
|
for raw_line in deepseek_resp.iter_lines():
|
||||||
try:
|
chunk = parse_deepseek_sse_line(raw_line)
|
||||||
line = raw_line.decode("utf-8")
|
if not chunk:
|
||||||
except Exception as e:
|
continue
|
||||||
logger.warning(f"[chat_completions] 解码失败: {e}")
|
if chunk.get("type") == "done":
|
||||||
if ptype == "thinking":
|
|
||||||
think_list.append("解码失败,请稍候再试")
|
|
||||||
else:
|
|
||||||
text_list.append("解码失败,请稍候再试")
|
|
||||||
data_queue.put(None)
|
data_queue.put(None)
|
||||||
break
|
break
|
||||||
if not line:
|
try:
|
||||||
continue
|
contents, is_finished, new_fragment_type = parse_sse_chunk_for_content(
|
||||||
if line.startswith("data:"):
|
chunk, thinking_enabled, current_fragment_type
|
||||||
data_str = line[5:].strip()
|
)
|
||||||
if data_str == "[DONE]":
|
current_fragment_type = new_fragment_type
|
||||||
data_queue.put(None)
|
if is_finished:
|
||||||
break
|
final_reasoning = "".join(think_list)
|
||||||
try:
|
final_content = "".join(text_list)
|
||||||
chunk = json.loads(data_str)
|
prompt_tokens = len(final_prompt) // 4
|
||||||
if "v" in chunk:
|
reasoning_tokens = len(final_reasoning) // 4
|
||||||
v_value = chunk["v"]
|
completion_tokens = len(final_content) // 4
|
||||||
if "p" in chunk and chunk.get("p") == "response/search_status":
|
|
||||||
continue
|
# 检测工具调用
|
||||||
if "p" in chunk and chunk.get("p") == "response/thinking_content":
|
detected_tools = []
|
||||||
ptype = "thinking"
|
finish_reason = "stop"
|
||||||
elif "p" in chunk and chunk.get("p") == "response/content":
|
if has_tools:
|
||||||
ptype = "text"
|
detected_tools = parse_tool_calls(final_content, [{"name": t.get("function", t).get("name")} for t in tools_requested])
|
||||||
if isinstance(v_value, str):
|
if detected_tools:
|
||||||
if search_enabled and v_value.startswith("[citation:"):
|
finish_reason = "tool_calls"
|
||||||
continue
|
|
||||||
if ptype == "thinking":
|
# 构建 message 对象
|
||||||
think_list.append(v_value)
|
message_obj = {
|
||||||
else:
|
"role": "assistant",
|
||||||
text_list.append(v_value)
|
"content": final_content if not detected_tools else None,
|
||||||
elif isinstance(v_value, list):
|
}
|
||||||
for item in v_value:
|
# 只有启用思考模式时才包含 reasoning_content
|
||||||
if item.get("p") == "status" and item.get("v") == "FINISHED":
|
if thinking_enabled and final_reasoning:
|
||||||
final_reasoning = "".join(think_list)
|
message_obj["reasoning_content"] = final_reasoning
|
||||||
final_content = "".join(text_list)
|
# 添加工具调用
|
||||||
prompt_tokens = len(final_prompt) // 4
|
if detected_tools:
|
||||||
reasoning_tokens = len(final_reasoning) // 4
|
tool_calls_data = format_openai_tool_calls(detected_tools)
|
||||||
completion_tokens = len(final_content) // 4
|
message_obj["tool_calls"] = tool_calls_data
|
||||||
|
message_obj["content"] = None
|
||||||
# 检测工具调用
|
|
||||||
detected_tools = []
|
result = {
|
||||||
finish_reason = "stop"
|
"id": completion_id,
|
||||||
if has_tools:
|
"object": "chat.completion",
|
||||||
detected_tools = parse_tool_calls(final_content, [{"name": t.get("function", t).get("name")} for t in tools_requested])
|
"created": created_time,
|
||||||
if detected_tools:
|
"model": model,
|
||||||
finish_reason = "tool_calls"
|
"choices": [{
|
||||||
|
"index": 0,
|
||||||
# 构建 message 对象
|
"message": message_obj,
|
||||||
message_obj = {
|
"finish_reason": finish_reason,
|
||||||
"role": "assistant",
|
}],
|
||||||
"content": final_content if not detected_tools else None,
|
"usage": {
|
||||||
}
|
"prompt_tokens": prompt_tokens,
|
||||||
# 只有启用思考模式时才包含 reasoning_content
|
"completion_tokens": reasoning_tokens + completion_tokens,
|
||||||
if thinking_enabled and final_reasoning:
|
"total_tokens": prompt_tokens + reasoning_tokens + completion_tokens,
|
||||||
message_obj["reasoning_content"] = final_reasoning
|
"completion_tokens_details": {"reasoning_tokens": reasoning_tokens},
|
||||||
# 添加工具调用
|
},
|
||||||
if detected_tools:
|
}
|
||||||
tool_calls_data = format_openai_tool_calls(detected_tools)
|
data_queue.put("DONE")
|
||||||
message_obj["tool_calls"] = tool_calls_data
|
return
|
||||||
message_obj["content"] = None
|
|
||||||
|
for content_text, content_type in contents:
|
||||||
result = {
|
if should_filter_citation(content_text, search_enabled):
|
||||||
"id": completion_id,
|
continue
|
||||||
"object": "chat.completion",
|
if content_type == "thinking":
|
||||||
"created": created_time,
|
think_list.append(content_text)
|
||||||
"model": model,
|
|
||||||
"choices": [{
|
|
||||||
"index": 0,
|
|
||||||
"message": message_obj,
|
|
||||||
"finish_reason": finish_reason,
|
|
||||||
}],
|
|
||||||
"usage": {
|
|
||||||
"prompt_tokens": prompt_tokens,
|
|
||||||
"completion_tokens": reasoning_tokens + completion_tokens,
|
|
||||||
"total_tokens": prompt_tokens + reasoning_tokens + completion_tokens,
|
|
||||||
"completion_tokens_details": {"reasoning_tokens": reasoning_tokens},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
data_queue.put("DONE")
|
|
||||||
return
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"[collect_data] 无法解析: {data_str}, 错误: {e}")
|
|
||||||
if ptype == "thinking":
|
|
||||||
think_list.append("解析失败,请稍候再试")
|
|
||||||
else:
|
else:
|
||||||
text_list.append("解析失败,请稍候再试")
|
text_list.append(content_text)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"[collect_data] 无法解析: {chunk}, 错误: {e}")
|
||||||
|
text_list.append("解析失败,请稍候再试")
|
||||||
data_queue.put(None)
|
data_queue.put(None)
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"[collect_data] 错误: {e}")
|
logger.warning(f"[collect_data] 错误: {e}")
|
||||||
if ptype == "thinking":
|
text_list.append("处理失败,请稍候再试")
|
||||||
think_list.append("处理失败,请稍候再试")
|
|
||||||
else:
|
|
||||||
text_list.append("处理失败,请稍候再试")
|
|
||||||
data_queue.put(None)
|
data_queue.put(None)
|
||||||
finally:
|
finally:
|
||||||
deepseek_resp.close()
|
deepseek_resp.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user