@optima-chat/optima-agent 0.9.4 → 0.9.6

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.
@@ -1,255 +1,143 @@
1
1
  ---
2
2
  name: video-edit
3
- description: "文本驱动的口播视频剪辑(带 AI 二次审片)。用于:剪口播 / 剪 talking head / 删卡顿停顿 / 删 NG 重复 / 给视频加中文字幕 / 视频质量审核。触发:用户上传一段口播视频说'帮我剪一下'/'去掉卡顿'/'剪成短视频'/'加字幕',或要求'剪辑'/'剪片'/'cut'/'review'/'字幕'/'subtitle'。"
4
- ---
5
-
6
- # Video-Edit Skill — 文本驱动的口播视频剪辑
3
+ description: "剪辑用户【已有的】口播视频——去除卡顿停顿让视频更流畅紧凑。
7
4
 
8
- 帮商家把原始口播视频(讲产品、讲品牌故事、TikTok / 小红书内容)剪成可发布的短视频。**核心理念:转写只是线索,业务语境决定取舍**。
5
+ 必备前提:用户已经有视频文件(拍好的、上传的、或给出文件路径)。
9
6
 
10
- ## Global Rules(违反会出脏片)
7
+ 触发:用户上传/给出视频文件 + 说'剪一下'/'去卡顿'/'变流畅'/
8
+ '剪辑'/'剪短点'/'加字幕'/'cut'/'edit'/'trim'/'让视频更紧凑'。"
9
+ ---
11
10
 
12
- 1. **业务语境优先于声学检测**
13
- 开剪前必问 / 必确认:(a) 视频用在哪个平台(TikTok/小红书/IG/详情页),(b) 钩子(hook)是什么,(c) 目标时长。**不知道这三件事就不要开始剪**——`video-edit` 只删卡顿不删废话;废话要靠 AI 在 cut_proposal.md 里自己判断。
11
+ # Video-Edit Skill — 让视频变流畅
14
12
 
15
- 2. **Claude 必须自己做语义审片,两关都过才交付**
16
- `video-edit cut` 出片只是声学层;交付前 **Claude 自己**还要做一关:
17
- - 把成片转写一遍(再调 `video-edit subtitle` 拿 subs.ass 或单独转写)
18
- - 抓"预期落空 / 语法断裂 / 重复 NG / 不完整句"等声学检测**永远抓不到的**问题
19
- - 抓到 → 改 cut_proposal.md → 重新 cut → 重新审,直到通过
13
+ 用户给原始视频,你交付剪好的成片。**中间所有步骤对用户透明**。
20
14
 
21
- 3. **模型名 / 服务名不出现在用户回复里**
22
- 状态、进度、错误统一用"剪辑中 / 转写中 / 审片中 / 字幕生成中"。`faster-whisper`、`ffmpeg`、`Microsoft YaHei` 这些字眼**不要回显给用户**。
15
+ ## 用户怎么说,你交付什么
23
16
 
24
- 4. **Anti-fabrication**
25
- `video-edit` 只有 5 个命令:`analyze` / `cut` / `review` / `subtitle` / `both`。其他 flag 不要凭印象拼。每个命令只接 1 个位置参数:视频文件路径。
17
+ **默认所有剪辑都带字幕**——中文短视频(TikTok / 小红书 / 视频号)99% 需要字幕,"剪一下"的潜台词就是"给我能直接发的成片"。
26
18
 
27
- ## 工作目录约定
19
+ | 用户说 | 你交付 |
20
+ |---|---|
21
+ | "剪一下" / "去卡顿" / "变流畅" | `<video>_subbed.mp4`(剪 + 字幕) |
22
+ | "剪成 X 秒短视频" / "30 秒" | `<video>_subbed.mp4`(压到目标时长 + 字幕) |
23
+ | "加字幕"(不需要剪) | `<video>_subbed.mp4`(仅字幕) |
24
+ | "剪一下不要字幕" / "无字幕版" | `<video>_edited.mp4` |
28
25
 
