--- name: skill-case-get description: "案例采集 / 拆解 / 归档。把各种素材(连续多图 / 九宫格、Word .docx、PPT .pptx、图文混合、裸图、视频)拆解为「案例信息」与「素材数组 materialAssets[]」,做合规判断(能否入库 / 客诉负面 / 隐私发现)与打标(学校别名归一 + 跟进状态七段 + 亮点/场景/异议),最后经云函数 caseSubmit 落到待审清单。适用场景:(1) 同事连发 6/9 张图其实是同一个素材,需要按九宫格阅读顺序编号归档;(2) 一份 Word/PPT 案例稿要抽出文字说明并拆出内嵌配图;(3) 判断这堆素材能不能进案例库、是不是客诉负面事件;(4) 按案例库标签体系打标并归一学校别名(IC → 帝国理工)。本 Skill 只处理已获授权素材。" description_en: "Case intake, decomposition and archiving. Turns raw material (image grids, .docx, .pptx, mixed text+image, bare images, video) into case fields plus an ordered materialAssets[] array, runs compliance triage and tagging, then submits to the review queue via the caseSubmit cloud function. Use for: (1) a run of 6/9 images that is ONE material needing 3x3 reading-order numbering, (2) extracting text and embedded media from Word/PPT, (3) deciding whether material may enter the case library or is a complaint/negative event, (4) tagging against the case-library tag system and normalising school aliases (IC -> Imperial College London). This skill only processes authorised material." version: 1.0.0 author: Yuyang001 (FmodeAgent) license: MPL-2.0 copyright: "Copyright (c) 2026 未来飞马 Fmode" tags: [未来飞马, 智能体技能, 超级技能, 服务级, 案例采集, 案例拆解, 素材归档, FmodeAgent, Hermes Agent, FmodeCode, Claude Code, case-library, case-intake, ocr, material-assets, 九宫格, 打标] --- 本 Skill 只处理已获授权素材。 # Fmode Case Get — 案例采集 / 拆解 / 归档 ## Overview 把素材变成**可入库的案例**: ``` 各种素材 → 拆解分析 → 能否进案例库判断 → 打标 → 上传归档(待审清单) ``` | 来源类型 | 处理方式 | | --- | --- | | ① 连续多张图片(朋友圈九宫格) | skill-vision OCR + 语义理解;按尺寸/时间/内容相似度**判为同一组**,按九宫格阅读顺序给显式 `order` | | ② Word `.docx` | python3 标准库 `zipfile` + `ElementTree` 解包:文字段落、表格、内嵌媒体、超链接 | | ③ PPT `.pptx` | 同上:按放映顺序抽每页标题/正文/备注/图片/表格 | | ④ 图文混合 | 文档文字走「案例说明」,内嵌图并进素材组一起编号 | | ⑤ 裸图片无文字说明 | 靠视觉理解补 `label` / `description` / `usageSuggestion`;分组回落到尺寸 + 时间信号 | | ⑥ 视频(附加) | ffmpeg 抽帧 → 交给图片链路;音轨走 skill-listen 转写 | **关键区分(必须分开,不能混)** - 「案例说明」——什么时候用、大概情况、背景 → 案例字段 `title / summary / targetCustomer / usageSuggestion / resultEvidence / outcome` - 「图片 / 视频」→ `materialAssets[]`(`order` 1 起,同组内按左上 → 右下) ## 红线(不可协商) 1. **授权前置**:`authorizationStatus != authorized` 一律不入库、不产生案例对象。默认值是 `pending`,必须显式传 `--authorization authorized`。 2. **不进公共素材库**:采集只写 `reviewStatus='pending'` + `readyForUse=false`,由负责人用 `caseApprove` 放行后才进检索结果。 3. **不落 PII**:真实 PII 只在本次请求内存中处理。`privacyFindings[].snippet` **本身就是掩码后的**(`138****5678`),不打码不落库。 4. **不伪造结果**:缺 ffmpeg / skill-vision / skill-listen 时,在 `warnings` 里明说,不编造 OCR 或转写内容。 5. **不写凭据**:token 只从环境变量 / 本地配置读,仅内存持有,不落盘、不进日志、不进报告。 ## 鉴权与依赖 - **云函数**:`POST https://server.lumistedu.com/api/functions`,请求体 `{"path":"/caseSubmit","params":{...},"token":"..."}`。 session token 来源:`CASE_PARSE_SESSION_TOKEN` → `PARSE_SESSION_TOKEN`。 - **图片理解**:复用兄弟技能 `skill-vision` 的 `analyze()`(`~/.claude/skills/skill-vision/scripts/vision-client.mjs`)。 该函数在**宿主自带多模态**时(FmodeCode / Claude Code)会返回读图指令而非调 API,此时由宿主 Agent 用自己的 Read 工具读图后补全。 可用 `--vision-model ` 覆盖,或 `--skip-vision` 跳过。 - **音视频**:复用兄弟技能 `skill-listen` 的 `listen-runner.mjs`(走 Fmode 网关,凭据仅服务端)。 - **python3**:解包 `.docx` / `.pptx`,**只用标准库**(本机没有 python-docx / python-pptx)。 - **ffmpeg / ffprobe**:视频抽帧、探测时长(可选)。 > 缺 token 是「缺配置」,不是「用不了」——请勿点任何付费/充值弹窗。 ## 用法 ### 命令行 ```bash # 只有图片(九宫格):先看分组与顺序,不调模型 npx skill-case-get@latest plan -- --image g1.jpg --image g2.jpg ... --image g9.jpg # 完整采集:拆解 + 图片理解 + 打标,产出案例包(不提交) npx skill-case-get@latest ingest -- \ --image g1.jpg --image g9.jpg \ --doc 案例稿.docx --deck 复盘.pptx \ --authorization authorized \ --source-ref wx-group-2026-10 \ --asset-base-url https://cdn.example.com/cases # 只给一个目录,自动按扩展名分流 npx skill-case-get@latest plan -- --input ./素材目录 # 调顺序(把第 3 张挪到第 1 位) npx skill-case-get@latest reorder -- --material-assets /material-assets.json --move "3:1" # 提交到待审清单 npx skill-case-get@latest submit -- --package /case-package.json --submitted-by user123 # 自检(含 office 解包、九宫格分组、打标、合规、顺序调整) npx skill-case-get@latest selftest ``` `ingest` / `plan` 之后必须加 `--`,其后参数透传给运行器。 ### 在 Node 脚本中调用 技能目录被复制进 `.claude/skills/` 时**不含 node_modules**,运行器是零依赖 ESM: ```js import { runPlan, runIngest, runSubmit } from './scripts/case-intake.mjs'; const report = await runIngest({ inputs: ['g1.jpg', 'g2.jpg', '案例稿.docx'], outDir: './case-get-outputs/run-001', authorizationStatus: 'authorized', assetBaseUrl: 'https://cdn.example.com/cases', }); console.log(report.casePackage.materialAssets); // order 已按九宫格排好 console.log(report.casePackage.riskFlags); // 合规判断 if (report.canSubmit) await runSubmit({ package: report.artifacts.casePackage }); ``` ## 产物 | 文件 | 内容 | | --- | --- | | `extracted.json` | 文档文字段落 / 表格 / 超链接 / 内嵌媒体 / 视频转写 | | `group-plan.json` | 分组(`groupId` / `layout` / `count` / `orderingRule`)与组内顺序 | | `vision.json` | 每张图的 `ocrText` / `description` / `label` / `usageSuggestion` / `piiHints` | | `material-assets.json` | `materialAssets[]`(可手工调顺序后回灌) | | `case-package.json` | 云函数 `caseSubmit` 入参,**逐字对齐共享契约** | | `report.md` | 人类可读报告(顺序表 / 标签 / 合规 / 下一步) | ## 分组与顺序规则(能力 3) 同事连发 6 张、9 张图**不是多个素材,而是同一个素材**(朋友圈素材按九宫格排)。 三种信号判同组,**至少 2 种成立**才并组: | 信号 | 判据 | 阈值 | | --- | --- | --- | | 尺寸 | 宽高比相似度 | ≥ 0.88 | | 时间 | 文件时间差 | ≤ 15 分钟(窗口内线性衰减) | | 内容 | OCR/描述 字符二元组 Jaccard | ≥ 0.25 | - 只有 1 种信号成立 → **不并组**(避免把不同素材误并); - 完全拿不到尺寸/时间(纯转发图)时,会按现有信号降级判定,理由写进 `reasons`; - 顺序:`orderingRule = left-to-right,top-to-bottom`,`order` **1 起**连续编号; 原始排版位置丢失时用「收图时间升序 + 文件名自然序」近似发送顺序; - 要人工干预:`reorder --move "3:1"` 或 `--order "3,1,2"`,也可在输入 manifest 里写 `groups[].items[].order`。 九宫格 = `layout: "3x3"`;6 张 = `3x2`;4 张 = `2x2`。 ## 打标(能力 6) - **硬性静态属性**:`schoolCanonical` / `country` / `major` / `stage` / `subject` - **学校别名归一**:`SchoolAlias` 表(`IC → 帝国理工`、`UCL → 伦敦大学学院`)。 别名表存在 `references/tag-dictionary.json` 的 `schoolAlias.entries`;命中的写法写入 `schoolAliases[]`。 英文别名按词边界匹配(`IC` 不会命中 `MAGIC`)。 - **销售阶段七段**:`新进线 / 挖需中 / 方案推荐中 / 异议处理中 / 待决策 / 沉默待跟进 / 已成交` 按 `docs/prd/dashboard/10-案例推荐策略.md` 的策略表反推,写进 `fitStatus[]`。 - **亮点 / 场景 / 异议**:`highlightTypes` / `scenarioTags` / `objectionTags` - **字典自进化**:采集到字典里没有的新取值时追加进 `references/tag-dictionary.json` (`--no-learn` 可关;本技能**只改文件、不自动 push**)。 ## 合规判断(能力 5) | 判定 | 落到哪 | | --- | --- | | 授权缺失 / pending / denied | `riskFlags: UNAUTHORIZED` + blocker,**不入库** | | 客诉 / 负面事件(投诉、退费纠纷、挂科、维权…) | `riskFlags: COMPLAINT` / `NEGATIVE_EVENT` + blocker,**不得对外展示** | | 隐私片段(手机号 / 邮箱 / 微信号 / 姓名…) | `privacyFindings[{field, rule, snippet}]`,snippet **已掩码** | | 与留学/课程无关 | `riskFlags: OFF_TOPIC` | | 无任何素材 | blocker,无法构成案例 | `complianceBlockers` 非空 → `submit` **拒绝提交**(即使授权通过)。 ## 归档通道(双通道,自动选择) `submit` 会**先试云函数,不可达时自动回落 Parse 直写**,两条通道落库字段逐字一致(都只进待审清单): | 通道 | 何时用 | 说明 | | --- | --- | --- | | 云函数 `caseSubmit` | 部署环境挂载了函数运行时 | `POST /api/functions`,`{path,params,token}`;返回 `{ok:true,result:{...}}` | | **Parse 直写**(本部署实际通道) | 云函数端点不可用(本部署:客户自有云未挂载函数运行时) | 直接写 `CaseAsset`,字段与 `caseSubmit.js` 对齐;`--no-direct` 可禁用回落 | - 本部署(`server.lumistedu.com`)**没有可用的函数运行时**:`/api/functions` 只是定位器端点、`/parse/functions/*` 只有 Parse 原生注册表。项目的真实数据架构就是浏览器端 Parse 直连(见 `web/src/app/core/data.service.ts`),归档走同一路径。 - **仍受同一套红线约束**:`reviewStatus='pending'`、`readyForUse=false`、`tenantId + idempotencyKey` 幂等 —— 新案例只进待审清单,不进公共素材库。 - 通道自检:`node scripts/case-intake.mjs probe`(只读,验证配置与连通性)。 - 服务端特权密钥只从环境变量 `CASE_PARSE_MASTER_KEY` 或 0600 的 `~/.fmode/config/enterprise/current.json` 读取,只进请求头,**不落盘、不打印**。 - 线上 `CaseAsset` 字段类型:`targetCustomer` / `resultEvidence` / `outcome` / `groupInfo` 是 **Object**(不是字符串),本通道已按此对齐。 ## 云函数(部署若挂载了函数运行时) | 函数 | 用途 | | --- | --- | | `caseSubmit` | 提交案例;写 `reviewStatus='pending'`、`readyForUse=false`;`tenantId + idempotencyKey` 幂等 | | `casePendingList` | 查待审清单 | | `caseApprove` | 负责人审核放行(`approve` → `readyForUse=true`) | | `caseSearch` | 检索(只返回 `reviewStatus='approved'` 且 `readyForUse=true`) | `tenantId` 由云函数从**服务端会话上下文**解析,客户端不传。 ## 安装为 FmodeCode / Claude Code 技能 ```bash npx --yes skill-case-get@latest workspace # 项目级 → ./.claude/skills/skill-case-get npx --yes skill-case-get@latest install # 用户级 → ~/.claude/skills/skill-case-get ``` 安装后可直接提示:`这 9 张图是同一个案例素材,帮我拆解、打标,然后归档到待审清单。` ## 注意事项 - `.docx` / `.pptx` 解包走 python3 标准库,**不要**为此引入 python-docx / python-pptx / 任何 npm 包。 - 本机不存储 / 不上传二进制:本地素材的 `url` 由 `--asset-base-url` 派生;没给就会在 `warnings` 里提示(不伪造 URL)。 - 视频抽帧是均匀取点(默认 6 帧,`--frame-count` 调整);转写走网关按音频时长计费。 - 枚举统一**小写**(对齐线上:`pending` / `authorized`),展示层再做中文化。