diff --git a/app/apps/components/NodePropertyPanel.tsx b/app/apps/components/NodePropertyPanel.tsx index d851414..acc4aff 100644 --- a/app/apps/components/NodePropertyPanel.tsx +++ b/app/apps/components/NodePropertyPanel.tsx @@ -16,6 +16,8 @@ import { X } from "lucide-react"; import { WorkflowNode } from "@/types/workflow"; import { Button } from "@/components/ui/button"; import { useTranslations } from "next-intl"; +import axios from "@/lib/axios"; +import { DEFAULT_LLM_MODEL_CODE, type LlmModelOption } from "@/lib/llmModels"; interface NodePropertyPanelProps { selectedNode: WorkflowNode | null; @@ -58,6 +60,7 @@ export default function NodePropertyPanel({ }: NodePropertyPanelProps) { const t = useTranslations("workflow"); const [localData, setLocalData] = useState(null); + const [llmModels, setLlmModels] = useState([]); const timeoutRef = useRef(null); // 当选中节点变化时,更新本地数据 @@ -67,6 +70,21 @@ export default function NodePropertyPanel({ } }, [selectedNode]); + useEffect(() => { + let cancelled = false; + axios + .get("/api/v1/llm-models") + .then((response) => { + if (!cancelled) setLlmModels(response.data?.items || []); + }) + .catch(() => { + if (!cancelled) setLlmModels([]); + }); + return () => { + cancelled = true; + }; + }, []); + // 清理定时器 useEffect(() => { return () => { @@ -182,16 +200,22 @@ export default function NodePropertyPanel({
diff --git a/app/apps/components/WorkflowEditor.tsx b/app/apps/components/WorkflowEditor.tsx index 5bc0af0..6fb5bd0 100644 --- a/app/apps/components/WorkflowEditor.tsx +++ b/app/apps/components/WorkflowEditor.tsx @@ -37,6 +37,7 @@ import NodePalette from "./NodePalette"; import NodePropertyPanel from "./NodePropertyPanel"; import { WorkflowConfig, WorkflowNode, AppWithWorkflow } from "@/types/workflow"; +import { DEFAULT_LLM_MODEL_CODE } from "@/lib/llmModels"; import { generateDefaultWorkflow, generateNodeId, @@ -372,7 +373,7 @@ function getDefaultNodeData(type: string, t: (key: string) => string): Record([]); // 定义加载函数(必须在 useEffect 之前) const loadApps = useCallback(async () => { @@ -259,6 +261,14 @@ export default function AppsPage() { } }, []); + const loadLlmModels = useCallback(async () => { + try { + const response = await axios.get("/api/v1/llm-models"); + setLlmModels(response.data?.items || []); + } catch { + setLlmModels([]); + } + }, []); const loadWechatAgents = useCallback(async () => { try { @@ -280,7 +290,7 @@ export default function AppsPage() { dataLoadedRef.current = true; // 并行加载所有数据 - Promise.all([loadApps(), loadDatasets()]).catch(() => { + Promise.all([loadApps(), loadDatasets(), loadLlmModels()]).catch(() => { dataLoadedRef.current = false; }); @@ -309,7 +319,7 @@ export default function AppsPage() { app_type: "Chat", platform: "Web", avatar_url: null, - ai_model: "deepseek", + ai_model: DEFAULT_LLM_MODEL_CODE, dataset_ids: [], email: "", settings: {}, @@ -335,7 +345,7 @@ export default function AppsPage() { description: t("qualityAgentDesc"), app_type: "Chat" as const, platform: "Web" as const, - ai_model: "deepseek", + ai_model: DEFAULT_LLM_MODEL_CODE, dataset_ids: ["quality_knowledge_base"], // 使用质量知识库 settings: { workflow: { @@ -377,7 +387,7 @@ export default function AppsPage() { data: { name: t("templateQualityClassification"), type: "ai", - aiModel: "deepseek", + aiModel: DEFAULT_LLM_MODEL_CODE, agentType: "quality_classify", knowledgeBase: t("templateQualityKnowledgeBase"), }, @@ -1206,9 +1216,17 @@ export default function AppsPage() { - Deepseek - Qwen - OpenAI + {llmModels.length === 0 ? ( + + DeepSeek Flash + + ) : ( + llmModels.map((m) => ( + + {m.display_name} + + )) + )} diff --git a/app/system-settings/page.tsx b/app/system-settings/page.tsx index 705304c..8cfbd0c 100644 --- a/app/system-settings/page.tsx +++ b/app/system-settings/page.tsx @@ -5,13 +5,6 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Settings, Mail, Building2, Upload, Eye, Palette, Check } from "lucide-react"; import { useState, useEffect } from "react"; @@ -110,7 +103,6 @@ interface SmtpSettings { } interface SystemSettings { - llm_model?: string; platform_name?: string; platform_logo?: string; platform_subtitle?: string; @@ -143,7 +135,6 @@ export default function SystemSettingsPage() { // 系统设置状态(平台名称、Logo等) const [systemSettings, setSystemSettings] = useState({ - llm_model: "", platform_name: "", platform_logo: "", platform_subtitle: "", @@ -177,7 +168,6 @@ export default function SystemSettingsPage() { }); if (response.data) { setSystemSettings({ - llm_model: response.data.llm_model || "", platform_name: response.data.platform_name || "", platform_logo: response.data.platform_logo || "", platform_subtitle: response.data.platform_subtitle || "", @@ -277,7 +267,6 @@ export default function SystemSettingsPage() { try { await axios.put("/api/system", { - llm_model: systemSettings.llm_model, platform_name: systemSettings.platform_name, platform_logo: systemSettings.platform_logo, platform_subtitle: systemSettings.platform_subtitle, @@ -506,29 +495,6 @@ export default function SystemSettingsPage() {

{t("subtitleTip")}

-
- - -

- {systemSettings.llm_model === "local" ? t("localModelTip") : t("remoteModelTip")} -

-
- {systemError && (
{systemError}
)} diff --git a/lib/llmModels.ts b/lib/llmModels.ts new file mode 100644 index 0000000..5752daa --- /dev/null +++ b/lib/llmModels.ts @@ -0,0 +1,8 @@ +/** 对话模型目录(与 ragent-service llm_models.code 对齐) */ + +export const DEFAULT_LLM_MODEL_CODE = "deepseek-flash"; + +export interface LlmModelOption { + code: string; + display_name: string; +} diff --git a/lib/workflowUtils.ts b/lib/workflowUtils.ts index 4ee3d70..4b0eebc 100644 --- a/lib/workflowUtils.ts +++ b/lib/workflowUtils.ts @@ -4,6 +4,7 @@ */ import { WorkflowConfig, WorkflowNode, WorkflowEdge, AppWithWorkflow } from "@/types/workflow"; +import { DEFAULT_LLM_MODEL_CODE } from "@/lib/llmModels"; /** * 从App配置生成默认工作流 @@ -32,7 +33,7 @@ export const generateDefaultWorkflow = (app: Partial): Workflow position: { x: 250, y: 150 }, data: { name: "会话智能体", - aiModel: app.ai_model || "deepseek", + aiModel: app.ai_model || DEFAULT_LLM_MODEL_CODE, temperature: 0.7, maxTokens: 2000, }, diff --git a/messages/en/systemSettings.json b/messages/en/systemSettings.json index 62d6e49..80afc39 100644 --- a/messages/en/systemSettings.json +++ b/messages/en/systemSettings.json @@ -47,12 +47,6 @@ "upload": "Upload", "uploading": "Uploading...", "logoPreview": "Logo Preview:", - "chatModel": "Chat Model", - "selectChatModel": "Select Chat Model", - "deepseekRemote": "Deepseek (Remote)", - "localModel": "Local Model", - "localModelTip": "Use local model for faster response, suitable for offline environments", - "remoteModelTip": "Use remote model for more powerful features and capabilities", "configSaved": "Configuration saved", "saveConfig": "Save Configuration", "loginLeftPanelHtml": "Login Page Left Panel Custom HTML", diff --git a/messages/zh-CN/systemSettings.json b/messages/zh-CN/systemSettings.json index 594846d..312c20e 100644 --- a/messages/zh-CN/systemSettings.json +++ b/messages/zh-CN/systemSettings.json @@ -35,7 +35,7 @@ "noPermission": "您需要向管理员申请权限", "platformSettingsTitle": "平台设置", "platformSettings": "平台设置", - "platformSettingsDesc": "配置平台名称、Logo 和 AI 模型", + "platformSettingsDesc": "配置平台名称、Logo 和登录页外观", "platformName": "平台名称", "platformNamePlaceholder": "请输入平台名称", "platformSubtitle": "平台副标题", @@ -47,12 +47,6 @@ "upload": "上传", "uploading": "上传中...", "logoPreview": "Logo 预览:", - "chatModel": "会话模型", - "selectChatModel": "选择会话模型", - "deepseekRemote": "Deepseek(远程)", - "localModel": "本地模型", - "localModelTip": "使用本地模型,响应速度快,适合离线环境", - "remoteModelTip": "使用远程模型,功能更强大,支持更多功能", "configSaved": "配置已保存", "saveConfig": "保存配置", "loginLeftPanelHtml": "登录页左侧面板 HTML", diff --git a/pages/api/system/index.ts b/pages/api/system/index.ts index e909d0e..5db6a8b 100644 --- a/pages/api/system/index.ts +++ b/pages/api/system/index.ts @@ -48,7 +48,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const hasThemePrimaryColor = existingColumns.includes("theme_primary_color"); const hasThemeSecondaryColor = existingColumns.includes("theme_secondary_color"); // 根据字段是否存在构建查询 - let selectFields = "platform_name, platform_logo, platform_subtitle, llm_model"; + let selectFields = "platform_name, platform_logo, platform_subtitle"; if (hasLoginPanelHtml) selectFields += ", login_left_panel_html"; if (hasThemePrimaryColor) selectFields += ", theme_primary_color"; if (hasThemeSecondaryColor) selectFields += ", theme_secondary_color"; @@ -72,10 +72,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) ? row.theme_secondary_color || null : null, }; - // 如果请求了 full_data,也返回 llm_model - if (req.query.full_data) { - publicData.llm_model = row.llm_model || null; - } return res.status(200).json(publicData); } else { // 没有系统设置记录,返回空数据 @@ -86,7 +82,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) login_left_panel_html: null, theme_primary_color: null, theme_secondary_color: null, - ...(req.query.full_data ? { llm_model: null } : {}), }); } } finally { @@ -102,7 +97,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) login_left_panel_html: null, theme_primary_color: null, theme_secondary_color: null, - ...(req.query.full_data ? { llm_model: null } : {}), }); } } diff --git a/pages/api/v1/llm-models/index.ts b/pages/api/v1/llm-models/index.ts new file mode 100644 index 0000000..4288101 --- /dev/null +++ b/pages/api/v1/llm-models/index.ts @@ -0,0 +1,10 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +import { proxySkillsApi } from "@/lib/skillsProxy"; + +/** GET /api/v1/llm-models → 后端对话模型目录(应用配置下拉) */ +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + return proxySkillsApi(req, res, { + path: "/api/v1/llm-models/", + allow: ["GET"], + }); +}