29
- 不需要全局 git 仓库。每个视频自己带 `<video_stem>.work/` 目录存中间产物:
26
+ 只有当用户提到平台但**没说目标时长**时(如"剪成 TikTok"无时长),才追问"目标多长?"。
27
+ 其他情况**直接动手**,不要废话。
30
28
 
31
- ```
32
- /home/aiuser/<workspace>/
33
- ├── input.mp4 # 用户上传的源视频
34
- ├── input.work/ # video-edit 自动创建
35
- │ ├── audio.wav
36
- │ ├── transcript.json # word-level 转写
37
- │ ├── silences.json # 静音检测
38
- │ ├── cut_proposal.md # ⭐ Claude 在这里编辑
39
- │ ├── review_report.md # review 命令产出
40
- │ └── subs.ass # subtitle 命令产出(可手改)
41
- ├── input_edited.mp4 # cut 输出
42
- └── input_edited_subbed.mp4 # subtitle 输出
43
- ```
29
+ ## 你的内部流程(用户不需要知道)
44
30
 
45
- ## 五命令工作流
31
+ ### 默认剪辑(剪 + 字幕,最常见)
46
32
 
47
- ```mermaid
48
- flowchart LR
49
- A[1. analyze] --> B[2. 编辑 proposal]
50
- B --> C[3. cut]
51
- C --> D[4. review]
52
- D -->|有 HARD issues| B
53
- D -->|通过| E[5. subtitle]
33
+ ```bash
34
+ video-edit both <video>
35
+ video-edit review <video>
36
+ # review 通过后烧字幕:
37
+ video-edit subtitle <video>
54
38
  ```
55
39
 
56
- ### Step 1:先问业务语境
57
-
58
- **Anti-pattern**:用户说"剪一下" → AI 直接跑 `analyze` → 出片不对路。
59
-
60
- **正确做法**:先 ask user(用 AskUserQuestion 或自然语言):
40
+ **3 关审片**全过才烧字幕交付:
61
41
 
62
- ```
63
- 我帮你剪。开始前确认几件事:
64
- 1. 视频投在哪?(TikTok / 小红书 / IG / 商品详情页)
65
- 2. 钩子是什么?(前 3 秒要让用户停下来的那句话)
66
- 3. 目标时长?(15s / 30s / 60s)
67
- ```
42
+ **第 1 关:声学审片(review 报告给)**
43
+ - 全 OK → 进入第 2 关
44
+ - HARD issue(dead air / 切到字中间 / 重复内容)→ **你自己**编辑 `<video>.work/cut_proposal.md`,把问题段行首加 `#`,重跑 `cut` → `review`
45
+ - **修复尝试上限**:≤ 2 次重剪还有同样的 HARD → 停止循环,按现状继续,**不主动**告诉用户残留小问题(黑盒交付原则;用户问起再答)
46
+ - **小残留静音容忍**:唯一 HARD `residual-silence-at-cut < 0.15s`(切点淡化固有产物,再剪也修不掉)→ 直接接受
68
47
 
69
- 如果用户说"你看着办" 用平台默认(TikTok 30s + 强钩子在前 3s)+ 立刻执行,**不要再回问**。
48
+ **第 2 关:语义审片(你自己做,必做)**
70
49
 
71
- ### Step 2:analyze(声学预处理)
50
+ 成片"实际说出来的话" 你保留的 phrase 拼接(有转写误差 + 切点丢字)。**你自己跑**:
72
51
 
73
52
  ```bash
74
- video-edit analyze "/home/aiuser/<workspace>/input.mp4"
75
- ```
53
+ # 重转写成片(输出到 work 目录避免并发冲突)
54
+ python3 -c "
55
+ from faster_whisper import WhisperModel
56
+ import json
57
+ m = WhisperModel('small', device='cpu', compute_type='int8')
58
+ segs, info = m.transcribe('<video>_edited.mp4', language='zh', word_timestamps=True, vad_filter=True)
59
+ words = [{'s':round(w.start,2),'e':round(w.end,2),'t':w.word} for s in segs for w in (s.words or [])]
60
+ print(json.dumps({'duration':round(info.duration,2),'words':words,'text':''.join(w['t'] for w in words)}, ensure_ascii=False, indent=2))
61
+ " > <video>.work/edited_audit.json
76
62
 
