Files
FastapiAdmin/backend/app/plugin/module_ai/chat/service.py
T
zhangtao aad10384d4 refactor(ai): 重构AI模块目录结构并优化代码
将AI模块从module_application迁移到module_ai目录
新增聊天会话和消息的CRUD、服务和控制器
实现WebSocket聊天接口和前端组件
优化代码结构和性能,修复已知问题
2026-02-15 01:24:38 +08:00

98 lines
3.5 KiB
Python

from collections.abc import AsyncGenerator
from typing import Any
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai import ChatOpenAI
from app.config.setting import settings
from app.core.exceptions import CustomException
from app.core.logger import log
from .schema import ChatQuerySchema
class ChatService:
"""
聊天会话管理模块服务层
"""
@classmethod
async def chat_query(cls, query: ChatQuerySchema) -> AsyncGenerator[str, Any]:
"""
处理聊天查询
参数:
- query (ChatQuerySchema): 聊天查询模型
- config (AgentConfigSchema | None): 智能体配置模型
返回:
- AsyncGenerator[str, None]: 异步生成器,每次返回一个聊天响应
"""
llm = ChatOpenAI(
api_key=lambda: settings.OPENAI_API_KEY,
model=settings.OPENAI_MODEL,
base_url=settings.OPENAI_BASE_URL,
streaming=True,
)
system_prompt = (
"""你是一个有用的AI助手,可以帮助用户回答问题和提供帮助。请用中文回答用户的问题。"""
)
messages = [
SystemMessage(content=system_prompt),
HumanMessage(content=query.message),
]
try:
async for chunk in llm.astream(messages):
yield chunk.text
except Exception as e:
log.debug(f"关闭 LLM 客户端时发生异常(预期行为,服务可能正在关闭): {e}")
status_code = getattr(e, "status_code", None)
body = getattr(e, "body", None)
message = None
error_type = None
error_code = None
try:
if isinstance(body, dict) and "error" in body:
err = body.get("error") or {}
error_type = err.get("type")
error_code = err.get("code")
message = err.get("message")
except Exception:
raise CustomException(f"解析 OpenAI 错误失败: {e!s}")
text = str(e)
msg = message or text
if (
(error_code == "Arrearage")
or (error_type == "Arrearage")
or ("in good standing" in (msg or ""))
):
raise ValueError(
"账户欠费或结算异常,访问被拒绝。请检查账号状态或更换有效的 API Key。"
)
if status_code == 401 or "invalid api key" in msg.lower():
raise ValueError("鉴权失败,API Key 无效或已过期。请检查系统配置中的 API Key。")
if status_code == 403 or error_type in {
"PermissionDenied",
"permission_denied",
}:
raise ValueError("访问被拒绝,权限不足或账号受限。请检查账户权限设置。")
if status_code == 429 or error_type in {
"insufficient_quota",
"rate_limit_exceeded",
}:
raise ValueError("请求过于频繁或配额已用尽。请稍后重试或提升账户配额。")
if status_code == 400:
raise ValueError(f"请求参数错误或服务拒绝:{message or '请检查输入内容。'}")
if status_code in {500, 502, 503, 504}:
raise ValueError("服务暂时不可用,请稍后重试。")
raise CustomException(f"处理您的请求时出现错误:{msg}")