sehsapneb commited on
Commit
b7de6d6
·
verified ·
1 Parent(s): a920e80

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +19 -51
app.py CHANGED
@@ -4,10 +4,10 @@ import uuid
4
  import time
5
  from flask import Flask, request, jsonify, Response
6
 
7
- # --- 1. 初始化Flask应用 ---
8
  app = Flask(__name__)
9
 
10
- # --- 2. gpt-oss.com API的固定配置 (来自我们之前的分析) ---
11
  GPT_OSS_API_URL = "https://api.gpt-oss.com/chatkit"
12
  GPT_OSS_HEADERS = {
13
  'authority': 'api.gpt-oss.com',
@@ -16,48 +16,42 @@ GPT_OSS_HEADERS = {
16
  'origin': 'https://gpt-oss.com',
17
  'referer': 'https://gpt-oss.com/',
18
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
19
- 'x-selected-model': 'gpt-oss-120b', # 模型可以在此硬编码,或后续从请求中动态获取
20
  }
21
 
22
- # --- 3. 核心:创建OpenAI兼容的API端点 ---
 
 
 
 
 
 
 
 
 
23
  @app.route('/v1/chat/completions', methods=['POST'])
24
  def chat_completions_proxy():
25
- """
26
- 这个端点模仿OpenAI的 `/v1/chat/completions` 接口。
27
- 它接收OpenAI格式的请求,然后代理到gpt-oss.com。
28
- """
29
- # 按照要求,我们不验证API Key。可以直接忽略 request.headers['Authorization']。
30
-
31
- # (一) 解析客户端发来的OpenAI格式请求
32
  try:
33
  openai_request_data = request.json
34
- # 从消息列表中找到用户最新的提问,作为我们的提示词
35
  messages = openai_request_data.get("messages", [])
36
  user_prompt = next((m['content'] for m in reversed(messages) if m.get('role') == 'user'), None)
37
 
38
  if not user_prompt:
39
  return jsonify({"error": "在请求中未找到用户消息。"}), 400
40
 
41
- # 检查客户端是否请求了流式响应
42
  stream_requested = openai_request_data.get("stream", False)
43
-
44
  except Exception as e:
45
  return jsonify({"error": f"请求格式无效: {e}"}), 400
46
 
47
- # (二) 准备发往 gpt-oss.com API 的请求
48
- # 为每个独立的对话生成一个全新的随机user_id
49
  random_user_id = str(uuid.uuid4())
50
  gpt_oss_cookies = {'user_id': random_user_id}
51
- # 构建gpt-oss服务需要的特殊Payload
52
  gpt_oss_payload = {
53
  "op": "threads.create",
54
  "params": {"input": {"text": user_prompt, "content": [{"type": "input_text", "text": user_prompt}]}}
55
  }
56
 
57
- # (三) 定义一个“生成器”函数,用于处理和转换流式数据
58
  def generate_stream():
59
  try:
60
- # 向真正的后端服务发起流式请求
61
  with requests.post(
62
  GPT_OSS_API_URL,
63
  headers=GPT_OSS_HEADERS,
@@ -66,9 +60,8 @@ def chat_completions_proxy():
66
  stream=True,
67
  timeout=120
68
  ) as response:
69
- response.raise_for_status() # 如果状态码不是2xx,则抛出异常
70
 
71
- # (四) 核心翻译逻辑:逐行读取gpt-oss的响应,并转换为OpenAI格式
72
  for line in response.iter_lines():
73
  if line:
74
  line_str = line.decode('utf-8')
@@ -77,59 +70,34 @@ def chat_completions_proxy():
77
  try:
78
  gpt_oss_data = json.loads(json_data_str)
79
 
80
- # 我们只关心包含文本片段的事件
81
  event_type = gpt_oss_data.get('type')
82
  if (event_type == 'thread.item_updated' and
83
  gpt_oss_data.get('update', {}).get('type') == 'assistant_message.content_part.text_delta'):
84
 
85
  delta_content = gpt_oss_data['update'].get('delta', '')
86
-
87
- # 构建一个OpenAI流式响应的JSON块
88
  openai_chunk = {
89
  "id": f"chatcmpl-{str(uuid.uuid4())}",
90
  "object": "chat.completion.chunk",
91
  "created": int(time.time()),
92
  "model": "gpt-oss-120b",
93
- "choices": [
94
- {
95
- "index": 0,
96
- "delta": {
97
- "content": delta_content
98
- },
99
- "finish_reason": None
100
- }
101
- ]
102
  }
103
- # 使用SSE(服务器发送事件)格式 yield 出去
104
  yield f"data: {json.dumps(openai_chunk)}\n\n"
105
 
106
  except json.JSONDecodeError:
107
- continue # 忽略无法解析的行
108
 
109
- # (五) 流式传输结束后,发送一个表示结束的特殊标记
110
  yield "data: [DONE]\n\n"
111
-
112
  except requests.exceptions.RequestException as e:
113
  error_chunk = {"error": f"与后端服务通信失败: {e}"}
114
  yield f"data: {json.dumps(error_chunk)}\n\n"
115
 
116
- # (六) 根据客户端请求,返回流式响应或一次性完整响应
117
  if stream_requested:
118
- # 如果客户端要流式,就返回我们的生成器函数
119
  return Response(generate_stream(), mimetype='text/event-stream')
120
  else:
121
- # 如果客户端要一次性响应,我们就在服务器端拼接完整结果再返回
122
- # (注意:gpt-oss本身就是流式的,所以这个分支需要我们在服务器端缓存)
123
- full_response_content = ""
124
- for chunk in generate_stream():
125
- # 这里需要更复杂的解析逻辑来拼接,为简化起见,我们优先推荐使用流式
126
- pass # 简单实现:非流式模式暂不支持或需要更复杂的实现
127
- # 为了简单起见,我们主要支持流式,因为这是最高效的方式
128
  return jsonify({"error": "非流式响应目前不受支持,请在请求中设置 'stream': true"}), 501
129
 
130
-
131
- # --- 4. 启动应用 ---
132
  if __name__ == '__main__':
133
- # 在本地测试时,可以使用 app.run()
134
- # 部署到Gunicorn时,它会直接使用'app'这个实例
135
- app.run(debug=True, port=7860)
 
4
  import time
5
  from flask import Flask, request, jsonify, Response
6
 
7
+ # 1. 初始化Flask应用
8
  app = Flask(__name__)
9
 
10
+ # 2. gpt-oss.com API的固定配置
11
  GPT_OSS_API_URL = "https://api.gpt-oss.com/chatkit"
12
  GPT_OSS_HEADERS = {
13
  'authority': 'api.gpt-oss.com',
 
16
  'origin': 'https://gpt-oss.com',
17
  'referer': 'https://gpt-oss.com/',
18
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
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
+ })
30
+
31
+ # 4. 核心:创建OpenAI兼容的API端点
32
  @app.route('/v1/chat/completions', methods=['POST'])
