75 lines
2.4 KiB
Python
75 lines
2.4 KiB
Python
import logging
|
||
import uuid
|
||
import json
|
||
|
||
from fastapi import APIRouter, HTTPException, status
|
||
from fastapi.responses import StreamingResponse
|
||
|
||
from config import QWEN_API_KEY, QWEN_UPSTREAM_URL
|
||
from models import ChatRequest
|
||
from utils import convert_prompt_to_messages, standard_sse_generator
|
||
|
||
router = APIRouter()
|
||
logger = logging.getLogger("proxy")
|
||
|
||
|
||
@router.post("/qwen/chat")
|
||
async def proxy_qwen_chat(request: ChatRequest):
|
||
|
||
# 为每个请求生成一个唯一的 ID,方便在日志中追踪
|
||
request_id = f"qwen-{uuid.uuid4()}"
|
||
|
||
# 检查 API Key 是否已在 config.py 中配置
|
||
if not QWEN_API_KEY:
|
||
raise HTTPException(
|
||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||
detail="Qwen API key is not configured.",
|
||
)
|
||
|
||
# 记录从客户端收到的原始请求体
|
||
client_request_body = request.model_dump()
|
||
logger.debug(
|
||
f"[{request_id}] === Qwen New Request ===\n"
|
||
f"[{request_id}] Client Request Body:\n"
|
||
f"{json.dumps(client_request_body, indent=2, ensure_ascii=False)}"
|
||
)
|
||
|
||
# 将 prompt 格式转换为 API 所需的 messages 格式
|
||
messages = convert_prompt_to_messages(request.prompt)
|
||
logger.debug(
|
||
f"[{request_id}] Agent Transformed Messages:\n"
|
||
f"{json.dumps(messages, indent=2, ensure_ascii=False)}"
|
||
)
|
||
|
||
# 构建发送到上游 API 的 payload
|
||
payload = {
|
||
"model": "qwen-plus", # 指定使用的模型
|
||
"messages": messages,
|
||
"stream": True,
|
||
"temperature": request.temperature,
|
||
"top_p": request.top_p,
|
||
"max_tokens": request.max_tokens,
|
||
}
|
||
|
||
# 如果客户端请求 web_search=True,则为 Qwen 启用网页搜索
|
||
if request.web_search is True:
|
||
payload["enable_search"] = True
|
||
logger.info(f"[{request_id}] Enabled web search for Qwen.")
|
||
|
||
logger.debug(
|
||
f"[{request_id}] Upstream Payload:\n"
|
||
f"{json.dumps(payload, indent=2, ensure_ascii=False)}"
|
||
)
|
||
|
||
# 请求头,包含认证信息
|
||
headers = {"Authorization": f"Bearer {QWEN_API_KEY}"}
|
||
|
||
# 返回一个流式响应对象
|
||
# standard_sse_generator 会处理与上游的通信和流式数据的转发
|
||
return StreamingResponse(
|
||
standard_sse_generator(
|
||
QWEN_UPSTREAM_URL, payload, headers, "Qwen", request_id
|
||
),
|
||
media_type="text/event-stream", # 指定 SSE 的 MIME 类型
|
||
)
|