import { App as AntApp, Button, Checkbox, Col, Form, Input, InputNumber, Modal, Row, Select, Space } from "antd"; import { useEffect, useState } from "react"; import type { CreateModelRequest, Model, ModelCapability, ModelTestResponse, ProviderOption, TestModelRequest, UpdateModelRequest, } from "../../../../shared/api"; interface FormValues { capabilities: ModelCapability[]; contextLength: null | number; maxOutputTokens: null | number; modelId: string; name: string; providerId: string; } interface ModelFormModalProps { editingModel: Model | null; onCancel: () => void; onCreate: (data: CreateModelRequest) => Promise; onOpenChange: (open: boolean) => void; onUpdate: (args: { data: UpdateModelRequest; id: string }) => Promise; open: boolean; providers: ProviderOption[]; providersError: Error | null; providersLoading: boolean; submitting: boolean; testModelConnection?: (data: TestModelRequest) => Promise; } const DEFAULT_CAPABILITIES: ModelCapability[] = ["text", "reasoning"]; const CAPABILITY_OPTIONS: Array<{ label: string; value: ModelCapability }> = [ { label: "文本", value: "text" }, { label: "推理", value: "reasoning" }, { label: "图片生成", value: "image-generation" }, { label: "视频生成", value: "video-generation" }, { label: "音频生成", value: "audio-generation" }, { label: "图片识别", value: "image-recognition" }, { label: "视频识别", value: "video-recognition" }, { label: "音频识别", value: "audio-recognition" }, ]; export function ModelFormModal({ editingModel, onCancel, onCreate, onOpenChange, onUpdate, open, providers, providersError, providersLoading, submitting, testModelConnection, }: ModelFormModalProps) { const { message } = AntApp.useApp(); const [form] = Form.useForm(); const [testing, setTesting] = useState(false); useEffect(() => { if (!open) return; if (editingModel) { form.setFieldsValue({ capabilities: editingModel.capabilities, contextLength: editingModel.contextLength, maxOutputTokens: editingModel.maxOutputTokens, modelId: editingModel.modelId, name: editingModel.name, providerId: editingModel.providerId, }); } else { form.resetFields(); form.setFieldsValue({ capabilities: DEFAULT_CAPABILITIES }); } }, [editingModel, form, open]); const handleFinish = async (values: FormValues) => { try { if (editingModel) { const reqData: UpdateModelRequest = {}; if (values.name !== editingModel.name) reqData.name = values.name; if (values.modelId !== editingModel.modelId) reqData.modelId = values.modelId; if (values.providerId !== editingModel.providerId) reqData.providerId = values.providerId; const capsChanged = values.capabilities.length !== editingModel.capabilities.length || values.capabilities.some((c, i) => c !== editingModel.capabilities[i]); if (capsChanged) reqData.capabilities = values.capabilities; if (values.contextLength !== editingModel.contextLength) reqData.contextLength = values.contextLength; if (values.maxOutputTokens !== editingModel.maxOutputTokens) reqData.maxOutputTokens = values.maxOutputTokens; await onUpdate({ data: reqData, id: editingModel.id }); message.success("模型已更新"); } else { const reqData: CreateModelRequest = { capabilities: values.capabilities, contextLength: values.contextLength ?? undefined, maxOutputTokens: values.maxOutputTokens ?? undefined, modelId: values.modelId, name: values.name, providerId: values.providerId, }; await onCreate(reqData); message.success("模型已创建"); } onOpenChange(false); } catch (err: unknown) { if (err instanceof Error) { message.error(err.message); } } }; const handleTest = async () => { if (!testModelConnection) return; const providerId: unknown = form.getFieldValue("providerId"); const modelId: unknown = form.getFieldValue("modelId"); if (typeof providerId !== "string" || !providerId) { message.warning("请先选择供应商"); return; } if (typeof modelId !== "string" || !modelId) { message.warning("请先输入模型 ID"); return; } setTesting(true); try { const result = await testModelConnection({ modelId, providerId }); if (result.ok) { message.success(result.message); } else { message.error(result.message); } } catch (err: unknown) { message.error((err as Error).message); } finally { setTesting(false); } }; const providerOptions = providers.map((p) => ({ label: p.name, value: p.id })); return ( void form.submit()} open={open} title={editingModel ? "编辑模型" : "新建模型"} width={600} >
void handleFinish(values)}> {CAPABILITY_OPTIONS.map((opt) => ( {opt.label} ))} {testModelConnection && ( )}
); } function getProviderNotFoundContent(loading: boolean, error: Error | null): string { if (loading) return "正在加载供应商"; if (error) return `供应商加载失败:${error.message}`; return "暂无供应商,请先新建供应商"; } function positiveIntegerRule(label: string) { return { validator(_: unknown, value: null | number | undefined) { if (value === undefined || value === null) return Promise.resolve(); if (Number.isInteger(value) && value > 0) return Promise.resolve(); return Promise.reject(new Error(`${label}必须为正整数`)); }, }; }