nanoppa commited on
Commit
022bf0c
·
verified ·
1 Parent(s): 9042813

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -178
app.py CHANGED
@@ -5,256 +5,210 @@ import json
5
  import time
6
  import os
7
  import re
 
8
 
9
- _COOKIES = os.environ.get("COOKIES", "")
 
10
 
 
11
  API_KEY = os.getenv("API_KEY", "linux.do")
 
 
12
 
13
  app = Flask(__name__)
14
 
15
  @app.before_request
16
  def check_api_key():
17
- key = request.headers.get("Authorization")
18
- if key != "Bearer "+API_KEY:
 
19
  return jsonify({"success": False, "message": "Unauthorized: Invalid API key"}), 403
20
 
21
  @app.route('/v1/models', methods=['GET'])
22
  def get_models():
23
- # 构建请求头
24
- headers = {
25
- "Content-Type": "application/json",
26
- "Cookie": _COOKIES
27
- }
28
- # 发送请求到Akash API
29
- response = requests.get(
30
- 'https://chat.akash.network/api/models',
31
- headers=headers
32
- )
33
  models_data = response.json()
34
- current_timestamp = int(time.time())
35
  converted_data = {
36
  "object": "list",
37
  "data": [
38
  {
39
  "id": model["id"],
40
  "object": "model",
41
- "created": current_timestamp,
42
  "owned_by": "openai" if "Meta" in model["id"] else "third_party",
43
  "permissions": [],
44
  "root": model["id"],
45
  "parent": None,
46
  "capabilities": {
47
- "temperature": model["temperature"],
48
- "top_p": model["top_p"]
49
  },
50
- "name": model["name"],
51
- "description": model["description"],
52
- "available": model["available"]
53
  }
54
  for model in models_data.get("models", [])
55
  ]
56
  }
57
- return converted_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  @app.route('/v1/chat/completions', methods=['POST'])
61
  def chat_completions():
62
- print("start")
63
  try:
64
- # 获取OpenAI格式的请求数据
65
- data = request.json
66
-
67
- # 生成唯一ID
68
  chat_id = str(uuid.uuid4()).replace('-', '')[:16]
69
-
70
- # 构建Akash格式的请求数据
71
  akash_data = {
72
  "id": chat_id,
73
  "messages": data.get('messages', []),
74
- "model": data.get('model', "DeepSeek-R1"),
75
  "system": data.get('system_message', "You are a helpful assistant."),
76
  "temperature": data.get('temperature', 0.6),
77
  "topP": data.get('top_p', 0.95)
78
  }
79
- # 构建请求头
80
- headers = {
81
- "Content-Type": "application/json",
82
- "Cookie": _COOKIES
83
- }
84
- _stream=data.get('stream', True)
85
- if data.get('model', "DeepSeek-R1") == "AkashGen":
86
- _stream = False
87
- # 发送请求到Akash API
88
- response = requests.post(
89
  'https://chat.akash.network/api/chat',
90
  json=akash_data,
91
  headers=headers,
92
- stream=_stream
93
  )
 
94
 
95
- print(response.text)
96
-
97
- def generate():
98
- content_buffer = ""
99
- for line in response.iter_lines():
100
- if not line:
101
- continue
102
-
103
- try:
104
- # 解析行数据,格式为 "type:json_data"
105
- line_str = line.decode('utf-8')
106
- msg_type, msg_data = line_str.split(':', 1)
107
-
108
- # 处理内容类型的消息
109
- if msg_type == '0':
110
- # 只去掉两边的双引号
111
- if msg_data.startswith('"') and msg_data.endswith('"'):
112
- msg_data = msg_data.replace('\\"', '"')
113
- msg_data = msg_data[1:-1]
114
- msg_data = msg_data.replace("\\n", "\n")
115
- content_buffer += msg_data
116
-
117
- # 构建 OpenAI 格式的响应块
118
- chunk = {
119
- "id": f"chatcmpl-{chat_id}",
120
- "object": "chat.completion.chunk",
121
- "created": int(time.time()),
122
- "model": data.get('model', "DeepSeek-R1"),
123
- "choices": [{
124
- "delta": {"content": msg_data},
125
- "index": 0,
126
- "finish_reason": None
127
- }]
128
- }
129
- yield f"data: {json.dumps(chunk)}\n\n"
130
-
131
- # 处理结束消息
132
- elif msg_type in ['e', 'd']:
133
- chunk = {
134
- "id": f"chatcmpl-{chat_id}",
135
- "object": "chat.completion.chunk",
136
- "created": int(time.time()),
137
- "model": data.get('model', "DeepSeek-R1"),
138
- "choices": [{
139
- "delta": {},
140
- "index": 0,
141
- "finish_reason": "stop"
142
- }]
143
- }
144
- yield f"data: {json.dumps(chunk)}\n\n"
145
- yield "data: [DONE]\n\n"
146
- break
147
-
148
- except Exception as e:
149
- print(f"Error processing line: {e}")
150
- continue
151
-
152
- if _stream == True:
153
  return Response(
154
- generate(),
155
  mimetype='text/event-stream',
156
  headers={
157
  'Cache-Control': 'no-cache',
158
- 'Connection': 'keep-alive',
159
- 'Content-Type': 'text/event-stream'
160
  }
161
  )
