feat: 模型测试功能 - 测试模型配置是否可用
- API: POST /api/v1/models/{id}/test 发送简单提示词验证模型连通性
- 前端: 模型列表新增测试按钮(实验图标),弹窗显示结果或错误详情
- 帮助用户快速定位配置问题(如 endpoint、api_key、model 参数错误)
This commit is contained in:
parent
ba2171e13e
commit
a8604ebc34
|
|
@ -1,5 +1,6 @@
|
||||||
# Storage
|
# Storage
|
||||||
storage/
|
storage/
|
||||||
|
backend/.vite/
|
||||||
|
|
||||||
# ---> Python
|
# ---> Python
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"hash": "9f45c68f",
|
||||||
|
"configHash": "0e3c7f00",
|
||||||
|
"lockfileHash": "e3b0c442",
|
||||||
|
"browserHash": "3bfaa9a9",
|
||||||
|
"optimized": {},
|
||||||
|
"chunks": {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ from app.core.database import get_db
|
||||||
from app.core.security import encrypt_api_key
|
from app.core.security import encrypt_api_key
|
||||||
from app.models.ai_model import AIModel
|
from app.models.ai_model import AIModel
|
||||||
from app.schemas.ai_model import AIModelCreate, AIModelUpdate, AIModelToggle, AIModelResponse
|
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模型管理"])
|
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.flush()
|
||||||
await db.refresh(model)
|
await db.refresh(model)
|
||||||
return 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)}
|
||||||
|
|
|
||||||
|
|
@ -29,3 +29,8 @@ export async function toggleModel(id: string, is_enabled: boolean) {
|
||||||
const { data } = await request.patch<AIModel>(`/models/${id}/toggle`, { is_enabled });
|
const { data } = await request.patch<AIModel>(`/models/${id}/toggle`, { is_enabled });
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function testModel(id: string) {
|
||||||
|
const { data } = await request.post<{ success: boolean; result?: string; error?: string }>(`/models/${id}/test`);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {
|
||||||
Table, Button, Modal, Form, Input, Select, Switch,
|
Table, Button, Modal, Form, Input, Select, Switch,
|
||||||
Space, message, Popconfirm, Tag,
|
Space, message, Popconfirm, Tag,
|
||||||
} from "antd";
|
} 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 type { AIModel } from "../types";
|
||||||
import * as modelApi from "../api/models";
|
import * as modelApi from "../api/models";
|
||||||
|
|
||||||
|
|
@ -110,6 +110,21 @@ export default function ModelList() {
|
||||||
fetchModels();
|
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 = [
|
const columns = [
|
||||||
{ title: "名称", dataIndex: "name", key: "name", width: 150 },
|
{ title: "名称", dataIndex: "name", key: "name", width: 150 },
|
||||||
{
|
{
|
||||||
|
|
@ -150,6 +165,12 @@ export default function ModelList() {
|
||||||
width: 160,
|
width: 160,
|
||||||
render: (_: unknown, record: AIModel) => (
|
render: (_: unknown, record: AIModel) => (
|
||||||
<Space>
|
<Space>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
size="small"
|
||||||
|
icon={<ExperimentOutlined />}
|
||||||
|
onClick={() => handleTest(record.id, record.name)}
|
||||||
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
size="small"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue