"use client"; import { App, Button, Form, Input, Modal, Segmented } from "antd"; import { useState } from "react"; import { ModelPicker } from "@/components/model-picker"; import { fetchImageModels } from "@/services/api/image"; import { useConfigStore, useEffectiveConfig, type AiConfig } from "@/stores/use-config-store"; export function AppConfigModal() { const { message } = App.useApp(); const [loadingModels, setLoadingModels] = useState(false); const config = useConfigStore((state) => state.config); const updateConfig = useConfigStore((state) => state.updateConfig); const isConfigOpen = useConfigStore((state) => state.isConfigOpen); const shouldPromptContinue = useConfigStore((state) => state.shouldPromptContinue); const setConfigDialogOpen = useConfigStore((state) => state.setConfigDialogOpen); const clearPromptContinue = useConfigStore((state) => state.clearPromptContinue); const publicSettings = useConfigStore((state) => state.publicSettings); const effectiveConfig = useEffectiveConfig(); const modelChannel = publicSettings?.modelChannel; const allowCustomChannel = modelChannel?.allowCustomChannel === true; const effectiveMode = allowCustomChannel ? config.channelMode : "remote"; const modelConfig = effectiveMode === "remote" ? effectiveConfig : config; const finishConfig = () => { setConfigDialogOpen(false); if (effectiveMode === "local" && (!config.baseUrl.trim() || !config.apiKey.trim())) return; if (!modelConfig.imageModel.trim() || !modelConfig.videoModel.trim() || !modelConfig.textModel.trim()) return; if (!allowCustomChannel && config.channelMode !== "remote") updateConfig("channelMode", "remote"); message.success(shouldPromptContinue ? "配置已保存,请继续刚才的请求" : "配置已保存"); clearPromptContinue(); }; const refreshModels = async () => { if (effectiveMode === "remote") return; if (!config.baseUrl.trim() || !config.apiKey.trim()) { message.error("请先填写 Base URL 和 API Key"); return; } setLoadingModels(true); try { const models = await fetchImageModels(config); updateConfig("models", models); if (models.length && !models.includes(config.imageModel)) updateConfig("imageModel", models[0]); if (models.length && !models.includes(config.videoModel)) updateConfig("videoModel", models[0]); if (models.length && !models.includes(config.textModel)) updateConfig("textModel", models[0]); message.success("模型列表已更新"); } catch (error) { message.error(error instanceof Error ? error.message : "读取模型失败"); } finally { setLoadingModels(false); } }; return (
配置
模型和密钥
} open={isConfigOpen} width={760} centered onCancel={() => setConfigDialogOpen(false)} footer={ } >
{allowCustomChannel ? ( updateConfig("channelMode", value as AiConfig["channelMode"])} options={[ { label: "本地直连", value: "local" }, { label: "云端渠道", value: "remote" }, ]} /> ) : null} {effectiveMode === "local" ? ( <>
updateConfig("baseUrl", event.target.value)} /> updateConfig("apiKey", event.target.value)} />
模型列表
当前已保存 {config.models.length} 个模型
) : (
云端渠道
由系统后台渠道转发请求,当前可用 {modelChannel?.availableModels.length || 0} 个模型。
)}
updateConfig("imageModel", model)} fullWidth /> updateConfig("videoModel", model)} fullWidth /> updateConfig("textModel", model)} fullWidth />
{effectiveMode === "local" ? ( updateConfig("systemPrompt", event.target.value)} /> ) : null}
); }