162
  else:
163
- if data.get('model', "DeepSeek-R1") != "AkashGen":
164
- text_matches = re.findall(r'0:"(.*?)"', response.text)
 
165
  parsed_text = "".join(text_matches)
166
- print(json.dumps({
167
- "object": "chat.completion",
168
- "created": int(time.time() * 1000),
169
- "model": data.get('model', "DeepSeek-R1"),
170
- "choices": [
171
- {
172
- "index": 0,
173
- "message": {
174
- "role": "user",
175
- "content": parsed_text
176
- },
177
- "finish_reason": "stop"
178
- }
179
- ]
180
- },ensure_ascii=False))
181
  return Response(
182
- json.dumps({
183
- "object": "chat.completion",
184
- "created": int(time.time() * 1000),
185
- "model": data.get('model', "DeepSeek-R1"),
186
- "choices": [
187
- {
188
- "index": 0,
189
- "message": {
190
- "role": "user",
191
- "content": parsed_text
192
- },
193
- "finish_reason": "stop"
194
- }
195
- ]
196
- },ensure_ascii=False),
197
- status=response.status_code,
198
- headers={
199
- 'Cache-Control': 'no-cache',
200
- 'Connection': 'keep-alive',
201
- 'Content-Type': 'application/json'
202
- }
203
  )
204
  else:
205
- match = re.search(r"jobId='([^']+)'", response.text)
206
- job_id = None
207
  if match:
208
  job_id = match.group(1)
209
- print("jobId:", job_id)
 
210
  while True:
211
  try:
212
- _img_response = requests.get(
213
- 'https://chat.akash.network/api/image-status?ids='+job_id,
214
  headers=headers
215
  )
216
- _data = _img_response.json()
217
- # 检查响应状态码是否为200
218
- if _data[0]["status"] == "completed":
219
- print("图片生成完成:", job_id)
 
 
 
 
 
 
 
 
 
 
 
 
220
  return Response(
221
- json.dumps({
222
- "object": "chat.completion",
223
- "created": int(time.time() * 1000),
224
- "model": data.get('model', "DeepSeek-R1"),
225
- "choices": [
226
- {
227
- "index": 0,
228
- "message": {
229
- "role": "user",
230
- "content": "根据您的描述,这里是一张���成的图片:\n\n![生成的图片]("+_data[0]['result']+")"
231
- },
232
- "finish_reason": "stop"
233
- }
234
- ]
235
- },ensure_ascii=False),
236
- status=response.status_code,
237
- headers={
238
- 'Cache-Control': 'no-cache',
239
- 'Connection': 'keep-alive',
240
- 'Content-Type': 'application/json'
241
- }
242
  )
243
  else:
244
- print("图片生成中:", job_id)
245
  except Exception as e:
246
- print("请求过程中出现异常:", e)
247
-
248
- # 每隔5秒请求一次
249
  time.sleep(5)
250
  else:
 
251
  return jsonify({"error": "当前官方服务异常"}), 500
252
-
253
-
254
-
255
  except Exception as e:
256
- print(e)
257
  return jsonify({"error": str(e)}), 500
258
 
259
  if __name__ == '__main__':
260
- app.run(host='0.0.0.0', port=5200,debug=True)
 
5
  import time
6
  import os
7
  import re
8
+ import logging
9
 
