diff --git a/backend/apps/swagger/i18n.py b/backend/apps/swagger/i18n.py index fd4f3ea5..bd7b843d 100644 --- a/backend/apps/swagger/i18n.py +++ b/backend/apps/swagger/i18n.py @@ -54,6 +54,14 @@ def load_translation(lang: str) -> Dict[str, str]: "name": "system_ws", "description": f"{PLACEHOLDER_PREFIX}system_ws_api" }, + { + "name": "system_model", + "description": f"{PLACEHOLDER_PREFIX}system_model_api" + }, + { + "name": "system_assistant", + "description": f"{PLACEHOLDER_PREFIX}system_assistant_api" + }, { "name": "Table Relation", "description": f"{PLACEHOLDER_PREFIX}tr_api" }, diff --git a/backend/apps/swagger/locales/en.json b/backend/apps/swagger/locales/en.json index e40626ce..da2dfe49 100644 --- a/backend/apps/swagger/locales/en.json +++ b/backend/apps/swagger/locales/en.json @@ -69,6 +69,39 @@ "weight": "Weight (1: Admin, 0: Regular User)", + "system_model_api": "Model Configuration APIs", + "system_model_default": "Set Default Model", + "system_model_grid": "Get Model List", + "system_model_query": "Get Model Details", + "system_model_create": "Save Model", + "system_model_update": "Update Model", + "system_model_del": "Delete Model", + "model_name": "Name", + "model_type": "Type", + "base_model": "Base Model", + "supplier": "Operator", + "protocol": "Protocol", + "default_model": "Is Default", + "api_domain": "Base URL", + "api_key": "API Key", + "config_list": "Parameter List", + "arg_name": "Parameter Name", + "arg_val": "Parameter Value", + "arg_show_name": "Parameter Display Name", + + "system_assistant_api": "Assistant APIs", + "assistant_picture_api": "Get Pictures", + "assistant_ui_api": "Set Appearance", + "assistant_grid_api": "Get List", + "assistant_query_api": "Get Details", + "assistant_create_api": "Create", + "assistant_update_api": "Update", + "assistant_del_api": "Delete", + "assistant_domain": "Domain", + "assistant_type": "Assistant Type (0: Basic, 1: Advanced, 4: Page)", + "assistant_configuration": "Configuration", + "assistant_description": "Description", + "per_api": "Data Permission", "per_save": "Save Permission", "per_delete": "Delete Permission", diff --git a/backend/apps/swagger/locales/zh.json b/backend/apps/swagger/locales/zh.json index 6fc4f3c2..5f007836 100644 --- a/backend/apps/swagger/locales/zh.json +++ b/backend/apps/swagger/locales/zh.json @@ -69,6 +69,39 @@ "weight": "权重(1: 管理员, 0: 普通用户)", + "system_model_api": "模型配置api", + "system_model_default": "设置默认模型", + "system_model_grid": "查询模型列表", + "system_model_query": "查询模型详情", + "system_model_create": "保存模型", + "system_model_update": "更新模型", + "system_model_del": "删除模型", + "model_name": "名称", + "model_type": "类型", + "base_model": "基础模型", + "supplier": "运营商", + "protocol": "协议", + "default_model": "是否默认", + "api_domain": "基础 Url", + "api_key": "Api key", + "config_list": "参数列表", + "arg_name": "参数名称", + "arg_val": "参数值", + "arg_show_name": "参数展示名称", + + "system_assistant_api": "小助手api", + "assistant_picture_api": "查询图片", + "assistant_ui_api": "设置外观", + "assistant_grid_api": "查询列表", + "assistant_query_api": "查询详情", + "assistant_create_api": "创建", + "assistant_update_api": "修改", + "assistant_del_api": "删除", + "assistant_domain": "域名", + "assistant_type": "助手类型(0: 基础, 1: 高级, 4: 页面)", + "assistant_configuration": "配置", + "assistant_description": "描述", + "per_api": "数据权限", "per_save": "保存权限", "per_delete": "删除权限", diff --git a/backend/apps/system/api/aimodel.py b/backend/apps/system/api/aimodel.py index 6abba7a2..8f01a419 100644 --- a/backend/apps/system/api/aimodel.py +++ b/backend/apps/system/api/aimodel.py @@ -3,8 +3,9 @@ from fastapi.responses import StreamingResponse from apps.ai_model.model_factory import LLMConfig, LLMFactory +from apps.swagger.i18n import PLACEHOLDER_PREFIX from apps.system.schemas.ai_model_schema import AiModelConfigItem, AiModelCreator, AiModelEditor, AiModelGridItem -from fastapi import APIRouter, Query +from fastapi import APIRouter, Path, Query from sqlmodel import func, select, update from apps.system.models.system_model import AiModelDetail @@ -14,9 +15,9 @@ from common.utils.time import get_timestamp from common.utils.utils import SQLBotLogUtil, prepare_model_arg -router = APIRouter(tags=["system/aimodel"], prefix="/system/aimodel") +router = APIRouter(tags=["system_model"], prefix="/system/aimodel") -@router.post("/status") +@router.post("/status", include_in_schema=False) async def check_llm(info: AiModelCreator, trans: Trans): async def generate(): try: @@ -43,7 +44,7 @@ async def generate(): return StreamingResponse(generate(), media_type="application/x-ndjson") -@router.get("/default") +@router.get("/default", include_in_schema=False) async def check_default(session: SessionDep, trans: Trans): db_model = session.exec( select(AiModelDetail).where(AiModelDetail.default_model == True) @@ -51,9 +52,9 @@ async def check_default(session: SessionDep, trans: Trans): if not db_model: raise Exception(trans('i18n_llm.miss_default')) -@router.put("/default/{id}") +@router.put("/default/{id}", summary=f"{PLACEHOLDER_PREFIX}system_model_default", description=f"{PLACEHOLDER_PREFIX}system_model_default") @require_permissions(permission=SqlbotPermission(role=['admin'])) -async def set_default(session: SessionDep, id: int): +async def set_default(session: SessionDep, id: int = Path(description="ID")): db_model = session.get(AiModelDetail, id) if not db_model: raise ValueError(f"AiModelDetail with id {id} not found") @@ -71,11 +72,11 @@ async def set_default(session: SessionDep, id: int): session.rollback() raise e -@router.get("", response_model=list[AiModelGridItem]) +@router.get("", response_model=list[AiModelGridItem], summary=f"{PLACEHOLDER_PREFIX}system_model_grid", description=f"{PLACEHOLDER_PREFIX}system_model_grid") @require_permissions(permission=SqlbotPermission(role=['admin'])) async def query( session: SessionDep, - keyword: Union[str, None] = Query(default=None, max_length=255) + keyword: Union[str, None] = Query(default=None, max_length=255, description=f"{PLACEHOLDER_PREFIX}keyword") ): statement = select(AiModelDetail.id, AiModelDetail.name, @@ -90,10 +91,10 @@ async def query( items = session.exec(statement).all() return items -@router.get("/{id}", response_model=AiModelEditor) +@router.get("/{id}", response_model=AiModelEditor, summary=f"{PLACEHOLDER_PREFIX}system_model_query", description=f"{PLACEHOLDER_PREFIX}system_model_query") async def get_model_by_id( session: SessionDep, - id: int + id: int = Path(description="ID") ): db_model = session.get(AiModelDetail, id) if not db_model: @@ -115,7 +116,7 @@ async def get_model_by_id( data["config_list"] = config_list return AiModelEditor(**data) -@router.post("") +@router.post("", summary=f"{PLACEHOLDER_PREFIX}system_model_create", description=f"{PLACEHOLDER_PREFIX}system_model_create") @require_permissions(permission=SqlbotPermission(role=['admin'])) async def add_model( session: SessionDep, @@ -132,7 +133,7 @@ async def add_model( session.add(detail) session.commit() -@router.put("") +@router.put("", summary=f"{PLACEHOLDER_PREFIX}system_model_update", description=f"{PLACEHOLDER_PREFIX}system_model_update") @require_permissions(permission=SqlbotPermission(role=['admin'])) async def update_model( session: SessionDep, @@ -148,12 +149,12 @@ async def update_model( session.add(db_model) session.commit() -@router.delete("/{id}") +@router.delete("/{id}", summary=f"{PLACEHOLDER_PREFIX}system_model_del", description=f"{PLACEHOLDER_PREFIX}system_model_del") @require_permissions(permission=SqlbotPermission(role=['admin'])) async def delete_model( session: SessionDep, trans: Trans, - id: int + id: int = Path(description="ID") ): item = session.get(AiModelDetail, id) if item.default_model: diff --git a/backend/apps/system/api/assistant.py b/backend/apps/system/api/assistant.py index c6036142..e2980642 100644 --- a/backend/apps/system/api/assistant.py +++ b/backend/apps/system/api/assistant.py @@ -3,11 +3,12 @@ from datetime import timedelta from typing import List, Optional -from fastapi import APIRouter, Form, HTTPException, Query, Request, Response, UploadFile +from fastapi import APIRouter, Form, HTTPException, Path, Query, Request, Response, UploadFile from fastapi.responses import StreamingResponse from sqlbot_xpack.file_utils import SQLBotFileUtils from sqlmodel import select +from apps.swagger.i18n import PLACEHOLDER_PREFIX from apps.system.crud.assistant import get_assistant_info from apps.system.crud.assistant_manage import dynamic_upgrade_cors, save from apps.system.models.system_model import AssistantModel @@ -19,10 +20,10 @@ from common.core.sqlbot_cache import clear_cache from common.utils.utils import get_origin_from_referer, origin_match_domain -router = APIRouter(tags=["system/assistant"], prefix="/system/assistant") +router = APIRouter(tags=["system_assistant"], prefix="/system/assistant") -@router.get("/info/{id}") +@router.get("/info/{id}", include_in_schema=False) async def info(request: Request, response: Response, session: SessionDep, trans: Trans, id: int) -> AssistantModel: if not id: raise Exception('miss assistant id') @@ -42,7 +43,7 @@ async def info(request: Request, response: Response, session: SessionDep, trans: return db_model -@router.get("/app/{appId}") +@router.get("/app/{appId}", include_in_schema=False) async def getApp(request: Request, response: Response, session: SessionDep, trans: Trans, appId: str) -> AssistantModel: if not appId: raise Exception('miss assistant appId') @@ -61,7 +62,7 @@ async def getApp(request: Request, response: Response, session: SessionDep, tran return db_model -@router.get("/validator", response_model=AssistantValidator) +@router.get("/validator", response_model=AssistantValidator, include_in_schema=False) async def validator(session: SessionDep, id: int, virtual: Optional[int] = Query(None)): if not id: raise Exception('miss assistant id') @@ -86,8 +87,8 @@ async def validator(session: SessionDep, id: int, virtual: Optional[int] = Query return AssistantValidator(True, True, True, access_token) -@router.get('/picture/{file_id}') -async def picture(file_id: str): +@router.get('/picture/{file_id}', summary=f"{PLACEHOLDER_PREFIX}assistant_picture_api", description=f"{PLACEHOLDER_PREFIX}assistant_picture_api") +async def picture(file_id: str = Path(description="file_id")): file_path = SQLBotFileUtils.get_file_path(file_id=file_id) if not os.path.exists(file_path): raise HTTPException(status_code=404, detail="File not found") @@ -104,7 +105,7 @@ def iterfile(): return StreamingResponse(iterfile(), media_type=media_type) -@router.patch('/ui') +@router.patch('/ui', summary=f"{PLACEHOLDER_PREFIX}assistant_ui_api", description=f"{PLACEHOLDER_PREFIX}assistant_ui_api") async def ui(session: SessionDep, data: str = Form(), files: List[UploadFile] = []): json_data = json.loads(data) uiSchema = AssistantUiSchema(**json_data) @@ -152,26 +153,26 @@ async def clear_ui_cache(id: int): pass -@router.get("", response_model=list[AssistantModel]) +@router.get("", response_model=list[AssistantModel], summary=f"{PLACEHOLDER_PREFIX}assistant_grid_api", description=f"{PLACEHOLDER_PREFIX}assistant_grid_api") async def query(session: SessionDep): list_result = session.exec(select(AssistantModel).where(AssistantModel.type != 4).order_by(AssistantModel.name, AssistantModel.create_time)).all() return list_result -@router.get("/advanced_application", response_model=list[AssistantModel]) +@router.get("/advanced_application", response_model=list[AssistantModel], include_in_schema=False) async def query_advanced_application(session: SessionDep): list_result = session.exec(select(AssistantModel).where(AssistantModel.type == 1).order_by(AssistantModel.name, AssistantModel.create_time)).all() return list_result -@router.post("") +@router.post("", summary=f"{PLACEHOLDER_PREFIX}assistant_create_api", description=f"{PLACEHOLDER_PREFIX}assistant_create_api") async def add(request: Request, session: SessionDep, creator: AssistantBase): await save(request, session, creator) -@router.put("") +@router.put("", summary=f"{PLACEHOLDER_PREFIX}assistant_update_api", description=f"{PLACEHOLDER_PREFIX}assistant_update_api") @clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="editor.id") async def update(request: Request, session: SessionDep, editor: AssistantDTO): id = editor.id @@ -185,8 +186,8 @@ async def update(request: Request, session: SessionDep, editor: AssistantDTO): dynamic_upgrade_cors(request=request, session=session) -@router.get("/{id}", response_model=AssistantModel) -async def get_one(session: SessionDep, id: int): +@router.get("/{id}", response_model=AssistantModel, summary=f"{PLACEHOLDER_PREFIX}assistant_query_api", description=f"{PLACEHOLDER_PREFIX}assistant_query_api") +async def get_one(session: SessionDep, id: int = Path(description="ID")): db_model = await get_assistant_info(session=session, assistant_id=id) if not db_model: raise ValueError(f"AssistantModel with id {id} not found") @@ -194,9 +195,9 @@ async def get_one(session: SessionDep, id: int): return db_model -@router.delete("/{id}") +@router.delete("/{id}", response_model=AssistantModel, summary=f"{PLACEHOLDER_PREFIX}assistant_del_api", description=f"{PLACEHOLDER_PREFIX}assistant_del_api") @clear_cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="id") -async def delete(request: Request, session: SessionDep, id: int): +async def delete(request: Request, session: SessionDep, id: int = Path(description="ID")): db_model = session.get(AssistantModel, id) if not db_model: raise ValueError(f"AssistantModel with id {id} not found") diff --git a/backend/apps/system/schemas/ai_model_schema.py b/backend/apps/system/schemas/ai_model_schema.py index 8b5946bf..019aa358 100644 --- a/backend/apps/system/schemas/ai_model_schema.py +++ b/backend/apps/system/schemas/ai_model_schema.py @@ -1,29 +1,30 @@ from typing import List -from pydantic import BaseModel +from pydantic import BaseModel, Field +from apps.swagger.i18n import PLACEHOLDER_PREFIX from common.core.schemas import BaseCreatorDTO class AiModelItem(BaseModel): - name: str - model_type: int - base_model: str - supplier: int - protocol: int - default_model: bool = False + name: str = Field(description=f"{PLACEHOLDER_PREFIX}model_name") + model_type: int = Field(description=f"{PLACEHOLDER_PREFIX}model_type") + base_model: str = Field(description=f"{PLACEHOLDER_PREFIX}base_model") + supplier: int = Field(description=f"{PLACEHOLDER_PREFIX}supplier") + protocol: int = Field(description=f"{PLACEHOLDER_PREFIX}protocol") + default_model: bool = Field(default=False, description=f"{PLACEHOLDER_PREFIX}default_model") class AiModelGridItem(AiModelItem, BaseCreatorDTO): pass class AiModelConfigItem(BaseModel): - key: str - val: object - name: str + key: str = Field(description=f"{PLACEHOLDER_PREFIX}arg_name") + val: object = Field(description=f"{PLACEHOLDER_PREFIX}arg_val") + name: str = Field(description=f"{PLACEHOLDER_PREFIX}arg_show_name") class AiModelCreator(AiModelItem): - api_domain: str - api_key: str - config_list: List[AiModelConfigItem] + api_domain: str = Field(description=f"{PLACEHOLDER_PREFIX}api_domain") + api_key: str = Field(description=f"{PLACEHOLDER_PREFIX}api_key") + config_list: List[AiModelConfigItem] = Field(description=f"{PLACEHOLDER_PREFIX}config_list") class AiModelEditor(AiModelCreator, BaseCreatorDTO): pass \ No newline at end of file diff --git a/backend/apps/system/schemas/system_schema.py b/backend/apps/system/schemas/system_schema.py index b23361e9..67d66e1d 100644 --- a/backend/apps/system/schemas/system_schema.py +++ b/backend/apps/system/schemas/system_schema.py @@ -103,11 +103,11 @@ class UserInfoDTO(UserEditor): class AssistantBase(BaseModel): - name: str - domain: str - type: int = 0 # 0普通小助手 1高级 4页面嵌入 - configuration: Optional[str] = None - description: Optional[str] = None + name: str = Field(description=f"{PLACEHOLDER_PREFIX}model_name") + domain: str = Field(description=f"{PLACEHOLDER_PREFIX}assistant_domain") + type: int = Field(default=0, description=f"{PLACEHOLDER_PREFIX}assistant_type") # 0普通小助手 1高级 4页面嵌入 + configuration: Optional[str] = Field(default=None, description=f"{PLACEHOLDER_PREFIX}assistant_configuration") + description: Optional[str] = Field(default=None, description=f"{PLACEHOLDER_PREFIX}assistant_description") class AssistantDTO(AssistantBase, BaseCreatorDTO):