@puyinkai/xiaobao-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +81 -0
  2. package/dist/api-Ccj5dLMo.mjs +100 -0
  3. package/dist/api-client-DwySN6x-.mjs +75 -0
  4. package/dist/audio-VmDQMq59.mjs +14 -0
  5. package/dist/auth-ChHvqjCS.mjs +15 -0
  6. package/dist/cli.d.mts +1 -0
  7. package/dist/cli.mjs +30 -0
  8. package/dist/consultant-ABFTL_jx.mjs +11 -0
  9. package/dist/customer-DtSnQqy_.mjs +11 -0
  10. package/dist/device-flow-BgsZipYA.mjs +166 -0
  11. package/dist/focus-BDYuP2vZ.mjs +11 -0
  12. package/dist/format-BZvv8lYc.mjs +610 -0
  13. package/dist/headers-D79npewp.mjs +11 -0
  14. package/dist/list--o5Q_PI8.mjs +80 -0
  15. package/dist/list-Bkyi95YO.mjs +76 -0
  16. package/dist/list-CGACp0y-.mjs +76 -0
  17. package/dist/list-CVKSGNu4.mjs +91 -0
  18. package/dist/list-CzB9_Jho.mjs +91 -0
  19. package/dist/list-DW6KAAaC.mjs +92 -0
  20. package/dist/list-iwd9cH1I.mjs +41 -0
  21. package/dist/login-BwkrByMm.mjs +91 -0
  22. package/dist/logout-BJm9pjje.mjs +49 -0
  23. package/dist/project-Ba05YzJ5.mjs +14 -0
  24. package/dist/project-store-Bz5kf-EI.mjs +62 -0
  25. package/dist/qa-D-B9FV9W.mjs +60 -0
  26. package/dist/resistance-Cf7zsdB3.mjs +11 -0
  27. package/dist/text-BLH4R3xv.mjs +49 -0
  28. package/dist/token-store-CHZ_rJQk.mjs +85 -0
  29. package/dist/use-DV9Ii3Tn.mjs +61 -0
  30. package/dist/util-DgwkUfV9.mjs +46 -0
  31. package/dist/visit-Ct3Vea8I.mjs +11 -0
  32. package/dist/whoami-DwTHvI4B.mjs +51 -0
  33. package/package.json +36 -0
  34. package/skills/wangxiaobao-audio-query/SKILL.md +252 -0
  35. package/skills/wangxiaobao-audio-wiki/SKILL.md +332 -0
  36. package/skills/wangxiaobao-customer-focus-query/SKILL.md +213 -0
  37. package/skills/wangxiaobao-customer-query/SKILL.md +214 -0
  38. package/skills/wangxiaobao-customer-resistance-query/SKILL.md +211 -0
  39. package/skills/wangxiaobao-quick-qa/SKILL.md +238 -0
  40. package/skills/wangxiaobao-switch-project/SKILL.md +179 -0
  41. package/skills/wangxiaobao-visit-query/SKILL.md +249 -0