10
+ # 配置日志输出(可调整级别为DEBUG以获得更详细日志)
11
+ logging.basicConfig(level=logging.INFO)
12
 
13
+ _COOKIES = ""
14
  API_KEY = os.getenv("API_KEY", "linux.do")
15
+ if not API_KEY:
16
+ logging.warning("API_KEY 未设置!")
17
 
18
  app = Flask(__name__)
19
 
20
  @app.before_request
21
  def check_api_key():
22
+ auth = request.headers.get("Authorization", "")
23
+ if auth != f"Bearer {API_KEY}":
24
+ logging.warning("未经授权的访问尝试,传入的 key: %s", auth)
25
  return jsonify({"success": False, "message": "Unauthorized: Invalid API key"}), 403
26
 
27
  @app.route('/v1/models', methods=['GET'])
28
  def get_models():
29
+ logging.info("收到 /v1/models 请求")
30
+ headers = {"Content-Type": "application/json", "Cookie": _COOKIES}
31
+ response = requests.get('https://chat.akash.network/api/models', headers=headers)
 
 
 
 
 
 
 
32
  models_data = response.json()
33
+ current_timestamp = int(time.time())
34
  converted_data = {
35
  "object": "list",
36
  "data": [
37
  {
38
  "id": model["id"],
39
  "object": "model",
40
+ "created": current_timestamp,
41
  "owned_by": "openai" if "Meta" in model["id"] else "third_party",
42
  "permissions": [],
43
  "root": model["id"],
44
  "parent": None,
45
  "capabilities": {
46
+ "temperature": model.get("temperature"),
47
+ "top_p": model.get("top_p")
48
  },
49
+ "name": model.get("name"),
50
+ "description": model.get("description"),
51
+ "available": model.get("available")
52
  }
53
  for model in models_data.get("models", [])
54
  ]
55
  }
56
+ logging.info("返回 /v1/models 响应: %s", json.dumps(converted_data, ensure_ascii=False))
57
+ return jsonify(converted_data)
58
+
59
+ def build_chunk(chat_id, model, token=None, finish_reason=None):
60
+ """
61
+ 构造单个 chunk 数据,符合 OpenAI API 流式响应格式。
62
+ """
63
+ chunk = {
64
+ "id": f"chatcmpl-{chat_id}",
65
+ "object": "chat.completion.chunk",
66
+ "created": int(time.time()),
67
+ "model": model,
68
+ "choices": [{
69
+ "delta": {"content": token} if token is not None else {},
70
+ "index": 0,
71
+ "finish_reason": finish_reason
72
+ }]
73
+ }
74
+ return chunk
75
 
76
+ def generate_stream(akash_response, chat_id, model):
77
+ """
78
+ 解析 Akash 接口的流式响应数据,并生成符合 OpenAI API 格式的 chunk 数据。
79
+ """
80
+ for line in akash_response.iter_lines():
81
+ if not line:
82
+ continue
83
+ try:
84
+ line_str = line.decode('utf-8').strip()
85
+ parts = line_str.split(':', 1)
86
+ if len(parts) != 2:
87
+ logging.error("流数据格式异常: %s", line_str)
88
+ continue
89
+ msg_type, msg_data = parts
90
+ if msg_type == '0':
91
+ token = msg_data.strip()
92
+ if token.startswith('"') and token.endswith('"'):
93
+ token = token[1:-1].replace('\\"', '"')
94
+ token = token.replace("\\n", "\n")
95
+ chunk = build_chunk(chat_id, model, token=token, finish_reason=None)
96
+ logging.info("流式 chunk: %s", json.dumps(chunk, ensure_ascii=False))
97
+ yield f"data: {json.dumps(chunk, ensure_ascii=False)}\n\n"
98
+ elif msg_type in ['e', 'd']:
99
+ chunk = build_chunk(chat_id, model, finish_reason="stop")
100
+ logging.info("流式结束 chunk: %s", json.dumps(chunk, ensure_ascii=False))
101
+ yield f"data: {json.dumps(chunk, ensure_ascii=False)}\n\n"
102
+ yield "data: [DONE]\n\n"
103
+ break
104
+ except Exception as ex:
105
+ logging.error("处理流数据时出错: %s", ex)
106
+ continue
107
 
108
  @app.route('/v1/chat/completions', methods=['POST'])