77
- 输出:
78
- - `<workspace>/input.work/cut_proposal.md` Claude 编辑这个
79
- - `<workspace>/input.work/transcript.json`、`silences.json`、`audio.wav`
80
-
81
- ⚠️ 如果 `cut_proposal.md` 已存在,命令**不会覆盖**(保留你之前的编辑)。重新生成要先 `rm cut_proposal.md`。
82
-
83
- ### Step 3:编辑 cut_proposal.md(这步是 Claude 干的活)
84
-
85
- 读 proposal,每行是一个"短语单元"(300ms 静音分组),格式:
86
-
87
- ```
88
- 00:01.234 - 00:03.456 (2.22s) [0.50s!] 这个保留单元的原文
63
+ cat <video>.work/edited_audit.json
64
+ cat <video>.work/cut_proposal.md # 看未被 # 注释的行
89
65
  ```
90
66
 
91
- **在要删的行首加 `#`**(保存即可)。判定标准:
67
+ **对比检查**(任一发现 → HARD,回去改 proposal 重剪,同样 ≤ 2 次上限):
68
+ - 句子被切半("我们..."没下文 / "因为..."没结果)
69
+ - 指代物丢失("这个" / "那种" / "上面那个" 但前文没了)
70
+ - 承诺没兑现("我说三个"但成片只剩两个)
71
+ - 词义跳段(前一句说苹果,下一句说香蕉,承接句被剪)
72
+ - 转写误差导致字错(whisper 把 "义乌" 转成 "亿物")
73
+ - **切点接合不顺**:成片转写的 words 里相邻 word gap > 0.4s 的位置(不是天然停顿)说明拼接生硬
92
74
 
93
- | 该删 | 该留 |
94
- |---|---|
95
- | NG / 重复 take("我说一下啊...呃我说一下...")| 完整业务点 |
96
- | 跑题闲聊("对...那个...")| 钩子句、卖点句 |
97
- | 嗯啊呃等填充词独占的短语 | 转折句、call-to-action |
98
- | 与平台/钩子/时长目标冲突的内容 | 与目标对齐的内容 |
75
+ **两关全过 subtitle 烧字幕 → 交付**
99
76
 
100
- **业务原则**:宁可短不可冗。30 秒目标 优先压到 25-28 秒留呼吸空间。
77
+ `subtitle` 命令传**原片路径**即可(脚本会自动用 `_edited.mp4` 做输入),输出固定是 `<原片>_subbed.mp4`。
101
78
 
102
- ### Step 4:cut(出片)
79
+ 如果第 1 关 review 显示语音占比 > 90%(说明几乎没卡顿要删,但用户原片可能有 NG 重录或跑题),改走"限时长精剪"路径让你自己决定删哪些短语——`both` 只删停顿,删不掉 NG / 废话。
80
+
81
+ ### 限时长精剪(用户给了目标时长)
103
82
 
104
83
  ```bash
105
- video-edit cut "/home/aiuser/<workspace>/input.mp4"
84
+ video-edit analyze <video>
106
85
  ```
107
86
 
108
- 输出 `<workspace>/input_edited.mp4`。
109
-
110
- ### Step 5:review(声学层质量检查)
87
+ `<video>.work/cut_proposal.md`,**你自己**做这些判断:
88
+ - 找钩子句放最前
89
+ - 删跑题、删 NG、删填充词
90
+ - 压到目标时长
91
+ - 把要删的行首加 `#`,保存
111
92
 
93
+ 然后:
112
94
  ```bash
113
- video-edit review "/home/aiuser/<workspace>/input.mp4"
95
+ video-edit cut <video>
96
+ video-edit review <video>
114
97
  ```
