From b7238ad6679afd4131272e0c5c93b3e07f11a4bf Mon Sep 17 00:00:00 2001 From: eaiadmin Date: Tue, 22 Sep 2026 23:38:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E6=94=B6=E5=8F=A3=E6=8A=80?= =?UTF-8?q?=E8=83=BD=E4=B8=8E=E4=B8=93=E5=91=98=E7=9B=AE=E5=BD=95=E5=AE=9A?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 统一 skill 与 specialist 清单,移除旧的 office 执行包与下线对象,并补入 text_to_speech、customer_followup 等当前目录定义与种子数据。 --- eai_agentplatform/PROJECT_STATE.md | 20 +- .../assets/knowledge/source/README.md | 4 +- eai_agentplatform/assets/sampledata/README.md | 54 +++++ .../sampledata/audio_transcribe/README.md | 16 ++ .../audio_transcribe/input/上午会议口述.mp3 | Bin 0 -> 65952 bytes .../assets/sampledata/batch_extract/README.md | 17 ++ .../batch_extract/input/期望字段.json | 27 +++ .../batch_extract/input/材料集/云帆科技.md | 10 + .../batch_extract/input/材料集/星海资本.md | 7 + .../sampledata/contract_brief/README.md | 16 ++ .../contract_brief/input/合同简介.md | 11 + .../sampledata/contract_review/README.md | 16 ++ .../contract_review/input/采购合同.md | 14 ++ .../sampledata/copy_proofreading/README.md | 16 ++ .../copy_proofreading/input/待校对文案.md | 9 + .../sampledata/document_translate/README.md | 15 ++ .../document_translate/input/中文简介.md | 3 + .../sampledata/interview_summary/README.md | 16 ++ .../interview_summary/input/面试记录.md | 11 + .../sampledata/longform_writing/README.md | 16 ++ .../longform_writing/input/写作主题.md | 14 ++ .../sampledata/meeting_minutes/README.md | 17 ++ .../meeting_minutes/input/会议速录.md | 25 +++ .../assets/sampledata/mind_map/README.md | 16 ++ .../sampledata/mind_map/input/产品规划要点.md | 13 ++ .../sampledata/ocr_understanding/README.md | 16 ++ .../ocr_understanding/images/公司介绍_帧1.png | 3 + .../ocr_understanding/input/识别要求.md | 8 + .../sampledata/policy_rewrite/README.md | 16 ++ .../policy_rewrite/input/高企认定政策原文.md | 12 ++ .../sampledata/ppt_generation/README.md | 16 ++ .../ppt_generation/input/汇报提纲.md | 12 ++ .../sampledata/progress_report/README.md | 16 ++ .../progress_report/input/本周工作流水.md | 8 + .../sampledata/report_generation/README.md | 18 ++ .../report_generation/input/调研数据.md | 15 ++ .../assets/sampledata/shared/公司背景.md | 35 ++++ .../sampledata/smart_assistant/README.md | 15 ++ .../smart_assistant/input/示例提问.md | 7 + .../assets/sampledata/table_cleanup/README.md | 15 ++ .../sampledata/table_cleanup/input/脏表格.md | 15 ++ .../sampledata/text_to_speech/README.md | 18 ++ .../text_to_speech/audio/考察通知_男声.mp3 | Bin 0 -> 75312 bytes .../text_to_speech/input/待合成文本.md | 7 + .../backend-go/deploy/DELIVERY.md | 2 +- .../backend-go/internal/api/points.go | 2 +- .../backend-go/internal/api/router.go | 2 + .../internal/skills/api/office_handlers.go | 2 +- .../internal/skills/api/tts_handlers.go | 192 ++++++++++++++++++ .../internal/skills/core/builtin.go | 12 +- .../internal/skills/model/skill_definition.go | 6 +- .../packages/audio_transcribe/manifest.go | 2 +- .../skills/packages/batch_extract/manifest.go | 2 +- .../packages/contract_brief/manifest.go | 2 +- .../skills/packages/contract_brief/runtime.go | 2 +- .../packages/contract_review/manifest.go | 2 +- .../packages/email_drafting/manifest.go | 11 - .../skills/packages/email_drafting/runtime.go | 14 -- .../packages/interview_summary/manifest.go | 2 +- .../packages/interview_summary/runtime.go | 2 +- .../packages/longform_writing/manifest.go | 2 +- .../packages/longform_writing/runtime.go | 2 +- .../packages/meeting_minutes/manifest.go | 2 +- .../packages/meeting_minutes/runtime.go | 2 +- .../skills/packages/mind_map/manifest.go | 2 +- .../skills/packages/mind_map/runtime.go | 2 +- .../packages/ocr_understanding/manifest.go | 2 +- .../packages/ocr_understanding/runtime.go | 2 +- .../packages/policy_rewrite/manifest.go | 2 +- .../skills/packages/policy_rewrite/runtime.go | 2 +- .../packages/ppt_generation/manifest.go | 2 +- .../skills/packages/ppt_generation/runtime.go | 2 +- .../packages/progress_report/manifest.go | 2 +- .../packages/progress_report/runtime.go | 2 +- .../packages/project_planning/manifest.go | 11 - .../packages/project_planning/runtime.go | 14 -- .../packages/proposal_summary/manifest.go | 11 - .../packages/proposal_summary/runtime.go | 14 -- .../packages/report_generation/manifest.go | 2 +- .../packages/smart_assistant/manifest.go | 2 +- .../packages/survey_summary/manifest.go | 11 - .../skills/packages/survey_summary/runtime.go | 14 -- .../skills/packages/table_cleanup/manifest.go | 2 +- .../skills/packages/table_cleanup/runtime.go | 2 +- .../packages/text_to_speech/manifest.go | 11 + .../skills/packages/text_toolkit/manifest.go | 11 - .../skills/packages/text_toolkit/runtime.go | 14 -- .../runtime/office/builders_communication.go | 106 ---------- .../runtime/office/builders_structure.go | 103 ---------- .../skills/runtime/office/builders_writing.go | 173 ---------------- .../internal/skills/runtime/office/builtin.go | 10 - .../skills/runtime/office/helpers_content.go | 46 ----- .../runtime/office/helpers_structure.go | 25 --- .../internal/specialists/core/builtin.go | 18 +- .../packages/customer_followup/manifest.go | 32 +++ .../packages/hr_email_sorter/manifest.go | 31 --- .../logistics_fulfillment/manifest.go | 31 --- .../presentation_briefing/manifest.go | 2 +- .../packages/process_coordination/manifest.go | 2 +- .../packages/resume_processor/manifest.go | 18 +- .../packages/solution_proposal/manifest.go | 2 +- .../packages/training_delivery/manifest.go | 30 --- .../api/official_account_delivery.go | 2 +- .../api/official_account_workflow.go | 10 +- .../wechat_official_account/manifest.go | 4 +- .../specialists/seeding/seed_specialists.go | 138 ++++++------- .../backend-go/internal/store/seed.go | 123 +++++++---- .../frontend/src/config/projectTemplates.js | 6 +- .../frontend/src/config/workbench.js | 147 +++++--------- .../frontend/src/skills/core/builtin.js | 10 - .../packages/audio-transcribe/manifest.js | 5 +- .../skills/packages/batch-extract/manifest.js | 5 +- .../packages/contract-brief/manifest.js | 4 +- .../packages/contract-review/manifest.js | 5 +- .../packages/copy-proofreading/manifest.js | 3 +- .../packages/document-translate/manifest.js | 3 +- .../packages/email-drafting/execution.js | 119 ----------- .../packages/email-drafting/manifest.js | 19 -- .../packages/interview-summary/manifest.js | 4 +- .../packages/longform-writing/manifest.js | 4 +- .../packages/meeting-minutes/manifest.js | 4 +- .../src/skills/packages/mind-map/manifest.js | 4 +- .../packages/ocr-understanding/manifest.js | 4 +- .../skills/packages/officeExecutions/index.js | 10 - .../packages/policy-rewrite/manifest.js | 4 +- .../packages/ppt-generation/manifest.js | 4 +- .../packages/progress-report/manifest.js | 4 +- .../packages/project-planning/execution.js | 115 ----------- .../packages/project-planning/manifest.js | 19 -- .../packages/proposal-summary/execution.js | 78 ------- .../packages/proposal-summary/manifest.js | 19 -- .../packages/report-generation/manifest.js | 5 +- .../packages/smart-assistant/manifest.js | 5 +- .../packages/survey-summary/execution.js | 77 ------- .../packages/survey-summary/manifest.js | 19 -- .../skills/packages/table-cleanup/manifest.js | 4 +- .../skills/packages/text-toolkit/execution.js | 62 ------ .../skills/packages/text-toolkit/manifest.js | 19 -- .../src/skills/shared/officeArtifacts.js | 32 --- .../frontend/src/skills/store/skillCatalog.js | 31 ++- .../frontend/src/specialists/core/builtin.js | 16 +- .../packages/customer-followup/manifest.js | 27 +++ .../packages/hr-email-sorter/manifest.js | 26 --- .../logistics-fulfillment/manifest.js | 26 --- .../packages/resume-processor/manifest.js | 15 +- .../packages/training-delivery/manifest.js | 26 --- .../wechat-official-account/manifest.js | 4 +- .../frontend/src/styles/global.css | 2 +- 148 files changed, 1230 insertions(+), 1710 deletions(-) create mode 100644 eai_agentplatform/assets/sampledata/README.md create mode 100644 eai_agentplatform/assets/sampledata/audio_transcribe/README.md create mode 100644 eai_agentplatform/assets/sampledata/audio_transcribe/input/上午会议口述.mp3 create mode 100644 eai_agentplatform/assets/sampledata/batch_extract/README.md create mode 100644 eai_agentplatform/assets/sampledata/batch_extract/input/期望字段.json create mode 100644 eai_agentplatform/assets/sampledata/batch_extract/input/材料集/云帆科技.md create mode 100644 eai_agentplatform/assets/sampledata/batch_extract/input/材料集/星海资本.md create mode 100644 eai_agentplatform/assets/sampledata/contract_brief/README.md create mode 100644 eai_agentplatform/assets/sampledata/contract_brief/input/合同简介.md create mode 100644 eai_agentplatform/assets/sampledata/contract_review/README.md create mode 100644 eai_agentplatform/assets/sampledata/contract_review/input/采购合同.md create mode 100644 eai_agentplatform/assets/sampledata/copy_proofreading/README.md create mode 100644 eai_agentplatform/assets/sampledata/copy_proofreading/input/待校对文案.md create mode 100644 eai_agentplatform/assets/sampledata/document_translate/README.md create mode 100644 eai_agentplatform/assets/sampledata/document_translate/input/中文简介.md create mode 100644 eai_agentplatform/assets/sampledata/interview_summary/README.md create mode 100644 eai_agentplatform/assets/sampledata/interview_summary/input/面试记录.md create mode 100644 eai_agentplatform/assets/sampledata/longform_writing/README.md create mode 100644 eai_agentplatform/assets/sampledata/longform_writing/input/写作主题.md create mode 100644 eai_agentplatform/assets/sampledata/meeting_minutes/README.md create mode 100644 eai_agentplatform/assets/sampledata/meeting_minutes/input/会议速录.md create mode 100644 eai_agentplatform/assets/sampledata/mind_map/README.md create mode 100644 eai_agentplatform/assets/sampledata/mind_map/input/产品规划要点.md create mode 100644 eai_agentplatform/assets/sampledata/ocr_understanding/README.md create mode 100644 eai_agentplatform/assets/sampledata/ocr_understanding/images/公司介绍_帧1.png create mode 100644 eai_agentplatform/assets/sampledata/ocr_understanding/input/识别要求.md create mode 100644 eai_agentplatform/assets/sampledata/policy_rewrite/README.md create mode 100644 eai_agentplatform/assets/sampledata/policy_rewrite/input/高企认定政策原文.md create mode 100644 eai_agentplatform/assets/sampledata/ppt_generation/README.md create mode 100644 eai_agentplatform/assets/sampledata/ppt_generation/input/汇报提纲.md create mode 100644 eai_agentplatform/assets/sampledata/progress_report/README.md create mode 100644 eai_agentplatform/assets/sampledata/progress_report/input/本周工作流水.md create mode 100644 eai_agentplatform/assets/sampledata/report_generation/README.md create mode 100644 eai_agentplatform/assets/sampledata/report_generation/input/调研数据.md create mode 100644 eai_agentplatform/assets/sampledata/shared/公司背景.md create mode 100644 eai_agentplatform/assets/sampledata/smart_assistant/README.md create mode 100644 eai_agentplatform/assets/sampledata/smart_assistant/input/示例提问.md create mode 100644 eai_agentplatform/assets/sampledata/table_cleanup/README.md create mode 100644 eai_agentplatform/assets/sampledata/table_cleanup/input/脏表格.md create mode 100644 eai_agentplatform/assets/sampledata/text_to_speech/README.md create mode 100644 eai_agentplatform/assets/sampledata/text_to_speech/audio/考察通知_男声.mp3 create mode 100644 eai_agentplatform/assets/sampledata/text_to_speech/input/待合成文本.md create mode 100644 eai_agentplatform/backend-go/internal/skills/api/tts_handlers.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/email_drafting/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/email_drafting/runtime.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/project_planning/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/project_planning/runtime.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/runtime.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/survey_summary/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/survey_summary/runtime.go create mode 100644 eai_agentplatform/backend-go/internal/skills/packages/text_to_speech/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/runtime.go create mode 100644 eai_agentplatform/backend-go/internal/specialists/packages/customer_followup/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/specialists/packages/hr_email_sorter/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/specialists/packages/logistics_fulfillment/manifest.go delete mode 100644 eai_agentplatform/backend-go/internal/specialists/packages/training_delivery/manifest.go delete mode 100644 eai_agentplatform/frontend/src/skills/packages/email-drafting/execution.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/email-drafting/manifest.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/project-planning/execution.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/project-planning/manifest.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/proposal-summary/execution.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/proposal-summary/manifest.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/survey-summary/execution.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/survey-summary/manifest.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/text-toolkit/execution.js delete mode 100644 eai_agentplatform/frontend/src/skills/packages/text-toolkit/manifest.js create mode 100644 eai_agentplatform/frontend/src/specialists/packages/customer-followup/manifest.js delete mode 100644 eai_agentplatform/frontend/src/specialists/packages/hr-email-sorter/manifest.js delete mode 100644 eai_agentplatform/frontend/src/specialists/packages/logistics-fulfillment/manifest.js delete mode 100644 eai_agentplatform/frontend/src/specialists/packages/training-delivery/manifest.js diff --git a/eai_agentplatform/PROJECT_STATE.md b/eai_agentplatform/PROJECT_STATE.md index 161652d..645c9c3 100644 --- a/eai_agentplatform/PROJECT_STATE.md +++ b/eai_agentplatform/PROJECT_STATE.md @@ -12,7 +12,7 @@ ## 2. 当前状态 ### 已完成 -- ✅ PRD V1.1 最终定稿(docs/PRD.md / 设计稿) +- ✅ PRD V1.1 最终定稿(docs/06_Product_Lines/Historical_PRD_And_Designs/产品需求文档.md / 设计稿) - ✅ 文档架构搭建(docs/ 体系) - ✅ 编码规范制定(TOP_CODING_RULES.md / CLAUDE.md / PROJECT_STATE.md) - ✅ 知识入库体系(BE05)后端代码落地:knowledge_source 表 + 解析/扫描/摄入 + 审批 API + 脚本 @@ -35,7 +35,7 @@ 社交社区/讨论区**定死不做** ### 待开始 -- ⬜ 按 `docs/01_System_Overall/SY19_Universal_Digital_Worker_Product_Planning.md` +- ⬜ 按 `docs/01_System_Overall/History_And_Retrospectives/系统演进旧稿/SY19_通用数字员工产品规划.md` 将当前项目从“已有专员雏形”进一步收口为“通用数字员工平台 V1.0” ## 3. 已拍板决策 @@ -61,12 +61,12 @@ | D17 | 错题本(学员自助,非学情分析,自测/正式均写)+ 简答题 LLM 评分(`essay` 题型,复用 title_gen 路由,`essay_grade` 不扣点) | 已定(P2 落地) | | D18 | 突破原「极致极简/杜绝学情分析」边界:新增学员成长体系 = 学习积分+排行榜(游戏化)+ 考试证书(认证)+ 学习档案/能力雷达(学情,学员自助视角);积分规则集中常量可调 | 已定(V1.6 落地) | | D19 | 部门组织架构(department 字典表,用户以 department 字符串归属、改名同步)+ 按部门学情统计;站内消息通知(考试发布/通过发证/设岗三事件);**社交社区/讨论区定死不做** | 已定(V1.7 落地) | -| D20 | 当前阶段产品路线收口为「先通用、后定制」:先做标准化通用数字员工产品包,不直接追 WorkBuddy 的高自由度路线;第一批优先沉淀知识运营、培训考试、内容生成、任务推进 4 个通用数字员工,后续再长行业包与企业半定制 | 已定(见 `docs/01_System_Overall/SY19_Universal_Digital_Worker_Product_Planning.md`) | +| D20 | 当前阶段产品路线收口为「先通用、后定制」:先做标准化通用数字员工产品包,不直接追 WorkBuddy 的高自由度路线;第一批优先沉淀知识运营、培训考试、内容生成、任务推进 4 个通用数字员工,后续再长行业包与企业半定制 | 已定(见 `docs/01_System_Overall/History_And_Retrospectives/系统演进旧稿/SY19_通用数字员工产品规划.md`) | | D21 | 前端曾短暂采用「冻结归档」机制保存停用代码;当前已取消该策略,早期历史代码直接删除,不再维护 `frontend/src/_frozen/`。站内通知如需恢复,按当前实现重新设计,不再依赖冻结稿。 | 已更新 | | D22 | 任务记录**延迟到发出第一条消息时创建**(对齐 WorkBuddy:新建任务只是导航动作,不落库)。「新建任务」只做「回到 /home 开场画布 + 清空当前任务」,任务标题由第一句话决定、专员取输入框 `+` 里先选的那个(`pendingSpecialistKey` 暂存,建任务时作为 `specialist_key` 一并提交,后端已支持)。**不允许存在没聊过天的空任务** —— 原实现点一次落一条 `新任务`,是「最近任务」堆满空行的根因 | 已定(V1.8 落地) | | D23 | 侧边栏「最近任务」的行菜单(对齐 ChatGPT 悬停 `⋯` + WorkBuddy 任务卡「更多」):**重命名**(就地编辑,回车提交/Esc 取消)、**置顶**(新增 `worker_task.pinned`,排序 `pinned DESC, updated_at DESC`)、**删除**(新增 `DELETE /api/worker/my-tasks/:id`,硬删、无回收站,确认框写明「无法恢复」)。对照后**不做**:分享任务(纯内网无意义)、打开文件夹(Web 无此能力)、保存到工作空间(项目无 workspace 概念)、归档(没有「已归档」入口可找回,等于软删陷阱)。`el-dropdown` 加 `:persistent="false"` —— 默认每行留一份隐藏菜单在 DOM 里,50 条任务就是 50 份 | 已定 | | D24 | SQLite **定期备份内置进二进制**(不用外部 cron/systemd timer):启动时补一次 + 每小时查是否到期,默认间隔 24h、保留最近 7 份,落在 `data/backups/`(systemd 是 `ProtectSystem=strict`,只放开了 `data/` 可写)。快照用 `VACUUM INTO` 而非 `cp` 主库 —— 边服务边写时 `cp` 可能拷到写了一半的页。产出自检 SQLite 文件头,不合格即删。另提供 `-backup` 子命令供升级/迁移前手工备一份。**边界**:只防误删/误改/写坏,不防整盘损坏,跨机保存仍需人工 | 已定(见 `deploy/DELIVERY.md` 第 7 节) | -| D25 | 平台总架构继续采用 6 层,但第 5 层正式升级为 **对象层(Expert / Skill / App)**;新增与“专家 / 技能”并列的第三类一级对象 **App**,其定位是“长程任务运行壳”而非页面或大技能。任务统一定义为“工作实例容器”,可挂载主 `app`、右栏 `expert`、后台 `skill`;消息流降级为对话轨迹,长程状态由 `app_state + app_event + domain_data` 承载。产品一级导航目标态需完整描述为 **新建任务 / 项目 / 专家·技能·连接器 / 长程APP / 知识库 / 后台管理 / 我的**,其中 `知识库` 被确认为组织级默认必装的内建 App,拥有一级直达入口;其它专题型业务主导航后续应优先收敛为 `app` 并归入“长程APP”。文档锚点:`docs/01_System_Overall/SY22_Role_Skill_App_Unified_Task_Architecture.md` | 已定 | +| D25 | 平台总架构继续采用 6 层,但第 5 层正式升级为 **对象层(Expert / Skill / App)**;新增与“专家 / 技能”并列的第三类一级对象 **App**,其定位是“长程任务运行壳”而非页面或大技能。任务统一定义为“工作实例容器”,可挂载主 `app`、右栏 `expert`、后台 `skill`;消息流降级为对话轨迹,长程状态由 `app_state + app_event + domain_data` 承载。产品一级导航目标态需完整描述为 **新建任务 / 项目 / 专家·技能·连接器 / 长程APP / 知识库 / 后台管理 / 我的**,其中 `知识库` 被确认为组织级默认必装的内建 App,拥有一级直达入口;其它专题型业务主导航后续应优先收敛为 `app` 并归入“长程APP”。文档锚点:`docs/01_System_Overall/SY22_角色技能应用统一任务架构.md` | 已定 | | D26 | 路由命名正式拆分为三类以避免混同:`ai_route_*` 专指 AI 模型路由;`object_entry_route` 专指 Expert / Skill / App 等业务对象的进入入口;`page_route` 专指普通页面导航。后端 API、前端对象配置与导航配置均按该口径收口;旧 `route / entry_route` 已降为启动时一次性迁移并随后删除的历史列,不再保留为日常兼容字段。 | 已定 | | D27 | 后端「仓库层」正式更名为**数据访问层**,英文同步改:包 `internal/repository` → `internal/dal`,类型 `XxxRepo` → `XxxDAO`(`TaskRecordDAO` / `SpecialistDAO`…),日志前缀 `[repository]` → `[dal]`。理由是原名的「仓库」是 repository 的直译,中文里与「代码仓库 / git 仓库」同词,而这一层做的事就是数据访问。命名规范见 AR09 §3.1 / §5.6 | 已定 | @@ -75,13 +75,13 @@ | 文档 | 路径 | 说明 | |------|------|------| -| PRD | `../docs/PRD.md` | 产品需求文档(V1.1 最终版) | +| PRD | `../docs/06_Product_Lines/Historical_PRD_And_Designs/产品需求文档.md` | 产品需求文档(V1.1 最终版) | | 设计稿 | `../docs/eaisalestrain_app设计稿.md` | 完整 PRD 中文原稿 | -| DB Schema | `../docs/db_schema.md` | 9 张核心表字段设计 | -| API 文档 | `../docs/api.md` | API 接口定义 | -| 部署文档 | `../docs/deploy.md` | 部署架构与步骤 | -| 变更日志 | `../docs/changelog.md` | 版本变更记录 | -| 知识入库体系 | `../docs/04_Backend/BE05_Knowledge_Ingest_Module.md` | 上传→生成→审批→入库总设计 | +| DB Schema | `../docs/04_Backend/数据库结构.md` | 9 张核心表字段设计 | +| API 文档 | `../docs/04_Backend/接口文档.md` | API 接口定义 | +| 部署文档 | `../docs/02_Architecture/部署文档.md` | 部署架构与步骤 | +| 变更日志 | `../docs/01_System_Overall/变更日志.md` | 版本变更记录 | +| 知识入库体系 | `../docs/04_Backend/BE05_知识导入模块.md` | 上传→生成→审批→入库总设计 | | 知识源目录 | `assets/knowledge/source/` | 结构化知识源 md(5 份,28 产品 + 20 题) | | 培训资料目录 | `assets/training/materials/` | 培训课程资产与种子源文件 | | 编码准则 | `../TOP_CODING_RULES.md` | 编码与调试最高准则 | diff --git a/eai_agentplatform/assets/knowledge/source/README.md b/eai_agentplatform/assets/knowledge/source/README.md index 95fd477..eae1162 100644 --- a/eai_agentplatform/assets/knowledge/source/README.md +++ b/eai_agentplatform/assets/knowledge/source/README.md @@ -1,7 +1,7 @@ # 知识源入库目录(Knowledge Source Ingest) > 本目录是「结构化知识源文档」的唯一入库口,与「素材上传流水线」(backend-go/data/kb_data)并行。 -> 数据权威源:`../../../../docs/博昇产品与渠道合作表.md`(对齐《客户介绍合作协议》第二条)。 +> 数据权威源:`../../../../docs/06_Product_Lines/Business_Materials/博昇产品与渠道合作表.md`(对齐《客户介绍合作协议》第二条)。 --- @@ -68,7 +68,7 @@ pending ──审批通过──▶ approved ──▶ 生效(product active / ## 6. 代码侧已实现(Go) -> 完整设计见 `../../../../docs/04_Backend/BE05_Knowledge_Ingest_Module.md`(知识入库体系总设计)。 +> 完整设计见 `../../../../docs/04_Backend/BE05_知识导入模块.md`(知识入库体系总设计)。 - [x] `internal/model/knowledge_source.go` —— 知识源文档表 - [x] `internal/model/knowledge_chunk.go` —— 来源扩展(media_file_id 可空 + knowledge_source_id) diff --git a/eai_agentplatform/assets/sampledata/README.md b/eai_agentplatform/assets/sampledata/README.md new file mode 100644 index 0000000..5ef45d5 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/README.md @@ -0,0 +1,54 @@ +# sampledata —— 全技能测试样例库 + +本目录为 **EAI 数字员工平台** 的测试样例数据,用于覆盖并验证平台全部技能(skill)的输入与预期产出。每个子目录对应一个技能(以技能的 key 命名),供接口联调、功能回归、演示与自动化测试复用。 + +## 目录约定 + +``` +sampledata/ + README.md # 本文件:总索引与使用说明 + shared/ # 跨技能共用的背景素材(公司简介、业务上下文等) + / # 每个技能一个子目录 + README.md # 该技能:用途 / 样例文件 / 调用方式 / 期望产出 + input.* # 输入样例(txt / md / json / 图片 / 音频) + expected/ # (可选)期望产出参考 +``` + +## 技能清单与覆盖情况 + +| 技能 key | 技能名 | 样例目录 | 实现状态 | +| --- | --- | --- | --- | +| audio-transcribe | 语音转写 | `audio_transcribe/` | 占位 | +| batch-extract | 批量抽取 | `batch_extract/` | 占位 | +| contract-brief | 合同要点提炼 | `contract_brief/` | 已实现 | +| contract-review | 合同审查 | `contract_review/` | 占位 | +| copy-proofreading | 文案校对 | `copy_proofreading/` | 占位 | +| document-translate | 文档翻译 | `document_translate/` | 占位 | +| interview-summary | 面试纪要 | `interview_summary/` | 已实现 | +| longform-writing | 长文写作 | `longform_writing/` | 已实现 | +| meeting-minutes | 会议纪要 | `meeting_minutes/` | 已实现 | +| mind-map | 思维导图 | `mind_map/` | 已实现 | +| ocr-understanding | OCR 图文理解 | `ocr_understanding/` | 已实现 | +| policy-rewrite | 政策解读改写 | `policy_rewrite/` | 已实现 | +| ppt-generation | PPT 生成 | `ppt_generation/` | 已实现 | +| progress-report | 周报 / 日报 | `progress_report/` | 已实现 | +| report-generation | 报告生成 | `report_generation/` | 已实现 | +| smart-assistant | 通用助手 | `smart_assistant/` | 占位 | +| table-cleanup | 表格清理 | `table_cleanup/` | 已实现 | +| text-to-speech | 文字转语音 | `text_to_speech/` | 已实现 | + +> 「占位」指该技能目前仅有 manifest 定义、尚无专属运行时实现,样例仍可用来预置输入。 + +## 使用方式 + +1. **人工联调**:直接以 `input.*` 内容作为相应接口的请求体,对照 `expected/` 检查产出。 +2. **前端演示**:进入对应专员的画布,粘贴 `input.*` 文本,触发技能执行。 +3. **自动化测试**:样例文件均为纯文本 / JSON / 标准格式,可直接被 Go 或脚本读取并断言结果。 + +## 公共背景 + +所有样例统一围绕以下业务背景,保证跨技能素材一致: +- 平台:博昇数字员工平台 +- 业务线:资本咨询、资质认定辅导、AI 咨询与落地、企业级 AI 工具与平台 +- 方法论:顾问式销售(FABE / SPIN / LSCPA) +- 详见 [shared/公司背景.md](shared/公司背景.md) diff --git a/eai_agentplatform/assets/sampledata/audio_transcribe/README.md b/eai_agentplatform/assets/sampledata/audio_transcribe/README.md new file mode 100644 index 0000000..c83ea6a --- /dev/null +++ b/eai_agentplatform/assets/sampledata/audio_transcribe/README.md @@ -0,0 +1,16 @@ +# 语音转写(audio-transcribe)样例 + +## 用途 +把音频里的语音转成文字,用于会议口述、培训录音转文档。 + +## 样例文件 +- `input/上午会议口述.mp3` —— 一段口述会议的语音(中文),内容涉及 10 月美国考察、云帆科技高企材料、销售培训新课表。 + +## 调用方式 +- 接口:`POST /api/audio/transcribe`(multipart 上传 `file`,可选 `language=zh`) +- 把 `input/上午会议口述.mp3` 作为上传文件。 + +## 期望产出 +一份转写文本,应包含「10月美国考察名单」「云帆科技高新认定材料」「销售培训新课表」三个要点。 + +> 说明:本技能当前为「占位」实现(仅有 manifest),实际转写依赖后端 Ollama whisper 服务;样例仍可用于接口预置。 diff --git a/eai_agentplatform/assets/sampledata/audio_transcribe/input/上午会议口述.mp3 b/eai_agentplatform/assets/sampledata/audio_transcribe/input/上午会议口述.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..c4156a2043fbb10b3564cbb1a38472f88df012f7 GIT binary patch literal 65952 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