109
  def chat_completions():
 
110
  try:
111
+ data = request.get_json()
112
+ logging.info("收到 /v1/chat/completions 请求: %s", json.dumps(data, ensure_ascii=False))
 
 
113
  chat_id = str(uuid.uuid4()).replace('-', '')[:16]
114
+ model = data.get('model', "DeepSeek-R1")
 
115
  akash_data = {
116
  "id": chat_id,
117
  "messages": data.get('messages', []),
118
+ "model": model,
119
  "system": data.get('system_message', "You are a helpful assistant."),
120
  "temperature": data.get('temperature', 0.6),
121
  "topP": data.get('top_p', 0.95)
122
  }
123
+ headers = {"Content-Type": "application/json", "Cookie": _COOKIES}
124
+ # 默认启用 stream 模式,但针对 AkashGen 模型关闭流式响应
125
+ stream_flag = data.get('stream', True)
126
+ if model == "AkashGen":
127
+ stream_flag = False
128
+
129
+ akash_response = requests.post(
 
 
 
130
  'https://chat.akash.network/api/chat',
131
  json=akash_data,
132
  headers=headers,
133
+ stream=stream_flag
134
  )
135
+ logging.info("Akash API 响应状态: %s", akash_response.status_code)
136
 
137
+ if stream_flag:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  return Response(
139
+ generate_stream(akash_response, chat_id, model),
140
  mimetype='text/event-stream',
141
  headers={
142
  'Cache-Control': 'no-cache',
143
+ 'Connection': 'keep-alive'
 
144
  }
145
  )
146
  else:
147
+ # 非流式响应处理
148
+ if model != "AkashGen":
149
+ text_matches = re.findall(r'0:"(.*?)"', akash_response.text)
150
  parsed_text = "".join(text_matches)
151
+ response_payload = {
152
+ "object": "chat.completion",
153
+ "created": int(time.time() * 1000),
154
+ "model": model,
155
+ "choices": [{
156
+ "index": 0,
157
+ "message": {"role": "assistant", "content": parsed_text},
158
+ "finish_reason": "stop"
159
+ }]
160
+ }
161
+ logging.info("非流式响应 payload: %s", json.dumps(response_payload, ensure_ascii=False))
 
 
 
 
162
  return Response(
163
+ json.dumps(response_payload, ensure_ascii=False),
164
+ status=akash_response.status_code,
165
+ mimetype='application/json'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  )
167
  else:
168
+ match = re.search(r"jobId='([^']+)'", akash_response.text)
 
169
  if match:
170
  job_id = match.group(1)
171
+ logging.info("AkashGen jobId: %s", job_id)
172
+ # 轮询图片生成状态
173
  while True:
174
  try:
175
+ img_response = requests.get(
176
+ f'https://chat.akash.network/api/image-status?ids={job_id}',
177
  headers=headers
178
  )
179
+ img_data = img_response.json()
180
+ if img_data and img_data[0]["status"] == "completed":
181
+ response_payload = {
182
+ "object": "chat.completion",
183
+ "created": int(time.time() * 1000),
184
+ "model": model,
185
+ "choices": [{
186
+ "index": 0,
187
+ "message": {
188
+ "role": "assistant",
189
+ "content": f"根据您的描述,这里是一张生成的图片:\n\n![生成的图片]({img_data[0]['result']})"
190
+ },
191
+ "finish_reason": "stop"
192
+ }]
193
+ }
194
+ logging.info("AkashGen 完成后的 payload: %s", json.dumps(response_payload, ensure_ascii=False))
195
  return Response(
196
+ json.dumps(response_payload, ensure_ascii=False),
197
+ status=akash_response.status_code,
198
+ mimetype='application/json'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  )
200
  else:
201
+ logging.info("图片生成中,jobId: %s", job_id)
202
  except Exception as e:
203
+ logging.error("请求图片状态异常: %s", e)
 
 
204
  time.sleep(5)
205
  else:
206
+ logging.error("未能解析到 jobId")
207
  return jsonify({"error": "当前官方服务异常"}), 500
208
+
 
 
209
  except Exception as e:
210
+ logging.exception("chat_completions 处理过程中出现异常:")
211
  return jsonify({"error": str(e)}), 500
212
 
213
  if __name__ == '__main__':
214
+ app.run(host='0.0.0.0', port=5200)