@@ -0,0 +1,332 @@
1
+ ---
2
+ name: wangxiaobao-audio-wiki
3
+ description: |
4
+ 旺小宝录音入库技能。把指定时间窗口的录音同步到本地,按 **项目/顾问/日期/录音** 四层目录归档到 llm-wiki 知识库(`wiki/projects/{projectId}-{projectName}/raw/audio/...`),并引导后续 ingest 阶段提炼出 **顾问画像 / 客户 / 话题 / 话术** 四类 Layer 2 知识页。每个旺小宝项目对应一个独立 wiki 目录,切项目不串味。一站式工作流:sync 阶段拉数据写 raw/,ingest 阶段提炼为可检索的销售知识。
5
+
6
+ **当以下情况时使用此 Skill**:
7
+ (1) 用户提到"拉录音"、"同步录音"、"旺小宝录音"、"音频归档"、"录音入库"、"建录音知识库"
8
+ (2) 用户希望把旺小宝的录音长期沉淀成可检索的销售知识 wiki
9
+ (3) 用户给定了时间范围或希望"从上次同步到现在"继续拉取
10
+ (4) 用户想为某位置业顾问建立画像、统计客户跟进、整理话术
11
+ (5) 用户在 query skill 看完一眼后想"完整存下来 + 提炼成知识"
12
+ ---
13
+
14
+ > **Host-agnostic CLI skill** — 本 skill 假设 `xiaobao-cli` 已装到 PATH
15
+ > (`npm i -g @puyinkai/xiaobao-cli` 或 `npx -y @puyinkai/xiaobao-cli`)。
16
+ > Agent 通过 shell 工具(Bash / Run / Shell)执行命令、读 **stdout JSON** 消费;
17
+ > stderr 是进度/错误提示。退出码 0 = 成功,非 0 = 业务/网络错(错误对象同时打到 stdout 可解析)。
18
+ >
19
+ > CLI 14 个子命令跟 openclaw-xiaobao plugin 14 个 tool **1:1 等价**,返回 JSON
20
+ > 结构完全一致(`{status, ok, data: {...}}`)。skill 里看到的 `resp.data.data.xxx`
21
+ > 取数路径直接对 stdout JSON 用 `jq` / `JSON.parse` 即可。
22
+ >
23
+ > **plugin tool → CLI 命令翻译表(数组参数走逗号分隔)**:
24
+ >
25
+ > | plugin tool | CLI 命令 |
26
+ > | --- | --- |
27
+ > | `xiaobao_authorize { force? }` | `xiaobao-cli auth login [--force]` |
28
+ > | `xiaobao_whoami` | `xiaobao-cli auth whoami` |
29
+ > | `xiaobao_logout` | `xiaobao-cli auth logout` |
30
+ > | `xiaobao_list_projects { keyword? }` | `xiaobao-cli project list [--keyword <kw>]` |
31
+ > | `xiaobao_switch_project { tenantId, tenantName, projectId, projectName }` | `xiaobao-cli project use --tenant-id ... --tenant-name ... --project-id ... --project-name ...` |
32
+ > | `xiaobao_list_consultants` | `xiaobao-cli consultant list` |
33
+ > | `xiaobao_list_audio { fromDate, toDate, userId?, userIdList?, page, size }` | `xiaobao-cli audio list --from "..." --to "..." [--user-id ...] [--user-id-list a,b,c] [--page N] [--size N]` |
34
+ > | `xiaobao_get_audio_text { audioId }` | `xiaobao-cli audio text <audioId>` |
35
+ > | `xiaobao_list_customers { ... }` | `xiaobao-cli customer list [--user-id] [--user-name] [--customer-name] [--customer-phone] [--portrait] [--from] [--to] [--page] [--size]` |
36
+ > | `xiaobao_list_visits { ... }` | `xiaobao-cli visit list [--customer-id] [--customer-name] [--from] [--to] [--page] [--size]` |
37
+ > | `xiaobao_list_customer_focus { visitIds, customerIds, audioIds, category, classification, fromDate, toDate, ... }` | `xiaobao-cli focus list [--visit-ids a,b] [--customer-ids a,b] [--audio-ids a,b] [--category ...] [--classification ...] [--from ...] [--to ...]` |
38
+ > | `xiaobao_list_customer_resistance { ... }` | `xiaobao-cli resistance list [同 focus]` |
39
+ > | `xiaobao_quick_qa { prompt, threadId? }` | `xiaobao-cli qa "<prompt>" [--thread-id ...]` |
40
+ > | `xiaobao_api { method, path, query, body, headers }` | `xiaobao-cli api <METHOD> <PATH> [--query k=v] [--body '<json>'] [--headers k=v]` |
41
+ >
42
+ > 用 `--format toon` 切到 TOON(uniform 数组省 30-50% token,LLM 上下文优化);
43
+ > 用 `--format json`(默认)保持 JSON。state 路径:`~/.xiaobao/`(fallback 读 `~/.openclaw/state/wangxiaobao/`)。
44
+
45
+
46
+ # 旺小宝录音入库
47
+
48
+ 完整工作流:**登录 → 选项目 → 翻页拉元数据 → 逐条取文本 → 按
49
+ **项目 / 顾问 / 日期 / 录音** 分层写 wiki → 推进游标 → ingest 提炼为
50
+ Layer 2 知识页**。
51
+
52
+ > 每个旺小宝项目落到独立的 `wiki/projects/{projectId}-{projectName}/`
53
+ > 目录,**切项目不会污染另一个项目的录音/顾问画像/客户档案**。同 cwd 下
54
+ > 可并存多个项目的 wiki。
55
+
56
+ > 只想看一眼录音元数据列表(不写文件、不推游标)请用 `wangxiaobao-audio-query`
57
+ > skill。本 skill 跟它的边界是 **写入 vs 只读**。
58
+
59
+ ## 上游接口
60
+
61
+ | 接口 | plugin tool | 用途 |
62
+ | --- | --- | --- |
63
+ | `POST /ai-open/audio/page` | `xiaobao_list_audio` | 分页列录音元数据 |
64
+ | `GET /ai-open/audio/text/{audioId}` | `xiaobao_get_audio_text` | 单条录音转录文本 + 说话人占比 |
65
+
66
+ ## 执行前必读
67
+
68
+ 1. **登录**:先调 `xiaobao_whoami`;未登录 / 过期就调 `xiaobao_authorize`。
69
+ 2. **激活项目**:tool 内部从 `~/.openclaw/state/wangxiaobao/active-project.json`
70
+ 读 tenant/project。如果任何 tool 返回 `error: 'NO_ACTIVE_PROJECT'`,
71
+ 先走 `wangxiaobao-switch-project` skill 让用户选。
72
+ 3. **拿到 projectId / projectName**(写 wiki 路径用):调一次
73
+ `xiaobao_list_projects` 后定位当前 active-project 对应行,或者直接复用
74
+ `xiaobao_switch_project` 上一次的返回值里的 `activeProject` 字段。
75
+ 4. **wiki 输出目录**:默认 `./wiki/`(cwd 下)。如果用户在 cwd `./.env`
76
+ 配了 `WIKI_DIR`,用 `${WIKI_DIR}/`。raw/ 子目录是 llm-wiki Layer 1,
77
+ **不可变**。
78
+ 5. **游标变量名**:`WB_SYNC_CURSOR`,**仍写到 cwd `./.env`**(游标是 per-workspace
79
+ 的同步进度,不是 plugin 全局状态,跟 active-project 不一样),格式
80
+ `yyyy-MM-dd HH:mm:ss`。
81
+ 6. **wiki schema 必读**:业务知识页结构详见
82
+ [`references/audio-wiki-schema.md`](references/audio-wiki-schema.md)
83
+ ——目录布局 / frontmatter / wikilinks 规则全在那里。
84
+
85
+ ## 时间格式
86
+
87
+ 上游用 pierre 框架 Jackson 配置,LocalDateTime 反序列化只接受
88
+ `yyyy-MM-dd HH:mm:ss`(中间空格分隔,**不是** ISO 的 `T`)。
89
+
90
+ - ✅ `"2026-05-12 12:00:00"`
91
+ - ⚠️ `"2026-05-12T12:00:00"`(plugin tool 内部会自动转空格,但 SKILL 里直接传空格更稳)
92
+ - ❌ `"2026-05-12T12:00:00+08:00"`(带时区会被剥掉,避免传)
93
+
94
+ ## 工作流
95
+
96
+ ### 第 1 步:确定时间范围
97
+
98
+ 按优先级:
99
+
100
+ 1. 用户显式给了 `--from` / `--to` → 直接用
101
+ 2. `.env` 里有 `WB_SYNC_CURSOR` → `from = WB_SYNC_CURSOR`, `to = now()`
102
+ 3. 都没有 → `from = now() - 7 days`, `to = now()`
103
+
104
+ ### 第 2 步:按 3 小时窗口翻页拉元数据
105
+
106
+ 把 `[from, to]` 切成连续的 3 小时窗口。每个窗口循环:
107
+
108
+ ```
109
+ for each window [winStart, winEnd):
110
+ page = 1 # ⚠️ PageParam 默认从 1 开始
111
+ loop:
112
+ resp = xiaobao_list_audio {
113
+ fromDate: winStart,
114
+ toDate: winEnd,
115
+ page,
116
+ size: 50
117
+ # ⚠️ 没有 tenantId / projectId —— plugin 自己从 active-project 读
118
+ }
119
+ pageResult = resp.data.data # Result<PageResult<...>> 拨开两层 envelope
120
+ records = pageResult.content
121
+ 把每条 record 进入第 3 步取文本
122
+
123
+ 若 records 长度 < size 或 page * size >= pageResult.total → break 翻页
124
+ 否则 page += 1
125
+ ```
126
+
127
+ 若 tool 返回 401 → 调 `xiaobao_authorize { force: true }` 后重试当前窗口
128
+ (最多重试一次)。
129
+
130
+ ### 第 3 步:逐条取文本
131
+
132
+ 每条 record(有 audioId)单独调一次:
133
+
134
+ ```
135
+ text = xiaobao_get_audio_text {
136
+ audioId: record.audioId
137
+ # ⚠️ 没有 tenantId / projectId
138
+ }
139
+ # text.data.data 是 AudioTextResp: { audioId, talkRatios[], texts[] }
140
+ ```
141
+
142
+ 如果 `texts` 为空(转录还没好 / 录音异常):**跳过**这条,不写文件、不阻塞
143
+ 游标推进。在最终汇总里报告"X 条无文本"。
144
+
145
+ ### 第 4 步:按 项目/顾问/日期/录音 四层写入 raw/
146
+
147
+ **路径**:
148
+
149
+ ```
150
+ wiki/projects/{projectId}-{projectName}/raw/audio/{userId}-{saleName}/{yyyy-MM-dd}/{audioId}.md
151
+ ```
152
+
153
+ - 第 0 层 `projects/{projectId}-{projectName}/` — 旺小宝项目隔离(projectId
154
+ 锚稳定 + projectName 给人看,name 含特殊字符要 sanitize)
155
+ - 第 1 层 `{userId}-{saleName}/` — 置业顾问目录(userId 在前保证稳定,
156
+ saleName 给人看;saleName 里的非法路径字符要 sanitize,详见 schema 文档)
157
+ - 第 2 层 `{yyyy-MM-dd}/` — 录音发生时的日期(从 `record.startTime` 拿)
158
+ - 第 3 层 `{audioId}.md` — 单条录音
159
+
160
+ > projectId / projectName 取自 plugin 全局 active-project 状态
161
+ > (`~/.openclaw/state/wangxiaobao/active-project.json`,由
162
+ > `wangxiaobao-switch-project` skill / `xiaobao_switch_project` tool 写入)。
163
+ > 本 skill **不读** cwd `.env` 里的 tenant/project,但 sync 游标
164
+ > `WB_SYNC_CURSOR` 仍写在 cwd `.env`。
165
+
166
+ **frontmatter 必填**:
167
+
168
+ ```yaml
169
+ ---
170
+ source: wangxiaobao-audio
171
+ audio_id: 12345
172
+ file_id: "..."
173
+ file_url: "..."
174
+
175
+ tenant_id: "395809723556831232"
176
+ project_id: "434616948240678912"
177
+
178
+ recorded_start: "2026-05-12 10:23:11"
179
+ recorded_end: "2026-05-12 10:35:42"
180
+ duration_sec: 751
181
+
182
+ consultant_user_id: 100
183
+ consultant_name: 张三
184
+
185
+ talk_ratios:
186
+ - role: 销售
187
+ ratio: 0.62
188
+ - role: 客户
189
+ ratio: 0.38
190
+
191
+ layer: raw
192
+ parent_consultant: "[[consultants/100-张三]]"
193
+ ---
194
+ ```
195
+
196
+ 正文:把 `text.texts[]` 按 "speaker: content" 逐行排好,行首带时间戳。
197
+
198
+ **写入策略**:
199
+ - 用 Write tool 创建文件,**同名文件已存在就跳过**(raw 幂等不可变)
200
+ - 写完一个窗口报"本窗口写入 N 条 / 跳过 M 条同名 / 跳过 K 条无文本"
201
+
202
+ > 完整 frontmatter 字段含义 + saleName sanitize 规则见
203
+ > [`references/audio-wiki-schema.md`](references/audio-wiki-schema.md) 第 1-2 节。
204
+
205
+ ### 第 5 步:推进游标
206
+
207
+ 每个窗口跑完且全部记录写盘后,立刻把 cwd `./.env` 的 `WB_SYNC_CURSOR`
208
+ 更新为 `winEnd`:
209
+
210
+ - Read `./.env`
211
+ - Edit 替换 `WB_SYNC_CURSOR=...` 行;没有就追加
212
+ - **保留** `.env` 其他 key
213
+
214
+ ### 第 6 步:sync 阶段汇总
215
+
216
+ ```
217
+ 📦 同步完成
218
+ - 时间范围:2026-05-01 00:00:00 ~ 2026-05-12 12:00:00
219
+ - 窗口数:64
220
+ - 元数据条数:215
221
+ - 写入 wiki/projects/9001-成都项目甲/raw/audio/:208 条
222
+ - 跳过(同名):3 条
223
+ - 跳过(无文本):4 条
224
+ - 游标推进到:2026-05-12 12:00:00
225
+
226
+ 下一步可执行 ingest,把本项目 raw/audio/ 提炼为 Layer 2 知识页。
227
+ ```
228
+
229
+ ---
230
+
231
+ ## 第 7 步:ingest 提炼 Layer 2 知识页
232
+
233
+ raw/ 数据落盘后,把内容按"**顾问 → 客户/话题 → 话术**"层级提炼成 Layer 2
234
+ 知识页。**ingest 跑在当前项目目录内**,不跨项目读写。Layer 2 目录结构:
235
+
236
+ ```
237
+ wiki/projects/{projectId}-{projectName}/
238
+ ├── consultants/{userId}-{saleName}.md # 置业顾问画像(沟通风格、客户类型、月度统计)
239
+ ├── customers/{customerName}.md # 客户画像(兴趣点、跟进时间线、状态)
240
+ ├── topics/{topic}.md # 话题/场景("户型疑虑"、"价格异议")
241
+ └── scripts/{scriptName}.md # 可复用话术("破冰寒暄"、"户型介绍")
242
+ ```
243
+
244
+ 每层页 frontmatter 字段、wikilinks 最少数量、tag 词表来源——都按
245
+ [`references/audio-wiki-schema.md`](references/audio-wiki-schema.md) 走。
246
+
247
+ 通用 ingest 流程(dedupe / wikilinks 检查 / log/index 维护 / Layer 不可变约束)
248
+ 继承 Karpathy LLM Wiki 规范,详见
249
+ [`references/llm-wiki-ingest.md`](references/llm-wiki-ingest.md)。
250
+
251
+ ### 三条必守 prime(给 LLM 一个最小约束集)
252
+
253
+ 1. **`raw/` 只读**——ingest 不要回写 raw/,新增内容只能写 Layer 2 + Layer 3 (index/log)
254
+ 2. **wikilinks ≥ 2**——每个 Layer 2 页至少 2 个 wikilinks(具体最小连接图见 schema 第 5 节)
255
+ 3. **tag 必须从 SCHEMA.md 词表选**——遇到词表外新词时**先 prompt 用户加进词表**,不要私自创建
256
+
257
+ ### ingest 阶段汇总
258
+
259
+ ```
260
+ 🧠 Ingest 完成
261
+ - 项目:9001-成都项目甲
262
+ - 扫描 raw/audio/:208 条新文件
263
+ - 新建 consultants 页:3 个
264
+ - 更新 consultants 页:5 个
265
+ - 新建 customers 页:12 个
266
+ - 新建 topics 页:4 个(其中 1 个等用户确认 SCHEMA 词表后再补)
267
+ - 新建 scripts 页:2 个
268
+ - 更新 index.md / log.md
269
+ ```
270
+
271
+ ---
272
+
273
+ ## 用户参数解析
274
+
275
+ | 用户说法 | 行为 |
276
+ | -------------------------- | ------------------------------------------------------------- |
277
+ | "拉一下今天的录音" | from = 今天 00:00:00, to = now |
278
+ | "把上周的录音入库" | from = 上周一 00:00:00, to = 上周日 23:59:59 |
279
+ | "从游标继续" / "继续同步" | from = WB_SYNC_CURSOR, to = now |
280
+ | "重跑某天" | 临时用指定窗口,**不**回退游标 |
281
+ | "干跑 / dry-run" | 走前 3 步但跳过第 4-5 步的写盘和游标更新 |
282
+ | "只看某个销售的" | 先调 `xiaobao_list_consultants` 反查 user-id,再 list_audio 带 `userId: <sale-user-id>` |
283
+ | "把张三本周的录音存下来" | 同上 + 时间窗口限定本周 |
284
+ | "ingest 录音建知识库" | 跳到第 7 步(前提:raw/ 已经有数据) |
285
+ | "拉完顺便 ingest" | 走完整 7 步(sync + ingest 一站式) |
286
+
287
+ ---
288
+
289
+ ## 完整链路
290
+
291
+ ```
292
+ 1. xiaobao_authorize — 拿到 token
293
+ 2. wangxiaobao-switch-project — 选好租户/项目,写 ~/.openclaw/state/wangxiaobao/active-project.json
294
+ 3. 本 skill - sync 阶段 — 翻页拉 → 逐条取文本 → 按 顾问/日期 写 raw → 推进游标
295
+ 4. 本 skill - ingest 阶段 — 读 raw/ → 提炼 4 层 Layer 2 知识页 → 更新 index/log
296
+ ```
297
+
298
+ > sync 跟 ingest 是同一个 skill 的两个阶段,用户可以分两次调用(先拉数据
299
+ > 后入库提炼),也可以一次性走完。
300
+
301
+ ---
302
+
303
+ ## 注意事项
304
+
305
+ - Token 有效期由 phoenix 端 client 配置决定(默认 1h access + 30d refresh)。
306
+ - 游标为空时默认从 7 天前开始。
307
+ - 首次跑或拉历史范围大时建议先 dry-run。
308
+ - API 路径已封装在 plugin tool 里,**不要**用 `xiaobao_api` 自己拼
309
+ `/audio/page` / `/audio/text/{id}`。
310
+ - 激活项目状态在 `~/.openclaw/state/wangxiaobao/active-project.json`(plugin
311
+ 全局单份,跟 cwd 无关);游标 `WB_SYNC_CURSOR` 在 cwd `.env`(per-workspace)。
312
+ - `wiki/projects/.../raw/audio/` 是 Layer 1 不可变,**不要**回写、改名、删除。
313
+ - **批量取文本要节制并发**:一个窗口可能几十条录音,串行调(不要 parallel
314
+ fan-out 太多),让 token refresh-on-401 不打架。
315
+ - ingest 阶段如果某个 Layer 2 页 wikilinks 凑不够 2 个,**先不创建那页**,
316
+ 留到累积够引用再建(避免孤儿页污染知识图)。
317
+
318
+ ## 常见错误与排查
319
+
320
+ - **`xiaobao_list_audio` 返回 401** — token 过期 → `xiaobao_authorize { force: true }` 重登
321
+ - **`xiaobao_get_audio_text` 返回 `data: null` / `texts: []`** — 转录未就绪 / 录音异常 → 跳过该条
322
+ - **page 翻不动 / 重复返回同一页** — 检查 page 是否从 1 开始;`total = 0` 直接结束窗口
323
+ - **fromDate/toDate 报参数错** — 用空格分隔的 `yyyy-MM-dd HH:mm:ss`,不带时区
324
+ - **游标没推进** — 窗口中途报错被跳过 → 查哪个窗口失败、修复后从上次成功窗口的末尾重跑
325
+ - **`error: 'NO_ACTIVE_PROJECT'`** — 还没设过激活项目 → 跑
326
+ `wangxiaobao-switch-project` skill。注意:plugin active-project 是全局单份,
327
+ 跟 cwd 无关;游标 `WB_SYNC_CURSOR` 在 cwd `.env` 里,用户切了 cwd 会丢失游标
328
+ 上下文,需要从指定时间继续或重新拉
329
+ - **raw/ 写文件冲突** — 同名 audioId 已存在 → 跳过(raw 幂等)
330
+ - **顾问名含特殊字符导致路径错** — 按 schema 文档 sanitize 规则处理(删 `/ \ : * ? " < > |` 和空格)
331
+ - **顾问改名导致 consultants/ 出现两个文件** — `git mv` 老路径到新路径,批量 replace 所有指向它的 wikilinks,**不要**两个文件并存
332
+ - **ingest 时 tag 词表外的新词** — 先 prompt 用户加进 SCHEMA.md,不要私自新建
@@ -0,0 +1,213 @@
1
+ ---
2
+ name: wangxiaobao-customer-focus-query
3
+ description: |
4
+ 旺小宝**客户关注点**分页查询 skill:按 visit/customer/audio ID 列表、一级/二级
5
+ 分类模糊、来访时间窗组合查 AI 在客户对话里抽出的「关注点」标签
6
+ (客户主动表达的关心:学区 / 户型 / 价格优惠 / 配套等)。**只读、不写文件、
7
+ 无副作用**。对应 `xiaobao_list_customer_focus` tool。排序固定 visit_time DESC。
8
+ 每条 tag 含 customer / userInfo / audio + value_str(详细说明) + text_fragment(录音原文片段)。
9
+
10
+ **当以下情况时使用此 Skill**:
11
+ (1) 用户问"客户关注点"、"客户最在意什么"、"客户关心什么"、"客户问得最多"
12
+ (2) 用户问某客户的关注点 —— 先调 `xiaobao_list_customers` 反查 customerId,
13
+ 再调本 skill 带 customerIds 精确过滤
14
+ (3) 用户问某次到访 / 某条录音里的关注点 —— 带 visitIds / audioIds
15
+ (4) 用户按分类找 —— 户型 / 价格 / 学区 / 交通 / 商业配套 等 → category 模糊
16
+ (5) 用户按二级分类找 —— "户型因素" / "位置因素" / "发展因素" → classification 模糊
17
+ (6) 用户给时间窗 —— "5 月份的关注点" / "本周关注点" → fromDate / toDate
18
+
19
+ **不要用本 skill 的场景**:
20
+ - 用户问的是**抗性点 / 疑虑 / 反对意见** → 走 `wangxiaobao-customer-resistance-query`
21
+ - 用户要的是客户**画像** / 标签 → 走 `wangxiaobao-customer-query`
22
+ - 用户问"完整录音文本" → 走 `wangxiaobao-audio-query` + `xiaobao_get_audio_text`
23
+ ---
24
+
25
+ > **Host-agnostic CLI skill** — 本 skill 假设 `xiaobao-cli` 已装到 PATH
26
+ > (`npm i -g @puyinkai/xiaobao-cli` 或 `npx -y @puyinkai/xiaobao-cli`)。
27
+ > Agent 通过 shell 工具(Bash / Run / Shell)执行命令、读 **stdout JSON** 消费;
28
+ > stderr 是进度/错误提示。退出码 0 = 成功,非 0 = 业务/网络错(错误对象同时打到 stdout 可解析)。
29
+ >
30
+ > CLI 14 个子命令跟 openclaw-xiaobao plugin 14 个 tool **1:1 等价**,返回 JSON
31
+ > 结构完全一致(`{status, ok, data: {...}}`)。skill 里看到的 `resp.data.data.xxx`
32
+ > 取数路径直接对 stdout JSON 用 `jq` / `JSON.parse` 即可。
33
+ >
34
+ > **plugin tool → CLI 命令翻译表(数组参数走逗号分隔)**:
35
+ >
36
+ > | plugin tool | CLI 命令 |
37
+ > | --- | --- |
38
+ > | `xiaobao_authorize { force? }` | `xiaobao-cli auth login [--force]` |
39
+ > | `xiaobao_whoami` | `xiaobao-cli auth whoami` |
40
+ > | `xiaobao_logout` | `xiaobao-cli auth logout` |
41
+ > | `xiaobao_list_projects { keyword? }` | `xiaobao-cli project list [--keyword <kw>]` |
42
+ > | `xiaobao_switch_project { tenantId, tenantName, projectId, projectName }` | `xiaobao-cli project use --tenant-id ... --tenant-name ... --project-id ... --project-name ...` |
43
+ > | `xiaobao_list_consultants` | `xiaobao-cli consultant list` |
44
+ > | `xiaobao_list_audio { fromDate, toDate, userId?, userIdList?, page, size }` | `xiaobao-cli audio list --from "..." --to "..." [--user-id ...] [--user-id-list a,b,c] [--page N] [--size N]` |
45
+ > | `xiaobao_get_audio_text { audioId }` | `xiaobao-cli audio text <audioId>` |
46
+ > | `xiaobao_list_customers { ... }` | `xiaobao-cli customer list [--user-id] [--user-name] [--customer-name] [--customer-phone] [--portrait] [--from] [--to] [--page] [--size]` |
47
+ > | `xiaobao_list_visits { ... }` | `xiaobao-cli visit list [--customer-id] [--customer-name] [--from] [--to] [--page] [--size]` |
48
+ > | `xiaobao_list_customer_focus { visitIds, customerIds, audioIds, category, classification, fromDate, toDate, ... }` | `xiaobao-cli focus list [--visit-ids a,b] [--customer-ids a,b] [--audio-ids a,b] [--category ...] [--classification ...] [--from ...] [--to ...]` |
49
+ > | `xiaobao_list_customer_resistance { ... }` | `xiaobao-cli resistance list [同 focus]` |
50
+ > | `xiaobao_quick_qa { prompt, threadId? }` | `xiaobao-cli qa "<prompt>" [--thread-id ...]` |
51
+ > | `xiaobao_api { method, path, query, body, headers }` | `xiaobao-cli api <METHOD> <PATH> [--query k=v] [--body '<json>'] [--headers k=v]` |
52
+ >
53
+ > 用 `--format toon` 切到 TOON(uniform 数组省 30-50% token,LLM 上下文优化);
54
+ > 用 `--format json`(默认)保持 JSON。state 路径:`~/.xiaobao/`(fallback 读 `~/.openclaw/state/wangxiaobao/`)。
55
+
56
+
57
+ # 旺小宝客户关注点查询
58
+
59
+ 调 `xiaobao_list_customer_focus` tool 查 AI 抽出的客户关注点标签。
60
+ 跟抗性点 skill 镜像,差别就是底层走 `mv_open_customer_focus` 表。
61
+
62
+ ## 执行前必读
63
+
64
+ - 必须有有效 token:先调 `xiaobao_whoami`;未登录就 `xiaobao_authorize`
65
+ - **必须有激活项目**:tool 内部自动读,缺失返回 `NO_ACTIVE_PROJECT`
66
+ - **数据权限隔离**:按当前用户授权可见顾问范围过滤(普通顾问看自己 /
67
+ 团队长看团队 / 项目管理员看全项目)
68
+ - LocalDateTime 格式:`yyyy-MM-dd HH:mm:ss`(空格分隔),plugin 自动转
69
+ - **不要**写文件、出报告
70
+
71
+ ---
72
+
73
+ ## 快速索引:意图 → 工具
74
+
75
+ | 用户意图 | plugin tool | 关键参数 |
76
+ | ------------------------------------ | --------------------------------- | ---------------------------------- |
77
+ | 列时段内全部关注点 | `xiaobao_list_customer_focus` | `fromDate` / `toDate` |
78
+ | 看某客户的关注点 | `xiaobao_list_customers` → `xiaobao_list_customer_focus` | `customerIds: [<wang_id>]` |
79
+ | 看某次到访的关注点 | `xiaobao_list_customer_focus` | `visitIds: [<visit_id>]` |
80
+ | 看某条录音的关注点 | `xiaobao_list_customer_focus` | `audioIds: [<audio_id>]` |
81
+ | 按分类找(一级) | `xiaobao_list_customer_focus` | `category: "户型"` 等 |
82
+ | 按分类找(二级) | `xiaobao_list_customer_focus` | `classification: "户型因素"` |
83
+ | 估算总数 | `xiaobao_list_customer_focus` | `page: 1, size: 1`,只读 `total` |
84
+
85
+ ---
86
+
87
+ ## 核心约束
88
+
89
+ ### 1. 客户名 → wang_id 反查
90
+
91
+ 用户说"屈哥的关注点"——先调 `xiaobao_list_customers { customerName: "屈哥" }`
92
+ 拿到 `customerId`(= wang_id),再传给 `customerIds` 数组(即使只有一个也用数组)。
93
+
94
+ ### 2. 分类模糊:一级 + 二级二选一或同时用
95
+
96
+ ```
97
+ category 一级常见值:户型 / 价格 / 环境 / 教育 / 交通 / 商业配套 / 装修 / 其他
98
+ classification 二级常见值:户型因素 / 价格因素 / 环境因素 / ... / 位置因素 / 发展因素
99
+ ```
100
+
101
+ 模糊关键词越短越宽:`category: "户型"` 同时命中 "户型因素" 和别的含 "户型" 的分类。
102
+
103
+ ### 3. 时间窗:用户没明确说就推断
104
+
105
+ | 用户说法 | fromDate / toDate |
106
+ | ------------ | ------------------------------------------------ |
107
+ | "今天关注点" | 今天 00:00:00 / 明天 00:00:00 |
108
+ | "本周关注点" | 周一 00:00:00 / 今天 23:59:59 |
109
+ | "5 月份" | 2026-05-01 00:00:00 / 2026-06-01 00:00:00 |
110
+ | "最近一个月" | 30 天前 / now |
111
+
112
+ ### 4. 响应字段重点
113
+
114
+ ```jsonc
115
+ {
116
+ "code": "0",
117
+ "data": {
118
+ "page": 1, "size": 10, "total": 47,
119
+ "content": [
120
+ {
121
+ "id": "507495633116995584", // tag 自身 ID
122
+ "visitId": "507016570438942720",
123
+ "audioId": "507494047338729472",
124
+ "customerId": "507016570019512320",
125
+ "textFragment": "新规户型我看了他们的那个四房的,还不错啊,", // 录音原文片段
126
+ "startOffset": 945120, // 在录音中的起始毫秒
127
+ "endOffset": 949840,
128
+ "keyStr": "对盛世禧悦户型感兴趣", // 简短描述
129
+ "valueStr": "客户表示看了盛世禧悦的新规四房户型觉得不错...", // 详细说明
130
+ "category": "户型因素", // 一级
131
+ "classification": "户型因素", // 二级
132
+ "visitTime": "2025-04-30 10:22:28",
133
+ "customer": { // 批量补全
134
+ "customerId": "507016570019512320",
135
+ "customerName": "屈哥",
136
+ "customerPhone": "173****7325",
137
+ "intentLevel": "A",
138
+ ...
139
+ },
140
+ "userInfo": { /* 接待顾问详情 */ },
141
+ "audio": { // 录音简要 + 签名 fileUrl
142
+ "audioId": 507494047338729472,
143
+ "fileId": "507494045212213248",
144
+ "startTime": "2025-04-30 10:22:50",
145
+ "duration": 2263,
146
+ "fileUrl": "https://oss.../...?sign=..."
147
+ }
148
+ }
149
+ ]
150
+ }
151
+ }
152
+ ```
153
+
154
+ plugin tool 又外包一层 → 渲染用 `resp.data.data.content`。
155
+
156
+ ### 5. 渲染给用户时只展示核心
157
+
158
+ - **必显**:keyStr(标题)+ valueStr(详细说明)+ visitTime + 客户名
159
+ - **可选**:category(分类标签)+ textFragment(原文,省略号截断)
160
+ - **链接**:如果用户要听原录音,给 `audio.fileUrl`(注意 18000 秒过期)
161
+
162
+ ---
163
+
164
+ ## 使用场景示例
165
+
166
+ ### 场景 1:本月客户最在意什么
167
+
168
+ ```jsonc
169
+ {
170
+ "fromDate": "2026-05-01 00:00:00",
171
+ "toDate": "2026-06-01 00:00:00",
172
+ "page": 1, "size": 50
173
+ }
174
+ ```
175
+
176
+ 后处理:按 `category` 聚合 → "5 月份 87 条关注点:户型因素 28 条 / 价格因素 19 条 / ..."。
177
+
178
+ ### 场景 2:屈哥本次到访的关注点
179
+
180
+ ```jsonc
181
+ // step 1: 反查 wang_id(如果只知名字)
182
+ // xiaobao_list_customers
183
+ { "customerName": "屈哥" }
184
+
185
+ // step 2: 拿到 customerId = 507016570019512320
186
+ // xiaobao_list_customer_focus
187
+ { "customerIds": ["507016570019512320"], "page": 1, "size": 20 }
188
+ ```
189
+
190
+ ### 场景 3:户型相关关注点
191
+
192
+ ```jsonc
193
+ { "category": "户型", "page": 1, "size": 30 }
194
+ ```
195
+
196
+ ### 场景 4:特定录音里的关注点
197
+
198
+ ```jsonc
199
+ { "audioIds": ["507494047338729472"], "page": 1, "size": 50 }
200
+ ```
201
+
202
+ 渲染:列出该录音里 AI 抽出的所有关注点,按 startOffset 升序展示原文 + 描述。
203
+
204
+ ---
205
+
206
+ ## 常见错误与排查
207
+
208
+ - **`error: 'NO_ACTIVE_PROJECT'`** — 跑 `wangxiaobao-switch-project` skill
209
+ - **401 / token 过期** — 调 `xiaobao_authorize { force: true }` 重登
210
+ - **`total: 0`** — 过滤条件没匹配 / 该时段没数据 / 当前用户授权范围内没匹配的接待顾问
211
+ - **传入的 ID 找不到对应数据** — 数据权限隔离把不属于授权顾问的 tag 过滤掉了;
212
+ 这是预期行为,不是 bug
213
+ - **category 模糊命中过多** — 加 classification 二级分类收敛