IHyP 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 literal 0 HcmV?d00001 diff --git a/eai_agentplatform/assets/sampledata/batch_extract/README.md b/eai_agentplatform/assets/sampledata/batch_extract/README.md new file mode 100644 index 0000000..dba90e2 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/batch_extract/README.md @@ -0,0 +1,17 @@ +# 批量抽取(batch-extract)样例 + +## 用途 +从多份文档中批量抽取结构化字段(如金额、日期、企业名、条款),用于合同/报价/申报材料的批量录入。 + +## 样例文件 +- `input/材料集/` 放置要批量抽取的文档;每个文档给一段可抽取的结构化表述。 +- `input/期望字段.json` —— 声明每份文档应抽出的字段与示例值。 + +## 调用方式 +- 接口:`POST /api/batch/extract` 或 `POST /api/batch/files` +- 把 `input/材料集/*.md` 作为待抽取输入。 + +## 期望产出 +每份文档对应的 JSON 字段表,可与 `input/期望字段.json` 对照。 + +> 说明:本技能当前为「占位」实现,样例用于接口预置与契约设计。 diff --git a/eai_agentplatform/assets/sampledata/batch_extract/input/期望字段.json b/eai_agentplatform/assets/sampledata/batch_extract/input/期望字段.json new file mode 100644 index 0000000..8ee9deb --- /dev/null +++ b/eai_agentplatform/assets/sampledata/batch_extract/input/期望字段.json @@ -0,0 +1,27 @@ +{ + "说明": "每份文档应抽取的字段,用于校验批量抽取结果", + "documents": [ + { + "doc": "云帆科技", + "fields": [ + {"字段": "企业名称", "类型": "string"}, + {"字段": "所属行业", "类型": "string"}, + {"字段": "营业收入", "类型": "number"}, + {"字段": "研发费用", "类型": "number"}, + {"字段": "科技人员占比", "类型": "percent"}, + {"字段": "主要知识产权", "类型": "list"}, + {"字段": "申请事项", "类型": "string"} + ] + }, + { + "doc": "星海资本", + "fields": [ + {"字段": "机构名称", "类型": "string"}, + {"字段": "联系人", "类型": "string"}, + {"字段": "意向", "类型": "string"}, + {"字段": "拟投资规模", "类型": "string"}, + {"字段": "关注方向", "类型": "string"} + ] + } + ] +} diff --git a/eai_agentplatform/assets/sampledata/batch_extract/input/材料集/云帆科技.md b/eai_agentplatform/assets/sampledata/batch_extract/input/材料集/云帆科技.md new file mode 100644 index 0000000..82093e4 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/batch_extract/input/材料集/云帆科技.md @@ -0,0 +1,10 @@ +# 云帆科技申报材料(批量抽取样例文档 1) + +企业名称:云帆科技 +类型:民营有限责任公司 +所属行业:软件与信息技术服务业 +2025 年营业收入:4800 万元 +研发费用:280 万元 +科技人员占比:30% +主要知识产权:软件著作权 6 项 +申请事项:高新技术企业认定 diff --git a/eai_agentplatform/assets/sampledata/batch_extract/input/材料集/星海资本.md b/eai_agentplatform/assets/sampledata/batch_extract/input/材料集/星海资本.md new file mode 100644 index 0000000..e2df779 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/batch_extract/input/材料集/星海资本.md @@ -0,0 +1,7 @@ +# 星海资本洽谈纪要(批量抽取样例文档 2) + +机构名称:星海资本 +联系人:周总监 +意向:随行 2026-10-18 美国考察,评估投资标的 +拟投资规模:单笔 1000 万元起 +关注方向:AI 落地、渠道复制能力 diff --git a/eai_agentplatform/assets/sampledata/contract_brief/README.md b/eai_agentplatform/assets/sampledata/contract_brief/README.md new file mode 100644 index 0000000..70974f5 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/contract_brief/README.md @@ -0,0 +1,16 @@ +# 合同要点提炼(contract-brief)样例 + +## 用途 +从合同文本中提炼要点、关键条款与风险点,供决策与审批用。 + +## 样例文件 +- `input/合同简介.md` —— 一份合作框架类合同的精简文本。 +- `expected/` —— (可选)期望的要点与风险清单。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`contract-brief`,把 `input/合同简介.md` 作为 input_text 粘贴)—— 需在已建任务下执行。 + +## 期望产出 +要点提炼(合作标的、付款条件、责任条款、保密、风险项)供后续决策。 + +> 说明:本技能为「已实现」技能,走 office 运行时,用 AI + 知识库生成要点。 diff --git a/eai_agentplatform/assets/sampledata/contract_brief/input/合同简介.md b/eai_agentplatform/assets/sampledata/contract_brief/input/合同简介.md new file mode 100644 index 0000000..7d4f158 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/contract_brief/input/合同简介.md @@ -0,0 +1,11 @@ +# 合作框架合同(精简样例) + +甲方:博昇数字员工平台(下称「甲方」) +乙方:云帆科技(下称「乙方」) + +1. **合作内容**:甲方为乙方提供高新技术企业认定辅导及 AI 落地咨询服务,服务期自 2026-01-01 至 2026-06-30。 +2. **费用与支付**:服务费总额 60 万元。合同签订后 3 日内支付 30% 作为启动款;高企申报受理后支付 40%;认定通过后 30 日内支付剩余 30%。 +3. **交付**:甲方按里程碑交付《申报材料》《AI 试点方案》等成果,成果知识产权归甲方所有,乙方享有使用权。 +4. **保密**:双方对合作中知悉的商业秘密负保密义务,保密期至合作结束后 3 年。 +5. **违约责任**:任何一方逾期履行主要义务,应向对方支付合同金额 10% 的违约金;累计逾期超 30 日可解除合同。 +6. **争议解决**:协商不成时,提交甲方所在地人民法院诉讼解决。 diff --git a/eai_agentplatform/assets/sampledata/contract_review/README.md b/eai_agentplatform/assets/sampledata/contract_review/README.md new file mode 100644 index 0000000..b17a3c6 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/contract_review/README.md @@ -0,0 +1,16 @@ +# 合同审查(contract-review)样例 + +## 用途 +对完整合同做合规审查、识别风险条款并给出修改建议。 + +## 样例文件 +- `input/采购合同.md` —— 一份采购类合同全文样例。 +- `expected/审查意见.md` —— (可选)期望的风险点与修改建议清单。 + +## 调用方式 +- 接口:`POST /api/contract/review`(以 `input/采购合同.md` 为合同文本)。 + +## 期望产出 +风险条款清单(付款、违约、交付标准、责任豁免等)+ 逐条修改建议。 + +> 说明:同名技能 `contract-review` 当前为「占位」实现,核心审查逻辑尚未落地;但平台已有独立契约审查接口可用于联调。 diff --git a/eai_agentplatform/assets/sampledata/contract_review/input/采购合同.md b/eai_agentplatform/assets/sampledata/contract_review/input/采购合同.md new file mode 100644 index 0000000..2f739d6 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/contract_review/input/采购合同.md @@ -0,0 +1,14 @@ +# 采购合同(样例全文) + +甲方(采购方):博昇数字员工平台 +乙方(供应商):上海某软件股份有限公司 + +## 条款 +1. 采购内容:企业智能体开发平台 License 一套,含源码交付。 +2. 金额:人民币 320 万元,含税。 +3. 付款:预付款 50% 于合同生效后支付;验收后支付 45%;质保期(12 个月)结束后支付 5%。 +4. 交付与验收:乙方收到预付款后 90 日内完成交付,甲方在 15 个工作日内验收。 +5. 违约:乙方逾期交付,每逾期一日按合同金额 0.5% 支付违约金;甲方逾期付款同上。 +6. 责任限制:在任何情况下,乙方对甲方的赔偿总额不超过合同金额。 +7. 保密:乙方对甲方业务数据负保密义务,保密期 5 年。 +8. 知识产权:交付源码的著作权归甲方。 diff --git a/eai_agentplatform/assets/sampledata/copy_proofreading/README.md b/eai_agentplatform/assets/sampledata/copy_proofreading/README.md new file mode 100644 index 0000000..645386e --- /dev/null +++ b/eai_agentplatform/assets/sampledata/copy_proofreading/README.md @@ -0,0 +1,16 @@ +# 文案校对(copy-proofreading)样例 + +## 用途 +检查文案的错别字、语法、标点与合规表述,输出修改建议。 + +## 样例文件 +- `input/待校对文案.md` —— 一段含常见错误的宣传/话术文案。 +- `expected/校对结果.md` —— (可选)期望的纠错清单。 + +## 调用方式 +- 接口:`POST /api/copy/proofread` 或 `GET /api/copy/quick`(快速校对)。 + +## 期望产出 +定位并逐条列出错字、标点、重复、合规风险,给出替换建议。 + +> 说明:技能 `copy-proofreading` 当前为「占位」;平台有独立校对接口可用于联调。 diff --git a/eai_agentplatform/assets/sampledata/copy_proofreading/input/待校对文案.md b/eai_agentplatform/assets/sampledata/copy_proofreading/input/待校对文案.md new file mode 100644 index 0000000..b10433f --- /dev/null +++ b/eai_agentplatform/assets/sampledata/copy_proofreading/input/待校对文案.md @@ -0,0 +1,9 @@ +# 待校对文案(样例,含刻意错误) + +博昇数字员工平台,专注为企业提**供**「数字化经营增**长**」解决方案。我们提供高新企业认定辅助、专**精**特新培育、AI落地实施的一站式服务。 + +- 高新技术企业认定,享**受**所得税优惠; +- Ai 与人工结合,顾问式销售陪**办**交付; +- 提供企业级智能体平**台**,帮**主**提效。 + +如有**愿**,请联系我们:**4006-1234-5678**,期待与您共创未来! diff --git a/eai_agentplatform/assets/sampledata/document_translate/README.md b/eai_agentplatform/assets/sampledata/document_translate/README.md new file mode 100644 index 0000000..cf1caa1 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/document_translate/README.md @@ -0,0 +1,15 @@ +# 文档翻译(document-translate)样例 + +## 用途 +中英互译文档,保留结构与术语一致性。 + +## 样例文件 +- `input/中文简介.md` —— 一段公司中英双语对照素材的中文版。 + +## 调用方式 +- 接口:`POST /api/document/translate`(`content` 传入文本,`target_language` 指定目标语言)。 + +## 期望产出 +对照翻译结果,术语(高企认定、智能体、顾问式销售等)应保持统一译法。 + +> 说明:技能 `document-translate` 当前为「占位」;平台有独立翻译接口可用于联调。 diff --git a/eai_agentplatform/assets/sampledata/document_translate/input/中文简介.md b/eai_agentplatform/assets/sampledata/document_translate/input/中文简介.md new file mode 100644 index 0000000..71bc0fe --- /dev/null +++ b/eai_agentplatform/assets/sampledata/document_translate/input/中文简介.md @@ -0,0 +1,3 @@ +# 公司中文简介(供翻译) + +博昇数字员工平台,聚焦资本咨询、资质认定辅导、AI 咨询与实施、企业级 AI 工具与平台建设。我们以顾问式销售方法论服务成长型企业,覆盖制造、科技与拟上市企业,提供从商业模式梳理到高企认定申报、再到 AI 落地交付的一站式陪伴服务。 diff --git a/eai_agentplatform/assets/sampledata/interview_summary/README.md b/eai_agentplatform/assets/sampledata/interview_summary/README.md new file mode 100644 index 0000000..3ce111e --- /dev/null +++ b/eai_agentplatform/assets/sampledata/interview_summary/README.md @@ -0,0 +1,16 @@ +# 面试纪要(interview-summary)样例 + +## 用途 +把面试双方问答整理成纪要,提炼候选人能力评估、亮点与风险。 + +## 样例文件 +- `input/面试记录.md` —— 一段 HR 与候选人对话速记。 +- `expected/面试纪要.md` ——(可选)期望的纪要结构。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`interview-summary`,粘贴 `input/面试记录.md`)。 + +## 期望产出 +候选人基本信息、能力评估、匹配度、亮点与风险、建议结论。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/interview_summary/input/面试记录.md b/eai_agentplatform/assets/sampledata/interview_summary/input/面试记录.md new file mode 100644 index 0000000..8ee6fae --- /dev/null +++ b/eai_agentplatform/assets/sampledata/interview_summary/input/面试记录.md @@ -0,0 +1,11 @@ +# 面试记录(样例速记) + +候选人:陈先生,目标岗位「AI 解决方案顾问」 +面试官:王助理(HR)+ 李董事长 + +- 陈先生有 6 年企业服务售前经验,服务过制造业与 SaaS 客户,主导过 3 个 AI 项目 POC。 +- 熟悉高企认定流程并有 2 个成功申报案例。 +- 沟通表达清晰,能用客户语言讲清「智能体 / 数字员工」的价值;对 FABE、SPIN 方法有基础认知。 +- 期望薪资 2.2 万/月,可接受出差(含海外考察)。 +- 风险点:此前公司产品偏 SaaS 标准化,独立方案设计经验略少;入职后需补充定制化方案训练。 +- 面试评价:总体匹配度高,建议进入二面并安排一次现场方案演练。 diff --git a/eai_agentplatform/assets/sampledata/longform_writing/README.md b/eai_agentplatform/assets/sampledata/longform_writing/README.md new file mode 100644 index 0000000..5ffb2c1 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/longform_writing/README.md @@ -0,0 +1,16 @@ +# 长文写作(longform-writing)样例 + +## 用途 +根据主题与要点生成结构化长文(公众号推文、深度文章)。 + +## 样例文件 +- `input/写作主题.md` —— 主题与结构要求。 +- `expected/文章样本.md` ——(可选)期望的开头与章节结构。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`longform-writing`,粘贴 `input/写作主题.md`)。 + +## 期望产出 +一篇标题 + 引言 + 若干章节(含小标题)+ 结尾的长文,主题统一采用平台业务。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/longform_writing/input/写作主题.md b/eai_agentplatform/assets/sampledata/longform_writing/input/写作主题.md new file mode 100644 index 0000000..94ca4a1 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/longform_writing/input/写作主题.md @@ -0,0 +1,14 @@ +# 长文写作素材 + +标题方向:《企业搞 AI 落地,为什么需要「数字员工」而不是一堆工具?》 + +目标读者:制造与科技型企业的经营者。 + +结构要求: +1. 开场:抛出企业 AI 落地常见的误区(买工具 ≠ 有用)。 +2. 第二段:什么是数字员工 / 智能体,与传统工具的区别。 +3. 第三段:从「顾问式销售」到「陪伴式交付」的价值闭环。 +4. 第四段:结合高企认定、AI 试点、流程智能化三个具体场景。 +5. 结尾:给经营者的行动建议。 + +行文要求:口语化中带专业,少堆术语,多用具体例证。 diff --git a/eai_agentplatform/assets/sampledata/meeting_minutes/README.md b/eai_agentplatform/assets/sampledata/meeting_minutes/README.md new file mode 100644 index 0000000..098cc0d --- /dev/null +++ b/eai_agentplatform/assets/sampledata/meeting_minutes/README.md @@ -0,0 +1,17 @@ +# 会议纪要(meeting-minutes)样例 + +## 用途 +把会议速录/要点整理成会议纪要:主题、结论、行动项。 + +## 样例文件 +- `input/会议速录.md` —— 一段商务会议现场对话速记(3 位男性:两位董事长 + 一位助理,讨论 2026-10-18 美国考察议程)。 +- `expected/会议纪要.md` —— 已人工整理的纪要参考(可直接对比产出)。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`meeting-minutes`,把 `input/会议速录.md` 作为输入)。 +- 也可直接用画布技能触发。 + +## 期望产出 +会议基本信息、参会人、议题讨论要点、决议、行动项(负责人+期限)。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/meeting_minutes/input/会议速录.md b/eai_agentplatform/assets/sampledata/meeting_minutes/input/会议速录.md new file mode 100644 index 0000000..b054f64 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/meeting_minutes/input/会议速录.md @@ -0,0 +1,25 @@ +# 会议速录(样例)—— 2026-10-18 美国企业考察议程讨论会 + +参会:张董事长(集团)、李董事长(海外业务)、王助理 +时间:2026-09-18 14:00 + +**张董事长(开场):** +> 今天先把 10 月 18 日这批去美国的考察定下来,目标要清晰,别走马观花。李董先谈谈这次最想解决什么问题。 + +**李董事长:** +> 我的判断三件事:一是把北美代理和分销的意向摸清楚;二看两家对标企业在新品和市场打法上的差距;三我们有一个潜在技术合作方,想当面谈合作框架。考察不贪多,聚焦 3-4 家,行程 7 天左右。 + +**张董事长:** +> 同意聚焦。天数我建议 10 月 18 日出发、10 月 25 日返程,共 8 天。去掉飞行和时差,有效商务时间约 5 个工作日,安排紧凑些。 + +**王助理:** +> 补充落地信息:美国东岸适合先落纽约,再沿波士顿到芝加哥一线走,目标企业大多在东岸中段。我可以按这个排城市和对接顺序,控差旅成本。 + +**李董事长:** +> 关键是派谁带队、谁去谈。考察要有决策权的人在场。建议张董挂帅,我带市场团队随行,王助理统筹日程和签证。 + +**张董事长:** +> 可以,基调定了:目标=渠道对接+技术合作+竞品对标;规模=4-5 人小团队;周期=10 月 18 日-25 日;美国东岸三城。把每一项落到人和时间上。 + +**王助理(小结):** +> 我整理成行动项:名单与签证、企业走访预约、技术合作洽谈预案、预算审批、宣传复盘,每项挂责任人。 diff --git a/eai_agentplatform/assets/sampledata/mind_map/README.md b/eai_agentplatform/assets/sampledata/mind_map/README.md new file mode 100644 index 0000000..d9da02e --- /dev/null +++ b/eai_agentplatform/assets/sampledata/mind_map/README.md @@ -0,0 +1,16 @@ +# 思维导图(mind-map)样例 + +## 用途 +把一段文字整理成结构化思维导图(主题-分支-子项)。 + +## 样例文件 +- `input/产品规划要点.md` —— 一段「客户成功产品规划」的描述,作为导图根节点素材。 +- `expected/导图结构.md` ——(可选)期望的分支层级参考。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`mind-map`,粘贴 `input/产品规划要点.md`)。 + +## 期望产出 +以「客户成功产品」为根的树形结构:核心价值 / 功能模块 / 落地阶段 / 度量指标。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/mind_map/input/产品规划要点.md b/eai_agentplatform/assets/sampledata/mind_map/input/产品规划要点.md new file mode 100644 index 0000000..8b096a8 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/mind_map/input/产品规划要点.md @@ -0,0 +1,13 @@ +# 客户成功产品规划要点 + +根节点:客户成功产品 + +主分支: +1. 核心价值:围绕高企认定、AI 落地、顾问式销售,让客户看得见「数字员工」的回报。 +2. 功能模块: + - 知识库 / 规则库 + - 专员与任务画布 + - 技能市场(会议纪要、PPT、报告等) + - 审批与交付物流转 +3. 落地阶段:导入期 → 试用期 → 正式付费 → 复购扩展。 +4. 度量指标:激活率、任务完成率、续费率、NPS。 diff --git a/eai_agentplatform/assets/sampledata/ocr_understanding/README.md b/eai_agentplatform/assets/sampledata/ocr_understanding/README.md new file mode 100644 index 0000000..cc83262 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/ocr_understanding/README.md @@ -0,0 +1,16 @@ +# OCR 图文理解(ocr-understanding)样例 + +## 用途 +识别图片中的文字并结构化输出(OCR / 图文理解)。 + +## 样例文件 +- `images/公司介绍_帧1.png` —— 从公司介绍视频抽取的一帧画面,作为图片输入样例。 + +## 调用方式 +- 接口:`POST /api/skills/office/ocr`(multipart 上传图片 `file`,带 `task_id`;如需可带 `prompt`)。 +- 把 `images/公司介绍_帧1.png` 作为上传图片。 + +## 期望产出 +识别出的文本(text)+ 行级坐标(lines)+ 引擎与上传信息,便于下游进一步整理。 + +> 说明:技能为「已实现」,走 office 自定义 OCR(PaddleOCR 脚本)运行时。 diff --git a/eai_agentplatform/assets/sampledata/ocr_understanding/images/公司介绍_帧1.png b/eai_agentplatform/assets/sampledata/ocr_understanding/images/公司介绍_帧1.png new file mode 100644 index 0000000..9f3bdb8 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/ocr_understanding/images/公司介绍_帧1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2a3d3031916105e504449c0a45dbd63b4bbd844b1a0e16afaf46f2d8752c6d9e +size 251494 diff --git a/eai_agentplatform/assets/sampledata/ocr_understanding/input/识别要求.md b/eai_agentplatform/assets/sampledata/ocr_understanding/input/识别要求.md new file mode 100644 index 0000000..c01a8fc --- /dev/null +++ b/eai_agentplatform/assets/sampledata/ocr_understanding/input/识别要求.md @@ -0,0 +1,8 @@ +# OCR 识别要求(样例) + +图片:`../images/公司介绍_帧1.png`(公司介绍视频画面) + +识别目标:提取画面中的公司名称、业务关键词、显著文案。 + +Prompt 建议: +> 请识别图中文字并整理为:公司名称、主营业务、关键卖点 三块。 diff --git a/eai_agentplatform/assets/sampledata/policy_rewrite/README.md b/eai_agentplatform/assets/sampledata/policy_rewrite/README.md new file mode 100644 index 0000000..54b1307 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/policy_rewrite/README.md @@ -0,0 +1,16 @@ +# 政策解读改写(policy-rewrite)样例 + +## 用途 +把政策/官方文本改写为通俗、可执行的企业解读。 + +## 样例文件 +- `input/高企认定政策原文.md` —— 一段高新技术企业认定政策要点。 +- `expected/通俗解读.md` ——(可选)期望的客户向解读。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`policy-rewrite`,粘贴 `input/高企认定政策原文.md`)。 + +## 期望产出 +把「八大条件」改写为老板能听懂的话 + 企业自查清单口径的解释。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/policy_rewrite/input/高企认定政策原文.md b/eai_agentplatform/assets/sampledata/policy_rewrite/input/高企认定政策原文.md new file mode 100644 index 0000000..014e8cd --- /dev/null +++ b/eai_agentplatform/assets/sampledata/policy_rewrite/input/高企认定政策原文.md @@ -0,0 +1,12 @@ +# 高新技术企业认定(政策原文要点样例) + +依据《高新技术企业认定管理办法》,认定的硬性条件主要包括: + +1. 企业须在中国境内注册成立一年以上(须正常经营)。 +2. 对其主要产品(服务)的核心技术拥有自主知识产权(专利/软著等)。 +3. 高新技术产品(服务)收入占总收入的比例不低于 60%。 +4. 科技人员占当年职工总数的比例不低于 10%。 +5. 近三个会计年度的研究开发费用总额占销售收入总额的比例须达到规定标准(销售收入 ≤ 5000 万:5%;5000 万-2 亿:4%;>2 亿:3%)。 +6. 创新能力评价须达到相应要求(知识产权、科技成果转化、成长性等指标综合评分)。 +7. 企业申请认定前一年内未发生重大安全、质量事故或严重环境违法行为。 +8. 须符合《国家重点支持的高新技术领域》范围。 diff --git a/eai_agentplatform/assets/sampledata/ppt_generation/README.md b/eai_agentplatform/assets/sampledata/ppt_generation/README.md new file mode 100644 index 0000000..fe9312e --- /dev/null +++ b/eai_agentplatform/assets/sampledata/ppt_generation/README.md @@ -0,0 +1,16 @@ +# PPT 生成(ppt-generation)样例 + +## 用途 +按提纲把内容排成演示文稿(幻灯片结构 + 页面要点)。 + +## 样例文件 +- `input/汇报提纲.md` —— 一段「赴美考察筹备汇报」的提纲。 +- `expected/幻灯片结构.md` ——(可选)期望的页序与每页标题。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`ppt-generation`,粘贴 `input/汇报提纲.md`)。 + +## 期望产出 +一份页序清晰的 PPT 框架:封面 / 背景 / 目的 / 行程 / 预算 / 分工 / 时间表 / 下一步。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/ppt_generation/input/汇报提纲.md b/eai_agentplatform/assets/sampledata/ppt_generation/input/汇报提纲.md new file mode 100644 index 0000000..85ac9ab --- /dev/null +++ b/eai_agentplatform/assets/sampledata/ppt_generation/input/汇报提纲.md @@ -0,0 +1,12 @@ +# 赴美考察筹备汇报(PPT 提纲) + +需要做一份向董事会汇报的 PPT,内容: + +- 封面:2026 美国商务考察筹备方案 +- 背景与目的:北美渠道对接、技术合作洽谈、竞品对标 +- 考察概要:10 月 18 日-25 日,美国东岸(纽约-波士顿-芝加哥),4-5 人 +- 行程安排:三城走访 3-4 家企业,按天排 +- 预算概览:机票、酒店、交通、接待 +- 分工表:张董带队 / 李董带市场 / 王助理统筹 +- 关键时间节点:9 月 30 日签注、10 月 8 日企业预约、10 月 12 日洽谈预案 +- 下一步与风险 diff --git a/eai_agentplatform/assets/sampledata/progress_report/README.md b/eai_agentplatform/assets/sampledata/progress_report/README.md new file mode 100644 index 0000000..45c4282 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/progress_report/README.md @@ -0,0 +1,16 @@ +# 周报 / 日报(progress-report)样例 + +## 用途 +把零散的工作条目整理成结构化的周报/日报(进展、风险、下一步)。 + +## 样例文件 +- `input/本周工作流水.md` —— 一周工作流水记录。 +- `expected/周报.md` ——(可选)期望的周报结构。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`progress-report`,粘贴 `input/本周工作流水.md`)。 + +## 期望产出 +本周进展 / 风险事项 / 下步计划 三段式周报。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/progress_report/input/本周工作流水.md b/eai_agentplatform/assets/sampledata/progress_report/input/本周工作流水.md new file mode 100644 index 0000000..3ed2559 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/progress_report/input/本周工作流水.md @@ -0,0 +1,8 @@ +# 本周工作流水(9-14 ~ 9-18) + +- 周一:梳理云帆科技高新申报材料缺口清单,补齐研发费用账目;约见星海资本,谈随行考察事宜。 +- 周二:更新《赴美考察企业走访清单》,确定 3 家候选;李董出差拜访 1 家对标企业。 +- 周三:组织 AI 顾问面试 2 场,推进 1 名候选人到二面;拟写《技术合作洽谈预案》初稿。 +- 周四:跟进客户新签 1 单(资质认定辅导),推动佣金结算;协调签证资料。 +- 周五:内部周例会,复盘考察筹备进度;输出本周遗留事项:考察预算未最终确认、1 家候选企业预约待回复。 +- 下周计划:锁定考察人数与预算、完成企业预约、推进新员工培训课表排期。 diff --git a/eai_agentplatform/assets/sampledata/report_generation/README.md b/eai_agentplatform/assets/sampledata/report_generation/README.md new file mode 100644 index 0000000..60dfc9e --- /dev/null +++ b/eai_agentplatform/assets/sampledata/report_generation/README.md @@ -0,0 +1,18 @@ +# 报告生成(report-generation)样例 + +## 用途 +根据调研/数据/要点生成正式报告,并导出 PDF/DOCX/PPTX/XLSX。 + +## 样例文件 +- `input/调研数据.md` —— 一份考察/调研的一手数据与要点。 +- `expected/报告结构.md` ——(可选)期望的报告章节结构。 + +## 调用方式 +- 生成:`POST /api/report/generate`(粘贴 `input/调研数据.md`)。 +- 导出:`POST /api/report/export/pdf` / `.../docx` / `.../pptx` / `.../xlsx`。 +- 预览:`POST /api/report/preview`。 + +## 期望产出 +结构化报告(摘要 / 发现 / 分析 / 建议 / 附件)+ 可导出的文件。 + +> 说明:技能为「已实现」,有独立处理器并按所选格式导出文件。 diff --git a/eai_agentplatform/assets/sampledata/report_generation/input/调研数据.md b/eai_agentplatform/assets/sampledata/report_generation/input/调研数据.md new file mode 100644 index 0000000..66a1788 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/report_generation/input/调研数据.md @@ -0,0 +1,15 @@ +# 赴美考察调研数据(样例输入) + +背景:2026-10-18 至 25 日赴美国东岸(纽约-波士顿-芝加哥)商务考察。 + +调研要点: +- 对标企业 A:渠道以区域分销为主,年增长约 18%,重视本地化服务。 +- 潜在技术合作方 B:在智能体/流程自动化上有成熟模块,愿以联合开发形式合作。 +- 北美市场共性:售后与本地合规是客户核心关切;报价普遍高于国内。 + +拟结论方向: +1. 渠道策略建议采用「区域分销 + 本地服务伙伴」双轨。 +2. 技术合作宜从联合开发 POC 切入,6 个月内出试用版。 +3. 报价需含本地化实施与合规项,附后续服务包。 + +(该样例输入供 report/generate 生成正式考察报告) diff --git a/eai_agentplatform/assets/sampledata/shared/公司背景.md b/eai_agentplatform/assets/sampledata/shared/公司背景.md new file mode 100644 index 0000000..dda2aab --- /dev/null +++ b/eai_agentplatform/assets/sampledata/shared/公司背景.md @@ -0,0 +1,35 @@ +# 公司背景(SampleData 共用素材) + +> 供 sampledata 下所有技能样例复用,保持业务上下文一致。测试时可直接把本文件内容作为「知识来源」粘贴到任务上下文里。 + +## 公司简介 + +博昇是一家专注「企业数字化转型与经营增长」的专业服务机构,围绕资本运作、资质认定辅导、AI 落地实施三大主线,为成长型企业提供顾问式服务。 + +- 主营业务:资本咨询、资质认定辅导、AI 咨询与实施、企业级 AI 工具与平台建设 +- 客户群体:制造业、科技型中小企业、拟上市 / 上新三板企业 +- 服务模式:顾问式销售 + 陪伴式交付,顾问深扎行业,按里程碑推进 + +## 业务线 + +1. **资本咨询与股权融资**:商业模式梳理、估值、融资结构设计、尽调资料准备、路演材料与投资对接。 +2. **资质认定辅导**:高新技术企业认定、专精特新梯度培育、各类政府补贴申报的合规辅导。 +3. **AI 咨询与实施**:AI 落地可行性评估、POC 试点、数据治理、智能体(数字员工)建设。 +4. **企业级 AI 工具与平台**:低代码 + 智能体平台搭建,覆盖销售、培训、审批、知识运营等场景。 + +## 销售方法论 + +- **FABE**:特征 → 优势 → 利益 → 证据,先讲客户听得懂的价值。 +- **SPIN**:背景问题 → 难点问题 → 暗示问题 → 需求-效益问题。 +- **LSCPA**:倾听 → 共担 → 澄清 → 提出方案 → 行动。 + +## 高频对象(样例里统一的人名 / 公司,便于对账) + +| 对象 | 角色 | +| --- | --- | +| 张董事长 | 集团董事长 | +| 李董事长 | 海外业务板块董事长 | +| 王助理 | 总裁办助理 | +| 云帆科技 | 客户(制造企业,拟申报高企) | +| 星海资本 | 投资机构 | +| 2026-10-18 美国考察 | 集团海外商务考察项目 | diff --git a/eai_agentplatform/assets/sampledata/smart_assistant/README.md b/eai_agentplatform/assets/sampledata/smart_assistant/README.md new file mode 100644 index 0000000..f5ec405 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/smart_assistant/README.md @@ -0,0 +1,15 @@ +# 通用助手(smart-assistant)样例 + +## 用途 +未指定专员的默认对话:答疑、查资料、推荐专员与拆任务。 + +## 样例文件 +- `input/示例提问.md` —— 几类典型提问(答疑类 / 资料类 / 任务类)。 + +## 调用方式 +- 接口:`POST /api/chat/message`(以 `input/示例提问.md` 中的提问为消息)。 + +## 期望产出 +先判断类型再作答:能从知识库答则答;能推荐专员则点明「为什么是这个专员、需要你提供什么」。 + +> 说明:技能当前为「占位」(仅有 manifest),实际依赖通用 AI 对话,样例用于预置和口径设计。 diff --git a/eai_agentplatform/assets/sampledata/smart_assistant/input/示例提问.md b/eai_agentplatform/assets/sampledata/smart_assistant/input/示例提问.md new file mode 100644 index 0000000..b7458ac --- /dev/null +++ b/eai_agentplatform/assets/sampledata/smart_assistant/input/示例提问.md @@ -0,0 +1,7 @@ +# 通用助手示例提问 + +1. (答疑类)「高新技术企业认定对我们的所得税有什么好处?」 +2. (答疑类)「我们公司能做 AI 落地吗?可以先做什么?」 +3. (资料类)「平台里有没有介绍产品卖点的资料?」 +4. (任务类)「我想把一段会议内容整理成纪要并在项目里留痕。」 +5. (任务类)「下周要给董事会做汇报,帮我准备一份考察方案的 PPT。」 diff --git a/eai_agentplatform/assets/sampledata/table_cleanup/README.md b/eai_agentplatform/assets/sampledata/table_cleanup/README.md new file mode 100644 index 0000000..9a8ca7f --- /dev/null +++ b/eai_agentplatform/assets/sampledata/table_cleanup/README.md @@ -0,0 +1,15 @@ +# 表格清理(table-cleanup)样例 + +## 用途 +清洗脏表格:去空行、合并重复、纠正格式、补全字段名。 + +## 样例文件 +- `input/脏表格.md` —— 一份带空行、错位、重复项的表格。 + +## 调用方式 +- 接口:`POST /api/skills/office/execute`(skill_key=`table-cleanup`,粘贴表格文本)。 + +## 期望产出 +规整后的表格(统一列名、补齐缺失、标注需人工确认项)。 + +> 说明:技能为「已实现」,走 office 运行时。 diff --git a/eai_agentplatform/assets/sampledata/table_cleanup/input/脏表格.md b/eai_agentplatform/assets/sampledata/table_cleanup/input/脏表格.md new file mode 100644 index 0000000..4f6d7b8 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/table_cleanup/input/脏表格.md @@ -0,0 +1,15 @@ +# 出差名单表(含脏数据样例) + +第一行应为表头,但混入多余说明行,存在空行、重复与格式不一致: + +`以下为赴美考察名单` + +| 姓名 | 部门 | 职务 | 备注 | +| --- | --- | --- | --- | +| 张董 | 集团 | 董事长 | 带队 | +| 李董 | 海外 | 董事长 | 市场 | +| 王助理 | 总裁办 | 助理 | 签证 | +| 王助理 | 总裁办 | 助理 | 签证(重复) | +| (空) | | | | +| 张 董 | 集团 | 董事长 | 带队(与首行重复,空格差异) | +| 陈经理 | 市场 | 经理 | 待确认 | diff --git a/eai_agentplatform/assets/sampledata/text_to_speech/README.md b/eai_agentplatform/assets/sampledata/text_to_speech/README.md new file mode 100644 index 0000000..ba1025c --- /dev/null +++ b/eai_agentplatform/assets/sampledata/text_to_speech/README.md @@ -0,0 +1,18 @@ +# 文字转语音(text-to-speech)样例 + +## 用途 +把文本合成语音(MP3),用于通知播报、培训内容朗读等。 + +## 样例文件 +- `input/待合成文本.md` —— 一段可合成语音的文本(考察通知 + 一段产品介绍)。 +- `audio/考察通知_男声.mp3` —— 已用本地 edge-tts 生成的一个参考输出(男声,可直接试听)。 + +## 调用方式 +- 接口:`POST /api/skills/office/tts`(JSON:`{task_id, text, voice?, rate?}`)。 +- 试听:`GET /api/tts/audio/`。 +- 默认音色 `zh-CN-XiaoxiaoNeural`;示例参考输出使用男声 `zh-CN-YunxiNeural`。 + +## 期望产出 +一段 MP3 音频产物 + 任务运行记录与交付物(artifact),音频 URL 可在线播放/下载。 + +> 说明:技能为「已实现」(本项目新增),调用本地 edge-tts。 diff --git a/eai_agentplatform/assets/sampledata/text_to_speech/audio/考察通知_男声.mp3 b/eai_agentplatform/assets/sampledata/text_to_speech/audio/考察通知_男声.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b5d3e116636b7765c5f68777a9ddc33432917dd2 GIT binary patch literal 75312 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 literal 0 HcmV?d00001 diff --git a/eai_agentplatform/assets/sampledata/text_to_speech/input/待合成文本.md b/eai_agentplatform/assets/sampledata/text_to_speech/input/待合成文本.md new file mode 100644 index 0000000..2acebd6 --- /dev/null +++ b/eai_agentplatform/assets/sampledata/text_to_speech/input/待合成文本.md @@ -0,0 +1,7 @@ +# 待合成语音文本(样例) + +文本 1(通知): +> 各位同事,我们定于十月十八日赴美国进行商务考察,为期八天,主要对接北美渠道与潜在技术合作方。请大家提前做好行程与签证准备。 + +文本 2(产品介绍,供培训朗读): +> 博昇数字员工平台,把知识库、专员与技能、审批和交付物流转整合在一起,让销售、培训和日常办公都能被 AI 接手。 diff --git a/eai_agentplatform/backend-go/deploy/DELIVERY.md b/eai_agentplatform/backend-go/deploy/DELIVERY.md index d912c93..7bbd7d8 100644 --- a/eai_agentplatform/backend-go/deploy/DELIVERY.md +++ b/eai_agentplatform/backend-go/deploy/DELIVERY.md @@ -37,7 +37,7 @@ │ ├── eai_agentplatform.db # SQLite(首启自动建) │ ├── backups/ # 定期备份(服务自动维护,见第 7 节) │ └── kb_data/ # 素材 + 提取缓存 -└── (前端静态资源由 Nginx 托管,见 ../docs/deploy.md) +└── (前端静态资源由 Nginx 托管,见 ../docs/02_Architecture/部署文档.md) ``` --- diff --git a/eai_agentplatform/backend-go/internal/api/points.go b/eai_agentplatform/backend-go/internal/api/points.go index 482572b..8cbf63e 100644 --- a/eai_agentplatform/backend-go/internal/api/points.go +++ b/eai_agentplatform/backend-go/internal/api/points.go @@ -12,7 +12,7 @@ import ( "eai_agentplatform/backend/internal/web" ) -// —— 积分规则(游戏化成长值,集中一处便于调整,见 docs/changelog.md 待确认项)—— +// —— 积分规则(游戏化成长值,集中一处便于调整,见 docs/01_System_Overall/变更日志.md 待确认项)—— const ( ptFirstCompany = 10 // 首次浏览公司介绍 ptFirstProduct = 2 // 首次浏览单个产品 diff --git a/eai_agentplatform/backend-go/internal/api/router.go b/eai_agentplatform/backend-go/internal/api/router.go index bad7582..ebce57c 100644 --- a/eai_agentplatform/backend-go/internal/api/router.go +++ b/eai_agentplatform/backend-go/internal/api/router.go @@ -156,6 +156,8 @@ func RegisterRoutes(r *gin.Engine, cfg *config.Config) { r.POST("/api/batch/files", middleware.Auth(cfg), ExtractFromFiles) r.POST("/api/skills/office/execute", middleware.Auth(cfg), skillapi.ExecuteOfficeSkill) r.POST("/api/skills/office/ocr", middleware.Auth(cfg), skillapi.ExecuteOfficeSkillOCR) + r.POST("/api/skills/office/tts", middleware.Auth(cfg), skillapi.ExecuteOfficeSkillTTS) + r.GET("/api/tts/audio/:filename", middleware.Auth(cfg), skillapi.ServeTTSAudio) r.POST("/api/chat/message", middleware.Auth(cfg), HandleChatMessage) // 语音工具 diff --git a/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go b/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go index 402acd5..acbca8f 100644 --- a/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go +++ b/eai_agentplatform/backend-go/internal/skills/api/office_handlers.go @@ -199,7 +199,7 @@ func ExecuteOfficeSkillOCR(c *gin.Context) { TaskID: task.ID, SpecialistKey: task.SpecialistKey, ActionKey: "ocr-understanding", - ActionTitle: "OCR / 图文理解", + ActionTitle: "图片/扫描件智能识别", ActionType: "ocr", Status: "done", InputJSON: string(inputJSON), diff --git a/eai_agentplatform/backend-go/internal/skills/api/tts_handlers.go b/eai_agentplatform/backend-go/internal/skills/api/tts_handlers.go new file mode 100644 index 0000000..2de0274 --- /dev/null +++ b/eai_agentplatform/backend-go/internal/skills/api/tts_handlers.go @@ -0,0 +1,192 @@ +package skillapi + +import ( + "crypto/sha1" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "strings" + "time" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" + + "eai_agentplatform/backend/internal/config" + "eai_agentplatform/backend/internal/middleware" + "eai_agentplatform/backend/internal/model" + specialistruntime "eai_agentplatform/backend/internal/specialists/runtime" + "eai_agentplatform/backend/internal/store" + "eai_agentplatform/backend/internal/web" +) + +// ttsDefaultVoice 默认中文女声(edge-tts 自带音色)。 +const ttsDefaultVoice = "zh-CN-XiaoxiaoNeural" + +// ttsAudioDir 存放合成 MP3 的目录,与公众号配图一致放在数据库同级的 tts_audio 下。 +func ttsAudioDir() string { + cfg := config.Load() + return filepath.Join(filepath.Dir(cfg.DBPath), "tts_audio") +} + +func defaultTTSText(text string) string { + text = strings.TrimSpace(text) + if text == "" { + return "这是一个文字转语音的示例。" + } + return text +} + +// ExecuteOfficeSkillTTS POST /api/skills/office/tts —— 文字转语音。 +// body: { "task_id": <任务ID>, "text": "要朗读的文字", "voice": "音色(可空)", "rate": "语速(可空, 如 +0% / -10%)" } +func ExecuteOfficeSkillTTS(c *gin.Context) { + user := middleware.CurrentUser(c) + if user == nil { + web.Fail(c, web.NewAuthError("未登录")) + return + } + var req struct { + TaskID uint `json:"task_id"` + Text string `json:"text"` + Voice string `json:"voice"` + Rate string `json:"rate"` + } + if err := c.ShouldBindJSON(&req); err != nil { + web.Fail(c, web.NewBadRequest("请求参数错误")) + return + } + if req.TaskID == 0 { + web.Fail(c, web.NewBadRequest("task_id 必填")) + return + } + + text := defaultTTSText(req.Text) + voice := strings.TrimSpace(req.Voice) + if voice == "" { + voice = ttsDefaultVoice + } + rate := strings.TrimSpace(req.Rate) + + task, ok := loadMyOwnedTask(c, user, req.TaskID) + if !ok { + return + } + + now := time.Now() + dir := ttsAudioDir() + if err := os.MkdirAll(dir, 0o755); err != nil { + web.Fail(c, web.NewBadRequest("无法创建音频目录")) + return + } + sum := sha1.Sum([]byte(text + "|" + voice)) + filename := fmt.Sprintf("task_%d_%s_%x.mp3", task.ID, now.Format("20060102-150405"), sum[:6]) + audioPath := filepath.Join(dir, filename) + + args := []string{"-m", "edge_tts", "--text", text, "--voice", voice, "--write-media", audioPath} + if rate != "" { + args = append(args, "--rate", rate) + } + cmd := exec.Command("python3", args...) + var stderr strings.Builder + cmd.Stderr = &stderr + if err := cmd.Run(); err != nil { + web.Fail(c, web.NewBadRequest("语音合成失败:"+firstNonEmpty(strings.TrimSpace(stderr.String()), err.Error()))) + return + } + if _, err := os.Stat(audioPath); err != nil { + web.Fail(c, web.NewBadRequest("语音合成失败:未生成音频文件")) + return + } + audioURL := "/api/tts/audio/" + filename + + inputJSON, _ := json.Marshal(gin.H{"text": text, "voice": voice, "rate": rate}) + outputJSON, _ := json.Marshal(gin.H{ + "summary": "已将文本合成为语音,可在线播放或下载。", + "text": text, + "voice": voice, + "audio_url": audioURL, + }) + logsJSON, _ := json.Marshal([]string{ + "接收文字转语音请求", + fmt.Sprintf("调用本地 TTS 引擎(voice=%s)", voice), + "已生成 MP3 音频", + }) + artifactPayloadJSON, _ := json.Marshal(gin.H{ + "text": text, + "voice": voice, + "audio_url": audioURL, + "format": "mp3", + }) + sourceRefsJSON, _ := json.Marshal([]string{"本地 edge-tts"}) + + var run model.TaskRun + var artifact model.TaskArtifact + err := store.DB.Transaction(func(tx *gorm.DB) error { + run = model.TaskRun{ + TaskID: task.ID, + SpecialistKey: task.SpecialistKey, + ActionKey: "text-to-speech", + ActionTitle: "文字转语音", + ActionType: "audio", + Status: "done", + InputJSON: string(inputJSON), + OutputJSON: string(outputJSON), + LogsJSON: string(logsJSON), + StartedAt: now, + FinishedAt: &now, + } + if err := tx.Create(&run).Error; err != nil { + return err + } + artifact = model.TaskArtifact{ + TaskID: task.ID, + SpecialistKey: task.SpecialistKey, + Title: fmt.Sprintf("%s - 语音合成结果", task.Title), + ArtifactType: "audio", + Status: specialistruntime.ArtifactStatusDraft, + ContentText: text, + ContentJSON: string(artifactPayloadJSON), + SourceRefsJSON: string(sourceRefsJSON), + CreatedByRunID: &run.ID, + } + if err := tx.Create(&artifact).Error; err != nil { + return err + } + task.CurrentRunID = &run.ID + task.CurrentResult = "已将文本合成为语音并生成 MP3。" + task.Status = specialistruntime.TaskStatusDraft + task.LastTriggeredAt = &now + return tx.Save(&task).Error + }) + if err != nil { + web.Fail(c, web.NewBadRequest("保存结果失败:"+err.Error())) + return + } + + freshTask, _ := reloadTask(task.ID) + web.OK(c, gin.H{ + "audio_url": audioURL, + "text": text, + "voice": voice, + "rate": rate, + "run": run, + "artifact": artifact, + "task": freshTask, + }) +} + +// ServeTTSAudio GET /api/tts/audio/:filename —— 提供生成的 MP3 音频文件。 +func ServeTTSAudio(c *gin.Context) { + filename := filepath.Base(strings.TrimSpace(c.Param("filename"))) + if filename == "." || filename == "" { + web.Fail(c, web.NewNotFoundError("音频不存在")) + return + } + fullPath := filepath.Join(ttsAudioDir(), filename) + if _, err := os.Stat(fullPath); err != nil { + web.Fail(c, web.NewNotFoundError("音频不存在")) + return + } + c.File(fullPath) +} diff --git a/eai_agentplatform/backend-go/internal/skills/core/builtin.go b/eai_agentplatform/backend-go/internal/skills/core/builtin.go index a59bd18..90327ee 100644 --- a/eai_agentplatform/backend-go/internal/skills/core/builtin.go +++ b/eai_agentplatform/backend-go/internal/skills/core/builtin.go @@ -7,7 +7,6 @@ import ( contractreview "eai_agentplatform/backend/internal/skills/packages/contract_review" copyproofreading "eai_agentplatform/backend/internal/skills/packages/copy_proofreading" documenttranslate "eai_agentplatform/backend/internal/skills/packages/document_translate" - emaildrafting "eai_agentplatform/backend/internal/skills/packages/email_drafting" interviewsummary "eai_agentplatform/backend/internal/skills/packages/interview_summary" longformwriting "eai_agentplatform/backend/internal/skills/packages/longform_writing" meetingminutes "eai_agentplatform/backend/internal/skills/packages/meeting_minutes" @@ -16,13 +15,10 @@ import ( policyrewrite "eai_agentplatform/backend/internal/skills/packages/policy_rewrite" pptgeneration "eai_agentplatform/backend/internal/skills/packages/ppt_generation" progressreport "eai_agentplatform/backend/internal/skills/packages/progress_report" - projectplanning "eai_agentplatform/backend/internal/skills/packages/project_planning" - proposalsummary "eai_agentplatform/backend/internal/skills/packages/proposal_summary" reportgeneration "eai_agentplatform/backend/internal/skills/packages/report_generation" smartassistant "eai_agentplatform/backend/internal/skills/packages/smart_assistant" - surveysummary "eai_agentplatform/backend/internal/skills/packages/survey_summary" tablecleanup "eai_agentplatform/backend/internal/skills/packages/table_cleanup" - texttoolkit "eai_agentplatform/backend/internal/skills/packages/text_toolkit" + texttospeech "eai_agentplatform/backend/internal/skills/packages/text_to_speech" ) var builtinRegistry = NewRegistry( @@ -36,18 +32,14 @@ var builtinRegistry = NewRegistry( pptgeneration.Manifest, mindmap.Manifest, longformwriting.Manifest, - texttoolkit.Manifest, ocrunderstanding.Manifest, meetingminutes.Manifest, - projectplanning.Manifest, - emaildrafting.Manifest, tablecleanup.Manifest, - proposalsummary.Manifest, progressreport.Manifest, contractbrief.Manifest, interviewsummary.Manifest, policyrewrite.Manifest, - surveysummary.Manifest, + texttospeech.Manifest, ) func BuiltinRegistry() *Registry { diff --git a/eai_agentplatform/backend-go/internal/skills/model/skill_definition.go b/eai_agentplatform/backend-go/internal/skills/model/skill_definition.go index 567508f..f91030d 100644 --- a/eai_agentplatform/backend-go/internal/skills/model/skill_definition.go +++ b/eai_agentplatform/backend-go/internal/skills/model/skill_definition.go @@ -11,8 +11,10 @@ type SkillDefinition struct { EAILogicCode string `gorm:"column:eailogic_code;size:32;default:'';index" json:"eailogic_code"` Description string `gorm:"type:text" json:"description"` ObjectKind string `gorm:"column:object_kind;size:32;not null;default:skill;index" json:"object_kind"` - Source string `gorm:"size:32;not null;default:eai;index" json:"source"` - ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;default:''" json:"object_entry_route"` + Source string `gorm:"size:32;not null;default:eai;index" json:"source"` + ObjectEntryRoute string `gorm:"column:object_entry_route;size:128;default:''" json:"object_entry_route"` // 业务对象进入入口(D26 口径) + Color string `gorm:"size:16;default:''" json:"color"` // 展示主色(面向用户展示层,唯一的真值在后端) + InteractionCardJSON string `gorm:"column:interaction_card_json;type:text" json:"interaction_card_json"` // 交互卡对象(JSON,snake_case 与专员一致) // 这里**有意不写** `default:true`。带上它,GORM 在 Create 时会跳过布尔零值字段 // (false 被当成「没填」),改由库默认值 true 生效 —— 于是对象显式设的 false // 被持久层改写成 true,创建接口永远设不出「不暴露给用户」的技能。 diff --git a/eai_agentplatform/backend-go/internal/skills/packages/audio_transcribe/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/audio_transcribe/manifest.go index 059562d..29a452a 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/audio_transcribe/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/audio_transcribe/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "audio-transcribe", - Label: "语音转写", + Label: "会议音频分析(转写)", OwnedDefinitionKeys: []string{"skill.audio-transcribe.definition"}, OwnedCatalogEntries: []string{"catalog.skill.audio-transcribe"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/batch_extract/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/batch_extract/manifest.go index a7f79d6..ba4a0f8 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/batch_extract/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/batch_extract/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "batch-extract", - Label: "批量提取", + Label: "批量字段提取 → Excel", OwnedDefinitionKeys: []string{"skill.batch-extract.definition"}, OwnedCatalogEntries: []string{"catalog.skill.batch-extract"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/manifest.go index ceb338f..c3550b8 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "contract-brief", - Label: "合同要点提炼", + Label: "合同批量审查与提取(提取)", OwnedDefinitionKeys: []string{"skill.contract-brief.definition"}, OwnedCatalogEntries: []string{"catalog.skill.contract-brief"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/runtime.go index 04357e3..d14b12c 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/contract_brief/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "contract-brief", - Label: "合同要点提炼", + Label: "合同批量审查与提取(提取)", PlanTitle: "合同要点提炼流程", PlanSteps: []string{"识别合同结构", "提炼核心条款", "标记风险事项", "输出摘要版本"}, ResultTitle: "合同要点摘要", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/contract_review/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/contract_review/manifest.go index 3820c63..e4c6b75 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/contract_review/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/contract_review/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "contract-review", - Label: "合同审查", + Label: "合同批量审查与提取(审查)", OwnedDefinitionKeys: []string{"skill.contract-review.definition"}, OwnedCatalogEntries: []string{"catalog.skill.contract-review"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/email_drafting/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/email_drafting/manifest.go deleted file mode 100644 index a38e97c..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/email_drafting/manifest.go +++ /dev/null @@ -1,11 +0,0 @@ -package emaildrafting - -import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" - -var Manifest = skillcontracts.Manifest{ - Key: "email-drafting", - Label: "邮件起草", - OwnedDefinitionKeys: []string{"skill.email-drafting.definition"}, - OwnedCatalogEntries: []string{"catalog.skill.email-drafting"}, - ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/email_drafting/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/email_drafting/runtime.go deleted file mode 100644 index 1fcf7d8..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/email_drafting/runtime.go +++ /dev/null @@ -1,14 +0,0 @@ -package emaildrafting - -import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" - -var OfficeRuntime = officecontracts.Runtime{ - Key: "email-drafting", - Label: "邮件起草", - PlanTitle: "邮件起草流程", - PlanSteps: []string{"识别沟通目的", "整理背景与重点", "生成正式邮件", "补充简短跟进版本"}, - ResultTitle: "邮件草稿", - Summary: "已生成一版可直接发送的邮件正文,并补了简短跟进版本和要点摘要。", - Highlights: []string{"适合汇报、催办、确认和通知", "兼顾正式语气与清晰表达", "默认沉淀长邮件和短消息版本"}, - ActionType: "communication", -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/manifest.go index 46ec577..f02f48f 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "interview-summary", - Label: "访谈整理", + Label: "招聘简历助手", OwnedDefinitionKeys: []string{"skill.interview-summary.definition"}, OwnedCatalogEntries: []string{"catalog.skill.interview-summary"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/runtime.go index 28c8dd1..1a9b50e 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/interview_summary/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "interview-summary", - Label: "访谈整理", + Label: "招聘简历助手", PlanTitle: "访谈整理流程", PlanSteps: []string{"归并访谈内容", "提炼主题观点", "总结关键洞察", "输出整理版本"}, ResultTitle: "访谈整理稿", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/manifest.go index fe574f2..14bedfd 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "longform-writing", - Label: "长文创作", + Label: "公文辅助写作(长文)", OwnedDefinitionKeys: []string{"skill.longform-writing.definition"}, OwnedCatalogEntries: []string{"catalog.skill.longform-writing"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/runtime.go index e3fdae3..5969630 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/longform_writing/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "longform-writing", - Label: "长文创作", + Label: "公文辅助写作(长文)", PlanTitle: "长文创作流程", PlanSteps: []string{"明确文体与受众", "规划章节大纲", "生成正文骨架", "整理摘要与交付稿"}, ResultTitle: "长文草稿", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/manifest.go index 05dea98..46ecd0b 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "meeting-minutes", - Label: "会议纪要", + Label: "会议音频分析(纪要)", OwnedDefinitionKeys: []string{"skill.meeting-minutes.definition"}, OwnedCatalogEntries: []string{"catalog.skill.meeting-minutes"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/runtime.go index b1823e8..e8f8414 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/meeting_minutes/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "meeting-minutes", - Label: "会议纪要", + Label: "会议音频分析(纪要)", PlanTitle: "会议纪要整理流程", PlanSteps: []string{"识别会议主题", "提炼关键结论", "整理行动项", "输出同步版本"}, ResultTitle: "会议纪要草稿", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/mind_map/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/mind_map/manifest.go index 1533315..873cb19 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/mind_map/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/mind_map/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "mind-map", - Label: "思维导图", + Label: "会议音频分析(思维导图)", OwnedDefinitionKeys: []string{"skill.mind-map.definition"}, OwnedCatalogEntries: []string{"catalog.skill.mind-map"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/mind_map/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/mind_map/runtime.go index cec4ac3..09cc93f 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/mind_map/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/mind_map/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "mind-map", - Label: "思维导图", + Label: "会议音频分析(思维导图)", PlanTitle: "思维导图生成流程", PlanSteps: []string{"识别主题主线", "拆分一级分支", "补齐关键节点", "整理导图源结构"}, ResultTitle: "导图结构草案", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/manifest.go index d175f70..4f3a7e3 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "ocr-understanding", - Label: "OCR / 图文理解", + Label: "图片/扫描件智能识别", OwnedDefinitionKeys: []string{"skill.ocr-understanding.definition"}, OwnedCatalogEntries: []string{"catalog.skill.ocr-understanding"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/runtime.go index 7059615..dc078b3 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/ocr_understanding/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "ocr-understanding", - Label: "OCR / 图文理解", + Label: "图片/扫描件智能识别", PlanTitle: "图文理解流程", PlanSteps: []string{"识别图像内容", "抽取文字与字段", "整理结构摘要", "输出可复用结果"}, ResultTitle: "识别结果摘要", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/manifest.go index abe65d8..77c91c8 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "policy-rewrite", - Label: "制度改写", + Label: "公文辅助写作(制度)", OwnedDefinitionKeys: []string{"skill.policy-rewrite.definition"}, OwnedCatalogEntries: []string{"catalog.skill.policy-rewrite"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/runtime.go index ce1f4d5..aae6a4d 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/policy_rewrite/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "policy-rewrite", - Label: "制度改写", + Label: "公文辅助写作(制度)", PlanTitle: "制度改写流程", PlanSteps: []string{"识别制度目标", "统一结构口径", "重写正式正文", "补充修订说明"}, ResultTitle: "制度改写稿", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/manifest.go index d47dc3a..9a1193a 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "ppt-generation", - Label: "PPT 生成", + Label: "一键生成 PPT", OwnedDefinitionKeys: []string{"skill.ppt-generation.definition"}, OwnedCatalogEntries: []string{"catalog.skill.ppt-generation"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/runtime.go index b34e78a..5b5e1a7 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/ppt_generation/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "ppt-generation", - Label: "PPT 生成", + Label: "一键生成 PPT", PlanTitle: "PPT 生成流程", PlanSteps: []string{"确认汇报目标", "规划页面结构", "提炼每页要点", "整理讲稿备注"}, ResultTitle: "演示文稿骨架", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/progress_report/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/progress_report/manifest.go index 1143365..e4a70ab 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/progress_report/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/progress_report/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "progress-report", - Label: "周报 / 日报", + Label: "一键周报", OwnedDefinitionKeys: []string{"skill.progress-report.definition"}, OwnedCatalogEntries: []string{"catalog.skill.progress-report"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/progress_report/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/progress_report/runtime.go index 96b3d78..c688103 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/progress_report/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/progress_report/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "progress-report", - Label: "周报 / 日报", + Label: "一键周报", PlanTitle: "进展汇报流程", PlanSteps: []string{"归并本期工作", "提炼关键进展", "整理风险事项", "输出汇报版本"}, ResultTitle: "进展汇报草稿", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/project_planning/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/project_planning/manifest.go deleted file mode 100644 index c9355ea..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/project_planning/manifest.go +++ /dev/null @@ -1,11 +0,0 @@ -package projectplanning - -import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" - -var Manifest = skillcontracts.Manifest{ - Key: "project-planning", - Label: "项目规划", - OwnedDefinitionKeys: []string{"skill.project-planning.definition"}, - OwnedCatalogEntries: []string{"catalog.skill.project-planning"}, - ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/project_planning/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/project_planning/runtime.go deleted file mode 100644 index d8fc53d..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/project_planning/runtime.go +++ /dev/null @@ -1,14 +0,0 @@ -package projectplanning - -import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" - -var OfficeRuntime = officecontracts.Runtime{ - Key: "project-planning", - Label: "项目规划", - PlanTitle: "项目规划流程", - PlanSteps: []string{"明确目标边界", "拆解阶段路径", "整理里程碑", "补齐风险与依赖"}, - ResultTitle: "项目规划草案", - Summary: "已把目标拆成阶段计划、里程碑和风险项,方便直接进入执行或评审。", - Highlights: []string{"适合启动、排期和推进对齐", "默认沉淀阶段计划与风险清单", "结果适合继续流转到任务治理"}, - ActionType: "plan", -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/manifest.go deleted file mode 100644 index 0c0ed20..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/manifest.go +++ /dev/null @@ -1,11 +0,0 @@ -package proposalsummary - -import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" - -var Manifest = skillcontracts.Manifest{ - Key: "proposal-summary", - Label: "方案摘要", - OwnedDefinitionKeys: []string{"skill.proposal-summary.definition"}, - OwnedCatalogEntries: []string{"catalog.skill.proposal-summary"}, - ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/runtime.go deleted file mode 100644 index 1c3cd80..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/proposal_summary/runtime.go +++ /dev/null @@ -1,14 +0,0 @@ -package proposalsummary - -import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" - -var OfficeRuntime = officecontracts.Runtime{ - Key: "proposal-summary", - Label: "方案摘要", - PlanTitle: "方案摘要流程", - PlanSteps: []string{"识别方案目标", "提炼核心亮点", "压缩实施路径", "输出摘要版本"}, - ResultTitle: "方案摘要稿", - Summary: "已提炼出方案核心结论、价值亮点和实施建议,适合快速汇报或同步。", - Highlights: []string{"适合方案汇报和管理层预读", "自动压缩价值点与实施路径", "默认沉淀摘要正文和亮点清单"}, - ActionType: "summary", -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/report_generation/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/report_generation/manifest.go index f3e288a..8da81dc 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/report_generation/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/report_generation/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "report-generation", - Label: "报告生成", + Label: "一键生成报告", OwnedDefinitionKeys: []string{"skill.report-generation.definition"}, OwnedCatalogEntries: []string{"catalog.skill.report-generation"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/smart_assistant/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/smart_assistant/manifest.go index e3c1075..d0e7f9f 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/smart_assistant/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/smart_assistant/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "smart-assistant", - Label: "通用助手", + Label: "智能助手", OwnedDefinitionKeys: []string{"skill.smart-assistant.definition"}, OwnedCatalogEntries: []string{"catalog.skill.smart-assistant"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/survey_summary/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/survey_summary/manifest.go deleted file mode 100644 index af7e37c..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/survey_summary/manifest.go +++ /dev/null @@ -1,11 +0,0 @@ -package surveysummary - -import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" - -var Manifest = skillcontracts.Manifest{ - Key: "survey-summary", - Label: "表单问卷汇总", - OwnedDefinitionKeys: []string{"skill.survey-summary.definition"}, - OwnedCatalogEntries: []string{"catalog.skill.survey-summary"}, - ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/survey_summary/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/survey_summary/runtime.go deleted file mode 100644 index 856629f..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/survey_summary/runtime.go +++ /dev/null @@ -1,14 +0,0 @@ -package surveysummary - -import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" - -var OfficeRuntime = officecontracts.Runtime{ - Key: "survey-summary", - Label: "表单问卷汇总", - PlanTitle: "问卷汇总流程", - PlanSteps: []string{"归并表单结果", "提炼重点发现", "整理问题与建议", "输出汇总版本"}, - ResultTitle: "问卷汇总稿", - Summary: "已整理出表单结果汇总、重点发现和改进建议,方便直接同步给负责人。", - Highlights: []string{"适合反馈表、报名表、调查问卷", "自动压缩重点发现和改进建议", "默认沉淀汇总报告和行动建议"}, - ActionType: "report", -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/manifest.go index cc7126c..226f4c7 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/manifest.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/manifest.go @@ -4,7 +4,7 @@ import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" var Manifest = skillcontracts.Manifest{ Key: "table-cleanup", - Label: "表格整理", + Label: "知识库表格视图", OwnedDefinitionKeys: []string{"skill.table-cleanup.definition"}, OwnedCatalogEntries: []string{"catalog.skill.table-cleanup"}, ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/runtime.go index 3c98830..5f0e7a7 100644 --- a/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/runtime.go +++ b/eai_agentplatform/backend-go/internal/skills/packages/table_cleanup/runtime.go @@ -4,7 +4,7 @@ import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office var OfficeRuntime = officecontracts.Runtime{ Key: "table-cleanup", - Label: "表格整理", + Label: "知识库表格视图", PlanTitle: "表格整理流程", PlanSteps: []string{"识别字段结构", "清洗原始数据", "整理表格内容", "补充字段说明"}, ResultTitle: "表格整理结果", diff --git a/eai_agentplatform/backend-go/internal/skills/packages/text_to_speech/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/text_to_speech/manifest.go new file mode 100644 index 0000000..0b853f4 --- /dev/null +++ b/eai_agentplatform/backend-go/internal/skills/packages/text_to_speech/manifest.go @@ -0,0 +1,11 @@ +package texttospeech + +import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" + +var Manifest = skillcontracts.Manifest{ + Key: "text-to-speech", + Label: "文字转语音", + OwnedDefinitionKeys: []string{"skill.text-to-speech.definition"}, + OwnedCatalogEntries: []string{"catalog.skill.text-to-speech"}, + ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, +} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/manifest.go b/eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/manifest.go deleted file mode 100644 index c08d895..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/manifest.go +++ /dev/null @@ -1,11 +0,0 @@ -package texttoolkit - -import skillcontracts "eai_agentplatform/backend/internal/skills/contracts" - -var Manifest = skillcontracts.Manifest{ - Key: "text-toolkit", - Label: "文本处理", - OwnedDefinitionKeys: []string{"skill.text-toolkit.definition"}, - OwnedCatalogEntries: []string{"catalog.skill.text-toolkit"}, - ReferencePolicy: skillcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/runtime.go b/eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/runtime.go deleted file mode 100644 index ec2223e..0000000 --- a/eai_agentplatform/backend-go/internal/skills/packages/text_toolkit/runtime.go +++ /dev/null @@ -1,14 +0,0 @@ -package texttoolkit - -import officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" - -var OfficeRuntime = officecontracts.Runtime{ - Key: "text-toolkit", - Label: "文本处理", - PlanTitle: "文本处理流程", - PlanSteps: []string{"识别清洗目标", "去除噪音符号", "统一格式与标点", "输出可复用文本"}, - ResultTitle: "清洗后文本", - Summary: "已完成文本清洗、格式整理和统计,可直接复制或下载结果。", - Highlights: []string{"去 Markdown 噪音", "输出文本统计", "适合高频复制到 Word 和 IM"}, - ActionType: "text", -} diff --git a/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_communication.go b/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_communication.go index 459cd27..f89fc4e 100644 --- a/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_communication.go +++ b/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_communication.go @@ -98,112 +98,6 @@ func BuildMeetingMinutesArtifacts(inputText string) []gin.H { } } -func BuildEmailDraftingArtifacts(inputText string) []gin.H { - fields, bodyText := parseOfficeFields(inputText, map[string][]string{ - "recipient": {"收件人", "对象", "recipient", "to"}, - "cc": {"抄送", "抄送人", "cc"}, - "topic": {"主题", "标题", "topic", "subject"}, - "purpose": {"目的", "意图", "purpose"}, - "action": {"希望对方", "需要对方", "action"}, - "deadline": {"时间", "截止时间", "deadline"}, - "tone": {"语气", "风格", "tone", "style"}, - }) - topic := firstNonEmpty(fields["topic"], pickOfficeTopic(firstNonEmpty(bodyText, inputText), "邮件主题")) - recipient := firstNonEmpty(fields["recipient"], "各位") - ccList := splitSimpleList(fields["cc"]) - purpose := firstNonEmpty(fields["purpose"], "同步背景和当前进展") - action := firstNonEmpty(fields["action"], "请协助确认并继续推进") - deadline := firstNonEmpty(fields["deadline"], "请尽快反馈") - tone := firstNonEmpty(fields["tone"], "正式、明确、礼貌") - points := extractOfficePoints(firstNonEmpty(bodyText, inputText), []string{"交代背景和当前情况", "说明希望对方配合或确认的事项", "给出时间点和下一步动作", "保持礼貌但结论清楚"}) - subjectVariants := buildEmailSubjectVariants(topic, purpose) - subject := subjectVariants[0] - emailContent := strings.TrimSpace(strings.Join([]string{ - "主题:" + subject, - "收件人:" + recipient, - "抄送:" + firstNonEmpty(strings.Join(ccList, "、"), "无"), - "", - recipient + "好,", - "", - purpose + "。" + firstNonEmpty(pointAt(points, 0), "这边同步一下当前事项的背景和进展。"), - action + "。" + firstNonEmpty(pointAt(points, 1), "目前需要大家协助确认相关事项。"), - deadline + "。" + firstNonEmpty(pointAt(points, 2), "如无问题,请按约定时间继续推进。"), - "", - "语气建议:" + tone + "。如有问题,请直接回复沟通。", - "", - "谢谢。", - }, "\n")) - shortContent := strings.TrimSpace(strings.Join([]string{ - "【" + topic + "】", - firstNonEmpty(pointAt(points, 1), "请协助确认相关事项。"), - firstNonEmpty(pointAt(points, 2), "如无问题请按时推进。"), - }, "\n")) - briefContent := strings.TrimSpace(strings.Join([]string{ - "# 邮件要点", - "", - "- 主题:" + subject, - "- " + firstNonEmpty(pointAt(points, 0), "交代背景和当前情况"), - "- " + firstNonEmpty(pointAt(points, 1), "说明希望对方配合或确认的事项"), - "- " + firstNonEmpty(pointAt(points, 2), "给出时间点和下一步动作"), - "- " + firstNonEmpty(pointAt(points, 3), "保持礼貌但结论清楚"), - }, "\n")) - subjectLines := []string{ - "# 主题与抄送建议", - "", - "- 收件人:" + recipient, - "- 抄送建议:" + firstNonEmpty(strings.Join(ccList, "、"), "建议抄送直属负责人 / 相关协同方"), - "", - "## 可选主题", - } - for index, item := range subjectVariants { - subjectLines = append(subjectLines, fmt.Sprintf("%d. %s", index+1, item)) - } - subjectContent := strings.TrimSpace(strings.Join(subjectLines, "\n")) - slug := officeSlug(topic, "email-drafting") - return []gin.H{ - { - "key": "email", - "title": "正式邮件", - "description": "可直接复制到邮箱发送的完整版本。", - "kind": "text", - "fileFormat": "txt", - "downloadName": slug + ".txt", - "mimeType": "text/plain;charset=utf-8", - "content": emailContent, - }, - { - "key": "short-followup", - "title": "简短跟进版", - "description": "适合发到 IM 或群里的短消息版本。", - "kind": "text", - "fileFormat": "txt", - "downloadName": slug + "-short.txt", - "mimeType": "text/plain;charset=utf-8", - "content": shortContent, - }, - { - "key": "brief", - "title": "邮件要点", - "description": "方便审批或复核邮件口径的要点版。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-brief.md", - "mimeType": "text/markdown;charset=utf-8", - "content": briefContent, - }, - { - "key": "subject-variants", - "title": "主题与抄送建议", - "description": "提供多版主题候选和抄送建议。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-subject.md", - "mimeType": "text/markdown;charset=utf-8", - "content": subjectContent, - }, - } -} - func BuildProgressReportArtifacts(inputText string) []gin.H { topic := pickOfficeTopic(inputText, "进展汇报") points := extractOfficePoints(inputText, []string{"本期完成的关键工作", "当前风险和阻塞项", "需要协同支持的事项", "下一步计划"}) diff --git a/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_structure.go b/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_structure.go index a51164f..dfc182e 100644 --- a/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_structure.go +++ b/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_structure.go @@ -114,109 +114,6 @@ func BuildMindMapArtifacts(inputText string) []gin.H { } } -func BuildProjectPlanningArtifacts(inputText string) []gin.H { - fields, bodyText := parseOfficeFields(inputText, map[string][]string{ - "topic": {"项目", "项目名称", "主题", "topic"}, - "deadline": {"时间要求", "截止时间", "deadline"}, - "owner": {"负责人", "owner"}, - "goal": {"目标", "goal"}, - "start": {"开始时间", "启动时间", "start"}, - }) - topic := firstNonEmpty(fields["topic"], pickOfficeTopic(firstNonEmpty(bodyText, inputText), "项目规划")) - deadline := firstNonEmpty(fields["deadline"], "待确认") - owner := firstNonEmpty(fields["owner"], "待指定") - goal := firstNonEmpty(fields["goal"], "先明确目标、阶段、依赖和协同方式") - start := firstNonEmpty(fields["start"], "尽快启动") - points := extractOfficePoints(firstNonEmpty(bodyText, inputText), []string{"明确目标、范围和成功标准", "梳理关键里程碑与交付节点", "安排执行分工与协同节奏", "识别风险与外部依赖"}) - stageRows := buildProjectStageRows(points, owner, deadline) - planContent := strings.TrimSpace(strings.Join([]string{ - "# " + topic, - "", - "## 项目目标", - fmt.Sprintf("围绕“%s”整理一版可执行的项目规划,先确保目标、阶段和依赖都清楚。", topic), - "- 负责人:" + owner, - "- 启动时间:" + start, - "- 时间要求:" + deadline, - "- 总体目标:" + goal, - "", - "## 阶段安排", - "### 阶段 1:启动与对齐", - "- " + firstNonEmpty(pointAt(points, 0), "明确目标和边界"), - "### 阶段 2:执行与推进", - "- " + firstNonEmpty(pointAt(points, 1), "推进关键里程碑和核心交付"), - "### 阶段 3:验收与收口", - "- " + firstNonEmpty(pointAt(points, 2), "完成验收、复盘和沉淀"), - }, "\n")) - milestoneContent := strings.TrimSpace(strings.Join([]string{ - "# 里程碑清单", - "", - "1. M1:" + firstNonEmpty(pointAt(points, 0), "明确目标和边界"), - "2. M2:" + firstNonEmpty(pointAt(points, 1), "推进关键里程碑和核心交付"), - "3. M3:" + firstNonEmpty(pointAt(points, 2), "完成验收、复盘和沉淀"), - "4. M4:" + firstNonEmpty(pointAt(points, 3), "确认依赖和外部配合事项"), - }, "\n")) - riskContent := strings.TrimSpace(strings.Join([]string{ - "# 风险与依赖", - "", - "- 风险 1:" + firstNonEmpty(pointAt(points, 3), "关键依赖尚未完全明确"), - "- 风险 2:跨团队协同节奏可能影响排期", - "- 建议:将关键依赖提前前置到周会或启动会确认", - }, "\n")) - scheduleLines := []string{ - "# 阶段排期表", - "", - "| 阶段 | 时间窗 | 负责人 | 目标 | 交付物 |", - "| --- | --- | --- | --- | --- |", - } - for _, item := range stageRows { - scheduleLines = append(scheduleLines, fmt.Sprintf("| %s | %s | %s | %s | %s |", asString(item["stage"]), asString(item["window"]), asString(item["owner"]), asString(item["goal"]), asString(item["output"]))) - } - scheduleContent := strings.TrimSpace(strings.Join(scheduleLines, "\n")) - slug := officeSlug(topic, "project-planning") - return []gin.H{ - { - "key": "project-plan", - "title": "项目计划", - "description": "适合直接评审和继续细化的主计划。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + ".md", - "mimeType": "text/markdown;charset=utf-8", - "content": planContent, - }, - { - "key": "milestones", - "title": "里程碑清单", - "description": "关键节点和交付节奏的简洁版列表。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-milestones.md", - "mimeType": "text/markdown;charset=utf-8", - "content": milestoneContent, - }, - { - "key": "risks", - "title": "风险清单", - "description": "项目推进前需要确认的风险与依赖。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-risks.md", - "mimeType": "text/markdown;charset=utf-8", - "content": riskContent, - }, - { - "key": "schedule", - "title": "阶段排期表", - "description": "更接近甘特视角的阶段、时间窗和交付物表。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-schedule.md", - "mimeType": "text/markdown;charset=utf-8", - "content": scheduleContent, - }, - } -} - func BuildTableCleanupArtifacts(inputText string) []gin.H { fields, bodyText := parseOfficeFields(inputText, map[string][]string{ "topic": {"主题", "标题", "topic", "title"}, diff --git a/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_writing.go b/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_writing.go index a78d75d..a7f8ffd 100644 --- a/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_writing.go +++ b/eai_agentplatform/backend-go/internal/skills/runtime/office/builders_writing.go @@ -58,115 +58,6 @@ func BuildLongformArtifacts(inputText string) []gin.H { } } -func BuildTextToolkitArtifacts(inputText string) []gin.H { - cleaned := stripMarkdownText(inputText) - stats := strings.Join([]string{ - "# 文本统计", - "", - fmt.Sprintf("- 字符数:%d", len([]rune(cleaned))), - fmt.Sprintf("- 行数:%d", len(splitMeaningfulLines(cleaned))), - fmt.Sprintf("- 原始长度:%d", len([]rune(strings.TrimSpace(inputText)))), - "", - "## 处理说明", - "- 已移除常见 Markdown 标记", - "- 已压缩多余空行", - "- 已保留正文可读性", - }, "\n") - slug := officeSlug(pickOfficeTopic(inputText, "cleaned-text"), "text-toolkit") - return []gin.H{ - { - "key": "cleaned", - "title": "清洗后文本", - "description": "适合直接粘贴到文档或聊天工具。", - "kind": "text", - "fileFormat": "txt", - "downloadName": slug + ".txt", - "mimeType": "text/plain;charset=utf-8", - "content": cleaned, - }, - { - "key": "stats", - "title": "文本统计", - "description": "记录本次清洗和统计结果。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-stats.md", - "mimeType": "text/markdown;charset=utf-8", - "content": stats, - }, - } -} - -func BuildProposalSummaryArtifacts(inputText string) []gin.H { - topic := pickOfficeTopic(inputText, "方案摘要") - points := extractOfficePoints(inputText, []string{"明确方案目标和解决的问题", "提炼核心价值与收益", "压缩关键实施路径", "明确需要决策的事项"}) - summaryContent := strings.TrimSpace(strings.Join([]string{ - "# " + topic, - "", - "## 核心结论", - fmt.Sprintf("%s 已压缩为适合汇报和快速预读的摘要版本,重点保留目标、价值点和实施建议。", topic), - "", - "## 关键亮点", - "- " + firstNonEmpty(pointAt(points, 0), "明确方案目标和解决的问题"), - "- " + firstNonEmpty(pointAt(points, 1), "提炼核心价值与收益"), - "- " + firstNonEmpty(pointAt(points, 2), "压缩关键实施路径"), - "- " + firstNonEmpty(pointAt(points, 3), "明确需要决策的事项"), - "", - "## 实施建议", - "- 建议先确认资源与排期", - "- 建议围绕高优先级场景先落一版 MVP", - "- 建议同步关键负责人做进一步评审", - }, "\n")) - highlightsContent := strings.TrimSpace(strings.Join([]string{ - "# 亮点清单", - "", - "1. " + firstNonEmpty(pointAt(points, 0), "明确方案目标和解决的问题"), - "2. " + firstNonEmpty(pointAt(points, 1), "提炼核心价值与收益"), - "3. " + firstNonEmpty(pointAt(points, 2), "压缩关键实施路径"), - "4. " + firstNonEmpty(pointAt(points, 3), "明确需要决策的事项"), - }, "\n")) - briefingContent := strings.TrimSpace(strings.Join([]string{ - "【" + topic + " 摘要】", - "1. " + firstNonEmpty(pointAt(points, 0), "明确方案目标和解决的问题"), - "2. " + firstNonEmpty(pointAt(points, 1), "提炼核心价值与收益"), - "3. " + firstNonEmpty(pointAt(points, 2), "压缩关键实施路径"), - "建议按上述结论进入下一步决策或评审。", - }, "\n")) - slug := officeSlug(topic, "proposal-summary") - return []gin.H{ - { - "key": "summary", - "title": "方案摘要", - "description": "适合直接汇报或继续细化的主摘要。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + ".md", - "mimeType": "text/markdown;charset=utf-8", - "content": summaryContent, - }, - { - "key": "highlights", - "title": "亮点清单", - "description": "压缩提炼后的价值点列表。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-highlights.md", - "mimeType": "text/markdown;charset=utf-8", - "content": highlightsContent, - }, - { - "key": "briefing", - "title": "汇报短版", - "description": "适合发群或口头汇报前快速同步的短摘要。", - "kind": "text", - "fileFormat": "txt", - "downloadName": slug + "-briefing.txt", - "mimeType": "text/plain;charset=utf-8", - "content": briefingContent, - }, - } -} - func BuildContractBriefArtifacts(inputText string) []gin.H { fields, bodyText := parseOfficeFields(inputText, map[string][]string{ "topic": {"合同名称", "主题", "topic"}, @@ -422,67 +313,3 @@ func BuildPolicyRewriteArtifacts(inputText string) []gin.H { }, } } - -func BuildSurveySummaryArtifacts(inputText string) []gin.H { - topic := pickOfficeTopic(inputText, "问卷汇总") - points := extractOfficePoints(inputText, []string{"参与者的主要反馈方向", "高频问题或不满意点", "值得保留的积极反馈", "后续改进建议"}) - reportContent := strings.TrimSpace(strings.Join([]string{ - "# " + topic, - "", - "## 汇总结论", - "- " + firstNonEmpty(pointAt(points, 0), "参与者的主要反馈方向"), - "- " + firstNonEmpty(pointAt(points, 1), "高频问题或不满意点"), - "- " + firstNonEmpty(pointAt(points, 2), "值得保留的积极反馈"), - "- " + firstNonEmpty(pointAt(points, 3), "后续改进建议"), - "", - "## 汇总说明", - "已把表单和问卷结果压缩成便于阅读和决策的汇总结论。", - }, "\n")) - findingsContent := strings.TrimSpace(strings.Join([]string{ - "# 重点发现", - "", - "- 发现 1:" + firstNonEmpty(pointAt(points, 0), "参与者主要关注体验和执行效果"), - "- 发现 2:" + firstNonEmpty(pointAt(points, 1), "部分问题集中在流程或内容安排上"), - "- 发现 3:" + firstNonEmpty(pointAt(points, 2), "已有若干积极反馈值得继续保留"), - }, "\n")) - actionsContent := strings.TrimSpace(strings.Join([]string{ - "# 改进建议", - "", - "- [ ] " + firstNonEmpty(pointAt(points, 3), "根据汇总结果制定下一步改进动作"), - "- [ ] 对高频问题安排专项优化", - "- [ ] 向负责人同步汇总结论和优先级建议", - }, "\n")) - slug := officeSlug(topic, "survey-summary") - return []gin.H{ - { - "key": "report", - "title": "汇总报告", - "description": "适合直接汇报或继续细化的主报告。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + ".md", - "mimeType": "text/markdown;charset=utf-8", - "content": reportContent, - }, - { - "key": "findings", - "title": "重点发现", - "description": "从表单结果中提炼出的关键发现。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-findings.md", - "mimeType": "text/markdown;charset=utf-8", - "content": findingsContent, - }, - { - "key": "actions", - "title": "改进建议", - "description": "建议后续继续推进的改进行动。", - "kind": "text", - "fileFormat": "md", - "downloadName": slug + "-actions.md", - "mimeType": "text/markdown;charset=utf-8", - "content": actionsContent, - }, - } -} diff --git a/eai_agentplatform/backend-go/internal/skills/runtime/office/builtin.go b/eai_agentplatform/backend-go/internal/skills/runtime/office/builtin.go index a3c66d8..325c3a6 100644 --- a/eai_agentplatform/backend-go/internal/skills/runtime/office/builtin.go +++ b/eai_agentplatform/backend-go/internal/skills/runtime/office/builtin.go @@ -2,7 +2,6 @@ package office import ( contractbrief "eai_agentplatform/backend/internal/skills/packages/contract_brief" - emaildrafting "eai_agentplatform/backend/internal/skills/packages/email_drafting" interviewsummary "eai_agentplatform/backend/internal/skills/packages/interview_summary" longformwriting "eai_agentplatform/backend/internal/skills/packages/longform_writing" meetingminutes "eai_agentplatform/backend/internal/skills/packages/meeting_minutes" @@ -11,11 +10,7 @@ import ( policyrewrite "eai_agentplatform/backend/internal/skills/packages/policy_rewrite" pptgeneration "eai_agentplatform/backend/internal/skills/packages/ppt_generation" progressreport "eai_agentplatform/backend/internal/skills/packages/progress_report" - projectplanning "eai_agentplatform/backend/internal/skills/packages/project_planning" - proposalsummary "eai_agentplatform/backend/internal/skills/packages/proposal_summary" - surveysummary "eai_agentplatform/backend/internal/skills/packages/survey_summary" tablecleanup "eai_agentplatform/backend/internal/skills/packages/table_cleanup" - texttoolkit "eai_agentplatform/backend/internal/skills/packages/text_toolkit" officecontracts "eai_agentplatform/backend/internal/skills/runtime/office/contracts" "github.com/gin-gonic/gin" ) @@ -29,18 +24,13 @@ var builtinRegistry = NewRegistry( withBuild(pptgeneration.OfficeRuntime, BuildPPTArtifacts), withBuild(mindmap.OfficeRuntime, BuildMindMapArtifacts), withBuild(longformwriting.OfficeRuntime, BuildLongformArtifacts), - withBuild(texttoolkit.OfficeRuntime, BuildTextToolkitArtifacts), ocrunderstanding.OfficeRuntime, withBuild(meetingminutes.OfficeRuntime, BuildMeetingMinutesArtifacts), - withBuild(projectplanning.OfficeRuntime, BuildProjectPlanningArtifacts), - withBuild(emaildrafting.OfficeRuntime, BuildEmailDraftingArtifacts), withBuild(tablecleanup.OfficeRuntime, BuildTableCleanupArtifacts), - withBuild(proposalsummary.OfficeRuntime, BuildProposalSummaryArtifacts), withBuild(progressreport.OfficeRuntime, BuildProgressReportArtifacts), withBuild(contractbrief.OfficeRuntime, BuildContractBriefArtifacts), withBuild(interviewsummary.OfficeRuntime, BuildInterviewSummaryArtifacts), withBuild(policyrewrite.OfficeRuntime, BuildPolicyRewriteArtifacts), - withBuild(surveysummary.OfficeRuntime, BuildSurveySummaryArtifacts), ) func BuiltinRegistry() *Registry { diff --git a/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_content.go b/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_content.go index f7581a9..eeb1681 100644 --- a/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_content.go +++ b/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_content.go @@ -71,26 +71,6 @@ func parseMeetingActions(text string, fallback []string) []gin.H { return out } -func buildEmailSubjectVariants(topic, purpose string) []string { - base := firstNonEmpty(topic, "事项") - context := strings.TrimSpace(purpose) - items := []string{ - base + " - 请协助确认", - base + " - 需要回复", - base + " - 进展同步", - } - if context != "" { - runes := []rune(context) - if len(runes) > 12 { - context = string(runes[:12]) - } - items = append(items, base+" - "+context) - } else { - items = append(items, base+" - 待处理提醒") - } - return items -} - func formatMeetingActionLine(actions []gin.H, index int) string { if index < 0 || index >= len(actions) { return fmt.Sprintf("%d. 待补充行动项", index+1) @@ -149,29 +129,3 @@ func buildContractRedlineItems(points, focusKeywords []string) []gin.H { } return out } - -func stripMarkdownText(text string) string { - text = strings.ReplaceAll(text, "\r", "\n") - blockCode := regexp.MustCompile("```[\\s\\S]*?```") - text = blockCode.ReplaceAllStringFunc(text, func(value string) string { - return strings.TrimSpace(strings.ReplaceAll(value, "```", "")) - }) - replacers := []struct { - pattern string - value string - }{ - {"`([^`]+)`", "$1"}, - {"^#{1,6}\\s+", ""}, - {"^\\s*[-*+]\\s+", ""}, - {"^\\s*\\d+[.)]\\s+", ""}, - {"\\*\\*(.*?)\\*\\*", "$1"}, - {"\\*(.*?)\\*", "$1"}, - {"!\\[[^\\]]*\\]\\([^)]*\\)", ""}, - {"\\[([^\\]]+)\\]\\(([^)]*)\\)", "$1"}, - } - for _, item := range replacers { - text = regexp.MustCompile(item.pattern).ReplaceAllString(text, item.value) - } - text = regexp.MustCompile(`\n{3,}`).ReplaceAllString(text, "\n\n") - return strings.TrimSpace(text) -} diff --git a/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_structure.go b/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_structure.go index c13f439..b143150 100644 --- a/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_structure.go +++ b/eai_agentplatform/backend-go/internal/skills/runtime/office/helpers_structure.go @@ -217,31 +217,6 @@ func splitSimpleList(value string) []string { return out } -func buildProjectStageRows(points []string, owner, deadline string) []gin.H { - labels := []string{"阶段 1", "阶段 2", "阶段 3", "阶段 4"} - windows := []string{"第 1 周", "第 2 周", "第 3 周", firstNonEmpty(deadline, "收口前")} - rows := make([]gin.H, 0, len(labels)) - for index, label := range labels { - output := "收口结论" - switch index { - case 0: - output = "目标确认" - case 1: - output = "阶段交付" - case 2: - output = "验收材料" - } - rows = append(rows, gin.H{ - "stage": label, - "window": windows[index], - "goal": firstNonEmpty(pointAt(points, index), "补充"+label+"目标"), - "owner": firstNonEmpty(owner, "待指定"), - "output": output, - }) - } - return rows -} - func repeatString(value string, count int) []string { items := make([]string, 0, count) for index := 0; index < count; index++ { diff --git a/eai_agentplatform/backend-go/internal/specialists/core/builtin.go b/eai_agentplatform/backend-go/internal/specialists/core/builtin.go index abde618..8aca020 100644 --- a/eai_agentplatform/backend-go/internal/specialists/core/builtin.go +++ b/eai_agentplatform/backend-go/internal/specialists/core/builtin.go @@ -2,31 +2,17 @@ package specialistcore import ( contractreview "eai_agentplatform/backend/internal/specialists/packages/contract_review" - generalassistant "eai_agentplatform/backend/internal/specialists/packages/general_assistant" - hremailsorter "eai_agentplatform/backend/internal/specialists/packages/hr_email_sorter" - knowledgeoperations "eai_agentplatform/backend/internal/specialists/packages/knowledge_operations" - logisticsfulfillment "eai_agentplatform/backend/internal/specialists/packages/logistics_fulfillment" - presentationbriefing "eai_agentplatform/backend/internal/specialists/packages/presentation_briefing" - processcoordination "eai_agentplatform/backend/internal/specialists/packages/process_coordination" - reportgeneration "eai_agentplatform/backend/internal/specialists/packages/report_generation" + customerfollowup "eai_agentplatform/backend/internal/specialists/packages/customer_followup" resumeprocessor "eai_agentplatform/backend/internal/specialists/packages/resume_processor" solutionproposal "eai_agentplatform/backend/internal/specialists/packages/solution_proposal" - trainingdelivery "eai_agentplatform/backend/internal/specialists/packages/training_delivery" wechatofficialaccount "eai_agentplatform/backend/internal/specialists/packages/wechat_official_account" ) var builtinRegistry = NewRegistry( - generalassistant.Manifest, - trainingdelivery.Manifest, - knowledgeoperations.Manifest, - processcoordination.Manifest, - reportgeneration.Manifest, wechatofficialaccount.Manifest, contractreview.Manifest, solutionproposal.Manifest, - presentationbriefing.Manifest, - logisticsfulfillment.Manifest, - hremailsorter.Manifest, + customerfollowup.Manifest, resumeprocessor.Manifest, ) diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/customer_followup/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/customer_followup/manifest.go new file mode 100644 index 0000000..e299c66 --- /dev/null +++ b/eai_agentplatform/backend-go/internal/specialists/packages/customer_followup/manifest.go @@ -0,0 +1,32 @@ +package customerfollowup + +import specialistcontracts "eai_agentplatform/backend/internal/specialists/contracts" + +var Manifest = specialistcontracts.Manifest{ + Key: "customer-followup", + Label: "客户跟进专员", + RuleFileMarkdown: `# 客户跟进专员 + +## 你是谁 +你负责客户资料整理到会议预约这一段的推进:资料归档、意向分级、联系建议、预约跟进、状态回写。 +你面对的是销售、售前或客户成功同学,他们要的是「哪些客户该先跟、怎么跟、何时约」。 + +## 你怎么推进 +1. 先给总览:客户一共多少个,分别处于新线索、已联系、待预约、已预约哪个阶段。 +2. 逐个客户整理「客户名称 / 关键背景 / 当前意向 / 最近动作 / 下一步建议」。 +3. 对高意向客户优先给出联系建议:推荐触达方式、首轮话术、会议目标和建议时间。 +4. 跟进结果要回写,明确哪些客户已联系、哪些待补资料、哪些需要升级处理。 + +## 输出要求 +- 客户资料要保留来源,标明来自 CRM、表格、邮件还是人工补录。 +- 意向判断要写依据,不要只给一个高、中、低标签。 +- 联系建议尽量可直接发出,避免只写空泛建议。 + +## 边界 +- 不伪造客户承诺,不代替用户直接发送外部联系。 +- 拿不到客户历史记录时如实说,不要按经验补全。`, + AllowedSkills: []string{"progress-report", "report-generation"}, + OwnedDefinitionKeys: []string{"specialist.customer-followup.definition"}, + OwnedCatalogEntries: []string{"catalog.specialist.customer-followup"}, + ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, +} diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/hr_email_sorter/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/hr_email_sorter/manifest.go deleted file mode 100644 index d7c914c..0000000 --- a/eai_agentplatform/backend-go/internal/specialists/packages/hr_email_sorter/manifest.go +++ /dev/null @@ -1,31 +0,0 @@ -package hremailsorter - -import specialistcontracts "eai_agentplatform/backend/internal/specialists/contracts" - -var Manifest = specialistcontracts.Manifest{ - Key: "hr-email-sorter", - Label: "HR 邮件整理专员", - RuleFileMarkdown: `# HR 邮件整理专员 - -## 你是谁 -你负责把 HR 邮箱里的简历邮件理清楚:简历邮件识别、候选人信息抽取、去重归类。 -你面对的是要快速筛出有效候选人的招聘同学。 - -## 你怎么推进 -1. 先分类:简历投递 / 面试安排 / 其他(通知、广告、内部邮件)。 -2. 简历邮件逐封抽字段:姓名、联系方式、应聘岗位、年限、学历、附件有没有。 -3. 去重:同一候选人多次投递的合并,列出重复来源。 -4. 输出归类清单,按岗位分组。 - -## 输出要求 -- 字段缺失写「未提供」,不要用工整的占位内容填充。 -- 附件解析失败的单列出来,标明原因。 - -## 边界 -- 候选人个人信息只出现在整理结果里,不外传、不写入其他文档。 -- 不做录用判断——那是简历处理专员和用人部门的事。`, - AllowedSkills: []string{"email-drafting", "batch-extract", "table-cleanup", "ocr-understanding"}, - OwnedDefinitionKeys: []string{"specialist.hr-email-sorter.definition"}, - OwnedCatalogEntries: []string{"catalog.specialist.hr-email-sorter"}, - ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/logistics_fulfillment/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/logistics_fulfillment/manifest.go deleted file mode 100644 index 6d3eb5e..0000000 --- a/eai_agentplatform/backend-go/internal/specialists/packages/logistics_fulfillment/manifest.go +++ /dev/null @@ -1,31 +0,0 @@ -package logisticsfulfillment - -import specialistcontracts "eai_agentplatform/backend/internal/specialists/contracts" - -var Manifest = specialistcontracts.Manifest{ - Key: "logistics-fulfillment", - Label: "履约跟单专员", - RuleFileMarkdown: `# 履约跟单专员 - -## 你是谁 -你负责订单履约的过程跟踪:节点跟踪、异常识别、催办升级、状态回写。 -你面对的是盯着一批单子的人,他要的是「哪几单要出事了」。 - -## 你怎么推进 -1. 先给总览:在途多少单、正常多少、异常多少。 -2. 异常单逐条给出「单号 / 卡在哪个节点 / 卡了多久 / 原因 / 建议动作」。 -3. 按节点时效判断该催谁,给出可直接发送的催办话术。 -4. 收尾确认状态已回写,没回写的列出来。 - -## 输出要求 -- 时间口径统一(统一时区、标明统计截止时点)。 -- 异常分级:影响交付日期的算高优先级,只影响体感的往下降。 - -## 边界 -- 只读订单与物流数据,不代替用户改单、取消单、承诺新的交期。 -- 拿不到物流节点信息时如实说,不要按经验推测位置。`, - AllowedSkills: []string{"progress-report", "table-cleanup", "email-drafting"}, - OwnedDefinitionKeys: []string{"specialist.logistics-fulfillment.definition"}, - OwnedCatalogEntries: []string{"catalog.specialist.logistics-fulfillment"}, - ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/presentation_briefing/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/presentation_briefing/manifest.go index d266a0c..930549c 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/presentation_briefing/manifest.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/presentation_briefing/manifest.go @@ -26,7 +26,7 @@ var Manifest = specialistcontracts.Manifest{ - 不编造数据、案例、客户反馈。 - 不把未确认方案写成既定事实。 - 视觉美化可以建议,但当前重点是结构与表达,不承诺设计成品。`, - AllowedSkills: []string{"ppt-generation", "proposal-summary", "mind-map", "progress-report"}, + AllowedSkills: []string{"ppt-generation", "mind-map", "progress-report"}, OwnedDefinitionKeys: []string{"specialist.presentation-briefing.definition"}, OwnedCatalogEntries: []string{"catalog.specialist.presentation-briefing"}, ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/process_coordination/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/process_coordination/manifest.go index dc3c275..256d79b 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/process_coordination/manifest.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/process_coordination/manifest.go @@ -23,7 +23,7 @@ var Manifest = specialistcontracts.Manifest{ ## 边界 - 只起草催办与升级建议,不代替用户对外发送。 - 不评价同事的工作态度,只陈述事项状态与时间事实。`, - AllowedSkills: []string{"progress-report", "project-planning", "email-drafting"}, + AllowedSkills: []string{"progress-report"}, OwnedDefinitionKeys: []string{"specialist.process-coordination.definition"}, OwnedCatalogEntries: []string{"catalog.specialist.process-coordination"}, ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/resume_processor/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/resume_processor/manifest.go index 29302a2..721d4a8 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/resume_processor/manifest.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/resume_processor/manifest.go @@ -4,20 +4,22 @@ import specialistcontracts "eai_agentplatform/backend/internal/specialists/contr var Manifest = specialistcontracts.Manifest{ Key: "resume-processor", - Label: "简历处理专员", - RuleFileMarkdown: `# 简历处理专员 + Label: "招聘筛选专员", + RuleFileMarkdown: `# 招聘筛选专员 ## 你是谁 -你负责简历筛选到面试安排:筛选、评分排序、跟进标记、面试安排。 -你面对的是用人部门,他们要的是一份能直接拿去约面试的名单。 +你负责从招聘入口整理到候选人筛选的闭环:邮件归档、候选人抽取、评分排序、跟进标记、面试安排。 +你面对的是招聘同学和用人部门,他们要的是一份能直接拿去推进的候选人清单。 ## 你怎么推进 -1. 先确认岗位要求与硬性门槛(学历、年限、必备技能),门槛项单独标。 -2. 逐份评分:按岗位要求逐项对照,给出总分与排序,并写明「为什么排这个位置」。 -3. 标出不确定项:信息缺失、表述含糊、需要电话确认的点。 -4. 给面试安排建议:分批、每批人选、建议面试重点。 +1. 先整理招聘入口:把招聘邮件、附件和候选人资料归到统一清单,重复投递先合并。 +2. 再确认岗位要求与硬性门槛(学历、年限、必备技能),门槛项单独标。 +3. 逐份评分:按岗位要求逐项对照,给出总分与排序,并写明「为什么排这个位置」。 +4. 标出不确定项:信息缺失、表述含糊、需要电话确认的点。 +5. 给面试安排建议:分批、每批人选、建议面试重点。 ## 输出要求 +- 候选人入口整理要保留来源,标明来自哪封邮件、哪个附件或哪次投递。 - 评分要能追溯到岗位要求的具体条目,不要只给一个分数。 - 排序理由写事实(做过什么、做了多久),不写「感觉不错」。 diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/solution_proposal/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/solution_proposal/manifest.go index 6192d45..8d459d1 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/solution_proposal/manifest.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/solution_proposal/manifest.go @@ -25,7 +25,7 @@ var Manifest = specialistcontracts.Manifest{ ## 边界 - 不承诺工期、不承诺价格——这两项由销售与交付确认。 - 不替研发承诺功能,不贬低竞品。`, - AllowedSkills: []string{"proposal-summary", "ppt-generation", "project-planning", "mind-map"}, + AllowedSkills: []string{"ppt-generation", "mind-map"}, OwnedDefinitionKeys: []string{"specialist.solution-proposal.definition"}, OwnedCatalogEntries: []string{"catalog.specialist.solution-proposal"}, ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/training_delivery/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/training_delivery/manifest.go deleted file mode 100644 index 3e8cd0e..0000000 --- a/eai_agentplatform/backend-go/internal/specialists/packages/training_delivery/manifest.go +++ /dev/null @@ -1,30 +0,0 @@ -package trainingdelivery - -import specialistcontracts "eai_agentplatform/backend/internal/specialists/contracts" - -var Manifest = specialistcontracts.Manifest{ - Key: "training-delivery", - Label: "培训交付专员", - RuleFileMarkdown: `# 培训交付专员 - -## 你是谁 -你负责新人销售训练营的交付闭环:班级状态、考试预警、复盘归档、交付清单。 -你面对的是培训负责人,他关心的是「哪个班要出问题了」,不是过程数据。 - -## 你怎么推进 -1. 先给结论:本期班级整体交付状态(正常 / 有风险 / 已阻塞)+ 一句话原因。 -2. 再给异常清单:按风险高低排,每条写清「谁 / 什么信号 / 建议动作」。 -3. 最后给交付清单:本期还缺哪些材料、谁补、什么时候要。 - -## 输出要求 -- 数字要带口径(哪个班、哪场考试、统计截止到什么时候)。 -- 预警必须给出可执行的下一步,不要只说「需关注」。 - -## 边界 -- 只读班级资料与考试结果,不替学员报名、不替教练打分。 -- 涉及具体学员的评价,只陈述记录里的事实,不做主观评判。`, - AllowedSkills: []string{"progress-report", "report-generation", "ppt-generation", "meeting-minutes"}, - OwnedDefinitionKeys: []string{"specialist.training-delivery.definition"}, - OwnedCatalogEntries: []string{"catalog.specialist.training-delivery"}, - ReferencePolicy: specialistcontracts.SharedReferenceReadonlyHistory, -} diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_delivery.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_delivery.go index 682e2ad..d37c99c 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_delivery.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_delivery.go @@ -573,7 +573,7 @@ func ExportOfficialAccountDocument(c *gin.Context) { return } if task.SpecialistKey != officialAccountSpecialistKey { - web.Fail(c, web.NewNotFoundError("当前事项不属于公众号助手")) + web.Fail(c, web.NewNotFoundError("当前事项不属于公众号专员")) return } diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go index cc066e0..1f6701c 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/api/official_account_workflow.go @@ -186,7 +186,7 @@ func CreateOfficialAccountTask(c *gin.Context) { // 任务挂在已下线的专员上,历史记录仍要解释得通。 specialist, found := specialistDAO.GetByKey(officialAccountSpecialistKey) if !found { - web.Fail(c, web.NewNotFoundError("公众号助手尚未配置")) + web.Fail(c, web.NewNotFoundError("公众号专员尚未配置")) return } @@ -230,7 +230,7 @@ func GetOfficialAccountWorkflow(c *gin.Context) { return } if task.SpecialistKey != officialAccountSpecialistKey { - web.Fail(c, web.NewNotFoundError("当前事项不属于公众号助手")) + web.Fail(c, web.NewNotFoundError("当前事项不属于公众号专员")) return } respondOfficialAccountWorkflow(c, task) @@ -243,7 +243,7 @@ func UpdateOfficialAccountTask(c *gin.Context) { return } if task.SpecialistKey != officialAccountSpecialistKey { - web.Fail(c, web.NewNotFoundError("当前事项不属于公众号助手")) + web.Fail(c, web.NewNotFoundError("当前事项不属于公众号专员")) return } @@ -393,7 +393,7 @@ func ExecuteOfficialAccountWorkflowStep(c *gin.Context) { return } if task.SpecialistKey != officialAccountSpecialistKey { - web.Fail(c, web.NewNotFoundError("当前事项不属于公众号助手")) + web.Fail(c, web.NewNotFoundError("当前事项不属于公众号专员")) return } @@ -524,7 +524,7 @@ func RegenerateOfficialAccountImage(c *gin.Context) { return } if task.SpecialistKey != officialAccountSpecialistKey { - web.Fail(c, web.NewNotFoundError("当前事项不属于公众号助手")) + web.Fail(c, web.NewNotFoundError("当前事项不属于公众号专员")) return } diff --git a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/manifest.go b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/manifest.go index 0736eb2..7391d1e 100644 --- a/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/manifest.go +++ b/eai_agentplatform/backend-go/internal/specialists/packages/wechat_official_account/manifest.go @@ -4,8 +4,8 @@ import specialistcontracts "eai_agentplatform/backend/internal/specialists/contr var Manifest = specialistcontracts.Manifest{ Key: "wechat-official-account", - Label: "公众号助手", - RuleFileMarkdown: `# 公众号助手 + Label: "公众号专员", + RuleFileMarkdown: `# 公众号专员 ## 你是谁 你负责公众号内容从选题到成稿:热点选题、标题、提纲、正文。 diff --git a/eai_agentplatform/backend-go/internal/specialists/seeding/seed_specialists.go b/eai_agentplatform/backend-go/internal/specialists/seeding/seed_specialists.go index ae11ba6..c62c730 100644 --- a/eai_agentplatform/backend-go/internal/specialists/seeding/seed_specialists.go +++ b/eai_agentplatform/backend-go/internal/specialists/seeding/seed_specialists.go @@ -38,30 +38,6 @@ func SeedSpecialists(db *gorm.DB) error { State: "system", SortOrder: 0, }, - { - Key: "training-delivery", - Label: "培训交付专员", - Tier: "generic", - SpecialistMode: "dw", - ObjectEntryRoute: "/apps/training-delivery", - Summary: "新人销售训练营第 3 周", - WorkStatus: "5 个进行中", - RiskLabel: "0 个异常", - Color: "#67c23a", - Stage: "交付归档", - Progress: 84, - MarketTag: "已安装", - Version: "v1.1", - ConnectorScope: "连接课程系统 / 知识库 / 考试模块", - PermissionScope: "班级资料读取、考试结果读取、交付包生成", - ResourceBindings: "课程系统、考试模块、知识库、交付模板中心", - InfoSources: "班级排期、学员成绩、互动记录、教练点评", - BaseSkills: "班级日报、考试预警、复盘归档、交付清单生成", - AIAssistance: "自动总结班级状态并给出补练建议", - GeneratedSkills: "基于优秀班级复盘沉淀新训练营模板", - State: "active", - SortOrder: 10, - }, { Key: "knowledge-operations", Label: "知识运营专员", @@ -136,7 +112,7 @@ func SeedSpecialists(db *gorm.DB) error { }, { Key: "wechat-official-account", - Label: "公众号助手", + Label: "公众号专员", Tier: "generic", SpecialistMode: "dw", ObjectEntryRoute: "/apps/wechat-official-account", @@ -207,76 +183,52 @@ func SeedSpecialists(db *gorm.DB) error { SortOrder: 60, }, { - Key: "logistics-fulfillment", - Label: "履约跟单专员", + Key: "customer-followup", + Label: "客户跟进专员", Tier: "industry", SpecialistMode: "adw", - ObjectEntryRoute: "/apps/logistics-fulfillment", - Summary: "美西航线本周履约看板", - WorkStatus: "1 个异常", - RiskLabel: "2 个节点延迟", + ObjectEntryRoute: "/apps/customer-followup", + Summary: "整理客户资料、识别意向并推进会议预约", + WorkStatus: "3 个客户待联系", + RiskLabel: "1 个高意向待确认", Color: "#e6a23c", - Stage: "异常处置", - Progress: 49, + Stage: "首轮触达", + Progress: 46, MarketTag: "试用", - Version: "v0.9", - ConnectorScope: "连接船司 / 邮件 / 企微", - PermissionScope: "节点读取、异常通知、履约状态写回、升级协同", - ResourceBindings: "船司系统、邮件、企微、履约看板", - InfoSources: "节点状态、异常邮件、订舱资料、客户承诺时间", - BaseSkills: "节点跟踪、异常识别、催办升级、状态回写", - AIAssistance: "自动判断异常影响范围并生成处置建议", - GeneratedSkills: "把高频异常处理流程沉淀为自动履约技能", + Version: "v1.0", + ConnectorScope: "连接 CRM / 邮件 / 日程", + PermissionScope: "客户资料读取、跟进状态写回、会议建议生成、提醒协同", + ResourceBindings: "CRM、客户跟进表、邮件、会议日程", + InfoSources: "客户资料、历史沟通记录、会议纪要、线索来源", + BaseSkills: "客户资料归档、意向分层、联系建议、会议预约、状态回写", + AIAssistance: "自动判断客户优先级并生成可直接发送的联系与邀约建议", + GeneratedSkills: "把高转化跟进套路沉淀为客户推进技能", State: "active", SortOrder: 70, }, - { - Key: "hr-email-sorter", - Label: "HR 邮件整理专员", - Tier: "industry", - SpecialistMode: "dw", - ObjectEntryRoute: "/apps/hr-email-sorter", - Summary: "识别并整理招聘邮箱中的简历邮件", - WorkStatus: "3 封待处理", - RiskLabel: "0 个异常", - Color: "#409eff", - Stage: "邮件处理", - Progress: 0, - MarketTag: "试用", - Version: "v1.0", - ConnectorScope: "连接 HR 招聘邮箱 / 邮件系统", - PermissionScope: "招聘邮箱读取、候选人表写入", - ResourceBindings: "HR 招聘邮箱、候选人管理表", - InfoSources: "HR 招聘邮箱收件箱", - BaseSkills: "简历邮件识别、候选人信息抽取、去重归类", - AIAssistance: "自动识别简历邮件并抽取候选人字段", - GeneratedSkills: "从历史招聘中沉淀简历筛选规则", - State: "active", - SortOrder: 80, - }, { Key: "resume-processor", - Label: "简历处理专员", + Label: "招聘筛选专员", Tier: "industry", SpecialistMode: "dw", ObjectEntryRoute: "/apps/resume-processor", - Summary: "筛选候选人并安排面试", - WorkStatus: "5 份待筛选", + Summary: "收拢招聘邮件、筛选候选人并推进面试", + WorkStatus: "5 份待筛选 / 3 封待归档", RiskLabel: "1 个匹配待确认", Color: "#67c23a", - Stage: "简历筛选", + Stage: "候选人筛选", Progress: 0, MarketTag: "试用", Version: "v1.0", - ConnectorScope: "连接候选人表 / 岗位需求表", - PermissionScope: "候选人表读写、面试安排表写入、岗位需求表读取", - ResourceBindings: "候选人表、岗位需求表、面试安排表", - InfoSources: "候选人表、岗位需求表", - BaseSkills: "简历筛选、评分排序、跟进标记、面试安排", - AIAssistance: "自动匹配岗位要求并给出排序建议", + ConnectorScope: "连接招聘邮箱 / 候选人表 / 岗位需求表", + PermissionScope: "招聘邮箱读取、候选人表读写、面试安排表写入、岗位需求表读取", + ResourceBindings: "招聘邮箱、候选人表、岗位需求表、面试安排表", + InfoSources: "招聘邮箱、候选人表、岗位需求表", + BaseSkills: "邮件归档、候选人抽取、简历筛选、评分排序、跟进标记、面试安排", + AIAssistance: "自动归并招聘入口并匹配岗位要求给出排序建议", GeneratedSkills: "从录用决策中沉淀筛选模型", State: "active", - SortOrder: 90, + SortOrder: 80, }, { Key: "presentation-briefing", @@ -375,6 +327,23 @@ func SeedSpecialists(db *gorm.DB) error { } } + if err := deleteSpecialists(db, []string{ + "training-delivery", + }); err != nil { + return err + } + + if err := retireSpecialists(db, []string{ + "knowledge-operations", + "process-coordination", + "report-generation", + "presentation-briefing", + "hr-email-sorter", + "logistics-fulfillment", + }); err != nil { + return err + } + specialistcore.LogRuleFileCoverage(db) log.Println("[OK] 专员目录种子已导入") return nil @@ -397,3 +366,20 @@ func applySpecialistCodes(items []specialistmodel.Specialist) []specialistmodel. } return items } + +func deleteSpecialists(db *gorm.DB, keys []string) error { + if len(keys) == 0 { + return nil + } + return db.Where("key IN ?", keys).Delete(&specialistmodel.Specialist{}).Error +} + +func retireSpecialists(db *gorm.DB, keys []string) error { + if len(keys) == 0 { + return nil + } + return db.Model(&specialistmodel.Specialist{}). + Where("key IN ?", keys). + Where("state = ?", "active"). + Update("state", "retired").Error +} diff --git a/eai_agentplatform/backend-go/internal/store/seed.go b/eai_agentplatform/backend-go/internal/store/seed.go index 9797ffb..bb2523f 100644 --- a/eai_agentplatform/backend-go/internal/store/seed.go +++ b/eai_agentplatform/backend-go/internal/store/seed.go @@ -322,8 +322,8 @@ func seedSkillDefinitions() error { items := applySkillCodes([]skillmodel.SkillDefinition{ { Key: "smart-assistant", - Label: "通用助手", - Description: "默认协作入口,负责问题梳理、任务拆解和对话推进。", + Label: "智能助手", + Description: "说句话,复杂任务自动完成。 操作:打开「智能助手」,用自然语言描述目标 → 可拖入多份文件、关联知识库 → 助手自动拆解为「计划→执行→验证→交付」,全程可见可控", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -335,13 +335,23 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"message": "assistant_reply"}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"summary", "plan"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"task", "knowledge_item"}, "action_types": []string{"analyze", "draft"}}), + Color: "#409eff", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "智能助手", + "tagline": "今天帮你做些什么?描述你的任务,或先挂载技能与材料", + "greeting": "博昇AI数字员工,您说,我做", + "relationship_to_user": "你的通用协作搭档", + "tone": "专业、直接、可执行", + "opening_prompt": "直接告诉我目标,或者把材料贴给我,我来帮你起步。", + "starter_prompts": []string{"帮我拆解这个任务,并列出下一步", "把这段产品介绍整理成正式文案", "先帮我判断这个问题该找哪个专员或技能"}, + }), State: "active", SortOrder: 10, }, { Key: "document-translate", Label: "文档翻译", - Description: "把文本和文档稳定翻成目标语言,并保留语气和结构。", + Description: "整份翻译,排版原封不动。 操作:打开「文档翻译」,上传文件(Word/PDF/PPT/Excel)→ 选择目标语言 → 下载译文——排版、表格、图片位置全部保留", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -353,13 +363,23 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"translation": "text"}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"translated_document"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"document"}, "action_types": []string{"translate"}}), + Color: "#67c23a", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "文档翻译", + "tagline": "不仅翻译文字,还会先统一术语、语气和交付格式。", + "greeting": "先识别语境和术语,再生成可交付译文,避免只做逐句直译。", + "relationship_to_user": "你的翻译协作技能", + "tone": "专业、直接、可执行", + "opening_prompt": "把原文贴给我,并说明目标语言、受众和语气要求;如果有术语表,也一起给我。", + "starter_prompts": []string{"把这段产品说明翻译成英文,保持专业语气", "把这封邮件翻译成日文,语气礼貌一点", "把这份中文文档整理成英文摘要"}, + }), State: "active", SortOrder: 20, }, { Key: "copy-proofreading", Label: "文案校对", - Description: "检查错别字、语病和表达不顺,输出润色建议。", + Description: "错别字、语病,一键标出。 操作:打开「文案校对」,上传文档 → AI 自动逐句检查,标注错别字、语法问题 → 返回带高亮修订版 + 修改建议,可一键采纳", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -371,13 +391,23 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"proofread_result": "text"}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"clean_copy"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"copy"}, "action_types": []string{"review"}}), + Color: "#e6a23c", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "文案校对", + "tagline": "不是只改错字,而是把整段表达修顺、修稳、修清楚。", + "greeting": "先找出问题句和语气风险,再给出能直接使用的修订版本。", + "relationship_to_user": "你的文案润色技能", + "tone": "专业、直接、可执行", + "opening_prompt": "把文案贴给我,并告诉我这段内容要发给谁、希望保留什么语气。", + "starter_prompts": []string{"检查这段销售话术里的错别字和语病", "把这段产品介绍润得更正式一点", "帮我校对这封对外邮件,保留原意"}, + }), State: "active", SortOrder: 30, }, { Key: "audio-transcribe", - Label: "语音转写", - Description: "把音频内容转成结构化文本,便于继续总结与提取。", + Label: "会议音频分析(转写)", + Description: "一小时录音,自动出纪要。 操作:打开「会议音频分析」,上传音频(MP3/M4A/WAV)→ AI 自动转写(带说话人标签)→ 同时输出纪要 + 待办清单 + 思维导图", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -389,13 +419,23 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"transcript": "text"}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"transcript"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"audio"}, "action_types": []string{"extract"}}), + Color: "#5263c3", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "会议音频分析(转写)", + "tagline": "把音频从“听过”变成“可查、可引用、可交付”的文本资产。", + "greeting": "先把语音内容转成可靠文本,再继续整理重点、纪要和后续动作。", + "relationship_to_user": "你的语音整理技能", + "tone": "专业、直接、可执行", + "opening_prompt": "把音频内容发给我,或者告诉我语言、场景和你最终想拿到什么结果。", + "starter_prompts": []string{"把这段会议录音转成文字,并分段整理", "先转写这段采访,再提取重点", "把语音内容整理成可发群里的纪要"}, + }), State: "active", SortOrder: 40, }, { Key: "batch-extract", - Label: "批量提取", - Description: "从一批内容里抽取结构化字段和关键信息。", + Label: "批量字段提取 → Excel", + Description: "上百份文件的关键信息,自动汇表。 操作:在「智能助手」中选择目标知识库 → 用自然语言告诉 AI 需要哪些字段 → AI 自动遍历每份文件,逐项提取,保存为 Excel", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -407,13 +447,23 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"rows": []string{"object"}}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"spreadsheet", "json"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"document", "resume", "contract"}, "action_types": []string{"extract"}}), + Color: "#39b07a", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "批量字段提取 → Excel", + "tagline": "不是只把内容抓出来,而是直接整理成后续系统能用的结构化结果。", + "greeting": "先把字段定义清楚,再批量抽取,并把异常项单独挑出来。", + "relationship_to_user": "你的结构化提取技能", + "tone": "专业、直接、可执行", + "opening_prompt": "告诉我想抽哪些字段、输出成什么格式、哪些情况需要标记为异常。", + "starter_prompts": []string{"从这批简历里提取姓名、岗位和年限", "把这些合同里的付款条款统一抽出来", "帮我批量提取文章标题、作者和发布时间"}, + }), State: "active", SortOrder: 50, }, { Key: "contract-review", - Label: "合同审查", - Description: "定位风险条款、待确认项并输出审查建议。", + Label: "合同批量审查与提取(审查)", + Description: "几十份合同,自动提取甲方、乙方、金额、付款方式等关键字段,一键汇总成 Excel 总表。还能按条件筛选\"百万以上合同\"或\"涉及公路运输的合同\",并自动归纳违约金条款。", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -425,13 +475,23 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"risk_report": "text"}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"risk_report", "redline"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"contract"}, "action_types": []string{"review", "analyze"}}), + Color: "#f56c6c", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "合同批量审查与提取(审查)", + "tagline": "不是只报风险,而是把风险依据、红线建议和后续确认项一起交出来。", + "greeting": "先定位高风险条款和待确认项,再整理成可交付的审查结果。", + "relationship_to_user": "你的合同审查技能", + "tone": "专业、直接、可执行", + "opening_prompt": "把合同发给我,并告诉我这次重点想看哪些条款,或者你站在哪一方立场。", + "starter_prompts": []string{"审查这份采购合同的风险点", "重点看赔偿责任和终止条款", "帮我整理一版待人工确认的风险清单"}, + }), State: "active", SortOrder: 60, }, { Key: "report-generation", - Label: "报告生成", - Description: "把过程材料整理成日报、周报、复盘和交付说明。", + Label: "一键生成报告", + Description: "聊完天,PDF/Word 报告就写好了。 操作:在「智能助手」中上传资料或讨论要点 → 说\"帮我做成 PDF 报告\"或\"整理成 Word\" → AI 自动生成结构化内容,排版为正式文档,一键下载", ObjectKind: "skill", Source: "eai", ObjectEntryRoute: "/home", @@ -443,6 +503,16 @@ func seedSkillDefinitions() error { OutputSchemaJSON: mustJSON(map[string]any{"report": "text"}), ArtifactSchemaJSON: mustJSON(map[string]any{"artifacts": []string{"report"}}), OntologyBindingJSON: mustJSON(map[string]any{"object_types": []string{"report", "task"}, "action_types": []string{"draft"}}), + Color: "#9c27b0", + InteractionCardJSON: mustJSON(map[string]any{ + "name": "一键生成报告", + "tagline": "不只是把记录拼起来,而是把过程信息收成完整、清楚、可汇报的结果。", + "greeting": "先把材料归并成结构,再输出可直接提交的正式报告。", + "relationship_to_user": "你的报告整理技能", + "tone": "专业、直接、可执行", + "opening_prompt": "把材料给我,并告诉我报告类型、受众、周期和你最想突出哪些重点。", + "starter_prompts": []string{"把今天的工作记录整理成日报", "根据这些节点生成项目周报", "帮我把这次交付过程整理成复盘说明"}, + }), State: "active", SortOrder: 70, }, @@ -469,6 +539,12 @@ func seedSkillDefinitions() error { if existing.ObjectEntryRoute == "" { updates["object_entry_route"] = item.ObjectEntryRoute } + if existing.Color == "" { + updates["color"] = item.Color + } + if existing.InteractionCardJSON == "" { + updates["interaction_card_json"] = item.InteractionCardJSON + } if existing.StarterPromptsJSON == "" { updates["starter_prompts_json"] = item.StarterPromptsJSON } @@ -783,29 +859,6 @@ func seedXAppDefinitions() error { State: "active", SortOrder: 60, }, - { - Key: "app-proposal-summary", - Label: "方案摘要", - Badge: "成品应用", - Kind: "汇报加速", - MarketTag: "成品应用", - XAppMode: "direct", - Tier: "business", - Source: "eai", - Color: "#7c3aed", - IconText: "方", - CoverTone: "linear-gradient(135deg, #6d28d9 0%, #a78bfa 100%)", - Summary: "直接进入方案摘要应用,把长方案压成管理层可读的短版本。", - Description: "适合售前方案、项目方案和内部提案的结论压缩与亮点提炼。", - SkillKey: "proposal-summary", - DefaultPrompt: "把这份解决方案压成一版管理层摘要", - PromptsJSON: mustJSON([]string{"把这份解决方案压成一版管理层摘要", "提炼亮点和实施建议", "生成汇报短版和亮点清单"}), - TagsJSON: mustJSON([]string{"方案摘要", "亮点提炼", "管理层预读", "汇报短版"}), - InstallState: "installed", - ExposedToUser: true, - State: "active", - SortOrder: 70, - }, { Key: "app-progress-report", Label: "周报 / 日报", diff --git a/eai_agentplatform/frontend/src/config/projectTemplates.js b/eai_agentplatform/frontend/src/config/projectTemplates.js index 32f901a..39931c5 100644 --- a/eai_agentplatform/frontend/src/config/projectTemplates.js +++ b/eai_agentplatform/frontend/src/config/projectTemplates.js @@ -49,13 +49,13 @@ export const projectTemplates = [ skillKeys: ['report-generation'], }, { - id: 'training-delivery', + id: 'internal-training', title: '培训交付', desc: '课件准备、现场记录到交付归档', icon: Reading, prompt: '本项目按培训交付流程走:课前确认学员与大纲,课中记录要点与答疑,课后 24 小时内出交付包。所有产出用统一模板,标题格式「〈客户〉-〈课程〉-〈环节〉」。', - specialistKeys: ['training-delivery'], + specialistKeys: [], skillKeys: ['document-translate', 'audio-transcribe'], }, { @@ -96,7 +96,7 @@ export const projectTemplates = [ prompt: '本项目按汇报交付口径推进:先确认汇报对象、场景、页数和主线,再生成页面结构、每页要点和讲稿备注。所有数字、时间和范围必须带口径;没有依据的地方明确标“待补”,不要为了好看自行补齐。', specialistKeys: ['presentation-briefing'], - skillKeys: ['ppt-generation', 'proposal-summary', 'mind-map'], + skillKeys: ['ppt-generation', 'mind-map'], }, ] diff --git a/eai_agentplatform/frontend/src/config/workbench.js b/eai_agentplatform/frontend/src/config/workbench.js index 0e2d618..be93198 100644 --- a/eai_agentplatform/frontend/src/config/workbench.js +++ b/eai_agentplatform/frontend/src/config/workbench.js @@ -113,10 +113,10 @@ const workspaceDemoData = { }, }, }, - 'training-delivery': { - title: '培训交付专员', + 'internal-training': { + title: '培训交付工作台', caseTitle: '新人销售训练营第 3 周', - subtitle: '围绕班级运营、课程推进、考试与交付归档的训练营工作台。', + subtitle: '围绕班级运营、课程推进、考试与交付归档的培训工作台。', cases: [ { id: 'td-01', title: '新人销售训练营第 3 周', owner: '班主任', priority: 'P1', due: '今天 20:00', summary: '日报、考试预警、复盘建议需要当天归档', status: '训练执行', contextPatch: { outputs: ['班级日报', '错题热点清单'], artifacts: ['训练营周报.pdf'], risks: ['考试规则待确认'], events: ['08:30 班级日报自动生成'] } }, { id: 'td-02', title: '华南销售陪练专项', owner: '培训经理', priority: 'P2', due: '周三', summary: '需要聚焦异议处理与高频错题复训', status: '课前准备', contextPatch: { outputs: ['陪练脚本包'], artifacts: ['陪练计划.xlsx'], risks: ['陪练素材还差两份'], events: ['09:05 生成陪练脚本初稿'] } }, @@ -296,133 +296,90 @@ const workspaceDemoData = { }, }, }, - 'logistics-fulfillment': { - title: '履约跟单专员', - caseTitle: '美西航线本周履约看板', - subtitle: '围绕节点跟踪、单证、异常处置与客户通知的履约控制塔。', + 'customer-followup': { + title: '客户跟进专员', + caseTitle: '本周客户跟进与会议预约', + subtitle: '围绕客户资料整理、意向分层、联系推进与会议预约的一体化跟进工作台。', cases: [ - { id: 'lf-01', title: '美西航线本周履约看板', owner: '运营经理', priority: 'P1', due: '实时', summary: '2 单延迟、1 单甩柜,需统一在一个控制塔里处置', status: '异常处置', contextPatch: { outputs: ['异常说明', '最新 ETA 清单'], artifacts: ['客户状态报告.pdf'], risks: ['甩柜异常未关闭'], events: ['09:00 生成客户状态说明'] } }, - { id: 'lf-02', title: '华东出口整柜周报', owner: '客服专员', priority: 'P2', due: '今天 16:00', summary: '需要同步对账草稿与客户状态说明', status: '节点跟踪', contextPatch: { outputs: ['对账草稿'], artifacts: ['周报对账.xlsx'], risks: ['一笔附加费待确认'], events: ['10:15 更新应收应付明细'] } }, - { id: 'lf-03', title: '欧洲空运急件批次', owner: '项目客服', priority: 'P1', due: '今天 14:00', summary: '航班调整后要重新生成客户 ETA 和改单任务', status: '客户同步', contextPatch: { outputs: ['客户 ETA 更新'], artifacts: ['空运调整通知.md'], risks: ['新航班仍待确认'], events: ['08:45 拉取新航班计划'] } }, + { id: 'cf-01', title: '本周客户线索优先级梳理', owner: '销售经理', priority: 'P1', due: '今天 18:00', summary: '8 个客户待分层,需明确优先联系顺序与本周触达计划', status: '意向分层', contextPatch: { outputs: ['客户优先级清单', '本周联系计划'], artifacts: ['客户跟进清单.xlsx'], risks: ['2 个客户资料不完整'], events: ['09:10 汇总 CRM 资料', '10:00 完成首轮意向分层'] } }, + { id: 'cf-02', title: 'A 客户演示会议预约', owner: '售前经理', priority: 'P1', due: '明天 15:00', summary: '高意向客户已回复,需确认会议目标、时间与参会人', status: '会议预约', contextPatch: { outputs: ['会议邀约建议', '跟进纪要'], artifacts: ['A客户会议准备.md'], risks: ['客户参会人未最终确认'], events: ['11:20 生成邀约话术'] } }, + { id: 'cf-03', title: '老客户续约回访推进', owner: '客户成功经理', priority: 'P2', due: '本周五', summary: '3 个续约客户需要补齐资料并确认下一轮回访节奏', status: '资料归档', contextPatch: { outputs: ['续约回访清单'], artifacts: ['续约客户跟进.md'], risks: ['一个客户历史沟通记录缺失'], events: ['14:30 补齐回访纪要'] } }, ], - tabs: ['进度', '时间线', '异常', '回放'], + tabs: ['进度', '时间线', '客户', '回放'], stageSummary: [ - { name: '委托接入', status: 'completed' }, - { name: '订舱执行', status: 'completed' }, - { name: '节点跟踪', status: 'active' }, - { name: '异常处置', status: 'active' }, - { name: '对账结算', status: 'pending' }, + { name: '资料归档', status: 'completed' }, + { name: '意向分层', status: 'active' }, + { name: '首轮触达', status: 'waiting' }, + { name: '会议预约', status: 'active' }, + { name: '跟进回写', status: 'pending' }, ], taskCards: [ - { title: '节点跟踪', status: '进行中', detail: '本周 18 单在途,2 单延迟,1 单需改单', tone: 'primary' }, - { title: '单证校验', status: '已完成', detail: '提单、装箱单、发票一致性校验通过', tone: 'success' }, - { title: '异常升级', status: '待处理', detail: '甩柜异常等待船司回复与客户确认', tone: 'danger' }, + { title: '资料归档', status: '已完成', detail: 'CRM、邮件和表格中的客户资料已整理进统一清单', tone: 'success' }, + { title: '意向判断', status: '进行中', detail: '正在对 8 个客户做高、中、低意向分层', tone: 'primary' }, + { title: '会议推进', status: '待处理', detail: '2 个高意向客户待确认演示时间与参会人', tone: 'warning' }, ], focusPanels: [ - { title: '当前关注', content: '需要把船司节点、邮件和企微异常同步到一个履约事项里。' }, - { title: '客户同步', content: '自动生成异常说明、下一步动作和最新 ETA。' }, - { title: '下一步', content: '异常关闭后进入费用归集与对账。' }, + { title: '当前关注', content: '本周新增客户线索较多,需要先整理资料,再确定优先跟进顺序。' }, + { title: '推进焦点', content: '优先推动高意向客户进入会议预约,资料不全的客户先补齐背景。' }, + { title: '下一步', content: '输出可直接发送的联系话术,并确认两场演示会议的时间。' }, ], - quickViews: ['全部节点', '异常单', '客户通知', '对账状态'], - relatedItems: ['本周舱位清单', '改单记录', '对账草稿'], + quickViews: ['客户资料清单', '意向分层', '联系草稿', '会议安排'], + relatedItems: ['CRM', '客户跟进表', '会议日程'], context: { - outputs: ['异常说明', '最新 ETA 清单', '改单任务'], - artifacts: ['客户状态报告.pdf', '提单资料包.zip', '对账草稿.xlsx'], - evidence: ['e-7011 船司节点回执', 'e-7012 邮件往来', 'e-7013 单证扫描件'], - risks: ['甩柜异常未关闭', '2 单节点延迟', '改单可能影响截关时间'], - checkpoints: ['客户确认 ETA', '运营经理确认改单'], - relatedObjects: ['Shipment: 美西航线-0816', 'Exception: 甩柜', 'Partner: XX 船司'], + outputs: ['客户优先级清单', '联系话术建议', '会议邀约建议'], + artifacts: ['客户跟进清单.xlsx', 'A客户会议准备.md', '续约客户跟进.md'], + evidence: ['e-cf-01 CRM 客户资料', 'e-cf-02 历史沟通记录', 'e-cf-03 演示需求摘要'], + risks: ['2 个客户资料不完整', '一个高意向客户会议时间未最终确认'], + checkpoints: ['销售经理确认优先级', '售前经理确认会议目标'], + relatedObjects: ['CRM: 客户库', 'Table: 客户跟进表', 'Calendar: 演示日程'], events: [ - '07:40 拉取船司节点', - '08:15 识别异常邮件', - '09:00 生成客户状态说明', + '09:10 汇总 CRM 资料', + '10:00 完成首轮意向分层', + '11:20 生成邀约话术', ], bottomPanel: { - timeline: ['07:40 节点同步', '08:15 异常识别', '09:00 通知客户'], - replay: ['回放节点 1: SyncMilestones', '回放节点 2: DetectException', '回放节点 3: NotifyCustomer'], - trace: ['connector.carrier.pullMilestone()', 'plugin.logistics.detectException()', 'connector.wecom.sendNotice()'], - logs: ['[INFO] 18 shipments synced', '[WARN] exception ship-002 delayed', '[INFO] notice sent to customer'], - }, - }, - }, - 'hr-email-sorter': { - title: 'HR 邮件整理专员', - caseTitle: '招聘邮箱邮件处理', - subtitle: '自动识别简历邮件、抽取候选人字段、去重归类并写入候选人表。', - cases: [ - { id: 'hes-01', title: '本周招聘邮箱邮件处理', owner: 'HR 专员', priority: 'P2', due: '今天 18:00', summary: '3 封待处理邮件需识别并归档', status: '邮件处理', contextPatch: { outputs: ['候选人提取清单'], artifacts: ['邮件处理日志.md'], risks: ['一封邮件附件格式不支持'], events: ['09:30 拉取未读邮件'] } }, - { id: 'hes-02', title: '华南销售岗简历归档', owner: '招聘经理', priority: 'P2', due: '明天 12:00', summary: '需从收件箱批量提取候选人并去重', status: '批量提取', contextPatch: { outputs: ['批量候选人清单'], artifacts: ['华南销售候选人.xlsx'], risks: ['同候选人重复投递'], events: ['10:15 完成去重比对'] } }, - ], - tabs: ['进度', '时间线', '邮件列表', '回放'], - stageSummary: [ - { name: '邮件拉取', status: 'completed' }, - { name: '简历识别', status: 'active' }, - { name: '候选人提取', status: 'waiting' }, - { name: '去重归档', status: 'pending' }, - ], - taskCards: [ - { title: '邮件识别', status: '进行中', detail: '正在扫描 3 封新邮件中的简历特征', tone: 'primary' }, - { title: '字段抽取', status: '待处理', detail: '识别完成后再抽取姓名、电话、岗位', tone: 'warning' }, - { title: '去重写入', status: '待处理', detail: '抽取后与现有候选人表比对去重', tone: 'warning' }, - ], - focusPanels: [ - { title: '当前关注', content: '招聘邮箱收到新邮件,需要判断是否为简历邮件。' }, - { title: '处理焦点', content: '确保附件(pdf/doc)正确解析、同发件人附件做去重。' }, - { title: '下一步', content: '抽取完成后写入候选人表,触发简历处理专员。' }, - ], - quickViews: ['待处理邮件', '已提取候选人', '去重记录', '归档日志'], - relatedItems: ['招聘邮箱收件箱', '候选人表', '岗位需求表'], - context: { - outputs: ['候选人提取清单', '邮件处理日志'], - artifacts: ['邮件处理日志.md', '候选人清单.xlsx'], - evidence: ['e-hr-01 招聘邮件', 'e-hr-02 简历附件'], - risks: ['一封邮件附件格式不支持', '同候选人重复投递'], - checkpoints: ['HR 专员确认提取结果'], - relatedObjects: ['Mailbox: HR 招聘邮箱', 'Table: 候选人表', 'Attachment: 简历 pdf/doc'], - events: ['09:30 拉取未读邮件', '10:15 完成去重比对'], - bottomPanel: { - timeline: ['09:00 检查收件箱', '09:30 拉取 3 封新邮件', '10:15 去重比对完成'], - replay: ['回放节点 1: FetchMails', '回放节点 2: IdentifyResumes', '回放节点 3: ExtractFields'], - trace: ['connector.email.fetchInbox()', 'plugin.resume.identify()', 'plugin.resume.extract()'], - logs: ['[INFO] 3 new emails fetched', '[WARN] 1 attachment format unsupported', '[INFO] dedup comparison done'], + timeline: ['09:10 资料同步', '10:00 意向分层', '11:20 生成邀约建议'], + replay: ['回放节点 1: CollectCustomerProfiles', '回放节点 2: ScoreIntent', '回放节点 3: DraftOutreach'], + trace: ['connector.crm.sync()', 'plugin.followup.rank()', 'plugin.meeting.compose()'], + logs: ['[INFO] customer profiles synced', '[WARN] 2 incomplete profiles detected', '[INFO] outreach draft generated'], }, }, }, 'resume-processor': { - title: '简历处理专员', - caseTitle: '候选人筛选与面试安排', - subtitle: '基于候选人表筛选匹配岗位要求、评分排序并发起面试安排。', + title: '招聘筛选专员', + caseTitle: '招聘入口归档、候选人筛选与面试安排', + subtitle: '先收拢招聘邮箱和候选人资料,再按岗位要求完成筛选、排序并推进面试安排。', cases: [ - { id: 'rp-01', title: '华南销售岗候选人筛选', owner: '招聘经理', priority: 'P1', due: '今天 17:00', summary: '5 份待筛选简历需匹配岗位要求并排序', status: '简历筛选', contextPatch: { outputs: ['候选人评分表', '面试推荐清单'], artifacts: ['华南销售筛选报告.pdf'], risks: ['一个候选人经历与岗位不完全匹配'], events: ['09:45 拉取候选人表', '10:30 完成自动评分'] } }, + { id: 'rp-01', title: '华南销售岗候选人筛选', owner: '招聘经理', priority: 'P1', due: '今天 17:00', summary: '3 封邮件待归档、5 份候选人待匹配岗位要求并排序', status: '候选人筛选', contextPatch: { outputs: ['候选人评分表', '面试推荐清单'], artifacts: ['华南销售筛选报告.pdf'], risks: ['一个候选人经历与岗位不完全匹配'], events: ['09:30 拉取招聘邮件', '09:45 拉取候选人表', '10:30 完成自动评分'] } }, { id: 'rp-02', title: '华东实施岗面试安排', owner: 'HR 主管', priority: 'P2', due: '明天 14:00', summary: '2 个候选人已通过初筛,需安排技术面试', status: '面试安排', contextPatch: { outputs: ['面试邀请草稿'], artifacts: ['面试安排表.xlsx'], risks: ['面试官时间待确认'], events: ['08:50 拉取通过名单'] } }, ], tabs: ['进度', '时间线', '候选人列表', '回放'], stageSummary: [ - { name: '候选人拉取', status: 'completed' }, - { name: '岗位匹配', status: 'active' }, + { name: '招聘入口归档', status: 'completed' }, + { name: '候选人整理', status: 'active' }, { name: '评分排序', status: 'waiting' }, { name: '面试安排', status: 'pending' }, ], taskCards: [ + { title: '入口归档', status: '已完成', detail: '已把 3 封招聘邮件和附件整理进候选人清单', tone: 'success' }, { title: '岗位匹配', status: '进行中', detail: '正在对比 5 份候选人与华南销售岗要求', tone: 'primary' }, - { title: '评分排序', status: '待处理', detail: '匹配完成后按综合评分排序', tone: 'warning' }, { title: '面试安排', status: '待处理', detail: '排序完成后发起面试邀请', tone: 'warning' }, ], focusPanels: [ - { title: '当前关注', content: '销售岗位要求 3 年以上经验,有行业客户资源优先。' }, - { title: '筛选焦点', content: '按经验年资、行业匹配度、沟通能力三个维度评分。' }, + { title: '当前关注', content: '招聘邮件和附件已归档,当前要按岗位要求完成候选人筛选。' }, + { title: '筛选焦点', content: '按经验年资、行业匹配度、沟通能力三个维度评分,并保留邮件来源。' }, { title: '下一步', content: '排序后生成推荐清单,等待招聘经理确认后发起面试。' }, ], - quickViews: ['待筛选简历', '已评分候选人', '面试排期', '通过率统计'], - relatedItems: ['岗位需求表', '候选人表', '面试安排表'], + quickViews: ['待处理邮件', '待筛选简历', '已评分候选人', '面试排期'], + relatedItems: ['招聘邮箱', '岗位需求表', '候选人表', '面试安排表'], context: { - outputs: ['候选人评分表', '面试推荐清单', '面试邀请'], + outputs: ['候选人归档清单', '候选人评分表', '面试推荐清单', '面试邀请'], artifacts: ['华南销售筛选报告.pdf', '面试安排表.xlsx'], - evidence: ['e-rp-01 候选人简历', 'e-rp-02 岗位描述', 'e-rp-03 面试反馈模板'], + evidence: ['e-rp-01 招聘邮件', 'e-rp-02 候选人简历', 'e-rp-03 岗位描述', 'e-rp-04 面试反馈模板'], risks: ['一个候选人经历与岗位不完全匹配', '面试官时间待确认'], checkpoints: ['招聘经理确认推荐清单', 'HR 主管确认面试安排'], - relatedObjects: ['Position: 华南销售岗', 'Table: 候选人表', 'Interview: 面试安排表'], - events: ['09:45 拉取候选人表', '10:30 完成自动评分', '10:50 生成面试推荐清单'], + relatedObjects: ['Mailbox: 招聘邮箱', 'Position: 华南销售岗', 'Table: 候选人表', 'Interview: 面试安排表'], + events: ['09:30 拉取招聘邮件', '09:45 拉取候选人表', '10:30 完成自动评分', '10:50 生成面试推荐清单'], bottomPanel: { timeline: ['09:00 拉取岗位需求', '09:45 获取候选人列表', '10:30 自动评分完成'], replay: ['回放节点 1: LoadCandidates', '回放节点 2: MatchRequirements', '回放节点 3: ScoreAndRank'], diff --git a/eai_agentplatform/frontend/src/skills/core/builtin.js b/eai_agentplatform/frontend/src/skills/core/builtin.js index 18f3ccd..cd23171 100644 --- a/eai_agentplatform/frontend/src/skills/core/builtin.js +++ b/eai_agentplatform/frontend/src/skills/core/builtin.js @@ -10,18 +10,13 @@ import reportGenerationManifest from '@/skills/packages/report-generation/manife import pptGenerationManifest from '@/skills/packages/ppt-generation/manifest' import mindMapManifest from '@/skills/packages/mind-map/manifest' import longformWritingManifest from '@/skills/packages/longform-writing/manifest' -import textToolkitManifest from '@/skills/packages/text-toolkit/manifest' import ocrUnderstandingManifest from '@/skills/packages/ocr-understanding/manifest' import meetingMinutesManifest from '@/skills/packages/meeting-minutes/manifest' -import projectPlanningManifest from '@/skills/packages/project-planning/manifest' -import emailDraftingManifest from '@/skills/packages/email-drafting/manifest' import tableCleanupManifest from '@/skills/packages/table-cleanup/manifest' -import proposalSummaryManifest from '@/skills/packages/proposal-summary/manifest' import progressReportManifest from '@/skills/packages/progress-report/manifest' import contractBriefManifest from '@/skills/packages/contract-brief/manifest' import interviewSummaryManifest from '@/skills/packages/interview-summary/manifest' import policyRewriteManifest from '@/skills/packages/policy-rewrite/manifest' -import surveySummaryManifest from '@/skills/packages/survey-summary/manifest' // Register office skill execution builders (side-effect import). // This centralizes all package→execution imports into one place. @@ -38,18 +33,13 @@ export const builtinSkillManifests = [ pptGenerationManifest, mindMapManifest, longformWritingManifest, - textToolkitManifest, ocrUnderstandingManifest, meetingMinutesManifest, - projectPlanningManifest, - emailDraftingManifest, tableCleanupManifest, - proposalSummaryManifest, progressReportManifest, contractBriefManifest, interviewSummaryManifest, policyRewriteManifest, - surveySummaryManifest, ] const builtinSkillRegistry = createRegistry(builtinSkillManifests) diff --git a/eai_agentplatform/frontend/src/skills/packages/audio-transcribe/manifest.js b/eai_agentplatform/frontend/src/skills/packages/audio-transcribe/manifest.js index c28bdb8..0c5df24 100644 --- a/eai_agentplatform/frontend/src/skills/packages/audio-transcribe/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/audio-transcribe/manifest.js @@ -6,8 +6,9 @@ import { export default createSkillManifest({ key: 'audio-transcribe', - label: '语音转写', - caption: '转写 / 分段 / 重点整理', + label: '会议音频分析(转写)', + caption: '一小时录音,自动出纪要。', + description: '一小时录音,自动出纪要。 操作:打开「会议音频分析」,上传音频(MP3/M4A/WAV)→ AI 自动转写(带说话人标签)→ 同时输出纪要 + 待办清单 + 思维导图', color: '#5263c3', skillTags: ['逐字转写', '说话人分段', '重点提炼', '纪要整理'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/batch-extract/manifest.js b/eai_agentplatform/frontend/src/skills/packages/batch-extract/manifest.js index 56ac1e9..bef1db1 100644 --- a/eai_agentplatform/frontend/src/skills/packages/batch-extract/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/batch-extract/manifest.js @@ -6,8 +6,9 @@ import { export default createSkillManifest({ key: 'batch-extract', - label: '批量提取', - caption: '字段设计 / 批量抽取 / 异常复核', + label: '批量字段提取 → Excel', + caption: '上百份文件的关键信息,自动汇表。', + description: '上百份文件的关键信息,自动汇表。 操作:在「智能助手」中选择目标知识库 → 用自然语言告诉 AI 需要哪些字段 → AI 自动遍历每份文件,逐项提取,保存为 Excel', color: '#39b07a', skillTags: ['字段抽取', '批量处理', '结构化输出', '异常回看'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/contract-brief/manifest.js b/eai_agentplatform/frontend/src/skills/packages/contract-brief/manifest.js index d6de0eb..0df2b60 100644 --- a/eai_agentplatform/frontend/src/skills/packages/contract-brief/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/contract-brief/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.contract-brief', code: 'EAI-T-212', key: 'contract-brief', - label: '合同要点提炼', + label: '合同批量审查与提取(提取)', category: 'document', artifactType: 'summary', fileFormat: 'md', color: '#dc2626', - description: '把合同、协议和条款材料压缩成核心要点、风险提示和待确认事项,方便业务快速预读。', + description: '几十份合同,自动提取甲方、乙方、金额、付款方式等关键字段,一键汇总成 Excel 总表。还能按条件筛选"百万以上合同"或"涉及公路运输的合同",并自动归纳违约金条款。', defaultPrompt: '把这份采购合同提炼成要点摘要和待确认项', resultTitle: '合同要点摘要', summary: '已提炼出合同核心条款、主要风险和待确认事项,方便快速预读和继续审查。', diff --git a/eai_agentplatform/frontend/src/skills/packages/contract-review/manifest.js b/eai_agentplatform/frontend/src/skills/packages/contract-review/manifest.js index b5a36f3..4b0d0a8 100644 --- a/eai_agentplatform/frontend/src/skills/packages/contract-review/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/contract-review/manifest.js @@ -6,8 +6,9 @@ import { export default createSkillManifest({ key: 'contract-review', - label: '合同审查', - caption: '条款识别 / 风险判断 / 审查交付', + label: '合同批量审查与提取(审查)', + caption: '几十份合同,自动提取关键字段,一键汇总成 Excel 总表。', + description: '几十份合同,自动提取甲方、乙方、金额、付款方式等关键字段,一键汇总成 Excel 总表。还能按条件筛选"百万以上合同"或"涉及公路运输的合同",并自动归纳违约金条款。', color: '#f56c6c', skillTags: ['风险识别', '待确认项', '红线建议', '审查结果'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/copy-proofreading/manifest.js b/eai_agentplatform/frontend/src/skills/packages/copy-proofreading/manifest.js index a54ab95..1b6286d 100644 --- a/eai_agentplatform/frontend/src/skills/packages/copy-proofreading/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/copy-proofreading/manifest.js @@ -7,7 +7,8 @@ import { export default createSkillManifest({ key: 'copy-proofreading', label: '文案校对', - caption: '问题定位 / 表达优化 / 风格收口', + caption: '错别字、语病,一键标出。', + description: '错别字、语病,一键标出。 操作:打开「文案校对」,上传文档 → AI 自动逐句检查,标注错别字、语法问题 → 返回带高亮修订版 + 修改建议,可一键采纳', color: '#e6a23c', skillTags: ['错别字检查', '语病修正', '语气统一', '风格优化'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/document-translate/manifest.js b/eai_agentplatform/frontend/src/skills/packages/document-translate/manifest.js index 62298cc..b3c4c41 100644 --- a/eai_agentplatform/frontend/src/skills/packages/document-translate/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/document-translate/manifest.js @@ -7,7 +7,8 @@ import { export default createSkillManifest({ key: 'document-translate', label: '文档翻译', - caption: '译文生成 / 术语统一 / 多格式导出', + caption: '整份翻译,排版原封不动。', + description: '整份翻译,排版原封不动。 操作:打开「文档翻译」,上传文件(Word/PDF/PPT/Excel)→ 选择目标语言 → 下载译文——排版、表格、图片位置全部保留', color: '#67c23a', skillTags: ['术语统一', '语气对齐', '格式保留', '双语摘要'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/email-drafting/execution.js b/eai_agentplatform/frontend/src/skills/packages/email-drafting/execution.js deleted file mode 100644 index db40344..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/email-drafting/execution.js +++ /dev/null @@ -1,119 +0,0 @@ -import { - buildEmailSubjectVariants, - extractPoints, - parseStructuredFields, - pickTopic, - slugify, - splitSimpleList, -} from '@/skills/shared/officeArtifacts' - -export function buildExecution(inputText = '') { - const { fields, bodyText } = parseStructuredFields(inputText, { - recipient: ['收件人', '对象', 'recipient', 'to'], - cc: ['抄送', '抄送人', 'cc'], - topic: ['主题', '标题', 'topic', 'subject'], - purpose: ['目的', '意图', 'purpose'], - action: ['希望对方', '需要对方', 'action'], - deadline: ['时间', '截止时间', 'deadline'], - tone: ['语气', '风格', 'tone', 'style'], - }) - const topic = fields.topic || pickTopic(bodyText || inputText, '邮件主题') - const recipient = fields.recipient || '各位' - const ccList = splitSimpleList(fields.cc) - const purpose = fields.purpose || '同步背景和当前进展' - const action = fields.action || '请协助确认并继续推进' - const deadline = fields.deadline || '请尽快反馈' - const tone = fields.tone || '正式、明确、礼貌' - const points = extractPoints(bodyText || inputText, [ - '交代背景和当前情况', - '说明希望对方配合或确认的事项', - '给出时间点和下一步动作', - '保持礼貌但结论清楚', - ]) - const subjectVariants = buildEmailSubjectVariants(topic, purpose) - const subject = subjectVariants[0] - const emailContent = [ - `主题:${subject}`, - `收件人:${recipient}`, - `抄送:${ccList.length ? ccList.join('、') : '无'}`, - '', - `${recipient}好,`, - '', - `${purpose}。${points[0] || '这边同步一下当前事项的背景和进展。'}`, - `${action}。${points[1] || '目前需要大家协助确认相关事项。'}`, - `${deadline}。${points[2] || '如无问题,请按约定时间继续推进。'}`, - '', - `语气建议:${tone}。如有问题,请直接回复沟通。`, - '', - '谢谢。', - ].join('\n').trim() - const shortContent = [ - `【${topic}】`, - `${points[1] || '请协助确认相关事项。'}`, - `${points[2] || '如无问题请按时推进。'}`, - ].join('\n').trim() - const briefContent = [ - '# 邮件要点', - '', - `- 主题:${subject}`, - ...points.slice(0, 4).map((item) => `- ${item}`), - ].join('\n').trim() - const subjectContent = [ - '# 主题与抄送建议', - '', - `- 收件人:${recipient}`, - `- 抄送建议:${ccList.length ? ccList.join('、') : '建议抄送直属负责人 / 相关协同方'}`, - '', - '## 可选主题', - ...subjectVariants.map((item, index) => `${index + 1}. ${item}`), - ].join('\n').trim() - const slug = slugify(topic, 'email-drafting') - - return { - title: '邮件草稿', - summary: `已按“${recipient} / ${topic}”生成正式邮件、短消息版和邮件要点摘要。`, - highlights: ['适合通知、催办、确认和汇报邮件', '会识别收件人、抄送、目的、时间和语气', '新增可直接挑选的主题变体'], - artifacts: [ - { - key: 'email', - title: '正式邮件', - description: '可直接复制到邮箱发送的完整版本。', - kind: 'text', - fileFormat: 'txt', - mimeType: 'text/plain;charset=utf-8', - downloadName: `${slug}.txt`, - content: emailContent, - }, - { - key: 'short-followup', - title: '简短跟进版', - description: '适合发到 IM 或群里的短消息版本。', - kind: 'text', - fileFormat: 'txt', - mimeType: 'text/plain;charset=utf-8', - downloadName: `${slug}-short.txt`, - content: shortContent, - }, - { - key: 'brief', - title: '邮件要点', - description: '方便审批或复核邮件口径的要点版。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-brief.md`, - content: briefContent, - }, - { - key: 'subject-variants', - title: '主题与抄送建议', - description: '提供多版主题候选和抄送建议。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-subject.md`, - content: subjectContent, - }, - ], - } -} diff --git a/eai_agentplatform/frontend/src/skills/packages/email-drafting/manifest.js b/eai_agentplatform/frontend/src/skills/packages/email-drafting/manifest.js deleted file mode 100644 index 93257ab..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/email-drafting/manifest.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createOfficeSkillManifest } from '@/skills/contracts/manifest' - -export default createOfficeSkillManifest({ - id: 'eai.email-drafting', - code: 'EAI-T-208', - key: 'email-drafting', - label: '邮件起草', - category: 'communication', - artifactType: 'document', - fileFormat: 'txt', - color: '#0f766e', - description: '把沟通意图、背景和要求整理成可直接发送的正式邮件,并附带简短跟进版本。', - defaultPrompt: '帮我起草一封推进客户回款的正式邮件', - resultTitle: '邮件草稿', - summary: '已生成一版可直接发送的邮件正文,并补了简短跟进版本和要点摘要。', - highlights: ['适合汇报、催办、确认和通知', '兼顾正式语气与清晰表达', '默认沉淀长邮件和短消息版本'], - taskPlanTitle: '邮件起草流程', - planSteps: ['识别沟通目的', '整理背景与重点', '生成正式邮件', '补充简短跟进版本'], -}) diff --git a/eai_agentplatform/frontend/src/skills/packages/interview-summary/manifest.js b/eai_agentplatform/frontend/src/skills/packages/interview-summary/manifest.js index 91b1a10..ecaa43c 100644 --- a/eai_agentplatform/frontend/src/skills/packages/interview-summary/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/interview-summary/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.interview-summary', code: 'EAI-T-213', key: 'interview-summary', - label: '访谈整理', + label: '招聘简历助手', category: 'summary', artifactType: 'document', fileFormat: 'md', color: '#7c3aed', - description: '把访谈记录、用户调研和深度沟通内容整理成主题摘要、洞察结论和后续动作。', + description: '自然语言筛简历,多人对比。 操作:打开「招聘简历助手」,上传简历文件 → 用自然语言描述岗位需求 → AI 逐条匹配,自动生成多人对比表', defaultPrompt: '把这份用户访谈记录整理成主题摘要和洞察结论', resultTitle: '访谈整理稿', summary: '已把访谈内容收成主题摘要、洞察结论和后续建议,方便继续分析或汇报。', diff --git a/eai_agentplatform/frontend/src/skills/packages/longform-writing/manifest.js b/eai_agentplatform/frontend/src/skills/packages/longform-writing/manifest.js index 8547956..b22743f 100644 --- a/eai_agentplatform/frontend/src/skills/packages/longform-writing/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/longform-writing/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.longform-writing', code: 'EAI-T-203', key: 'longform-writing', - label: '长文创作', + label: '公文辅助写作(长文)', category: 'writing', artifactType: 'document', fileFormat: 'docx', color: '#b45309', - description: '统一承接论文、方案、制度文档、公众号长文等长文任务,先搭大纲,再分段生成正文。', + description: '通知、报告、函,一键起草。 操作:选择「公文辅助写作」→ 用自然语言描述公文内容 → AI 自动生成符合规范的公文初稿,字体字号符合标准', defaultPrompt: '围绕企业 AI 落地写一篇完整方案', resultTitle: '长文草稿', summary: '已按长文写作流程生成大纲与正文骨架,适合继续细化为正式稿。', diff --git a/eai_agentplatform/frontend/src/skills/packages/meeting-minutes/manifest.js b/eai_agentplatform/frontend/src/skills/packages/meeting-minutes/manifest.js index a8a8269..3adaa6f 100644 --- a/eai_agentplatform/frontend/src/skills/packages/meeting-minutes/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/meeting-minutes/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.meeting-minutes', code: 'EAI-T-206', key: 'meeting-minutes', - label: '会议纪要', + label: '会议音频分析(纪要)', category: 'document', artifactType: 'document', fileFormat: 'md', color: '#7c3aed', - description: '把会议记录、聊天记录和零散讨论整理成正式纪要、决议摘要和待办清单。', + description: '一小时录音,自动出纪要。 操作:打开「会议音频分析」,上传音频(MP3/M4A/WAV)→ AI 自动转写(带说话人标签)→ 同时输出纪要 + 待办清单 + 思维导图', defaultPrompt: '把这段项目例会记录整理成正式会议纪要', resultTitle: '会议纪要草稿', summary: '已按会议纪要结构整理出主题、结论和待办,方便直接同步给参会人。', diff --git a/eai_agentplatform/frontend/src/skills/packages/mind-map/manifest.js b/eai_agentplatform/frontend/src/skills/packages/mind-map/manifest.js index 3cbc1f9..ff24af0 100644 --- a/eai_agentplatform/frontend/src/skills/packages/mind-map/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/mind-map/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.mind-map', code: 'EAI-T-202', key: 'mind-map', - label: '思维导图', + label: '会议音频分析(思维导图)', category: 'structure', artifactType: 'mindmap', fileFormat: 'svg', color: '#0f766e', - description: '把一句话主题、会议纪要或长文本快速展开成结构化导图,适合梳理任务与知识结构。', + description: '一小时录音,自动出纪要。 操作:打开「会议音频分析」,上传音频(MP3/M4A/WAV)→ AI 自动转写(带说话人标签)→ 同时输出纪要 + 待办清单 + 思维导图', defaultPrompt: '把这次项目启动会整理成一版思维导图', resultTitle: '导图结构草案', summary: '已把输入内容压缩成层级结构,方便继续扩展节点或导出成导图文件。', diff --git a/eai_agentplatform/frontend/src/skills/packages/ocr-understanding/manifest.js b/eai_agentplatform/frontend/src/skills/packages/ocr-understanding/manifest.js index 9719e52..6a66025 100644 --- a/eai_agentplatform/frontend/src/skills/packages/ocr-understanding/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/ocr-understanding/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.ocr-understanding', code: 'EAI-T-205', key: 'ocr-understanding', - label: 'OCR / 图文理解', + label: '图片/扫描件智能识别', category: 'vision', artifactType: 'document', fileFormat: 'md', color: '#0ea5e9', - description: '识别图片、截图和扫描件中的文字与结构信息,并提炼为摘要或结构化字段。', + description: '拍照即提取,长图也能问。 操作:把图片拖进聊天框(JPG/PNG/长图/扫描件均可)→ 用自然语言描述要提取什么 → AI 自动识别内容并结构化输出', defaultPrompt: '识别这张截图里的文字并整理成结构化摘要', resultTitle: '识别结果摘要', summary: '已按图文理解流程准备好识别与整理结果的第一版结构,方便继续抽字段或生成摘要。', diff --git a/eai_agentplatform/frontend/src/skills/packages/officeExecutions/index.js b/eai_agentplatform/frontend/src/skills/packages/officeExecutions/index.js index 15a48ca..c606633 100644 --- a/eai_agentplatform/frontend/src/skills/packages/officeExecutions/index.js +++ b/eai_agentplatform/frontend/src/skills/packages/officeExecutions/index.js @@ -9,14 +9,12 @@ import { registerOfficeExecution } from '@/skills/shared/officeExecutionRegistry' // Communication skills -import { buildExecution as buildEmailDraftingExecution } from '@/skills/packages/email-drafting/execution' import { buildExecution as buildMeetingMinutesExecution } from '@/skills/packages/meeting-minutes/execution' import { buildExecution as buildProgressReportExecution } from '@/skills/packages/progress-report/execution' // Structure skills import { buildExecution as buildMindMapExecution } from '@/skills/packages/mind-map/execution' import { buildExecution as buildPptExecution } from '@/skills/packages/ppt-generation/execution' -import { buildExecution as buildProjectPlanningExecution } from '@/skills/packages/project-planning/execution' import { buildExecution as buildTableCleanupExecution } from '@/skills/packages/table-cleanup/execution' // Writing skills @@ -25,23 +23,15 @@ import { buildExecution as buildInterviewSummaryExecution } from '@/skills/packa import { buildExecution as buildLongformExecution } from '@/skills/packages/longform-writing/execution' import { buildExecution as buildOcrExecution } from '@/skills/packages/ocr-understanding/execution' import { buildExecution as buildPolicyRewriteExecution } from '@/skills/packages/policy-rewrite/execution' -import { buildExecution as buildProposalSummaryExecution } from '@/skills/packages/proposal-summary/execution' -import { buildExecution as buildSurveySummaryExecution } from '@/skills/packages/survey-summary/execution' -import { buildExecution as buildTextToolkitExecution } from '@/skills/packages/text-toolkit/execution' // Register all execution builders -registerOfficeExecution('email-drafting', buildEmailDraftingExecution) registerOfficeExecution('meeting-minutes', buildMeetingMinutesExecution) registerOfficeExecution('progress-report', buildProgressReportExecution) registerOfficeExecution('mind-map', buildMindMapExecution) registerOfficeExecution('ppt-generation', buildPptExecution) -registerOfficeExecution('project-planning', buildProjectPlanningExecution) registerOfficeExecution('table-cleanup', buildTableCleanupExecution) registerOfficeExecution('contract-brief', buildContractBriefExecution) registerOfficeExecution('interview-summary', buildInterviewSummaryExecution) registerOfficeExecution('longform-writing', buildLongformExecution) registerOfficeExecution('ocr-understanding', buildOcrExecution) registerOfficeExecution('policy-rewrite', buildPolicyRewriteExecution) -registerOfficeExecution('proposal-summary', buildProposalSummaryExecution) -registerOfficeExecution('survey-summary', buildSurveySummaryExecution) -registerOfficeExecution('text-toolkit', buildTextToolkitExecution) diff --git a/eai_agentplatform/frontend/src/skills/packages/policy-rewrite/manifest.js b/eai_agentplatform/frontend/src/skills/packages/policy-rewrite/manifest.js index 11be10f..3ea0c82 100644 --- a/eai_agentplatform/frontend/src/skills/packages/policy-rewrite/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/policy-rewrite/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.policy-rewrite', code: 'EAI-T-214', key: 'policy-rewrite', - label: '制度改写', + label: '公文辅助写作(制度)', category: 'writing', artifactType: 'document', fileFormat: 'md', color: '#6d28d9', - description: '把制度、规范和说明文本重写成更清楚、更统一的正式版本,并补出修订说明。', + description: '通知、报告、函,一键起草。 操作:选择「公文辅助写作」→ 用自然语言描述公文内容 → AI 自动生成符合规范的公文初稿,字体字号符合标准', defaultPrompt: '把这份报销制度改写成更正式清晰的版本', resultTitle: '制度改写稿', summary: '已将原制度改写为更清楚统一的正式版本,并补了修订说明和执行提示。', diff --git a/eai_agentplatform/frontend/src/skills/packages/ppt-generation/manifest.js b/eai_agentplatform/frontend/src/skills/packages/ppt-generation/manifest.js index fcaace9..d667c14 100644 --- a/eai_agentplatform/frontend/src/skills/packages/ppt-generation/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/ppt-generation/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.ppt-generation', code: 'EAI-T-201', key: 'ppt-generation', - label: 'PPT 生成', + label: '一键生成 PPT', category: 'document', artifactType: 'presentation', fileFormat: 'pptx', color: '#4f46e5', - description: '根据主题、受众和材料,先整理演示逻辑,再生成可继续细化的演示文稿骨架。', + description: '从资料到演示文稿,一步到位。 操作:在「智能助手」中上传资料或录音 → 说"基于这份资料生成一份 8 页 PPT" → 下载 .pptx 文件,每页标题清晰、要点完整', defaultPrompt: '为季度经营复盘生成一版 8 页 PPT 大纲', resultTitle: '演示文稿骨架', summary: '已按主题、受众和页数要求整理出演示逻辑,并给出可继续细化的文稿骨架。', diff --git a/eai_agentplatform/frontend/src/skills/packages/progress-report/manifest.js b/eai_agentplatform/frontend/src/skills/packages/progress-report/manifest.js index bb0871b..b171042 100644 --- a/eai_agentplatform/frontend/src/skills/packages/progress-report/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/progress-report/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.progress-report', code: 'EAI-T-211', key: 'progress-report', - label: '周报 / 日报', + label: '一键周报', category: 'report', artifactType: 'document', fileFormat: 'md', color: '#16a34a', - description: '把工作记录、聊天记录和事项进展整理成日报、周报或阶段同步,补齐风险和下步计划。', + description: '把一周的日报丢给智能体,自动归纳重点工作、进展与下周计划,生成结构化周报,直接提交。', defaultPrompt: '根据这些工作记录整理一版项目周报', resultTitle: '进展汇报草稿', summary: '已整理出本期进展、风险事项和下一步计划,方便直接同步给负责人。', diff --git a/eai_agentplatform/frontend/src/skills/packages/project-planning/execution.js b/eai_agentplatform/frontend/src/skills/packages/project-planning/execution.js deleted file mode 100644 index 171caa1..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/project-planning/execution.js +++ /dev/null @@ -1,115 +0,0 @@ -import { - buildProjectStageRows, - extractPoints, - parseStructuredFields, - pickTopic, - slugify, -} from '@/skills/shared/officeArtifacts' - -export function buildExecution(inputText = '') { - const { fields, bodyText } = parseStructuredFields(inputText, { - topic: ['项目', '项目名称', '主题', 'topic'], - deadline: ['时间要求', '截止时间', 'deadline'], - owner: ['负责人', 'owner'], - goal: ['目标', 'goal'], - start: ['开始时间', '启动时间', 'start'], - }) - const topic = fields.topic || pickTopic(bodyText || inputText, '项目规划') - const deadline = fields.deadline || '待确认' - const owner = fields.owner || '待指定' - const goal = fields.goal || '先明确目标、阶段、依赖和协同方式' - const start = fields.start || '尽快启动' - const points = extractPoints(bodyText || inputText, [ - '明确目标、范围和成功标准', - '梳理关键里程碑与交付节点', - '安排执行分工与协同节奏', - '识别风险与外部依赖', - ]) - const stageRows = buildProjectStageRows(points, owner, deadline) - const planContent = [ - `# ${topic}`, - '', - '## 项目目标', - `围绕“${topic}”整理一版可执行的项目规划,先确保目标、阶段和依赖都清楚。`, - `- 负责人:${owner}`, - `- 启动时间:${start}`, - `- 时间要求:${deadline}`, - `- 总体目标:${goal}`, - '', - '## 阶段安排', - '### 阶段 1:启动与对齐', - `- ${points[0] || '明确目标和边界'}`, - '### 阶段 2:执行与推进', - `- ${points[1] || '推进关键里程碑和核心交付'}`, - '### 阶段 3:验收与收口', - `- ${points[2] || '完成验收、复盘和沉淀'}`, - ].join('\n').trim() - const milestoneContent = [ - '# 里程碑清单', - '', - ...points.slice(0, 5).map((item, index) => `${index + 1}. M${index + 1}:${item}`), - ].join('\n').trim() - const riskContent = [ - '# 风险与依赖', - '', - `- 风险 1:${points[3] || '关键依赖尚未完全明确'}`, - '- 风险 2:跨团队协同节奏可能影响排期', - '- 建议:将关键依赖提前前置到周会或启动会确认', - ].join('\n').trim() - const ganttContent = [ - '# 阶段排期表', - '', - '| 阶段 | 时间窗 | 负责人 | 目标 | 交付物 |', - '| --- | --- | --- | --- | --- |', - ...stageRows.map((item) => `| ${item.stage} | ${item.window} | ${item.owner} | ${item.goal} | ${item.output} |`), - ].join('\n').trim() - const slug = slugify(topic, 'project-planning') - - return { - title: '项目规划草案', - summary: `已按“${topic} / ${deadline}”整理出阶段计划、里程碑和风险清单。`, - highlights: ['阶段计划清晰', '会识别负责人、时间要求和项目目标', '新增可直接评审的阶段排期表'], - artifacts: [ - { - key: 'project-plan', - title: '项目计划', - description: '适合直接评审和继续细化的主计划。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}.md`, - content: planContent, - }, - { - key: 'milestones', - title: '里程碑清单', - description: '关键节点和交付节奏的简洁版列表。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-milestones.md`, - content: milestoneContent, - }, - { - key: 'risks', - title: '风险清单', - description: '项目推进前需要确认的风险与依赖。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-risks.md`, - content: riskContent, - }, - { - key: 'schedule', - title: '阶段排期表', - description: '更接近甘特视角的阶段、时间窗和交付物表。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-schedule.md`, - content: ganttContent, - }, - ], - } -} diff --git a/eai_agentplatform/frontend/src/skills/packages/project-planning/manifest.js b/eai_agentplatform/frontend/src/skills/packages/project-planning/manifest.js deleted file mode 100644 index 8776e8f..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/project-planning/manifest.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createOfficeSkillManifest } from '@/skills/contracts/manifest' - -export default createOfficeSkillManifest({ - id: 'eai.project-planning', - code: 'EAI-T-207', - key: 'project-planning', - label: '项目规划', - category: 'planning', - artifactType: 'plan', - fileFormat: 'md', - color: '#2563eb', - description: '根据目标、约束和现状整理项目阶段、里程碑、执行分工和风险清单。', - defaultPrompt: '为新产品上线项目整理一版执行计划和里程碑', - resultTitle: '项目规划草案', - summary: '已把目标拆成阶段计划、里程碑和风险项,方便直接进入执行或评审。', - highlights: ['适合启动、排期和推进对齐', '默认沉淀阶段计划与风险清单', '结果适合继续流转到任务治理'], - taskPlanTitle: '项目规划流程', - planSteps: ['明确目标边界', '拆解阶段路径', '整理里程碑', '补齐风险与依赖'], -}) diff --git a/eai_agentplatform/frontend/src/skills/packages/proposal-summary/execution.js b/eai_agentplatform/frontend/src/skills/packages/proposal-summary/execution.js deleted file mode 100644 index e98fb60..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/proposal-summary/execution.js +++ /dev/null @@ -1,78 +0,0 @@ -import { - extractPoints, - pickTopic, - slugify, -} from '@/skills/shared/officeArtifacts' - -export function buildExecution(inputText = '') { - const topic = pickTopic(inputText, '方案摘要') - const points = extractPoints(inputText, [ - '明确方案目标和解决的问题', - '提炼核心价值与收益', - '压缩关键实施路径', - '明确需要决策的事项', - ]) - const summaryContent = [ - `# ${topic}`, - '', - '## 核心结论', - `${topic} 已压缩为适合汇报和快速预读的摘要版本,重点保留目标、价值点和实施建议。`, - '', - '## 关键亮点', - ...points.slice(0, 4).map((item) => `- ${item}`), - '', - '## 实施建议', - '- 建议先确认资源与排期', - '- 建议围绕高优先级场景先落一版 MVP', - '- 建议同步关键负责人做进一步评审', - ].join('\n').trim() - const highlightsContent = [ - '# 亮点清单', - '', - ...points.slice(0, 5).map((item, index) => `${index + 1}. ${item}`), - ].join('\n').trim() - const briefingContent = [ - `【${topic} 摘要】`, - ...points.slice(0, 3).map((item, index) => `${index + 1}. ${item}`), - '建议按上述结论进入下一步决策或评审。', - ].join('\n').trim() - const slug = slugify(topic, 'proposal-summary') - - return { - title: '方案摘要稿', - summary: '已提炼出方案核心结论、价值亮点和实施建议,适合快速汇报或同步。', - highlights: ['适合方案汇报和管理层预读', '自动压缩价值点与实施路径', '默认沉淀摘要正文和亮点清单'], - artifacts: [ - { - key: 'summary', - title: '方案摘要', - description: '适合直接汇报或继续细化的主摘要。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}.md`, - content: summaryContent, - }, - { - key: 'highlights', - title: '亮点清单', - description: '压缩提炼后的价值点列表。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-highlights.md`, - content: highlightsContent, - }, - { - key: 'briefing', - title: '汇报短版', - description: '适合发群或口头汇报前快速同步的短摘要。', - kind: 'text', - fileFormat: 'txt', - mimeType: 'text/plain;charset=utf-8', - downloadName: `${slug}-briefing.txt`, - content: briefingContent, - }, - ], - } -} diff --git a/eai_agentplatform/frontend/src/skills/packages/proposal-summary/manifest.js b/eai_agentplatform/frontend/src/skills/packages/proposal-summary/manifest.js deleted file mode 100644 index e649512..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/proposal-summary/manifest.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createOfficeSkillManifest } from '@/skills/contracts/manifest' - -export default createOfficeSkillManifest({ - id: 'eai.proposal-summary', - code: 'EAI-T-210', - key: 'proposal-summary', - label: '方案摘要', - category: 'summary', - artifactType: 'document', - fileFormat: 'md', - color: '#9333ea', - description: '把长方案、材料包和售前文档压缩成高密度摘要,保留核心结论、价值点和实施建议。', - defaultPrompt: '把这份解决方案压成一版管理层可读摘要', - resultTitle: '方案摘要稿', - summary: '已提炼出方案核心结论、价值亮点和实施建议,适合快速汇报或同步。', - highlights: ['适合方案汇报和管理层预读', '自动压缩价值点与实施路径', '默认沉淀摘要正文和亮点清单'], - taskPlanTitle: '方案摘要流程', - planSteps: ['识别方案目标', '提炼核心亮点', '压缩实施路径', '输出摘要版本'], -}) diff --git a/eai_agentplatform/frontend/src/skills/packages/report-generation/manifest.js b/eai_agentplatform/frontend/src/skills/packages/report-generation/manifest.js index a556068..864b19c 100644 --- a/eai_agentplatform/frontend/src/skills/packages/report-generation/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/report-generation/manifest.js @@ -6,8 +6,9 @@ import { export default createSkillManifest({ key: 'report-generation', - label: '报告生成', - caption: '材料归并 / 结构规划 / 正式输出', + label: '一键生成报告', + caption: '聊完天,PDF/Word 报告就写好了。', + description: '聊完天,PDF/Word 报告就写好了。 操作:在「智能助手」中上传资料或讨论要点 → 说"帮我做成 PDF 报告"或"整理成 Word" → AI 自动生成结构化内容,排版为正式文档,一键下载', color: '#9c27b0', skillTags: ['日报周报', '复盘总结', '章节规划', '管理摘要'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/smart-assistant/manifest.js b/eai_agentplatform/frontend/src/skills/packages/smart-assistant/manifest.js index 5b31f52..38dc68e 100644 --- a/eai_agentplatform/frontend/src/skills/packages/smart-assistant/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/smart-assistant/manifest.js @@ -6,8 +6,9 @@ import { export default createSkillManifest({ key: 'smart-assistant', - label: '通用助手', - caption: '对话 / 任务拆解 / 文案生成', + label: '智能助手', + caption: '说句话,复杂任务自动完成。', + description: '说句话,复杂任务自动完成。 操作:打开「智能助手」,用自然语言描述目标 → 可拖入多份文件、关联知识库 → 助手自动拆解为「计划→执行→验证→交付」,全程可见可控', color: '#409eff', skillTags: ['任务澄清', '方案拆解', '对象分派', '交付起步'], workflowSchema: [ diff --git a/eai_agentplatform/frontend/src/skills/packages/survey-summary/execution.js b/eai_agentplatform/frontend/src/skills/packages/survey-summary/execution.js deleted file mode 100644 index 9b3f30f..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/survey-summary/execution.js +++ /dev/null @@ -1,77 +0,0 @@ -import { - extractPoints, - pickTopic, - slugify, -} from '@/skills/shared/officeArtifacts' - -export function buildExecution(inputText = '') { - const topic = pickTopic(inputText, '问卷汇总') - const points = extractPoints(inputText, [ - '参与者的主要反馈方向', - '高频问题或不满意点', - '值得保留的积极反馈', - '后续改进建议', - ]) - const reportContent = [ - `# ${topic}`, - '', - '## 汇总结论', - ...points.slice(0, 4).map((item) => `- ${item}`), - '', - '## 汇总说明', - '已把表单和问卷结果压缩成便于阅读和决策的汇总结论。', - ].join('\n').trim() - const findingsContent = [ - '# 重点发现', - '', - `- 发现 1:${points[0] || '参与者主要关注体验和执行效果'}`, - `- 发现 2:${points[1] || '部分问题集中在流程或内容安排上'}`, - `- 发现 3:${points[2] || '已有若干积极反馈值得继续保留'}`, - ].join('\n').trim() - const actionsContent = [ - '# 改进建议', - '', - `- [ ] ${points[3] || '根据汇总结果制定下一步改进动作'}`, - '- [ ] 对高频问题安排专项优化', - '- [ ] 向负责人同步汇总结论和优先级建议', - ].join('\n').trim() - const slug = slugify(topic, 'survey-summary') - - return { - title: '问卷汇总稿', - summary: '已整理出表单结果汇总、重点发现和改进建议,方便直接同步给负责人。', - highlights: ['适合反馈表、报名表、调查问卷', '自动压缩重点发现和改进建议', '默认沉淀汇总报告和行动建议'], - artifacts: [ - { - key: 'report', - title: '汇总报告', - description: '适合直接汇报或继续细化的主报告。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}.md`, - content: reportContent, - }, - { - key: 'findings', - title: '重点发现', - description: '从表单结果中提炼出的关键发现。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-findings.md`, - content: findingsContent, - }, - { - key: 'actions', - title: '改进建议', - description: '建议后续继续推进的改进行动。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-actions.md`, - content: actionsContent, - }, - ], - } -} diff --git a/eai_agentplatform/frontend/src/skills/packages/survey-summary/manifest.js b/eai_agentplatform/frontend/src/skills/packages/survey-summary/manifest.js deleted file mode 100644 index 2c0fbe4..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/survey-summary/manifest.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createOfficeSkillManifest } from '@/skills/contracts/manifest' - -export default createOfficeSkillManifest({ - id: 'eai.survey-summary', - code: 'EAI-T-215', - key: 'survey-summary', - label: '表单问卷汇总', - category: 'report', - artifactType: 'report', - fileFormat: 'md', - color: '#2563eb', - description: '把问卷、报名表和收集表单结果整理成汇总报告、重点发现和后续动作建议。', - defaultPrompt: '把这批培训反馈问卷整理成汇总结论和改进建议', - resultTitle: '问卷汇总稿', - summary: '已整理出表单结果汇总、重点发现和改进建议,方便直接同步给负责人。', - highlights: ['适合反馈表、报名表、调查问卷', '自动压缩重点发现和改进建议', '默认沉淀汇总报告和行动建议'], - taskPlanTitle: '问卷汇总流程', - planSteps: ['归并表单结果', '提炼重点发现', '整理问题与建议', '输出汇总版本'], -}) diff --git a/eai_agentplatform/frontend/src/skills/packages/table-cleanup/manifest.js b/eai_agentplatform/frontend/src/skills/packages/table-cleanup/manifest.js index 6044c6a..d6d2df5 100644 --- a/eai_agentplatform/frontend/src/skills/packages/table-cleanup/manifest.js +++ b/eai_agentplatform/frontend/src/skills/packages/table-cleanup/manifest.js @@ -4,12 +4,12 @@ export default createOfficeSkillManifest({ id: 'eai.table-cleanup', code: 'EAI-T-209', key: 'table-cleanup', - label: '表格整理', + label: '知识库表格视图', category: 'data', artifactType: 'table', fileFormat: 'md', color: '#475569', - description: '把零散字段、半结构化列表和杂乱数据整理成清晰表格,并补出字段说明与清洗备注。', + description: '几十份文件秒变一张表。 操作:所有文件拖入知识库 → 切换到「表格视图」,AI 自动发现共有字段 → 自动生成表格,可排序、编辑、一键导出 Excel', defaultPrompt: '把这批客户跟进记录整理成结构化表格', resultTitle: '表格整理结果', summary: '已把输入内容整理成结构化表格,并补了字段说明和清洗备注。', diff --git a/eai_agentplatform/frontend/src/skills/packages/text-toolkit/execution.js b/eai_agentplatform/frontend/src/skills/packages/text-toolkit/execution.js deleted file mode 100644 index d652ade..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/text-toolkit/execution.js +++ /dev/null @@ -1,62 +0,0 @@ -import { - meaningfulLines, - pickTopic, - slugify, -} from '@/skills/shared/officeArtifacts' - -function stripMarkdown(text) { - return meaningfulLines(String(text || '') - .replace(/```[\s\S]*?```/g, '') - .replace(/`([^`]+)`/g, '$1') - .replace(/\[(.*?)\]\((.*?)\)/g, '$1') - .replace(/[*_>#-]+/g, ' ')) - .join('\n') -} - -export function buildExecution(inputText = '') { - const cleaned = stripMarkdown(inputText) - const chars = cleaned.length - const lines = meaningfulLines(cleaned).length - const statsContent = [ - '# 文本统计', - '', - `- 字符数:${chars}`, - `- 行数:${lines}`, - `- 原始长度:${String(inputText || '').trim().length}`, - '', - '## 处理说明', - '- 已移除常见 Markdown 标记', - '- 已压缩多余空行', - '- 已保留正文可读性', - ].join('\n') - const topic = pickTopic(inputText, 'cleaned-text') - const slug = slugify(topic, 'text-toolkit') - - return { - title: '清洗后文本', - summary: '已完成 Markdown 去噪、格式整理和文本统计,可直接下载或复制结果。', - highlights: ['去 Markdown 噪音', '输出文本统计', '适合高频复制到 Word / IM 场景'], - artifacts: [ - { - key: 'cleaned', - title: '清洗后文本', - description: '适合直接粘贴到文档或聊天工具。', - kind: 'text', - fileFormat: 'txt', - mimeType: 'text/plain;charset=utf-8', - downloadName: `${slug}.txt`, - content: cleaned, - }, - { - key: 'stats', - title: '文本统计', - description: '记录本次清洗和统计结果。', - kind: 'text', - fileFormat: 'md', - mimeType: 'text/markdown;charset=utf-8', - downloadName: `${slug}-stats.md`, - content: statsContent, - }, - ], - } -} diff --git a/eai_agentplatform/frontend/src/skills/packages/text-toolkit/manifest.js b/eai_agentplatform/frontend/src/skills/packages/text-toolkit/manifest.js deleted file mode 100644 index 6337c76..0000000 --- a/eai_agentplatform/frontend/src/skills/packages/text-toolkit/manifest.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createOfficeSkillManifest } from '@/skills/contracts/manifest' - -export default createOfficeSkillManifest({ - id: 'eai.text-toolkit', - code: 'EAI-T-204', - key: 'text-toolkit', - label: '文本处理', - category: 'text', - artifactType: 'document', - fileFormat: 'md', - color: '#334155', - description: '用于去 Markdown 符号、格式整理、文本统计与批量清洗,让复制出来的内容更适合继续使用。', - defaultPrompt: '把这段 AI 回答清洗成适合粘贴到 Word 的纯文本', - resultTitle: '清洗后文本', - summary: '已按文本处理工具箱模式整理好内容,方便继续复制、统计或二次编辑。', - highlights: ['去 Markdown 噪音', '统一段落和标点', '适合高频复制粘贴场景'], - taskPlanTitle: '文本处理流程', - planSteps: ['识别清洗目标', '去除噪音符号', '统一格式与标点', '输出可复用文本'], -}) diff --git a/eai_agentplatform/frontend/src/skills/shared/officeArtifacts.js b/eai_agentplatform/frontend/src/skills/shared/officeArtifacts.js index 41ea897..acd4609 100644 --- a/eai_agentplatform/frontend/src/skills/shared/officeArtifacts.js +++ b/eai_agentplatform/frontend/src/skills/shared/officeArtifacts.js @@ -171,38 +171,6 @@ export function buildCsvText(columns, rows) { .join('\n') } -export function splitSimpleList(value) { - return [...new Set( - String(value || '') - .split(/[,,、/;;\n]/) - .map((item) => item.trim()) - .filter(Boolean), - )] -} - -export function buildProjectStageRows(points, owner, deadline) { - const labels = ['阶段 1', '阶段 2', '阶段 3', '阶段 4'] - const windows = ['第 1 周', '第 2 周', '第 3 周', deadline || '收口前'] - return labels.map((label, index) => ({ - stage: label, - window: windows[index] || `第 ${index + 1} 周`, - goal: points[index] || `补充 ${label} 目标`, - owner: owner || '待指定', - output: index === 0 ? '目标确认' : index === 1 ? '阶段交付' : index === 2 ? '验收材料' : '收口结论', - })) -} - -export function buildEmailSubjectVariants(topic, purpose) { - const base = String(topic || '事项').trim() - const context = String(purpose || '').trim() - return [ - `${base} - 请协助确认`, - `${base} - 需要回复`, - `${base} - 进展同步`, - context ? `${base} - ${context.slice(0, 12)}` : `${base} - 待处理提醒`, - ] -} - export function splitFocusKeywords(value) { return [...new Set( String(value || '') diff --git a/eai_agentplatform/frontend/src/skills/store/skillCatalog.js b/eai_agentplatform/frontend/src/skills/store/skillCatalog.js index 45af4dc..7beb3ac 100644 --- a/eai_agentplatform/frontend/src/skills/store/skillCatalog.js +++ b/eai_agentplatform/frontend/src/skills/store/skillCatalog.js @@ -76,8 +76,26 @@ function normalizeSkillTags(remote, fallback) { ].map((item) => String(item || '').trim()).filter(Boolean) } +function parseInteractionCard(item) { + const raw = safeParse(item?.interaction_card_json, null) + if (raw && typeof raw === 'object' && String(raw?.greeting || '').trim()) { + return { + greeting: String(raw.greeting || '').trim(), + tagline: String(raw.tagline || '').trim(), + openingPrompt: String(raw.opening_prompt || '').trim(), + relationshipToUser: String(raw.relationship_to_user || '').trim(), + tone: String(raw.tone || '').trim(), + starterPrompts: Array.isArray(raw.starter_prompts) + ? raw.starter_prompts.map((p) => String(p || '').trim()).filter(Boolean) + : [], + } + } + return null +} + function normalizeSkill(item) { const fallback = getStaticSkillByKey(item?.key) + const cardFromBackend = parseInteractionCard(item) const starterPrompts = safeParse(item?.starter_prompts_json, []) const remote = { ...item, @@ -86,7 +104,7 @@ function normalizeSkill(item) { display_code: String(item?.display_code || '').trim() || String(fallback?.display_code || '').trim(), eailogic_code: String(item?.eailogic_code || '').trim() || String(fallback?.eailogic_code || '').trim(), caption: String(item?.description || '').trim() || String(fallback?.caption || '').trim(), - color: String(fallback?.color || '#409eff').trim(), + color: String(item?.color || fallback?.color || '#409eff').trim(), objectEntryRoute: String(item?.object_entry_route || '').trim() || String(fallback?.objectEntryRoute || '').trim(), @@ -102,7 +120,16 @@ function normalizeSkill(item) { skillTags: normalizeSkillTags(item, fallback), workflowSchema: normalizeWorkflowSchema(item, fallback), artifactSchema: normalizeArtifactSchema(item?.artifact_schema_json, fallback), - interactionCard: buildFallbackInteractionCard(remote, fallback), + interactionCard: cardFromBackend + ? { + ...cardFromBackend, + starterPrompts: cardFromBackend.starterPrompts.length + ? cardFromBackend.starterPrompts + : (remote.starterPrompts.length + ? remote.starterPrompts + : (fallback?.interactionCard?.starterPrompts || [])), + } + : buildFallbackInteractionCard(remote, fallback), } } diff --git a/eai_agentplatform/frontend/src/specialists/core/builtin.js b/eai_agentplatform/frontend/src/specialists/core/builtin.js index 90a4457..63ebd48 100644 --- a/eai_agentplatform/frontend/src/specialists/core/builtin.js +++ b/eai_agentplatform/frontend/src/specialists/core/builtin.js @@ -2,28 +2,16 @@ import { withObjectCodes } from '@/utils/objectCode' import { createRegistry } from '@/specialists/core/registry' import contractReviewManifest from '@/specialists/packages/contract-review/manifest' import solutionProposalManifest from '@/specialists/packages/solution-proposal/manifest' -import trainingDeliveryManifest from '@/specialists/packages/training-delivery/manifest' -import knowledgeOperationsManifest from '@/specialists/packages/knowledge-operations/manifest' -import processCoordinationManifest from '@/specialists/packages/process-coordination/manifest' -import reportGenerationManifest from '@/specialists/packages/report-generation/manifest' import wechatOfficialAccountManifest from '@/specialists/packages/wechat-official-account/manifest' -import logisticsFulfillmentManifest from '@/specialists/packages/logistics-fulfillment/manifest' -import hrEmailSorterManifest from '@/specialists/packages/hr-email-sorter/manifest' +import customerFollowupManifest from '@/specialists/packages/customer-followup/manifest' import resumeProcessorManifest from '@/specialists/packages/resume-processor/manifest' -import presentationBriefingManifest from '@/specialists/packages/presentation-briefing/manifest' const builtinSpecialistRegistry = createRegistry([ contractReviewManifest, solutionProposalManifest, - trainingDeliveryManifest, - knowledgeOperationsManifest, - processCoordinationManifest, - reportGenerationManifest, wechatOfficialAccountManifest, - logisticsFulfillmentManifest, - hrEmailSorterManifest, + customerFollowupManifest, resumeProcessorManifest, - presentationBriefingManifest, ]) export function getBuiltinSpecialistRegistry() { diff --git a/eai_agentplatform/frontend/src/specialists/packages/customer-followup/manifest.js b/eai_agentplatform/frontend/src/specialists/packages/customer-followup/manifest.js new file mode 100644 index 0000000..aa4052e --- /dev/null +++ b/eai_agentplatform/frontend/src/specialists/packages/customer-followup/manifest.js @@ -0,0 +1,27 @@ +import { createSpecialistManifest } from '@/specialists/contracts/manifest' + +export default createSpecialistManifest({ + key: 'customer-followup', + label: '客户跟进专员', + tier: 'industry', + specialistMode: 'adw', + marketTag: '试用', + summary: '整理客户资料、识别意向并推进会议预约', + status: '3 个客户待联系', + risk: '1 个高意向待确认', + color: '#e6a23c', + stage: '首轮触达', + progress: 46, + interactionCard: { + greeting: '我是客户跟进专员,可以帮你整理客户资料、判断客户意向,并把联系和预约动作继续往前推。', + tagline: '把客户线索、跟进动作和会议预约收在一条推进线上。', + openingPrompt: '把客户资料、沟通背景和这轮目标发给我,我先帮你梳理跟进优先级。', + relationshipToUser: '你的客户推进协作搭档', + starterPrompts: [ + '先把这些客户资料整理成一张跟进清单', + '帮我判断这些客户的意向等级', + '给我一版首轮联系话术和会议邀约建议', + '把本周待跟进客户排成优先级列表', + ], + }, +}) diff --git a/eai_agentplatform/frontend/src/specialists/packages/hr-email-sorter/manifest.js b/eai_agentplatform/frontend/src/specialists/packages/hr-email-sorter/manifest.js deleted file mode 100644 index c181f48..0000000 --- a/eai_agentplatform/frontend/src/specialists/packages/hr-email-sorter/manifest.js +++ /dev/null @@ -1,26 +0,0 @@ -import { createSpecialistManifest } from '@/specialists/contracts/manifest' - -export default createSpecialistManifest({ - key: 'hr-email-sorter', - label: 'HR 邮件整理专员', - tier: 'industry', - specialistMode: 'dw', - marketTag: '试用', - summary: '识别并整理招聘邮箱中的简历邮件', - status: '3 封待处理', - risk: '0 个异常', - color: '#409eff', - stage: '邮件处理', - progress: 0, - interactionCard: { - greeting: '我是 HR 邮件整理专员,可以帮你识别、分类并整理招聘邮箱里的邮件。', - tagline: '把招聘邮箱里的内容收成可继续处理的人才线索。', - openingPrompt: '把邮件内容或整理目标告诉我,我先帮你分组归档。', - relationshipToUser: '你的招聘整理协作搭档', - starterPrompts: [ - '帮我整理今天收到的招聘邮件', - '把这些邮件按岗位和优先级分类', - '先筛出适合继续跟进的候选人邮件', - ], - }, -}) diff --git a/eai_agentplatform/frontend/src/specialists/packages/logistics-fulfillment/manifest.js b/eai_agentplatform/frontend/src/specialists/packages/logistics-fulfillment/manifest.js deleted file mode 100644 index 896123d..0000000 --- a/eai_agentplatform/frontend/src/specialists/packages/logistics-fulfillment/manifest.js +++ /dev/null @@ -1,26 +0,0 @@ -import { createSpecialistManifest } from '@/specialists/contracts/manifest' - -export default createSpecialistManifest({ - key: 'logistics-fulfillment', - label: '履约跟单专员', - tier: 'industry', - specialistMode: 'adw', - marketTag: '试用', - summary: '美西航线本周履约看板', - status: '1 个异常', - risk: '2 个节点延迟', - color: '#e6a23c', - stage: '异常处置', - progress: 49, - interactionCard: { - greeting: '我是履约跟单专员,可以帮你跟进节点、识别异常并整理处置建议。', - tagline: '把履约过程里的异常、催办和交付节奏收在一条线上。', - openingPrompt: '把当前订单、节点和异常情况发给我,我先帮你排查。', - relationshipToUser: '你的履约协作搭档', - starterPrompts: [ - '帮我梳理这票货当前的履约状态', - '把这些延迟节点整理成跟单清单', - '针对这次异常给我一版处置建议', - ], - }, -}) diff --git a/eai_agentplatform/frontend/src/specialists/packages/resume-processor/manifest.js b/eai_agentplatform/frontend/src/specialists/packages/resume-processor/manifest.js index 8d7a980..5475018 100644 --- a/eai_agentplatform/frontend/src/specialists/packages/resume-processor/manifest.js +++ b/eai_agentplatform/frontend/src/specialists/packages/resume-processor/manifest.js @@ -2,22 +2,23 @@ import { createSpecialistManifest } from '@/specialists/contracts/manifest' export default createSpecialistManifest({ key: 'resume-processor', - label: '简历处理专员', + label: '招聘筛选专员', tier: 'industry', specialistMode: 'dw', marketTag: '试用', - summary: '筛选候选人并安排面试', - status: '5 份待筛选', + summary: '收拢招聘邮件、筛选候选人并推进面试', + status: '5 份待筛选 / 3 封待归档', risk: '1 个匹配待确认', color: '#67c23a', - stage: '简历筛选', + stage: '候选人筛选', progress: 0, interactionCard: { - greeting: '我是简历处理专员,可以帮你筛选候选人、整理匹配理由并安排后续动作。', - tagline: '把简历筛选从海量阅读变成结构化判断。', - openingPrompt: '告诉我岗位要求和筛选标准,我先帮你做一轮初筛。', + greeting: '我是招聘筛选专员,可以先收拢招聘邮件与候选人资料,再完成筛选、排序和后续面试推进。', + tagline: '把招聘入口整理、候选人筛选和后续推进收成一条闭环。', + openingPrompt: '告诉我岗位要求、招聘邮箱情况和筛选标准,我先帮你做一轮归档与初筛。', relationshipToUser: '你的招聘筛选协作搭档', starterPrompts: [ + '先把今天收到的招聘邮件和附件归档成候选人清单', '根据这个 JD 帮我筛选一批候选人', '把这些简历按匹配度排序', '帮我整理一版面试建议和待确认点', diff --git a/eai_agentplatform/frontend/src/specialists/packages/training-delivery/manifest.js b/eai_agentplatform/frontend/src/specialists/packages/training-delivery/manifest.js deleted file mode 100644 index 5f10384..0000000 --- a/eai_agentplatform/frontend/src/specialists/packages/training-delivery/manifest.js +++ /dev/null @@ -1,26 +0,0 @@ -import { createSpecialistManifest } from '@/specialists/contracts/manifest' - -export default createSpecialistManifest({ - key: 'training-delivery', - label: '培训交付专员', - tier: 'generic', - specialistMode: 'dw', - marketTag: '已安装', - summary: '新人销售训练营第 3 周', - status: '5 个进行中', - risk: '0 个异常', - color: '#67c23a', - stage: '交付归档', - progress: 84, - interactionCard: { - greeting: '我是培训交付专员,可以帮你推进训练计划、交付节点和归档结果。', - tagline: '把培训交付从排期、推进到归档串成闭环。', - openingPrompt: '把交付背景、学员范围和目标发给我,我来帮你推进。', - relationshipToUser: '你的培训交付协作搭档', - starterPrompts: [ - '帮我整理这期训练营的交付计划', - '把这些交付节点汇总成执行清单', - '根据培训记录生成交付归档说明', - ], - }, -}) diff --git a/eai_agentplatform/frontend/src/specialists/packages/wechat-official-account/manifest.js b/eai_agentplatform/frontend/src/specialists/packages/wechat-official-account/manifest.js index 6037107..a9ecea2 100644 --- a/eai_agentplatform/frontend/src/specialists/packages/wechat-official-account/manifest.js +++ b/eai_agentplatform/frontend/src/specialists/packages/wechat-official-account/manifest.js @@ -2,7 +2,7 @@ import { createSpecialistManifest } from '@/specialists/contracts/manifest' export default createSpecialistManifest({ key: 'wechat-official-account', - label: '公众号助手', + label: '公众号专员', tier: 'generic', specialistMode: 'dw', marketTag: '已安装', @@ -13,7 +13,7 @@ export default createSpecialistManifest({ stage: '正文创作', progress: 0, interactionCard: { - greeting: '我是公众号助手,可以帮你把选题、提纲、正文和发布准备串起来。', + greeting: '我是公众号专员,可以帮你把选题、提纲、正文和发布准备串起来。', tagline: '把内容创作流程从想法推进到可发布。', openingPrompt: '告诉我主题、受众和语气,我先帮你起草内容结构。', relationshipToUser: '你的内容创作协作搭档', diff --git a/eai_agentplatform/frontend/src/styles/global.css b/eai_agentplatform/frontend/src/styles/global.css index ca55fd9..3084f3c 100644 --- a/eai_agentplatform/frontend/src/styles/global.css +++ b/eai_agentplatform/frontend/src/styles/global.css @@ -1,5 +1,5 @@ /* EAI 数字员工平台 — 全局样式 */ -/* 参考:docs/08_Design_Rules/DR01_Theme_System.md */ +/* 参考:docs/08_Design_Rules/DR01_主题系统.md */ :root { --nav-width: 189px;