diff --git a/.gitignore b/.gitignore index 4fd5a94..254ae35 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Storage storage/ +backend/.vite/ # ---> Python # Byte-compiled / optimized / DLL files diff --git a/.vite/deps/_metadata.json b/.vite/deps/_metadata.json new file mode 100644 index 0000000..7b52a56 --- /dev/null +++ b/.vite/deps/_metadata.json @@ -0,0 +1,8 @@ +{ + "hash": "9f45c68f", + "configHash": "0e3c7f00", + "lockfileHash": "e3b0c442", + "browserHash": "3bfaa9a9", + "optimized": {}, + "chunks": {} +} \ No newline at end of file diff --git a/.vite/deps/package.json b/.vite/deps/package.json new file mode 100644 index 0000000..3dbc1ca --- /dev/null +++ b/.vite/deps/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/backend/app/api/models.py b/backend/app/api/models.py index 78a8216..f8d63ff 100644 --- a/backend/app/api/models.py +++ b/backend/app/api/models.py @@ -5,6 +5,7 @@ from app.core.database import get_db from app.core.security import encrypt_api_key from app.models.ai_model import AIModel from app.schemas.ai_model import AIModelCreate, AIModelUpdate, AIModelToggle, AIModelResponse +from app.services.ai_adapter import call_ai_model router = APIRouter(prefix="/models", tags=["AI模型管理"]) @@ -91,3 +92,24 @@ async def toggle_model(model_id: str, data: AIModelToggle, db: AsyncSession = De await db.flush() await db.refresh(model) return model + + +@router.post("/{model_id}/test") +async def test_model(model_id: str, db: AsyncSession = Depends(get_db)): + result = await db.execute(select(AIModel).where(AIModel.id == model_id)) + model = result.scalar_one_or_none() + if not model: + raise HTTPException(status_code=404, detail="模型不存在") + + model_config = { + "provider": model.provider, + "endpoint": model.endpoint, + "api_key": model.api_key, + "extra_params": model.extra_params, + } + + try: + response = await call_ai_model(model_config, "请用一句话介绍你自己。") + return {"success": True, "result": response} + except Exception as e: + return {"success": False, "error": str(e)} diff --git a/web/src/api/models.ts b/web/src/api/models.ts index 66b1fea..035de73 100644 --- a/web/src/api/models.ts +++ b/web/src/api/models.ts @@ -29,3 +29,8 @@ export async function toggleModel(id: string, is_enabled: boolean) { const { data } = await request.patch(`/models/${id}/toggle`, { is_enabled }); return data; } + +export async function testModel(id: string) { + const { data } = await request.post<{ success: boolean; result?: string; error?: string }>(`/models/${id}/test`); + return data; +} diff --git a/web/src/pages/ModelList.tsx b/web/src/pages/ModelList.tsx index b073a3d..6ecaaed 100644 --- a/web/src/pages/ModelList.tsx +++ b/web/src/pages/ModelList.tsx @@ -3,7 +3,7 @@ import { Table, Button, Modal, Form, Input, Select, Switch, Space, message, Popconfirm, Tag, } from "antd"; -import { PlusOutlined, EditOutlined, DeleteOutlined } from "@ant-design/icons"; +import { PlusOutlined, EditOutlined, DeleteOutlined, ExperimentOutlined } from "@ant-design/icons"; import type { AIModel } from "../types"; import * as modelApi from "../api/models"; @@ -110,6 +110,21 @@ export default function ModelList() { fetchModels(); }; + const handleTest = async (id: string, name: string) => { + message.loading({ content: `正在测试 ${name}...`, key: "test" }); + try { + const res = await modelApi.testModel(id); + if (res.success) { + message.success({ content: `${name} 测试通过`, key: "test" }); + Modal.info({ title: `测试结果 - ${name}`, content: res.result, width: 600 }); + } else { + message.error({ content: `测试失败: ${res.error}`, key: "test", duration: 5 }); + } + } catch (err: unknown) { + message.error({ content: err instanceof Error ? err.message : "测试失败", key: "test", duration: 5 }); + } + }; + const columns = [ { title: "名称", dataIndex: "name", key: "name", width: 150 }, { @@ -150,6 +165,12 @@ export default function ModelList() { width: 160, render: (_: unknown, record: AIModel) => ( +