From 894c0d7b151405dbc9ee3a8c4f6a7c1dc86698ee Mon Sep 17 00:00:00 2001 From: iven Date: Sat, 4 Apr 2026 10:48:47 +0800 Subject: [PATCH] feat(desktop): pipeline result preview + industry templates + onboarding auto-trigger MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprint 2: 产品体验打磨 + 行业模板 - Create PipelineResultPreview component with tab-based output switching - Connect workflow/hand messages to PresentationContainer in ChatArea - Add auto-trigger first Hand after onboarding (industry-specific queries) - Seed 3 industry agent templates (education, healthcare, design-shantou) Co-Authored-By: Claude Opus 4.6 --- ...0260405000001_industry_agent_templates.sql | 171 ++++++++++++++++++ desktop/src/App.tsx | 20 ++ desktop/src/components/ChatArea.tsx | 16 ++ .../pipeline/PipelineResultPreview.tsx | 85 +++++++++ 4 files changed, 292 insertions(+) create mode 100644 crates/zclaw-saas/migrations/20260405000001_industry_agent_templates.sql create mode 100644 desktop/src/components/pipeline/PipelineResultPreview.tsx diff --git a/crates/zclaw-saas/migrations/20260405000001_industry_agent_templates.sql b/crates/zclaw-saas/migrations/20260405000001_industry_agent_templates.sql new file mode 100644 index 0000000..ba86cb5 --- /dev/null +++ b/crates/zclaw-saas/migrations/20260405000001_industry_agent_templates.sql @@ -0,0 +1,171 @@ +-- Industry Agent Template Seed Data +-- Three target user groups: Education, Healthcare, Design (Shantou) +-- Each template maps to pipeline YAML templates in pipelines/ directory + +-- ============================================================ +-- 1. Education — 教学助手 +-- ============================================================ +INSERT INTO agent_templates ( + id, name, description, category, source, emoji, + model, system_prompt, tools, capabilities, temperature, max_tokens, + visibility, status, current_version, + soul_content, scenarios, welcome_message, quick_commands, + personality, communication_style, source_id, version +) VALUES ( + 'edu-teacher-001', + '教学助手', + '专为教师和教培机构设计的 AI 助手,擅长课件生成、学情分析、测验出题和教案设计', + 'education', + 'builtin', + '📚', + NULL, + '你是一个专业的教学助手,帮助教师完成备课、课件制作、学情分析和测验出题等工作。你熟悉中国教育体系,了解各学科教学大纲和课程标准。回答要专业、准确、有教育洞察。', + '["web-search", "data-analysis", "chart-visualization", "deep-research", "classroom-generator", "translation"]', + '["quiz", "whiteboard", "slideshow", "speech", "collector"]', + 0.7, + 4096, + 'public', + 'active', + 1, + '# 教学助手人格定义 + +## 身份 +你是一位经验丰富的教学顾问和备课助手,熟悉中国 K-12 和高等教育的教学实践。 + +## 核心价值观 +- 以学生为中心的教学理念 +- 注重因材施教和差异化教学 +- 鼓励互动式、探究式学习 + +## 行为准则 +- 提供具体可执行的教学建议 +- 内容符合课程标准要求 +- 生成结构清晰的课件和测验', + '["课件生成", "学情分析", "教案设计", "教研辅助", "测验出题"]', + '你好!我是你的智能教学助手 📚 + +我可以帮你: +• 生成课件和幻灯片 +• 分析学情数据 +• 设计测验题目 +• 编写教案 + +请告诉我你需要什么帮助?', + '[{"label":"生成课件","command":"帮我生成一个关于这个主题的课件,包含教学目标、知识点讲解和课堂活动"},{"label":"学情分析","command":"帮我分析这组学生的成绩数据,找出薄弱环节和改进建议"},{"label":"出测验题","command":"帮我出10道这个知识点的测验题,包含选择题、填空题和简答题"},{"label":"生成教案","command":"帮我设计一节45分钟的教案,包含导入、新授、练习和总结环节"}]', + 'friendly', + '温暖、耐心、善于用易懂的语言解释复杂概念', + 'education-teacher', + 1 +); + +-- ============================================================ +-- 2. Healthcare — 医疗行政助手 +-- ============================================================ +INSERT INTO agent_templates ( + id, name, description, category, source, emoji, + model, system_prompt, tools, capabilities, temperature, max_tokens, + visibility, status, current_version, + soul_content, scenarios, welcome_message, quick_commands, + personality, communication_style, source_id, version +) VALUES ( + 'healthcare-admin-001', + '医疗行政助手', + '专为医院行政科室设计,擅长政策解读、数据报告、合规检查和会议纪要', + 'healthcare', + 'builtin', + '🏥', + NULL, + '你是一个专业的医疗行政管理助手,帮助医院行政人员处理政策文件解读、数据报告生成、合规检查和会议纪要等工作。你熟悉中国医疗体系和相关法规政策。回答要严谨、准确、有法律依据。', + '["web-search", "data-analysis", "deep-research", "consulting-analysis", "translation", "legal-compliance-checker"]', + '["researcher", "browser", "collector"]', + 0.5, + 4096, + 'public', + 'active', + 1, + '# 医疗行政助手人格定义 + +## 身份 +你是一位专业的医疗行政顾问,熟悉医院管理流程和医疗法规政策。 + +## 核心价值观 +- 严格遵守医疗法规和政策要求 +- 注重数据准确性和可追溯性 +- 以合规和安全为第一优先级 + +## 行为准则 +- 引用具体政策条款和文件编号 +- 数据分析结果需标注来源和统计方法 +- 涉及患者隐私的内容需提醒脱敏处理', + '["政策解读", "数据报告", "合规检查", "文献研究", "会议纪要"]', + '你好!我是你的医疗行政助手 🏥 + +我可以帮你: +• 解读最新医疗政策文件 +• 生成科室数据报告 +• 检查制度合规性 +• 整理会议纪要 + +请告诉我你需要什么帮助?', + '[{"label":"政策解读","command":"帮我解读最新的医疗政策文件,提取关键要点和影响分析"},{"label":"数据报告","command":"帮我生成科室运营数据报告,包含趋势分析和改进建议"},{"label":"会议纪要","command":"帮我把会议录音/笔记整理成结构化纪要,包含决议和待办事项"},{"label":"合规检查","command":"帮我检查这项制度是否符合最新的医疗法规要求"}]', + 'professional', + '专业、准确、注重细节,提供技术深度和可操作建议', + 'healthcare-admin', + 1 +); + +-- ============================================================ +-- 3. Design (Shantou) — 设计助手 +-- ============================================================ +INSERT INTO agent_templates ( + id, name, description, category, source, emoji, + model, system_prompt, tools, capabilities, temperature, max_tokens, + visibility, status, current_version, + soul_content, scenarios, welcome_message, quick_commands, + personality, communication_style, source_id, version +) VALUES ( + 'design-shantou-001', + '设计助手', + '专为汕头制衣、玩具设计行业打造,擅长趋势分析、竞品研究、客户沟通和方案设计', + 'design-shantou', + 'builtin', + '🎨', + NULL, + '你是一个专业的设计行业助手,专注于汕头特色产业(制衣、玩具)。你擅长趋势分析、竞品调研、设计灵感和客户沟通辅助。你了解潮汕地区的产业特点和市场需求。回答要富有创意、实用且有商业洞察。', + '["web-search", "data-analysis", "deep-research", "consulting-analysis", "content-creator"]', + '["browser", "collector", "researcher", "clip"]', + 0.8, + 4096, + 'public', + 'active', + 1, + '# 设计助手人格定义 + +## 身份 +你是一位创意设计顾问,专注于汕头制衣和玩具设计行业,了解全球设计趋势和本地市场需求。 + +## 核心价值观 +- 设计要以市场需求为导向 +- 鼓励创新但注重可行性 +- 尊重原创,保护知识产权 + +## 行为准则 +- 提供具体可落地的设计建议 +- 趋势分析需引用权威来源 +- 竞品分析要客观全面', + '["趋势分析", "竞品研究", "客户沟通", "供应链查询", "方案设计"]', + '你好!我是你的设计助手 🎨 + +我可以帮你: +• 分析行业设计趋势 +• 调研竞品产品和策略 +• 辅助客户沟通方案 +• 整理供应链信息 + +请告诉我你需要什么帮助?', + '[{"label":"趋势分析","command":"帮我分析2026年制衣/玩具行业的流行设计趋势,包含色彩、材质和风格"},{"label":"竞品研究","command":"帮我调研这个产品的竞品,对比价格、设计和市场定位"},{"label":"客户沟通","command":"帮我准备客户提案,包含产品推荐和报价方案"},{"label":"供应链查询","command":"帮我收集和整理相关原材料/配件的供应商信息"}]', + 'creative', + '富有创意、思维开放,鼓励探索新想法和解决方案', + 'design-shantou', + 1 +); diff --git a/desktop/src/App.tsx b/desktop/src/App.tsx index f4e2b35..41c2a7d 100644 --- a/desktop/src/App.tsx +++ b/desktop/src/App.tsx @@ -357,6 +357,26 @@ function App() { time: '', }); setShowOnboarding(false); + + // Auto-trigger first Hand based on industry template + const templateId = clone.source_template_id || ''; + const industryQueries: Record = { + 'edu-teacher-001': { hand: 'researcher', action: 'report', query: '帮我研究2026年教育数字化转型趋势,包括AI教学工具的最新进展' }, + 'healthcare-admin-001': { hand: 'collector', action: 'collect', query: '帮我采集最新的医疗政策文件摘要,重点关注基层医疗改革方向' }, + 'design-shantou-001': { hand: 'researcher', action: 'report', query: '帮我研究2026年服装设计流行趋势,包括色彩、面料和款式创新' }, + }; + const task = industryQueries[templateId]; + if (task) { + // Delay slightly to let UI settle + setTimeout(() => { + useHandStore.getState().triggerHand(task.hand, { + action: task.action, + query: { query: task.query }, + }).catch(() => { + // Non-critical — user can trigger manually + }); + }, 2000); + } }; // 处理主视图切换 diff --git a/desktop/src/components/ChatArea.tsx b/desktop/src/components/ChatArea.tsx index df9d6ae..16e9186 100644 --- a/desktop/src/components/ChatArea.tsx +++ b/desktop/src/components/ChatArea.tsx @@ -32,6 +32,8 @@ import { ChatMode } from './ai/ChatMode'; import { ModelSelector } from './ai/ModelSelector'; import { TaskProgress } from './ai/TaskProgress'; import { SuggestionChips } from './ai/SuggestionChips'; +import { PipelineResultPreview } from './pipeline/PipelineResultPreview'; +import { PresentationContainer } from './presentation/PresentationContainer'; // TokenMeter temporarily unused — using inline text counter instead // Default heights for virtualized messages @@ -665,6 +667,20 @@ function MessageBubble({ message, setInput }: { message: Message; setInput: (tex ) : '...'} + {/* Pipeline / Hand result presentation */} + {!isUser && (message.role === 'workflow' || message.role === 'hand') && message.workflowResult && typeof message.workflowResult === 'object' && message.workflowResult !== null && ( +
+ } + pipelineId={message.workflowId} + /> +
+ )} + {!isUser && message.role === 'hand' && message.handResult && typeof message.handResult === 'object' && message.handResult !== null && !message.workflowResult && ( +
+ +
+ )} {message.error && (

{message.error}

diff --git a/desktop/src/components/pipeline/PipelineResultPreview.tsx b/desktop/src/components/pipeline/PipelineResultPreview.tsx new file mode 100644 index 0000000..25d012d --- /dev/null +++ b/desktop/src/components/pipeline/PipelineResultPreview.tsx @@ -0,0 +1,85 @@ +/** + * PipelineResultPreview — Pipeline 输出结果预览 + * + * 将 Pipeline outputs 的多个顶层键以 tab 切换展示, + * 每个 tab 内嵌 PresentationContainer 做智能渲染。 + */ + +import { useState, useMemo } from 'react'; +import { PresentationContainer } from '../presentation/PresentationContainer'; +import { FileText, BarChart3, HelpCircle, Presentation, PenTool } from 'lucide-react'; + +interface PipelineResultPreviewProps { + /** Pipeline outputs 对象(多键 JSON) */ + outputs: Record; + /** Pipeline ID */ + pipelineId?: string; + className?: string; +} + +const KEY_ICONS: Record = { + summary: , + report: , + analysis: , + quiz: , + scenes: , + slides: , + plan: , +}; + +function getKeyIcon(key: string): React.ReactNode { + for (const [pattern, icon] of Object.entries(KEY_ICONS)) { + if (key.toLowerCase().includes(pattern)) return icon; + } + return ; +} + +export function PipelineResultPreview({ outputs, pipelineId, className = '' }: PipelineResultPreviewProps) { + const keys = useMemo(() => Object.keys(outputs), [outputs]); + const [activeKey, setActiveKey] = useState(keys[0]); + + if (keys.length === 0) { + return ( +
+ Pipeline 执行完成,无输出数据 +
+ ); + } + + return ( +
+ {/* Tab bar */} + {keys.length > 1 && ( +
+ {keys.map((key) => ( + + ))} +
+ )} + + {/* Content */} +
+ {outputs[activeKey] !== undefined && outputs[activeKey] !== null ? ( + + ) : ( +

该部分无数据

+ )} +
+
+ ); +}