From 048c274bd1c4034cec5482f4db26d73aebe9524e Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Mon, 8 Jun 2026 11:11:10 +0800 Subject: [PATCH] Refactor Sidebar and AssistantPage components to enhance type definitions and user interaction Updated the Sidebar component to include an optional className property in the icon type definition for better styling flexibility. In the AssistantPage, introduced new FastGptForm and DifyForm types, updated the assistant type options to reflect their availability, and enhanced the state management for creating and editing assistants. Improved the user experience by refining the view handling logic and adding dedicated forms for FastGPT and Dify configurations. --- src/components/layout/Sidebar.tsx | 8 +- src/components/pages/AssistantPage.tsx | 316 ++++++++++++++++++++++++- 2 files changed, 312 insertions(+), 12 deletions(-) diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 50f7574..4f57e85 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -26,7 +26,7 @@ type SidebarProps = { const mainItems: Array<{ key: NavKey; label: string; - icon: React.ComponentType<{ size?: number }>; + icon: React.ComponentType<{ size?: number; className?: string }>; }> = [ { key: "home", label: "首页", icon: Home }, { key: "test", label: "测试助手", icon: PlayCircle }, @@ -35,7 +35,7 @@ const mainItems: Array<{ const componentSubItems: Array<{ key: NavKey; label: string; - icon: React.ComponentType<{ size?: number }>; + icon: React.ComponentType<{ size?: number; className?: string }>; }> = [ { key: "components-models", label: "模型资源", icon: Brain }, { key: "components-knowledge", label: "知识库", icon: Database }, @@ -45,7 +45,7 @@ const componentSubItems: Array<{ const monitorSubItems: Array<{ key: NavKey; label: string; - icon: React.ComponentType<{ size?: number }>; + icon: React.ComponentType<{ size?: number; className?: string }>; }> = [ { key: "history", label: "历史记录", icon: Clock3 }, { key: "dashboard", label: "数据看板", icon: Database }, @@ -294,7 +294,7 @@ function NavButton({ }: { active: boolean; collapsed: boolean; - icon: React.ComponentType<{ size?: number }>; + icon: React.ComponentType<{ size?: number; className?: string }>; label: string; onClick: () => void; small?: boolean; diff --git a/src/components/pages/AssistantPage.tsx b/src/components/pages/AssistantPage.tsx index a0866ec..f8059d5 100644 --- a/src/components/pages/AssistantPage.tsx +++ b/src/components/pages/AssistantPage.tsx @@ -74,6 +74,25 @@ type AssistantForm = { enableInterrupt: boolean; }; +type FastGptForm = { + name: string; + appId: string; + apiUrl: string; + apiKey: string; + asr: string; + voice: string; + enableInterrupt: boolean; +}; + +type DifyForm = { + name: string; + apiUrl: string; + apiKey: string; + asr: string; + voice: string; + enableInterrupt: boolean; +}; + type AssistantType = "提示词" | "工作流" | "Dify" | "FastGPT"; const assistantTypes: AssistantType[] = ["提示词", "工作流", "Dify", "FastGPT"]; @@ -83,7 +102,7 @@ type AssistantTypeOption = { label: string; description: string; icon: React.ReactNode; - /** 提示词类型已落地,其余三种暂时显示占位页 */ + /** 提示词、Dify、FastGPT 类型已落地,工作流暂时显示占位页 */ available: boolean; }; @@ -107,14 +126,14 @@ const assistantTypeOptions: AssistantTypeOption[] = [ label: "使用 Dify 构建", description: "对接 Dify 应用,复用其编排能力与知识库配置。", icon: , - available: false, + available: true, }, { type: "FastGPT", label: "使用 FastGPT 构建", description: "对接 FastGPT 应用,复用其知识库问答与工作流能力。", icon: , - available: false, + available: true, }, ]; @@ -220,9 +239,26 @@ export function AssistantPage() { knowledgeBase: "无", enableInterrupt: true, }); - const [view, setView] = useState<"list" | "choose" | "create" | "placeholder">( - "list", - ); + const [fastGptForm, setFastGptForm] = useState({ + name: "FastGPT 售后咨询助手", + appId: "", + apiUrl: "https://api.fastgpt.in/api/v1/chat/completions", + apiKey: "", + asr: "SenseVoice", + voice: "晓宁", + enableInterrupt: true, + }); + const [difyForm, setDifyForm] = useState({ + name: "Dify 知识库问答助手", + apiUrl: "https://api.dify.ai/v1/chat-messages", + apiKey: "", + asr: "SenseVoice", + voice: "晓宁", + enableInterrupt: true, + }); + const [view, setView] = useState< + "list" | "choose" | "create" | "create-dify" | "create-fastgpt" | "placeholder" + >("list"); const [searchQuery, setSearchQuery] = useState(""); const [typeFilter, setTypeFilter] = useState("全部"); const [currentPage, setCurrentPage] = useState(1); @@ -238,6 +274,25 @@ export function AssistantPage() { setView("choose"); } + // 编辑:根据助手类型进入对应的构建/编辑页,并把名称带入相应表单 + function handleEdit(assistant: AssistantListItem) { + if (assistant.type === "提示词") { + updateForm("name", assistant.name); + setView("create"); + } else if (assistant.type === "FastGPT") { + updateFastGptForm("name", assistant.name); + setView("create-fastgpt"); + } else if (assistant.type === "Dify") { + updateDifyForm("name", assistant.name); + setView("create-dify"); + } else { + // 工作流:暂时显示占位页 + setDraftName(assistant.name); + setDraftType(assistant.type); + setView("placeholder"); + } + } + function confirmType() { if (!draftName.trim() || !draftType) { return; @@ -247,8 +302,16 @@ export function AssistantPage() { // 提示词类型:复用现有创建表单,并把已填的名称带过去 updateForm("name", draftName.trim()); setView("create"); + } else if (draftType === "FastGPT") { + // FastGPT 类型:进入 FastGPT 构建表单,并把已填的名称带过去 + updateFastGptForm("name", draftName.trim()); + setView("create-fastgpt"); + } else if (draftType === "Dify") { + // Dify 类型:进入 Dify 构建表单,并把已填的名称带过去 + updateDifyForm("name", draftName.trim()); + setView("create-dify"); } else { - // 工作流 / Dify / FastGPT:暂时显示占位页 + // 工作流:暂时显示占位页 setView("placeholder"); } } @@ -296,6 +359,26 @@ export function AssistantPage() { [key]: value, })); } + + function updateFastGptForm( + key: K, + value: FastGptForm[K], + ) { + setFastGptForm((prev) => ({ + ...prev, + [key]: value, + })); + } + + function updateDifyForm( + key: K, + value: DifyForm[K], + ) { + setDifyForm((prev) => ({ + ...prev, + [key]: value, + })); + } if (view === "list") { return (
@@ -400,7 +483,7 @@ export function AssistantPage() { variant="outline" size="sm" className="gap-1.5 border-hairline-strong text-xs text-muted-foreground hover:text-foreground" - onClick={() => setView("create")} + onClick={() => handleEdit(assistant)} > 编辑 @@ -680,6 +763,194 @@ export function AssistantPage() { ); } + if (view === "create-dify") { + return ( +
+
+
+ updateDifyForm("name", value)} + /> +
+ +
+ + + +
+
+ +
+
+ } + title="Dify 应用配置" + description="填写 API URL 与 API Key 以对接 Dify 应用。开场白、知识库、提示词等对话编排请在 Dify 平台配置,本页不重复设置。" + > + updateDifyForm("apiUrl", value)} + placeholder="https://api.dify.ai/v1/chat-messages" + /> + updateDifyForm("apiKey", value)} + placeholder="请输入 Dify API Key" + type="password" + /> + + + } + title="语音配置" + description="配置本平台的语音识别与播报音色。大模型、知识库与开场白由 Dify 应用提供,请前往 Dify 平台配置。" + > + updateDifyForm("asr", value)} + options={["SenseVoice", "Paraformer", "Whisper", "FunASR"]} + /> + updateDifyForm("voice", value)} + options={["晓宁", "晓美", "晓宇", "晓晨"]} + /> + + + } + title="交互策略" + description="设置实时视频对话时的交互体验" + > + + updateDifyForm("enableInterrupt", checked) + } + /> + +
+ + +
+
+ ); + } + + if (view === "create-fastgpt") { + return ( +
+
+
+ updateFastGptForm("name", value)} + /> +
+ +
+ + + +
+
+ +
+
+ } + title="FastGPT 应用配置" + description="填写 App ID、API URL 与 API Key 以对接 FastGPT 应用。开场白、知识库、提示词等对话编排请在 FastGPT 平台配置,本页不重复设置。" + > + updateFastGptForm("appId", value)} + placeholder="请输入 FastGPT 应用 ID" + /> + updateFastGptForm("apiUrl", value)} + placeholder="https://api.fastgpt.in/api/v1/chat/completions" + /> + updateFastGptForm("apiKey", value)} + placeholder="请输入 FastGPT API Key" + type="password" + /> + + + } + title="语音配置" + description="配置本平台的语音识别与播报音色。大模型、知识库与开场白由 FastGPT 应用提供,请前往 FastGPT 平台配置。" + > + updateFastGptForm("asr", value)} + options={["SenseVoice", "Paraformer", "Whisper", "FunASR"]} + /> + updateFastGptForm("voice", value)} + options={["晓宁", "晓美", "晓宇", "晓晨"]} + /> + + + } + title="交互策略" + description="设置实时视频对话时的交互体验" + > + + updateFastGptForm("enableInterrupt", checked) + } + /> + +
+ + +
+
+ ); + } + return (
@@ -1148,6 +1419,35 @@ function SectionCard({ ); } +function InputField({ + label, + value, + placeholder, + type = "text", + onChange, +}: { + label?: string; + value: string; + placeholder?: string; + type?: string; + onChange: (value: string) => void; +}) { + return ( + + ); +} + function TextAreaField({ label, value,