sehsapneb commited on
Commit
1e42396
·
verified ·
1 Parent(s): 39bacc7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +37 -78
app.py CHANGED
@@ -19,43 +19,36 @@ GPT_OSS_HEADERS = {
19
  'x-selected-model': 'gpt-oss-120b',
20
  }
21
 
22
- # 3. 根路由
23
  @app.route('/', methods=['GET'])
24
  def root():
25
- return jsonify({
26
- "message": "欢迎使用 GPT-OSS to OpenAI 格式代理API",
27
- "status": "ok",
28
- "api_endpoint": "/v1/chat/completions",
29
- "features": {
30
- "stream": "支持",
31
- "non_stream": "支持",
32
- "conditional_reasoning": "思考过程在流式模式下通过 <think> 标签显示"
33
- }
34
- })
 
35
 
36
  # 4. 核心API端点
37
  @app.route('/v1/chat/completions', methods=['POST'])
38
  def chat_completions_proxy():
39
  try:
40
  openai_request_data = request.json
41
- messages = openai_request_data.get("messages", [])
42
- user_prompt = next((m['content'] for m in reversed(messages) if m.get('role') == 'user'), None)
43
-
44
- if not user_prompt:
45
- return jsonify({"error": "在请求中未找到用户消息。"}), 400
46
-
47
  stream_requested = openai_request_data.get("stream", False)
48
  except Exception as e:
49
  return jsonify({"error": f"请求格式无效: {e}"}), 400
50
 
51
  request_headers = GPT_OSS_HEADERS.copy()
52
- if stream_requested:
53
- request_headers['x-show-reasoning'] = 'true'
54
- else:
55
- request_headers['x-show-reasoning'] = 'false'
56
 
57
- random_user_id = str(uuid.uuid4())
58
- gpt_oss_cookies = {'user_id': random_user_id}
59
  gpt_oss_payload = {
60
  "op": "threads.create",
61
  "params": {"input": {"text": user_prompt, "content": [{"type": "input_text", "text": user_prompt}]}}
@@ -69,81 +62,48 @@ def chat_completions_proxy():
69
  ) as response:
70
  response.raise_for_status()
71
  for line in response.iter_lines():
72
- if line:
73
- line_str = line.decode('utf-8')
74
- if line_str.startswith('data: '):
75
- json_data_str = line_str[6:]
76
- try:
77
- yield json.loads(json_data_str)
78
- except json.JSONDecodeError:
79
- continue
80
  except requests.exceptions.RequestException as e:
81
  raise IOError(f"与后端服务通信失败: {e}")
82
 
83
  if stream_requested:
84
  def stream_formatter():
85
  try:
86
- # --- 关键改动在这里 ---
87
- # 用于拼接所有思考过程的变量
88
- all_thoughts = []
89
-
90
  for gpt_oss_data in _internal_proxy_stream():
91
  event_type = gpt_oss_data.get('type')
 
92
 
93
- # 步骤1: 捕获并暂存所有思考过程
94
- if (event_type == 'thread.item_updated' and
95
- gpt_oss_data.get('update', {}).get('type') == 'cot.entry_added'):
96
  thought = gpt_oss_data['update']['entry']['content']
97
- all_thoughts.append(thought)
98
-
99
- # 步骤2: 当第一个文本片段出现时,一次性将所有思考过程格式化并发送
100
- if (event_type == 'thread.item_updated' and
101
- gpt_oss_data.get('update', {}).get('type') == 'assistant_message.content_part.text_delta' and
102
- all_thoughts): # 确保只在第一次发送
103
-
104
- # 格式化所有思考过程
105
- formatted_thoughts = "<think>\n"
106
- for i, t in enumerate(all_thoughts, 1):
107
- formatted_thoughts += f" Step {i}: {t}\n"
108
- formatted_thoughts += "</think>\n\n"
109
-
110
- # 构建一个标准的OpenAI流块来发送思考过程
111
- openai_chunk = {
112
- "id": f"chatcmpl-{str(uuid.uuid4())}", "object": "chat.completion.chunk",
113
- "created": int(time.time()), "model": "gpt-oss-120b",
114
- "choices": [{"index": 0, "delta": {"content": formatted_thoughts}, "finish_reason": None}]
115
- }
116
- yield f"data: {json.dumps(openai_chunk)}\n\n"
117
-
118
- # 清空思考过程,防止重复发送
119
- all_thoughts = []
120
 
121
- # 步骤3: 正常发送文本片段
122
- if (event_type == 'thread.item_updated' and
123
- gpt_oss_data.get('update', {}).get('type') == 'assistant_message.content_part.text_delta'):
124
  delta_content = gpt_oss_data['update'].get('delta', '')
125
- openai_chunk = {
126
- "id": f"chatcmpl-{str(uuid.uuid4())}", "object": "chat.completion.chunk",
127
- "created": int(time.time()), "model": "gpt-oss-120b",
128
- "choices": [{"index": 0, "delta": {"content": delta_content}, "finish_reason": None}]
129
- }
130
- yield f"data: {json.dumps(openai_chunk)}\n\n"
131
 
132
  yield "data: [DONE]\n\n"
133
  except IOError as e:
134
- error_chunk = {"error": str(e)}
135
- yield f"data: {json.dumps(error_chunk)}\n\n"
136
 
137
  return Response(stream_formatter(), mimetype='text/event-stream')
138
 
139
- else:
140
- # 非流式逻辑保持不变
141
  try:
142
  full_response_content = ""