115
98
 
116
- 输出 `<workspace>/input.work/review_report.md`,分两类问题:
117
-
118
- | 类别 | 含义 | 处理 |
119
- |---|---|---|
120
- | **HARD** | 残留静音 / 切到字中间 / 输出有重复内容 | **必须修**,回到 Step 3 改 proposal 重剪 |
121
- | **WARN** | 能量突变 / 语速异常 / 语音占比低 | 评估后决定 |
122
-
123
- 报告底部三种判定:
124
- - `[OK] ALL CLEAR` → 进入 Step 5(字幕)
125
- - `[OK] NO HARD ISSUES` → 看 WARN,决定是否要修
126
- - `[FAIL] HARD ISSUES` → 必须回 Step 3
127
-
128
- ### Step 5.5:⭐ Claude 自己做语义审片(声学检测抓不到的)
129
-
130
- `review` 是声学层。**Claude 在交付前必须自己做语义层**:
99
+ **剪完同样走"默认剪辑"里的 2 关审片**(声学 + 语义),全过再跑 `video-edit subtitle` → 交付 `<原片>_subbed.mp4`。
131
100
 
132
- 1. 让转写跑一遍成片,或用 subtitle 命令产出 `subs.ass` 后读它
133
- 2. 把 `cut_proposal.md` 里**保留的短语序列**和**成片转写**对比
134
- 3. 检查这些**声学检测查不出**的问题:
135
- - **预期落空**:"我跟你讲三个特点。第一是..." 但成片只剩两个特点
136
- - **语法断裂**:句子被砍到主语没了 / 宾语没了
137
- - **逻辑跳跃**:Step A 直接跳 Step C,Step B 被剪掉
138
- - **指代失效**:"这个" / "那种" 的指代物被剪掉
139
- - **重复语义**:同一意思用不同词说了两遍都被保留
101
+ 限时长场景为了压时长更激进地删,**比默认剪辑更需要**这两关 不要跳过。
140
102
 
141
- 抓到任何一条 → 回 Step 3 改 proposal → 重剪 → 重审。**两关都过才交付**。
142
-
143
- ### Step 6:subtitle(烧字幕)
103
+ ### 仅字幕(用户明确说不剪)
144
104
 
145
105
  ```bash
146
- video-edit subtitle "/home/aiuser/<workspace>/input.mp4"
106
+ video-edit subtitle <video>
147
107
  ```
148
108
 
149
- 行为:
150
- - 自动转写成片 → 智能分段(标点 / 词间 gap / 14 字 / 3s 多策略)→ 写 `subs.ass`
151
- - **如果 `subs.ass` 已存在则跳过生成**(保留 Claude 或用户的文字修正),直接重烧
152
- - 输出 `<workspace>/input_edited_subbed.mp4`(如果传的是 `_edited.mp4` 则去掉 `_edited` 后缀)
153
-
154
- 修字幕:直接编辑 `subs.ass` 然后重跑 `subtitle` 命令即可。
155
-
156
- ## 典型场景
157
-
158
- ### 场景 1:TikTok 30s 短视频(最常见)
159
-
160
- ```
161
- 用户:"帮我剪成 TikTok 30 秒"
162
-
163
- Claude 流程:
164
- 1. 上传视频到 /home/aiuser/work/raw.mp4
165
- 2. video-edit analyze → 读 cut_proposal.md
166
- 3. 找钩子(最有冲击力的开场)放最前,删跑题、删 NG,目标 25-28s
167
- 4. video-edit cut → 看产出
168
- 5. video-edit review → 处理 HARD issues
169
- 6. 自己审一遍语义 → 确认逻辑通顺
170
- 7. video-edit subtitle → 烧字幕
171
- 8. 给用户:raw_edited_subbed.mp4
172
- ```
109
+ 没有 `_edited.mp4` 时,命令直接对原片烧字幕,输出 `<原片>_subbed.mp4`。
173
110
 
