|
|
@@ -12,46 +12,46 @@ from utils.logger import logger
|
|
|
|
|
|
class AIChatProxy:
|
|
|
"""AIChat 服务代理"""
|
|
|
-
|
|
|
+
|
|
|
def __init__(self):
|
|
|
self.base_url = settings.aichat.api_url.rstrip('/')
|
|
|
self.timeout = settings.aichat.timeout
|
|
|
-
|
|
|
+
|
|
|
def _get_auth_headers(self, request: Request) -> dict:
|
|
|
"""提取并转发认证 headers"""
|
|
|
headers = {}
|
|
|
-
|
|
|
+
|
|
|
# 支持多种 header 名称
|
|
|
for header_name in ["Authorization", "Token", "token"]:
|
|
|
header_value = request.headers.get(header_name, "").strip()
|
|
|
if header_value:
|
|
|
headers[header_name] = header_value
|
|
|
-
|
|
|
+
|
|
|
return headers
|
|
|
-
|
|
|
+
|
|
|
async def proxy_sse(
|
|
|
- self,
|
|
|
- path: str,
|
|
|
+ self,
|
|
|
+ path: str,
|
|
|
request: Request,
|
|
|
request_body: bytes
|
|
|
) -> StreamingResponse:
|
|
|
"""
|
|
|
代理 SSE 流式请求到 aichat
|
|
|
-
|
|
|
+
|
|
|
Args:
|
|
|
path: API 路径(如 /report/complete-flow)
|
|
|
request: FastAPI Request 对象
|
|
|
request_body: 请求体
|
|
|
-
|
|
|
+
|
|
|
Returns:
|
|
|
StreamingResponse
|
|
|
"""
|
|
|
url = f"{self.base_url}{path}"
|
|
|
headers = self._get_auth_headers(request)
|
|
|
headers["Content-Type"] = "application/json"
|
|
|
-
|
|
|
+
|
|
|
logger.info(f"[AIChat代理] SSE 请求: {url}")
|
|
|
-
|
|
|
+
|
|
|
async def stream_generator() -> AsyncGenerator[bytes, None]:
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=self.timeout) as client:
|
|
|
@@ -63,26 +63,27 @@ class AIChatProxy:
|
|
|
) as response:
|
|
|
if response.status_code != 200:
|
|
|
error_text = await response.aread()
|
|
|
- logger.error(f"[AIChat代理] SSE 请求失败: {response.status_code} {error_text.decode()}")
|
|
|
+ logger.error(
|
|
|
+ f"[AIChat代理] SSE 请求失败: {response.status_code} {error_text.decode()}")
|
|
|
error_msg = f"data: {{\"type\": \"online_error\", \"message\": \"AIChat服务返回异常: {response.status_code}\"}}\n\n"
|
|
|
yield error_msg.encode('utf-8')
|
|
|
yield b"data: {\"type\": \"completed\"}\n\n"
|
|
|
return
|
|
|
-
|
|
|
+
|
|
|
# 流式转发响应
|
|
|
async for chunk in response.aiter_bytes(chunk_size=4096):
|
|
|
yield chunk
|
|
|
-
|
|
|
+
|
|
|
except httpx.TimeoutException:
|
|
|
logger.error("[AIChat代理] SSE 请求超时")
|
|
|
- yield b"data: {\"type\": \"online_error\", \"message\": \"AIChat服务请求超时\"}\n\n"
|
|
|
+ yield f'data: {{"type": "online_error", "message": "AIChat服务请求超时"}}\n\n'.encode('utf-8')
|
|
|
yield b"data: {\"type\": \"completed\"}\n\n"
|
|
|
except Exception as e:
|
|
|
logger.error(f"[AIChat代理] SSE 请求异常: {e}")
|
|
|
- error_msg = f"data: {{\"type\": \"online_error\", \"message\": \"AIChat服务异常: {str(e)}\"}}\n\n"
|
|
|
+ yield f'data: {{"type": "online_error", "message": "AIChat服务请求超时"}}\n\n'.encode('utf-8')
|
|
|
yield error_msg.encode('utf-8')
|
|
|
yield b"data: {\"type\": \"completed\"}\n\n"
|
|
|
-
|
|
|
+
|
|
|
return StreamingResponse(
|
|
|
stream_generator(),
|
|
|
media_type="text/event-stream",
|
|
|
@@ -92,7 +93,7 @@ class AIChatProxy:
|
|
|
"Access-Control-Allow-Origin": "*",
|
|
|
}
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
async def proxy_json(
|
|
|
self,
|
|
|
path: str,
|
|
|
@@ -101,21 +102,21 @@ class AIChatProxy:
|
|
|
) -> JSONResponse:
|
|
|
"""
|
|
|
代理 JSON 请求到 aichat
|
|
|
-
|
|
|
+
|
|
|
Args:
|
|
|
path: API 路径(如 /report/update-ai-message)
|
|
|
request: FastAPI Request 对象
|
|
|
request_body: 请求体
|
|
|
-
|
|
|
+
|
|
|
Returns:
|
|
|
JSONResponse
|
|
|
"""
|
|
|
url = f"{self.base_url}{path}"
|
|
|
headers = self._get_auth_headers(request)
|
|
|
headers["Content-Type"] = "application/json"
|
|
|
-
|
|
|
+
|
|
|
logger.info(f"[AIChat代理] JSON 请求: {url}")
|
|
|
-
|
|
|
+
|
|
|
try:
|
|
|
async with httpx.AsyncClient(timeout=30) as client:
|
|
|
response = await client.post(
|
|
|
@@ -123,13 +124,13 @@ class AIChatProxy:
|
|
|
content=request_body,
|
|
|
headers=headers
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
# 转发响应
|
|
|
return JSONResponse(
|
|
|
content=response.json(),
|
|
|
status_code=response.status_code
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
except httpx.TimeoutException:
|
|
|
logger.error("[AIChat代理] JSON 请求超时")
|
|
|
return JSONResponse(
|
|
|
@@ -142,11 +143,11 @@ class AIChatProxy:
|
|
|
content={"success": False, "message": f"AIChat服务异常: {str(e)}"},
|
|
|
status_code=500
|
|
|
)
|
|
|
-
|
|
|
+
|
|
|
async def health_check(self) -> bool:
|
|
|
"""
|
|
|
检查 aichat 服务健康状态
|
|
|
-
|
|
|
+
|
|
|
Returns:
|
|
|
True 表示服务可用,False 表示不可用
|
|
|
"""
|