143
  for gpt_oss_data in _internal_proxy_stream():
144
- event_type = gpt_oss_data.get('type')
145
- if (event_type == 'thread.item_updated' and
146
- gpt_oss_data.get('update', {}).get('type') == 'assistant_message.content_part.text_delta'):
147
  full_response_content += gpt_oss_data['update'].get('delta', '')
148
 
149
  final_response = {
@@ -153,7 +113,6 @@ def chat_completions_proxy():
153
  "usage": {"prompt_tokens": None, "completion_tokens": None, "total_tokens": None}
154
  }
155
  return jsonify(final_response)
156
-
157
  except IOError as e:
158
  return jsonify({"error": str(e)}), 500
159
 
 
19
  'x-selected-model': 'gpt-oss-120b',
20
  }
21
 
22
+ # 3. 根路由,用于健康检查
23
  @app.route('/', methods=['GET'])
24
  def root():
25
+ return jsonify({"message": "欢迎使用 GPT-OSS to OpenAI 格式代理API", "status": "ok"})
26
+
27
+ # 辅助函数:创建一个标准的OpenAI流式数据块
28
+ def create_openai_chunk(content, model="gpt-oss-120b", custom_id_prefix="chatcmpl"):
29
+ return {
30
+ "id": f"{custom_id_prefix}-{str(uuid.uuid4())}",
31
+ "object": "chat.completion.chunk",
32
+ "created": int(time.time()),
33
+ "model": model,
34
+ "choices": [{"index": 0, "delta": {"content": content}, "finish_reason": None}]
35
+ }
36
 
37
  # 4. 核心API端点
38
  @app.route('/v1/chat/completions', methods=['POST'])
39
  def chat_completions_proxy():
40
  try:
41
  openai_request_data = request.json
42
+ user_prompt = next((m['content'] for m in reversed(openai_request_data.get("messages", [])) if m.get('role') == 'user'), None)
43
+ if not user_prompt: return jsonify({"error": "未找到用户消息。"}), 400
 
 
 
 
44
  stream_requested = openai_request_data.get("stream", False)
45
  except Exception as e:
46
  return jsonify({"error": f"请求格式无效: {e}"}), 400
47
 
48
  request_headers = GPT_OSS_HEADERS.copy()
49
+ request_headers['x-show-reasoning'] = 'true' if stream_requested else 'false'
 
 
 
50
 
51
+ gpt_oss_cookies = {'user_id': str(uuid.uuid4())}
 
52
  gpt_oss_payload = {
53
  "op": "threads.create",
54
  "params": {"input": {"text": user_prompt, "content": [{"type": "input_text", "text": user_prompt}]}}
 
62
  ) as response:
63
  response.raise_for_status()
64
  for line in response.iter_lines():
65
+ if line and line.decode('utf-8').startswith('data: '):
66
+ try:
67
+ yield json.loads(line.decode('utf-8')[6:])
68
+ except json.JSONDecodeError: continue
 
 
 
 
69
  except requests.exceptions.RequestException as e:
70
  raise IOError(f"与后端服务通信失败: {e}")
71
 
72
  if stream_requested:
73
  def stream_formatter():
74
  try:
 
 
 
 
75
  for gpt_oss_data in _internal_proxy_stream():
76
  event_type = gpt_oss_data.get('type')
77
+ update_type = gpt_oss_data.get('update', {}).get('type')
78
 
79
+ # --- 关键改动:模拟思考过程的打字效果 ---
80
+ if event_type == 'thread.item_updated' and update_type == 'cot.entry_added':
 
81
  thought = gpt_oss_data['update']['entry']['content']
82
+ # 立即发送前缀
83
+ yield f"data: {json.dumps(create_openai_chunk('[思考中] '))}\n\n"
84
+ # 逐字流式传输思考内容
85
+ for char in thought:
86
+ yield f"data: {json.dumps(create_openai_chunk(char))}\n\n"
87
+ time.sleep(0.02) # 加入微小延迟,以获得更好的视觉效果
88
+ # 发送换行符以分隔
89
+ yield f"data: {json.dumps(create_openai_chunk('\\n\\n'))}\n\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ # 普通文本片段的流式传输(这部分本身就是逐字/逐词的)
92
+ if event_type == 'thread.item_updated' and update_type == 'assistant_message.content_part.text_delta':
 
93
  delta_content = gpt_oss_data['update'].get('delta', '')
94
+ yield f"data: {json.dumps(create_openai_chunk(delta_content))}\n\n"
 
 
 
 
 
95
 
96
  yield "data: [DONE]\n\n"
97
  except IOError as e:
98
+ yield f"data: {json.dumps({'error': str(e)})}\n\n"
 
99
 
100
  return Response(stream_formatter(), mimetype='text/event-stream')
101
 
102
+ else: # 非流式请求逻辑保持不变
 
103
  try:
104
  full_response_content = ""
105
  for gpt_oss_data in _internal_proxy_stream():
106
+ if gpt_oss_data.get('type') == 'thread.item_updated' and gpt_oss_data.get('update', {}).get('type') == 'assistant_message.content_part.text_delta':
 
 
107
  full_response_content += gpt_oss_data['update'].get('delta', '')
108
 
109
  final_response = {
 
113
  "usage": {"prompt_tokens": None, "completion_tokens": None, "total_tokens": None}
114
  }
115
  return jsonify(final_response)
 
116
  except IOError as e:
117
  return jsonify({"error": str(e)}), 500
118