174
- ### 场景 2:详情页 PDP 视频(节奏稍慢)
111
+ ### 无字幕版(用户明确说不要字幕)
175
112
 
176
- ```
177
- 用户:"剪个商品详情页用的视频,1 分钟内"
113
+ 只跑 `both` + `review`,**不跑 subtitle**,交付 `<原片>_edited.mp4`。
178
114
 
179
- Claude 流程:
180
- - 钩子可以稍弱(用户已有购买意向才会看 PDP)
181
- - 重点保留产品参数 / 使用场景 / 信任背书
182
- - review WARN: pace-slow 可以容忍(PDP 容许喘息)
183
- - 字幕字体可以大一点(修改 subs.ass 里 Fontsize)
184
- ```
115
+ ## 交付怎么说
185
116
 
186
- ### 场景 3:纯字幕需求(不剪)
117
+ 简洁,**只说结果**:
187
118
 
188
- ```
189
- 用户:"这个视频不用剪,帮我加个字幕"
119
+ - ✅ "剪好了,xxx_subbed.mp4,时长 23 秒"(默认带字幕的情况)
120
+ - ✅ "无字幕版剪好了,xxx_edited.mp4,时长 23 秒"(用户要无字幕时)
121
+ - ❌ "我用了 video-edit analyze,然后编辑了 cut_proposal.md..."
122
+ - ❌ "review 显示 3 个 WARN,但都不影响..."
190
123
 
191
- 直接 video-edit subtitle "/path/to/video.mp4"
192
- 跳过 analyze / cut / review。
193
- ```
124
+ review 自动修过的问题不用提;改了几次也不用提。
194
125
 
195
- ### 场景 4:剪完用户要再调(迭代)
126
+ ## 不要做的事
196
127
 
197
- ```
198
- 用户:"开头那段还是不要了"
199
-
200
- 不要重跑 analyze(会丢之前的 proposal 编辑)。
201
- 做法:
202
- 1. 直接编辑现有的 cut_proposal.md,把开头几行加上 #
203
- 2. video-edit cut
204
- 3. video-edit review
205
- 4. video-edit subtitle(subs.ass 已存在会复用,可能要 rm 重生成)
206
- ```
128
+ - ❌ 用户说"剪一下"就追问平台/钩子/时长——直接动手
129
+ - ❌ 用户说"剪一下"只交付 `_edited.mp4` 不烧字幕——**默认带字幕**,除非用户明说不要
130
+ - ❌ 让用户编辑 cut_proposal.md——**你来编辑**
131
+ - 把命令名暴露给用户——简单交付即可
132
+ - ❌ 编造命令(仅 5 个:both / analyze / cut / review / subtitle)
133
+ - 用户说"剪掉前 X 秒"/"剪掉中间一段"——这是定点裁剪不是去卡顿停顿,video-edit 不做这个;直接告诉用户"我擅长去卡顿停顿,定点裁剪请用别的方式"
207
134
 
208
- ## 决策表:什么时候用什么命令
135
+ ## 命令参考(你内部用)
209
136
 
210
- | 用户场景 | 命令序列 |
137
+ | 命令 | 用途 |
211
138
  |---|---|
