mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-10-08 02:36:07 +00:00
feat: 添加LangJin文档功能并优化代码结构
添加前端LangJin文档页面和路由 完善后端文档配置和错误处理 优化代码格式和导入顺序 更新系统菜单和配置项
This commit is contained in:
@@ -25,7 +25,6 @@ from .service import ChatMessageService, ChatSessionService
|
||||
AIRouter = APIRouter(route_class=OperationLogRoute, prefix="/ai", tags=["AI模块"])
|
||||
|
||||
|
||||
|
||||
@AIRouter.get(
|
||||
"/session/detail/{id}",
|
||||
summary="获取聊天会话详情",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import time
|
||||
from typing import Any, AsyncGenerator
|
||||
from collections.abc import AsyncGenerator
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, WebSocket
|
||||
from langchain_core.messages import HumanMessage, SystemMessage
|
||||
@@ -8,13 +9,13 @@ from langchain_openai import ChatOpenAI
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.config.setting import settings
|
||||
from app.core.database import async_db_session
|
||||
from app.core.dependencies import _verify_token
|
||||
from app.core.exceptions import CustomException
|
||||
from app.core.logger import log
|
||||
from app.core.router_class import OperationLogRoute
|
||||
from app.core.database import async_db_session
|
||||
|
||||
from .schema import ChatQuerySchema, ChatMessageCreateSchema
|
||||
from .schema import ChatMessageCreateSchema, ChatQuerySchema
|
||||
from .service import ChatMessageService
|
||||
|
||||
WS_AI = APIRouter(
|
||||
@@ -38,7 +39,7 @@ async def websocket_chat_controller(
|
||||
ws://127.0.0.1:8001/api/v1/application/ai/ws?token=xxx
|
||||
"""
|
||||
await websocket.accept()
|
||||
|
||||
|
||||
# 从查询参数获取token并认证
|
||||
token = websocket.query_params.get("token")
|
||||
auth = None
|
||||
@@ -50,10 +51,10 @@ async def websocket_chat_controller(
|
||||
auth = await _verify_token(token, db, redis)
|
||||
user_info = f"用户: {auth.user.username}" if auth and auth.user else "未认证用户"
|
||||
log.info(f"WebSocket连接已建立: {websocket.client} - {user_info}")
|
||||
|
||||
|
||||
# 保存用户信息到websocket状态
|
||||
websocket.state.auth = auth
|
||||
|
||||
|
||||
# 进入消息循环
|
||||
while True:
|
||||
data = await websocket.receive_text()
|
||||
@@ -61,7 +62,7 @@ async def websocket_chat_controller(
|
||||
message_data = json.loads(data)
|
||||
query = ChatQuerySchema(**message_data)
|
||||
log.info(f"收到聊天查询: {query}- 会话ID: {query.session_id}")
|
||||
|
||||
|
||||
# 保存用户消息到数据库(使用独立的事务)
|
||||
if query.session_id:
|
||||
async with async_db_session() as msg_db:
|
||||
@@ -77,17 +78,17 @@ async def websocket_chat_controller(
|
||||
)
|
||||
log.info(f"准备保存用户消息: session_id={query.session_id}, content={query.message[:50]}...")
|
||||
await ChatMessageService.create_service(auth=msg_auth, data=user_message_data)
|
||||
log.info(f"用户消息保存成功")
|
||||
log.info("用户消息保存成功")
|
||||
else:
|
||||
log.warning(f"未提供会话ID,跳过保存用户消息")
|
||||
|
||||
log.warning("未提供会话ID,跳过保存用户消息")
|
||||
|
||||
# 处理AI回复并保存
|
||||
full_response = ""
|
||||
async for chunk in chat_query(query=query):
|
||||
if chunk:
|
||||
await websocket.send_text(chunk)
|
||||
full_response += chunk
|
||||
|
||||
|
||||
# 保存AI回复到数据库(使用独立的事务)
|
||||
if query.session_id and full_response:
|
||||
async with async_db_session() as msg_db:
|
||||
@@ -103,7 +104,7 @@ async def websocket_chat_controller(
|
||||
)
|
||||
log.info(f"准备保存AI回复: session_id={query.session_id}, content={full_response[:50]}...")
|
||||
await ChatMessageService.create_service(auth=msg_auth, data=assistant_message_data)
|
||||
log.info(f"AI回复保存成功")
|
||||
log.info("AI回复保存成功")
|
||||
else:
|
||||
log.warning(f"未提供会话ID或AI回复为空,跳过保存AI回复: session_id={query.session_id}, full_response_length={len(full_response)}")
|
||||
except json.JSONDecodeError:
|
||||
@@ -127,80 +128,80 @@ async def websocket_chat_controller(
|
||||
async def chat_query(
|
||||
query: ChatQuerySchema
|
||||
) -> AsyncGenerator[str, Any]:
|
||||
"""
|
||||
处理聊天查询
|
||||
"""
|
||||
处理聊天查询
|
||||
|
||||
参数:
|
||||
- query (ChatQuerySchema): 聊天查询模型
|
||||
- config (AgentConfigSchema | None): 智能体配置模型
|
||||
参数:
|
||||
- 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,
|
||||
)
|
||||
返回:
|
||||
- AsyncGenerator[str, None]: 异步生成器,每次返回一个聊天响应
|
||||
"""
|
||||
|
||||
system_prompt = (
|
||||
"""你是一个有用的AI助手,可以帮助用户回答问题和提供帮助。请用中文回答用户的问题。"""
|
||||
)
|
||||
llm = ChatOpenAI(
|
||||
api_key=lambda: settings.OPENAI_API_KEY,
|
||||
model=settings.OPENAI_MODEL,
|
||||
base_url=settings.OPENAI_BASE_URL,
|
||||
streaming=True,
|
||||
)
|
||||
|
||||
messages = [
|
||||
SystemMessage(content=system_prompt),
|
||||
HumanMessage(content=query.message),
|
||||
]
|
||||
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:
|
||||
async for chunk in llm.astream(messages):
|
||||
yield chunk.text
|
||||
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}")
|
||||
|
||||
except Exception as e:
|
||||
log.debug(f"关闭 LLM 客户端时发生异常(预期行为,服务可能正在关闭): {e}")
|
||||
text = str(e)
|
||||
msg = message or text
|
||||
|
||||
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}")
|
||||
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("服务暂时不可用,请稍后重试。")
|
||||
|
||||
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}")
|
||||
raise CustomException(f"处理您的请求时出现错误:{msg}")
|
||||
|
||||
Reference in New Issue
Block a user