Spaces:
Running
Running
Upload 9 files
Browse files- app.py +5 -11
- src/model_tester.py +12 -31
app.py
CHANGED
|
@@ -88,18 +88,12 @@ async def chat_completions(request: ChatCompletionRequest):
|
|
| 88 |
|
| 89 |
async def stream_chat(model_hint: Optional[str], messages: list):
|
| 90 |
# 直接代理OpenRouter的流式响应
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
| 95 |
yield "data: [DONE]\n\n"
|
| 96 |
-
return
|
| 97 |
-
|
| 98 |
-
# 直接转发流式数据
|
| 99 |
-
async for chunk in stream:
|
| 100 |
-
yield chunk.decode() if isinstance(chunk, bytes) else chunk
|
| 101 |
-
|
| 102 |
-
yield "data: [DONE]\n\n"
|
| 103 |
|
| 104 |
|
| 105 |
@fastapi_app.get("/health")
|
|
|
|
| 88 |
|
| 89 |
async def stream_chat(model_hint: Optional[str], messages: list):
|
| 90 |
# 直接代理OpenRouter的流式响应
|
| 91 |
+
try:
|
| 92 |
+
async for chunk in model_tester.chat_completion_stream(model_hint, messages):
|
| 93 |
+
yield chunk.decode() if isinstance(chunk, bytes) else chunk
|
| 94 |
+
except Exception as e:
|
| 95 |
+
yield f'data: {{"error": "{str(e)}"}}\n\n'
|
| 96 |
yield "data: [DONE]\n\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
|
| 98 |
|
| 99 |
@fastapi_app.get("/health")
|
src/model_tester.py
CHANGED
|
@@ -145,8 +145,8 @@ class ModelTester:
|
|
| 145 |
model_id: str,
|
| 146 |
api_key: str,
|
| 147 |
messages: List[Dict[str, str]]
|
| 148 |
-
)
|
| 149 |
-
"""发送流式请求到OpenRouter"""
|
| 150 |
url = "https://openrouter.ai/api/v1/chat/completions"
|
| 151 |
payload = {
|
| 152 |
"model": model_id,
|
|
@@ -159,26 +159,9 @@ class ModelTester:
|
|
| 159 |
"Content-Type": "application/json"
|
| 160 |
}
|
| 161 |
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
if response.status == 200:
|
| 166 |
-
return {
|
| 167 |
-
"success": True,
|
| 168 |
-
"model": model_id,
|
| 169 |
-
"stream": response.content,
|
| 170 |
-
"method": "direct"
|
| 171 |
-
}
|
| 172 |
-
else:
|
| 173 |
-
body = await response.text()
|
| 174 |
-
return {
|
| 175 |
-
"success": False,
|
| 176 |
-
"model": model_id,
|
| 177 |
-
"error": f"HTTP {response.status}: {body[:100]}",
|
| 178 |
-
"method": "direct"
|
| 179 |
-
}
|
| 180 |
-
except Exception as e:
|
| 181 |
-
return {"success": False, "model": model_id, "error": str(e), "method": "direct"}
|
| 182 |
|
| 183 |
async def try_model_direct(
|
| 184 |
self,
|
|
@@ -399,7 +382,7 @@ class ModelTester:
|
|
| 399 |
return self.scan_all_models()
|
| 400 |
|
| 401 |
async def chat_completion_stream(self, model_hint: Optional[str], messages: List[Dict[str, str]]):
|
| 402 |
-
"""流式聊天 - 返回
|
| 403 |
api_keys = config.get_api_keys()
|
| 404 |
api_key = random.choice(api_keys)
|
| 405 |
|
|
@@ -408,9 +391,9 @@ class ModelTester:
|
|
| 408 |
full_model_id = self.find_model_in_list(model_hint)
|
| 409 |
if full_model_id:
|
| 410 |
async with aiohttp.ClientSession() as session:
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
|
| 415 |
# 方案2:从列表中找到可用模型
|
| 416 |
self.refresh_model_list()
|
|
@@ -428,8 +411,6 @@ class ModelTester:
|
|
| 428 |
|
| 429 |
async with aiohttp.ClientSession() as session:
|
| 430 |
for model_id in candidates:
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
return None, None
|
|
|
|
| 145 |
model_id: str,
|
| 146 |
api_key: str,
|
| 147 |
messages: List[Dict[str, str]]
|
| 148 |
+
):
|
| 149 |
+
"""发送流式请求到OpenRouter,返回流式迭代器"""
|
| 150 |
url = "https://openrouter.ai/api/v1/chat/completions"
|
| 151 |
payload = {
|
| 152 |
"model": model_id,
|
|
|
|
| 159 |
"Content-Type": "application/json"
|
| 160 |
}
|
| 161 |
|
| 162 |
+
async with session.post(url, json=payload, headers=headers, timeout=aiohttp.ClientTimeout(total=120)) as response:
|
| 163 |
+
async for line in response.content:
|
| 164 |
+
yield line
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
async def try_model_direct(
|
| 167 |
self,
|
|
|
|
| 382 |
return self.scan_all_models()
|
| 383 |
|
| 384 |
async def chat_completion_stream(self, model_hint: Optional[str], messages: List[Dict[str, str]]):
|
| 385 |
+
"""流式聊天 - 返回生成器"""
|
| 386 |
api_keys = config.get_api_keys()
|
| 387 |
api_key = random.choice(api_keys)
|
| 388 |
|
|
|
|
| 391 |
full_model_id = self.find_model_in_list(model_hint)
|
| 392 |
if full_model_id:
|
| 393 |
async with aiohttp.ClientSession() as session:
|
| 394 |
+
async for chunk in self.try_model_direct_stream(session, full_model_id, api_key, messages):
|
| 395 |
+
yield chunk
|
| 396 |
+
return
|
| 397 |
|
| 398 |
# 方案2:从列表中找到可用模型
|
| 399 |
self.refresh_model_list()
|
|
|
|
| 411 |
|
| 412 |
async with aiohttp.ClientSession() as session:
|
| 413 |
for model_id in candidates:
|
| 414 |
+
async for chunk in self.try_model_direct_stream(session, model_id, api_key, messages):
|
| 415 |
+
yield chunk
|
| 416 |
+
return
|
|
|
|
|
|