212
- | 完整剪一支带字幕成片 | analyze 编辑 proposal → cut → review → 自己审 → subtitle |
213
- | 只剪不要字幕 | analyze 编辑 proposal cut → review → 自己审 |
214
- | 只加字幕 | subtitle |
215
- | 用户说"你帮我直接剪好" | both(autocut,不编辑 proposal) review 自己审 → subtitle |
216
- | 二次调整(已剪过一次) | cut_proposal.md cut review → 自己审 → 重 subtitle(可能要 rm subs.ass) |
217
-
218
- `both` 用法是 `analyze + cut` 一把跑(不给 Claude 编辑 proposal 的机会),**不推荐**——业务语境会丢。仅当用户明确说"你直接剪不用问"时用。
219
-
220
- ## 卓越标准(这是好成片的判定)
221
-
222
- - **开场 3 秒内出钩子** —— TikTok / 小红书第一关
223
- - **节奏密度 ≥ 80%** —— review 的 speech_ratio 不应低于 80%
224
- - **逻辑闭环** —— 所有"我说三个" / "首先...其次...最后"的承诺都要兑现
225
- - **句子完整** —— 主谓宾不缺,不出现切到字中间
226
- - **重复 take 删干净** —— review 的 `repeated-content` 必为 0
227
- - **字幕断行自然** —— 标点处断,不在词中间断
228
-
229
- ## 常见错误(不要犯)
230
-
231
- ### ❌ 错误 1:不问业务语境直接剪
232
- **症状**:剪完用户说"这不是我要的感觉"
233
- **正确**:开剪前 3 个问题(平台/钩子/时长)至少要问到,或从用户已有信息推断+告知
234
-
235
- ### ❌ 错误 2:跳过自己的语义审片
236
- **症状**:交付的成片有逻辑断裂、指代失效但 review 显示通过
237
- **正确**:声学 review 通过 ≠ 可以交付。Claude 必须自己再读转写
238
-
239
- ### ❌ 错误 3:重剪时重跑 analyze
240
- **症状**:用户的 cut_proposal.md 编辑全丢
241
- **正确**:迭代时直接改 `cut_proposal.md`,不要碰 analyze
242
-
243
- ### ❌ 错误 4:subs.ass 修改后没保留
244
- **症状**:用户说"字幕里那个字打错了我改了",下次 subtitle 又被覆盖
245
- **正确**:subs.ass 已存在时命令会跳过生成。如果要全重新生成,先 `rm`
246
-
247
- ### ❌ 错误 5:把 ffmpeg / faster-whisper 写进给用户的回复
248
- **症状**:用户:"为什么这么慢?" Claude:"faster-whisper 转写 small 模型..."
249
- **正确**:"正在分析音频和转写文字,大约需要 X 秒"
250
-
251
- ## 相关工具
252
-
253
- - **ffmpeg skill** — 如果用户要的是非剪辑类音视频处理(合成 BGM、压缩、缩略图、格式转换),转 ffmpeg skill
254
- - **video-gen skill** — 如果用户要 AI 生成视频(不是已有素材剪辑),转 video-gen skill
255
- - **markdown-pdf skill** — 如果用户要把 review_report.md 导出 PDF
139
+ | `video-edit both <video>` | 一键自动剪辑 |
140
+ | `video-edit analyze <video>` | 生成 `<video>.work/cut_proposal.md` |
141
+ | `video-edit cut <video>` | proposal 剪辑 |
142
+ | `video-edit review <video>` | 检查 `<video>_edited.mp4`,输出 review_report.md |
143
+ | `video-edit subtitle <video>` | 烧字幕。传**原片路径**即可,自动找 `_edited.mp4` 做输入;输出固定是 `<原片>_subbed.mp4`(不会带 `_edited`) |
@@ -0,0 +1,161 @@
1
+ ---
2
+ name: wechat
3
+ description: "微信视频号视频下载 + metadata。使用场景:下载微信视频号视频(下载视频号/微信视频/weixin.qq.com/sph/...)、查看视频号 metadata(视频号信息/作者/话题/点赞)。使用 scout wechat 命令。当前仅覆盖视频号(Channels),未来可扩展到公众号/小程序。"
4
+ ---
5
+
6
+ # 微信 - 视频号视频下载与 metadata
7
+
8
+ 所有命令使用 `scout wechat` 前缀。当前覆盖**视频号(Channels)**,未来可扩展到公众号、小程序等其他微信 surface。
9
+
10
+ > **依赖**:`@optima-chat/scout-cli >= 0.14.0`(`scout wechat` 命令在 0.14.0 引入)。如果 CLI 报 `unknown command 'wechat'`,说明环境里 scout-cli 版本太低,**不要重试**,直接告诉用户"请升级 scout-cli 到 0.14.0 或以上"。
11
+
12
+ ---
13
+
14
+ ## 快速选择
15
+
16
+ | 你的目标 | 命令 |
17
+ |---------|------|
18
+ | **下载视频号视频**(拿可播放 mp4) | `scout wechat fetch <url或exportId>` |
19
+ | **只看 metadata**(作者/话题/点赞,不下载) | `scout wechat metadata <url或exportId>` |
20
+
21
+ ---
22
+
23
+ ## 典型场景
24
+
25
+ 当用户说:
26
+ - "下载这个视频号" + 链接 → `scout wechat fetch <url>`
27
+ - "下载微信视频" + 链接 → `scout wechat fetch <url>`
28
+ - "看看这个视频号的信息" / "这个视频号谁发的" → `scout wechat metadata <url>`
29
+ - 用户直接贴 `weixin.qq.com/sph/xxx` 或 `channels.weixin.qq.com/.../sph?id=xxx` → 默认走 `fetch`
30
+
31
+ ---
32
+
33
+ ## URL 解析 - 视频号链接处理
34
+
35
+ 视频号视频有三种形态,**都直接传给命令即可,不需要自己解析**(命令内置正则):
36
+
37
+ | URL 形态 | 示例 |
38
+ |---------|------|
39
+ | 短链 | `https://weixin.qq.com/sph/Azn5HYOeb0` |
40
+ | 完整链 | `https://channels.weixin.qq.com/finder-preview/pages/sph?id=Azn5HYOeb0` |
41
+ | 裸 exportId(10 位短码) | `Azn5HYOeb0` |
42
+
43
+ ```bash
44
+ # 三种都行
45
+ scout wechat fetch https://weixin.qq.com/sph/Azn5HYOeb0
46
+ scout wechat fetch "https://channels.weixin.qq.com/finder-preview/pages/sph?id=Azn5HYOeb0"
47
+ scout wechat fetch Azn5HYOeb0
48
+ ```
49
+
50
+ **不要用 WebFetch** 去抓视频号页面 — 视频是加密的,WebFetch 拿不到。
51
+
52
+ ---
53
+
54
+ ## 核心命令
55
+
56
+ ### 1. fetch - 下载视频 + metadata
57
+
58
+ 完整 pipeline:解析 URL → TikHub 拿 metadata + 加密 CDN → 下载 + 解密 → 上传 S3 → 返回可播放 mp4 URL。
59
+
60
+ ```bash
61
+ scout wechat fetch https://weixin.qq.com/sph/Azn5HYOeb0
62
+ ```
63
+
64
+ **返回数据**(JSON):
65
+ - `data.videoUrl` — 可直接播放/下载的 mp4 URL(S3,公开读)
66
+ - `data.videoSize` — 文件字节数
67
+ - `data.metadata.title` — 标题
68
+ - `data.metadata.author.nickname` — 作者昵称
69
+ - `data.metadata.author.auth` — 认证身份(若有)
70
+ - `data.metadata.topics` — 话题列表(从 `#xxx` 解析)
71
+ - `data.metadata.video.durationSec` — 视频时长(秒)
72
+ - `data.metadata.video.width / height` — 分辨率
73
+ - `data.metadata.stats` — `like / comment / forward / fav`
74
+ - `data.metadata.coverUrl` — 封面图
75
+
76
+ **下载视频文件**:拿到 `videoUrl` 后用任意 HTTP 工具:
77
+ ```bash
78
+ # Linux/macOS 通常有 wget
79
+ wget -O video.mp4 "<videoUrl>"
80
+
81
+ # Windows / 没有 wget — 用 curl (curl 在 macOS / Win10+ 都自带)
82
+ curl -L -o video.mp4 "<videoUrl>"
83
+ ```
84
+
85
+ ### 2. metadata - 只看信息
86
+
87
+ 不下载视频文件,只拿 metadata 字段(省 S3 流量,但仍消耗 1 次 TikHub 额度)。
88
+
89
+ ```bash
90
+ scout wechat metadata https://weixin.qq.com/sph/Azn5HYOeb0
91
+ ```
92
+
93
+ 返回字段跟 `fetch` 的 `data.metadata` 一致,但没有 `videoUrl / videoSize`。
94
+
95
+ **何时用 metadata 而不是 fetch**:
96
+ - 用户问"这视频谁发的""讲什么的""多少赞" → 用 metadata
97
+ - 用户要"下载""视频文件""保存下来" → 用 fetch
98
+
99
+ ---
100
+
101
+ ## 限制与注意事项
102
+
103
+ 1. **画质**:目前只能拿低清版本(约 576×1024,1-3 MB),TikHub 公开 API 不返回高清 30 MB 版
104
+ 2. **每次消费 TikHub 额度**:`fetch_video_detail` 大约 \$0.01/次,频繁调用会烧钱,先 `metadata` 看看有没有必要再 `fetch`
105
+ 3. **依赖 decrypt server**:`fetch` 的解密步骤依赖外部部署的 decrypt 服务,如果返回 **503 Service Unavailable**,说明 backend 配置缺失(`WECHAT_DECRYPT_API_URL` 没设),应该告知用户"视频号下载服务暂未配置,请联系 SRE"
106
+ 4. **错误码语义**:
107
+ - `400` — URL 解析不出 exportId(用户给的链接不对)
108
+ - `502` — TikHub / CDN / decrypt server 上游失败(短期重试可能恢复)
109
+ - `503` — backend 没配解密服务(SRE 还没部署)
110
+ - `500` — 其它内部异常
111
+ 5. **视频是一次性签名链接**:`fetch` 内部 pipeline 必须一气呵成,不要尝试缓存中间结果
112
+ 6. **scope 限定**:这个 skill 只管视频号(Channels),不要用它处理公众号文章 / 小程序 / 朋友圈
113
+
114
+ ---
115
+
116
+ ## 工作流示例
117
+
118
+ ### 用户给链接要下载
119
+
120
+ ```
121
+ 用户:帮我下载这个视频号 https://weixin.qq.com/sph/Azn5HYOeb0
122
+ ```
123
+
124
+ ```bash
125
+ scout wechat fetch https://weixin.qq.com/sph/Azn5HYOeb0 --format json
126
+ ```
127
+
128
+ 返回 JSON 后,把 `videoUrl` 给用户(可点开播放/右键下载),并用 metadata 简述视频内容(标题/作者/时长)。
129
+
130
+ ### 用户问"这视频啥情况"
131
+
132
+ ```
133
+ 用户:这条视频号链接讲啥的 https://weixin.qq.com/sph/Azn5HYOeb0
134
+ ```
135
+
136
+ ```bash
137
+ scout wechat metadata https://weixin.qq.com/sph/Azn5HYOeb0
138
+ ```
139
+
140
+ 只取 metadata 简介给用户,不消耗 S3 / 解密资源。
141
+
142
+ ### 用户给的是 exportId(纯字符串)
143
+
144
+ ```
145
+ 用户:看下 Azn5HYOeb0 这个视频号
146
+ ```
147
+
148
+ ```bash
149
+ scout wechat metadata Azn5HYOeb0
150
+ ```
151
+
152
+ 直接传短码,命令内部识别。
153
+
154
+ ### 出错怎么办
155
+
156
+ | 状态 | 处理 |
157
+ |------|------|
158
+ | 400 (URL 解析失败) | 跟用户说"这个链接不是视频号链接,请贴 `weixin.qq.com/sph/...` 或 `channels.weixin.qq.com/...` 的链接" |
159
+ | 502 (上游失败) | 重试 1 次;仍失败告诉用户"上游服务波动,稍后再试" |
160
+ | 503 (服务未配置) | 告诉用户"视频号下载服务暂未上线,请联系运维"(不要重试) |
161
+ | 500 (内部异常) | 让用户提供链接给运维排查 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/optima-agent",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "基于 Claude Agent SDK 的电商运营 AI 助手",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",