33
  def chat_completions_proxy():
 
 
 
 
 
 
 
34
  try:
35
  openai_request_data = request.json
 
36
  messages = openai_request_data.get("messages", [])
37
  user_prompt = next((m['content'] for m in reversed(messages) if m.get('role') == 'user'), None)
38
 
39
  if not user_prompt:
40
  return jsonify({"error": "在请求中未找到用户消息。"}), 400
41
 
 
42
  stream_requested = openai_request_data.get("stream", False)
 
43
  except Exception as e:
44
  return jsonify({"error": f"请求格式无效: {e}"}), 400
45
 
 
 
46
  random_user_id = str(uuid.uuid4())
47
  gpt_oss_cookies = {'user_id': random_user_id}
 
48
  gpt_oss_payload = {
49
  "op": "threads.create",
50
  "params": {"input": {"text": user_prompt, "content": [{"type": "input_text", "text": user_prompt}]}}
51
  }
52
 
 
53
  def generate_stream():
54
  try:
 
55
  with requests.post(
56
  GPT_OSS_API_URL,
57
  headers=GPT_OSS_HEADERS,
 
60
  stream=True,
61
  timeout=120
62
  ) as response:
63
+ response.raise_for_status()
64
 
 
65
  for line in response.iter_lines():
66
  if line:
67
  line_str = line.decode('utf-8')
 
70
  try:
71
  gpt_oss_data = json.loads(json_data_str)
72
 
 
73
  event_type = gpt_oss_data.get('type')
74
  if (event_type == 'thread.item_updated' and
75
  gpt_oss_data.get('update', {}).get('type') == 'assistant_message.content_part.text_delta'):
76
 
77
  delta_content = gpt_oss_data['update'].get('delta', '')
 
 
78
  openai_chunk = {
79
  "id": f"chatcmpl-{str(uuid.uuid4())}",
80
  "object": "chat.completion.chunk",
81
  "created": int(time.time()),
82
  "model": "gpt-oss-120b",
83
+ "choices": [{"index": 0, "delta": {"content": delta_content}, "finish_reason": None}]
 
 
 
 
 
 
 
 
84
  }
 
85
  yield f"data: {json.dumps(openai_chunk)}\n\n"
86
 
87
  except json.JSONDecodeError:
88
+ continue
89
 
 
90
  yield "data: [DONE]\n\n"
 
91
  except requests.exceptions.RequestException as e:
92
  error_chunk = {"error": f"与后端服务通信失败: {e}"}
93
  yield f"data: {json.dumps(error_chunk)}\n\n"
94
 
 
95
  if stream_requested:
 
96
  return Response(generate_stream(), mimetype='text/event-stream')
97
  else:
 
 
 
 
 
 
 
98
  return jsonify({"error": "非流式响应目前不受支持,请在请求中设置 'stream': true"}), 501
99
 
100
+ # 5. 启动应用
 
101
  if __name__ == '__main__':
102
+ # 使用 gunicorn 部署时不会执行这里,但在本地测试时会用到
103
+ app.run(host='0.0.0.0', port=7860)