@iducky/media-agent 1.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 (96) hide show
  1. package/README.md +90 -0
  2. package/SHA256SUMS +94 -0
  3. package/bin/media-agent.mjs +89 -0
  4. package/docs/guides/capabilities.md +103 -0
  5. package/docs/guides/image-text-publishing.md +81 -0
  6. package/docs/guides/installation.md +103 -0
  7. package/docs/guides/runtime.md +13 -0
  8. package/manifest.json +382 -0
  9. package/package.json +42 -0
  10. package/pyproject.toml +20 -0
  11. package/resources/capabilities.json +34 -0
  12. package/resources/configs/accounts.yaml +21 -0
  13. package/resources/configs/profile.template.json +20 -0
  14. package/resources/configs/ranking-profiles.yaml +21 -0
  15. package/resources/configs/toutiao-profile.template.json +22 -0
  16. package/resources/configs/xiaohongshu-profile.template.json +27 -0
  17. package/resources/data/industry-taxonomy.yaml +326 -0
  18. package/skills/douyin-competitor-collect/SKILL.md +177 -0
  19. package/skills/douyin-competitor-collect/agents/openai.yaml +4 -0
  20. package/skills/douyin-competitor-collect/references/output-schema.md +178 -0
  21. package/skills/douyin-creator-image-text-publish/SKILL.md +44 -0
  22. package/skills/douyin-creator-image-text-publish/agents/openai.yaml +4 -0
  23. package/skills/douyin-creator-image-text-publish/references/LICENSE.social-auto-upload +21 -0
  24. package/skills/douyin-creator-image-text-publish/references/execution-contract.md +46 -0
  25. package/skills/douyin-creator-image-text-publish/references/upstream.md +30 -0
  26. package/skills/douyin-creator-index/SKILL.md +32 -0
  27. package/skills/douyin-creator-index/agents/openai.yaml +4 -0
  28. package/skills/douyin-creator-login/SKILL.md +58 -0
  29. package/skills/douyin-creator-login/agents/openai.yaml +4 -0
  30. package/skills/douyin-creator-publish/SKILL.md +56 -0
  31. package/skills/douyin-creator-publish/agents/openai.yaml +4 -0
  32. package/skills/douyin-enterprise-leads/SKILL.md +26 -0
  33. package/skills/douyin-enterprise-leads/agents/openai.yaml +4 -0
  34. package/skills/douyin-enterprise-leads-login/SKILL.md +36 -0
  35. package/skills/douyin-enterprise-leads-login/agents/openai.yaml +4 -0
  36. package/skills/douyin-enterprise-short-video-export/SKILL.md +29 -0
  37. package/skills/douyin-enterprise-short-video-export/agents/openai.yaml +4 -0
  38. package/skills/douyin-enterprise-video-rankings/SKILL.md +51 -0
  39. package/skills/douyin-enterprise-video-rankings/agents/openai.yaml +4 -0
  40. package/skills/douyin-enterprise-video-rankings/references/industry-taxonomy.md +29 -0
  41. package/skills/douyin-web-login/SKILL.md +102 -0
  42. package/skills/douyin-web-login/agents/openai.yaml +4 -0
  43. package/skills/toutiao-creator-article-draft/SKILL.md +154 -0
  44. package/skills/toutiao-creator-article-draft/agents/openai.yaml +4 -0
  45. package/skills/toutiao-web-login/SKILL.md +96 -0
  46. package/skills/toutiao-web-login/agents/openai.yaml +4 -0
  47. package/skills/xiaohongshu-creator-image-text-publish/SKILL.md +46 -0
  48. package/skills/xiaohongshu-creator-image-text-publish/agents/openai.yaml +4 -0
  49. package/skills/xiaohongshu-creator-image-text-publish/references/LICENSE.social-auto-upload +21 -0
  50. package/skills/xiaohongshu-creator-image-text-publish/references/execution-contract.md +46 -0
  51. package/skills/xiaohongshu-creator-image-text-publish/references/upstream.md +31 -0
  52. package/skills/xiaohongshu-creator-login/SKILL.md +106 -0
  53. package/skills/xiaohongshu-creator-login/agents/openai.yaml +4 -0
  54. package/skills/xiaohongshu-creator-publish/SKILL.md +153 -0
  55. package/skills/xiaohongshu-creator-publish/agents/openai.yaml +4 -0
  56. package/src/media_agent/__init__.py +1 -0
  57. package/src/media_agent/cli.py +28 -0
  58. package/src/media_agent/commands.sh +436 -0
  59. package/src/media_agent/platforms/__init__.py +1 -0
  60. package/src/media_agent/platforms/douyin/__init__.py +1 -0
  61. package/src/media_agent/platforms/douyin/check_login.py +196 -0
  62. package/src/media_agent/platforms/douyin/collect_industry_taxonomy.py +184 -0
  63. package/src/media_agent/platforms/douyin/collect_video_rankings.py +352 -0
  64. package/src/media_agent/platforms/douyin/douyin_full_login.py +391 -0
  65. package/src/media_agent/platforms/douyin/douyin_hotspot_v2.py +454 -0
  66. package/src/media_agent/platforms/douyin/douyin_publish.py +1135 -0
  67. package/src/media_agent/platforms/douyin/enterprise_login.py +128 -0
  68. package/src/media_agent/platforms/douyin/export_short_video.py +70 -0
  69. package/src/media_agent/platforms/douyin/login_controller.py +508 -0
  70. package/src/media_agent/platforms/douyin/validate_industry_taxonomy.py +152 -0
  71. package/src/media_agent/platforms/douyin/validate_rankings.py +254 -0
  72. package/src/media_agent/platforms/toutiao/__init__.py +1 -0
  73. package/src/media_agent/platforms/toutiao/toutiao_check_login.py +54 -0
  74. package/src/media_agent/platforms/toutiao/toutiao_login_controller.py +250 -0
  75. package/src/media_agent/platforms/toutiao/toutiao_login_evidence.py +50 -0
  76. package/src/media_agent/platforms/toutiao/toutiao_login_ipc.py +70 -0
  77. package/src/media_agent/platforms/xiaohongshu/__init__.py +1 -0
  78. package/src/media_agent/platforms/xiaohongshu/xiaohongshu_check_login.py +189 -0
  79. package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_controller.py +449 -0
  80. package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_evidence.py +64 -0
  81. package/src/media_agent/platforms/xiaohongshu/xiaohongshu_login_ipc.py +120 -0
  82. package/src/media_agent/platforms/xiaohongshu/xiaohongshu_publish.py +925 -0
  83. package/src/media_agent/runtime/__init__.py +1 -0
  84. package/src/media_agent/runtime/account_manager.py +672 -0
  85. package/src/media_agent/runtime/browser.py +5 -0
  86. package/src/media_agent/runtime/paths.py +7 -0
  87. package/src/media_agent/script_map.json +23 -0
  88. package/src/node/config.mjs +48 -0
  89. package/src/node/integrity.mjs +34 -0
  90. package/src/node/skills.mjs +85 -0
  91. package/tools/archive_releases.py +83 -0
  92. package/tools/artifacts.py +56 -0
  93. package/tools/build_release.py +82 -0
  94. package/tools/check_catalog.py +23 -0
  95. package/tools/install_runtime.py +144 -0
  96. package/tools/run_tests.py +21 -0
@@ -0,0 +1,326 @@
1
+ industries:
2
+ - children:
3
+ - name: 会展服务
4
+ value: ''
5
+ - name: 减肥加盟
6
+ value: ''
7
+ - name: 食品加盟
8
+ value: ''
9
+ - name: 美容美发加盟
10
+ value: ''
11
+ - name: 酒加盟
12
+ value: ''
13
+ - name: 酒店加盟
14
+ value: ''
15
+ - name: 管理咨询
16
+ value: ''
17
+ - name: 商务服务加盟
18
+ value: ''
19
+ - name: 饮品烘焙加盟
20
+ value: ''
21
+ - name: 保健品加盟
22
+ value: ''
23
+ - name: 人力资源服务
24
+ value: ''
25
+ - name: 广告服务
26
+ value: ''
27
+ - name: 生活服务加盟
28
+ value: ''
29
+ - name: 安全安保
30
+ value: ''
31
+ - name: 其他商务服务
32
+ value: ''
33
+ - name: 教育培训加盟
34
+ value: ''
35
+ children_count: 16
36
+ name: 企服加盟
37
+ reached_end: true
38
+ value: ''
39
+ verification_status: complete
40
+ - children:
41
+ - name: 宗教
42
+ value: ''
43
+ - name: 景点
44
+ value: ''
45
+ - name: 社会组织
46
+ value: ''
47
+ - name: 政府政务文化旅游
48
+ value: ''
49
+ - name: 外旅局
50
+ value: ''
51
+ - name: 其他出行旅游
52
+ value: ''
53
+ - name: 政府政务环境安全
54
+ value: ''
55
+ - name: 其他社会公共
56
+ value: ''
57
+ - name: 商旅票务代理
58
+ value: ''
59
+ - name: 邮轮
60
+ value: ''
61
+ - name: 旅行社
62
+ value: ''
63
+ - name: 政府政务科教卫生
64
+ value: ''
65
+ - name: 航空公司
66
+ value: ''
67
+ - name: 公路客运公司
68
+ value: ''
69
+ - name: OTA(online travel Agent)
70
+ value: ''
71
+ children_count: 15
72
+ name: 政务文旅
73
+ reached_end: true
74
+ value: ''
75
+ verification_status: complete
76
+ - children:
77
+ - name: 汽车厂商
78
+ value: ''
79
+ - name: 其他汽车
80
+ value: ''
81
+ - name: 新车线下零售
82
+ value: ''
83
+ - name: 汽车综合服务平台
84
+ value: ''
85
+ - name: 二手车线下零售
86
+ value: ''
87
+ - name: 汽车后市场
88
+ value: ''
89
+ - name: 汽车经销商
90
+ value: ''
91
+ children_count: 7
92
+ name: 汽车
93
+ reached_end: true
94
+ value: ''
95
+ verification_status: complete
96
+ - children:
97
+ - name: 其他教育培训
98
+ value: ''
99
+ - name: 职业资格考证培训
100
+ value: ''
101
+ - name: 幼儿教育
102
+ value: ''
103
+ - name: 学习卡
104
+ value: ''
105
+ - name: 企业管理培训
106
+ value: ''
107
+ - name: 新媒体运营培训
108
+ value: ''
109
+ - name: 兴趣培训
110
+ value: ''
111
+ - name: 语言及留学
112
+ value: ''
113
+ - name: 智能教育
114
+ value: ''
115
+ - name: 学历教育
116
+ value: ''
117
+ - name: 职业技能
118
+ value: ''
119
+ - name: 理财培训
120
+ value: ''
121
+ - name: 中小学教育
122
+ value: ''
123
+ - name: 特殊人群教育
124
+ value: ''
125
+ children_count: 14
126
+ name: 教育培训
127
+ reached_end: true
128
+ value: ''
129
+ verification_status: complete
130
+ - children:
131
+ - name: 第三方支付
132
+ value: ''
133
+ - name: 基金
134
+ value: ''
135
+ - name: 贷款服务
136
+ value: ''
137
+ - name: 其他金融业
138
+ value: ''
139
+ - name: 另类投资
140
+ value: ''
141
+ - name: 金融门户网站
142
+ value: ''
143
+ - name: 银行业
144
+ value: ''
145
+ - name: 拍卖典当
146
+ value: ''
147
+ - name: 综合金融平台
148
+ value: ''
149
+ - name: 征信机构
150
+ value: ''
151
+ - name: 证券业
152
+ value: ''
153
+ - name: 金融理财培训
154
+ value: ''
155
+ - name: 保险业
156
+ value: ''
157
+ children_count: 13
158
+ name: 金融业
159
+ reached_end: true
160
+ value: ''
161
+ verification_status: complete
162
+ - children:
163
+ - name: 回收买卖
164
+ value: ''
165
+ - name: 其他生活服务
166
+ value: ''
167
+ - name: 租赁服务
168
+ value: ''
169
+ - name: 便民服务
170
+ value: ''
171
+ - name: 情感咨询
172
+ value: ''
173
+ - name: 城市出行
174
+ value: ''
175
+ - name: 结婚服务
176
+ value: ''
177
+ - name: 生活服务综合平台
178
+ value: ''
179
+ - name: 摄影
180
+ value: ''
181
+ - name: 移民服务
182
+ value: ''
183
+ - name: 配送服务
184
+ value: ''
185
+ - name: 婚嫁平台
186
+ value: ''
187
+ - name: 家政服务
188
+ value: ''
189
+ - name: 美容美发
190
+ value: ''
191
+ - name: 护养服务
192
+ value: ''
193
+ - name: 婚恋服务
194
+ value: ''
195
+ children_count: 16
196
+ name: 生活服务
197
+ reached_end: true
198
+ value: ''
199
+ verification_status: complete
200
+ - children:
201
+ - name: 药品
202
+ value: ''
203
+ - name: 保健品-国内
204
+ value: ''
205
+ - name: 美妆特殊化妆品
206
+ value: ''
207
+ - name: 膳食营养品
208
+ value: ''
209
+ - name: 传统滋补营养品
210
+ value: ''
211
+ - name: 保健品-跨境
212
+ value: ''
213
+ - name: 日化特殊化妆品
214
+ value: ''
215
+ - name: 医疗机构
216
+ value: ''
217
+ - name: 医疗器械
218
+ value: ''
219
+ children_count: 9
220
+ name: 健康
221
+ reached_end: true
222
+ value: ''
223
+ verification_status: complete
224
+ - children:
225
+ - name: 物业管理公司
226
+ value: ''
227
+ - name: 房地产分销商
228
+ value: ''
229
+ - name: 房地产综合服务平台
230
+ value: ''
231
+ - name: 房地产渠道机构
232
+ value: ''
233
+ - name: 房地产开发商
234
+ value: ''
235
+ - name: 其他房地产
236
+ value: ''
237
+ children_count: 6
238
+ name: 房地产
239
+ reached_end: true
240
+ value: ''
241
+ verification_status: complete
242
+ - children:
243
+ - name: 家装平台
244
+ value: ''
245
+ - name: 床上用品
246
+ value: ''
247
+ - name: 家装辅材
248
+ value: ''
249
+ - name: 家装主材
250
+ value: ''
251
+ - name: 家用五金
252
+ value: ''
253
+ - name: 家具
254
+ value: ''
255
+ - name: 家居百货
256
+ value: ''
257
+ - name: 装修设计及工程服务
258
+ value: ''
259
+ - name: 家饰
260
+ value: ''
261
+ - name: 家用电工
262
+ value: ''
263
+ - name: 家居建材线下零售
264
+ value: ''
265
+ - name: 居家布艺
266
+ value: ''
267
+ - name: 家装灯饰光源
268
+ value: ''
269
+ - name: 其他家居建材
270
+ value: ''
271
+ children_count: 14
272
+ name: 家居建材
273
+ reached_end: true
274
+ value: ''
275
+ verification_status: complete
276
+ readback_validation:
277
+ attempted_readback_count: 9
278
+ failed_readback_count: 0
279
+ passed_readback_count: 9
280
+ readback_completed: true
281
+ required_readback_count: 9
282
+ verifications:
283
+ - actual: 企服加盟/会展服务
284
+ l1: 企服加盟
285
+ l2: 会展服务
286
+ success: true
287
+ - actual: 企服加盟/饮品烘焙加盟
288
+ l1: 企服加盟
289
+ l2: 饮品烘焙加盟
290
+ success: true
291
+ - actual: 企服加盟/教育培训加盟
292
+ l1: 企服加盟
293
+ l2: 教育培训加盟
294
+ success: true
295
+ - actual: 金融业/第三方支付
296
+ l1: 金融业
297
+ l2: 第三方支付
298
+ success: true
299
+ - actual: 金融业/银行业
300
+ l1: 金融业
301
+ l2: 银行业
302
+ success: true
303
+ - actual: 金融业/保险业
304
+ l1: 金融业
305
+ l2: 保险业
306
+ success: true
307
+ - actual: 家居建材/家装平台
308
+ l1: 家居建材
309
+ l2: 家装平台
310
+ success: true
311
+ - actual: 家居建材/装修设计及工程服务
312
+ l1: 家居建材
313
+ l2: 装修设计及工程服务
314
+ success: true
315
+ - actual: 家居建材/其他家居建材
316
+ l1: 家居建材
317
+ l2: 其他家居建材
318
+ success: true
319
+ source:
320
+ collected_at: '2026-07-29T23:10:36.259968+08:00'
321
+ collector_version: 2
322
+ page: https://leads.cluerich.com/pc/analysis/short-video/rank
323
+ platform: douyin_enterprise_leads
324
+ taxonomy_verified: true
325
+ total_l1: 9
326
+ total_l2: 110
@@ -0,0 +1,177 @@
1
+ ---
2
+ name: douyin-competitor-collect
3
+ description: 使用已登录的 douyin.com 持久化浏览器 Profile 搜索、人工确认并采集抖音竞品账号公开信息。用于在顶部搜索框输入竞品昵称或抖音号、从搜索结果定位候选账号、打开头像进入主页并截图等待用户确认,然后严格按主页“作品”页签网格顺序采集前 20 个作品(不足 20 个时采集全部),采集头像、昵称、认证、作品数以及每个作品的封面、完整作品文案、标签、时长、发布时间、点赞、评论、收藏和分享等可见数据。不要用于登录、发布、关注、点赞、评论、私信或绕过风控。
4
+ ---
5
+
6
+ # 抖音竞品账号采集
7
+
8
+ 将登录与采集拆成独立任务。仅在 `douyin-web-login` 已完成、目标 Profile 主站登录有效时执行。读取 [references/output-schema.md](references/output-schema.md) 生成账号、作品和证据结果。
9
+
10
+ ## 执行边界
11
+
12
+ - 使用用户指定的 `social_profile`、原 `browser_data` 和固定指纹;先获取唯一 lock。
13
+ - 先做只读登录检查。未登录返回 `LOGIN_REQUIRED` 并结束,不在采集任务中扫码。
14
+ - 使用真实可视浏览器和当前可见页面数据。不得调用未授权私有 API、注入 Cookie、绕过验证码或批量并发请求。
15
+ - 全程只读。不得关注、点赞、收藏、评论、分享、私信、下载作品或修改账号状态。
16
+ - 保持一个 controller、browser 和 context。主页保留在原标签页,每次只在一个新标签页打开一个作品,采集后关闭该详情标签页;不要并发打开多个作品。
17
+ - 遇到验证码、访问频繁、滑块、风控或 DOM 无法确定时返回 `WAIT_MANUAL_ACTION` 或 `PAGE_STRUCTURE_UNKNOWN`,保存非敏感证据后停止。
18
+ - 页面字段不可见时保存 `null` 和缺失原因,不能写成真实的 `0`。
19
+
20
+ ## 阶段一:搜索并确认账号
21
+
22
+ 1. 打开 `https://www.douyin.com/` 并确认右上角已登录头像存在。
23
+ 2. 在页面顶部唯一可见的全站搜索框中填入用户给出的竞品昵称或抖音号,例如“一叶智能”。
24
+ 3. 验证输入框读回值完全一致,只点击一次顶部“搜索”按钮。
25
+ 4. 等待搜索结果稳定,优先切换或定位“用户”结果;不要把综合页作品作者、广告或搜索建议当成账号结果。
26
+ 5. 在结果中匹配昵称、抖音号、认证文本和头像。完全匹配优先;有多个候选时不得自行猜测。
27
+ 6. 点击候选账号头像或用户卡片,进入该账号主页。
28
+ 7. 确认页面是用户主页,读取当前 URL、昵称、抖音号、认证和可见统计。
29
+ 8. 截取包含头像、昵称、抖音号、认证、作品数和作品网格的主页证据图,通过飞书发送真实图片附件。
30
+ 9. 返回 `WAIT_COMPETITOR_CONFIRM`,列出候选账号的非敏感信息并等待用户确认。未经匹配 `task_id` 的明确确认,不得打开作品详情或开始采集。
31
+ 10. 用户否认时返回 `COMPETITOR_REJECTED`,回到搜索结果等待新指示;不得自动选择下一个候选。
32
+
33
+ ## 阶段二:采集账号资料
34
+
35
+ 用户确认后固定 `competitor_profile_url` 和可见抖音号作为本批次账号标识,再采集:
36
+
37
+ - 账号层必须采集并验收 8 项:头像、昵称、抖音号、认证信息、关注数、粉丝数、获赞数、作品数。
38
+ - 头像必须保存主页中的账号头像截图;可安全读取时同时保存头像 URL。
39
+ - 认证信息同时保存页面原文和认证类型;页面确实没有认证时保存 `null` 并标记 `not_verified`,不得遗漏字段。
40
+ - 关注数、粉丝数、获赞数和作品数同时保存页面展示原文与解析整数。页面使用“万/亿”等缩写时保留原文,并仅在转换确定时填写整数。
41
+ - 主页 URL、采集时间、页面展示原文和解析数值。
42
+
43
+ 必须在账号主页顶部信息区截取一张清晰证据图,使头像、昵称、抖音号、认证信息、关注数、粉丝数、获赞数和作品数全部可辨认。若单张截图无法覆盖,允许使用两张主页截图,但必须在账号 JSON 和证据清单中逐一引用。搜索结果列表、作品详情页或右侧作者卡片不能替代主页证据。
44
+
45
+ 上述 8 项未全部获得“可见值”或明确的缺失原因时,不得返回 `COLLECTION_COMPLETE`。主页证据截图缺失时只能返回 `PARTIAL_COMPLETE`,不得以此前人工确认代替证据。
46
+
47
+ 账号确认后如果昵称或抖音号发生变化,返回 `ACCOUNT_CHANGED` 并暂停,不继续沿用旧确认。
48
+
49
+ ## 阶段三:确定主页前 20 个作品
50
+
51
+ 1. 保持在已确认账号的“作品”页签,以页面当前网格从左到右、从上到下的可见顺序作为唯一选择顺序;不得改用发布时间排序。
52
+ 2. 逐张检查作品卡片左上角。出现黄色“置顶”文字角标时,该作品必须记录 `is_pinned=true`;没有该角标时记录 `is_pinned=false`。不得根据网格位置、发布时间或播放量猜测置顶状态。
53
+ 3. 从“作品”页签实际网格父容器读取全部直属或固定层级作品卡片节点。每个候选的详情链接、封面、可见标题、置顶角标和 bounding box 必须从同一个卡片节点内读取;禁止分别取得卡片列表与链接列表后按数组下标拼接,也禁止从 `document` 全局视频链接集合取值。
54
+ 4. 不得只筛选 `/video/`。视频、图文和页面实际存在的其他公开作品类型都占用一个网格位置;至少支持 `/video/<id>` 与 `/note/<id>`,分别记录 `work_type=video|note`。如需描述内容形态,另存 `content_format=video|image_text`,不得把路由类型 `note` 改写成 `image_text`。无法解析的卡片仍保留其真实位置,记录 `work_type=unknown`、`work_id=null` 和具体缺失原因,不得让后续卡片向前补位。
55
+ 5. 使用卡片 bounding box 还原响应式网格顺序:先按 `top` 从小到大分行,同一行按 `left` 从小到大排序。列数必须根据当前页面实际布局检测,不得固定假设为 4 列或 6 列,也不得用固定坐标点击或推算位置。
56
+ 6. 截取能够证明网格顺序和“置顶”角标的连续网格证据。只读取已确认账号主页“作品”页签内的卡片;右侧推荐、喜欢、合集、搜索结果、隐藏预加载节点和详情页推荐均不是候选作品。
57
+ 7. 先生成完整候选清单 `candidates.json`,每条至少包含 `profile_grid_position`、`work_id`、`work_type`、原始/规范化详情 URL、卡片可见标题、置顶标记、bounding box、卡片截图和网格截图引用。不得边发现候选边写入未经身份核验的作品结果。
58
+ 8. 默认选择网格位置 1–20。置顶作品即使发布时间较旧,只要位于主页前 20 个就必须保留;不得为追求“最新”而排除置顶作品或加载第 21 个以后替换它。
59
+ 9. 使用“平台 + 作品 ID”去重;无法获得作品 ID 时使用规范化详情 URL,并标记 `dedupe_method=url`。候选不足目标数量时继续滚动主页加载,但不得越过主页作品页签寻找补充内容。
60
+ 10. 主页展示作品总数时,候选发现阶段应持续加载并解释直属卡片数与展示总数的差异。账号公开作品不足 20 个时按实际数量采集,返回 `insufficient_public_works=true`;账号作品数大于等于 20 时,候选清单和最终结果默认都必须恰好包含视觉位置 1–20,不能因为某种作品类型无法解析而用第 21 个补位。
61
+ 11. 通过飞书发送 `candidates.json` 和能够连续覆盖全部候选位置的网格/卡片证据,返回 `WAIT_CANDIDATES_CONFIRM`。只有收到匹配 `task_id` 的明确候选确认后才能进入作品详情;用户否认或指出错位时必须留在候选阶段修复,不得先采后改。
62
+
63
+ ## 阶段四:顺序采集作品详情
64
+
65
+ 对候选清单按 `profile_grid_position` 升序逐条执行:
66
+
67
+ 1. 保留账号主页原标签页,将候选的规范化详情 URL 在一个新标签页中打开:`video` 使用 `/video/<id>`,`note` 使用 `/note/<id>`,其他类型使用卡片自身的规范化详情路径。不得依赖详情页“上一个/下一个”、上下箭头、轮播或推荐卡片切换作品。
68
+ 2. 等待标题、媒体区域和互动栏稳定,不要求播放完整视频。读取当前详情页 URL 并重新解析实际作品 ID;验证它与候选 `work_id` 完全一致,同时验证作者昵称或抖音号仍属于已确认竞品。
69
+ 3. 实际作品 ID、详情 URL 或作者身份任一不一致时,不得读取、截图或绑定为该候选的成功证据;记录具体失败原因并返回 `PARTIAL_COMPLETE`。
70
+ 4. 保存作品封面/首屏截图,以及包含作品完整文案、标签、时长和互动指标的详情证据截图。避免把评论正文、用户头像等非必要个人信息纳入截图。
71
+ 5. 读取并保存:
72
+ - 作品 ID、详情 URL、封面 URL或截图路径;
73
+ - 作品完整文案,沿用兼容字段名 `title`;
74
+ - 话题标签,保留页面顺序;
75
+ - 视频时长;
76
+ - 发布时间;
77
+ - 点赞、评论、收藏、分享的页面原始展示值和可靠解析值;
78
+ - 是否置顶,以及当前采集序号。
79
+ `is_pinned` 必须来自主页作品卡片左上角的可见“置顶”角标,不得从详情页缺少角标推导为 `false`。
80
+ 6. 按 `work_type` 使用对应详情布局,不得用视频 selector 读取 Note,也不得用 Note selector 读取视频:
81
+ - `video`:作品文案通常位于播放器下方、发布时间附近;互动指标通常为底部横向的点赞、评论、收藏、分享栏。
82
+ - `note`:作品文案和发布时间通常位于页面右侧作者信息区;互动指标通常为媒体区域右缘的竖向点赞、评论、收藏、分享栏。右侧更外层的“相关推荐”卡片不是当前作品数据源。
83
+ 7. `card_visible_title` 只用于候选核验,不能直接作为最终 `title`。卡片文本可能混入点赞数前缀或因 DOM/无障碍文本重复两遍;最终文案必须从当前详情页对应布局的作品文案区域重新读取。规范化时可移除已确认来自卡片指标的前缀和完全重复副本,但不得误删正文中的真实数字、表情、话题或换行顺序。
84
+ 8. 抖音详情页通常只有一段作品文案。为兼容既有表格,CSV/JSONL 只用 `title` 保存这段完整原文,不再生成 `description`、`display_text` 或 `title_status` 等重复文本列;批次元数据记录 `text_schema=legacy_title_as_full_caption_v1`。每条非空 `title` 必须填写 `title_extraction_method=visible_dom|evidence_screenshot_transcription`,不能只给转录行填写。只有页面和该作品证据截图均无作品文案时才保存 `null`,并填写 `missing_reasons.title=no_caption_visible`。
85
+ 9. 播放器控件、快捷键提示、悬浮提示、自动播放提示和无障碍操作文案不是作品文案。例如“1s 后循环播放当前视频”只能判定为播放器 UI,禁止写入 `title`。无法找到真实作品文案时保留 `title=null` 并记录缺失原因,不得用 UI 文案补位。
86
+ 10. 截图中作品文案清晰可见但结构化 `title` 为空、仍含指标前缀、完全重复副本或播放器 UI 文案,均属于提取失败;未修复时只能返回 `PARTIAL_COMPLETE`。
87
+ 11. 指标可能显示为“1.2万”等缩写。始终保存 `*_display` 原文;只有能确定转换规则时填写 `*_count`,否则为 `null` 并记录原因。
88
+ 12. 抖音详情页使用特定操作文案表示零值时,按页面语义记录为 `0`,不能记为缺失:
89
+ - 点赞心形图标旁显示“赞”:保存 `likes_display="赞"`、`likes_count=0`。
90
+ - 评论图标旁显示“抢首评”:保存 `comments_display="抢首评"`、`comments_count=0`。
91
+ - 收藏图标旁显示“收藏”:保存 `favorites_display="收藏"`、`favorites_count=0`。
92
+ - 分享图标旁显示“分享”:保存 `shares_display="分享"`、`shares_count=0`。
93
+ 只有准确识别到当前作品互动栏对应图标旁的上述文字时才能应用该规则,不能把其他区域、右侧推荐内容或评论正文中的同名文字当作当前作品指标。
94
+ 13. 分享数或收藏数既没有数字,也没有上述可确认的零值文案时保持 `null`;不要根据按钮存在、网络请求或其他指标推算。任何空字段都必须在 `missing_reasons` 写明具体原因,不得出现字段为空但 `missing_reasons={}`。若 `missing_reasons` 声明某互动栏或指标未找到,该作品不得计入 `complete_works`,相应 `interaction_extraction_failures` 必须增加;不能同时宣称互动失败为 0。
95
+ 14. 每采集一条立即追加保存结构化记录和进度,使用作品 ID 去重。保存后关闭当前详情标签页,确认原主页仍是同一竞品账号,再打开下一条。
96
+ 15. 在作品间使用短暂停顿并保持串行。出现平台限制时立即停止,不以重试加速方式规避限制。
97
+
98
+ ## 证据与交付
99
+
100
+ - 保存账号主页确认截图、每个作品的证据截图、来源 URL、采集时间和字段缺失状态。
101
+ - 至少保存一张作品网格截图,用于证明候选顺序和各作品卡片的置顶角标;使用 `evidence_type=works_grid`,作品记录通过 `grid_screenshot` 引用该证据。
102
+ - 账号主页截图必须加入证据 ZIP 和 manifest,使用独立的 `evidence_type=account_profile`;每个作品详情截图使用 `evidence_type=work_detail`。三类证据不得混用或笼统写成 `profile`;manifest 为每项保存 `final_filename`、`source_url` 和最终 ZIP 内文件的实际 SHA-256,作品证据另存 `work_id` 与 `profile_grid_position`。
103
+ - 最终 JSON/JSONL/CSV 和 manifest 只引用 ZIP 内可解析的相对路径,如 `profile.png`、`grid_full.png`、`work_01.png`;不得交付 `/Users/...`、`~/.media-agent/...` 等发送方本机绝对路径。
104
+ - 生成一个账号 JSON、一个候选清单 JSON、一个作品 JSONL 和一个作品 CSV;字段遵循参考 schema。CSV 与 JSONL 的共享业务字段和必填状态必须一致;JSONL 可额外保存溯源字段,但不得出现某必填字段只在部分 JSONL 行中存在。
105
+ - JSON/JSONL 是事实来源,CSV 和飞书摘要是展示层。飞书必须发送真实附件,远端路径不算交付。
106
+ - 汇总成功数、失败数、缺失字段数、实际作品数、去重数和截图数。
107
+ - 交付前逐条核验候选 `work_id`、详情 URL 中的实际作品 ID、JSONL/CSV 的 `work_id`、Manifest 的 `work_id` 和截图可见标题/发布时间属于同一个作品。任一错位都必须记录 `evidence_binding_mismatch` 并返回 `PARTIAL_COMPLETE`。
108
+ - 交付前统计 `manifest_hash_mismatches` 和 `absolute_screenshot_paths`;任一非零都不得返回 `COLLECTION_COMPLETE`。
109
+ - `collected_works` 表示已生成唯一作品记录的数量,`complete_works` 表示必需字段和证据均通过验收的数量;不得把“15 条完整”表述成“只采到 15 个作品”。
110
+ - 不在本 Skill 中计算或宣称“官方爆款”。如后续计算项目互动值,必须另行保存算法版本和实际参与指标。
111
+
112
+ ## 状态与返回
113
+
114
+ 确认前返回:
115
+
116
+ ```text
117
+ [state=WAIT_COMPETITOR_CONFIRM]
118
+ [task_id=<稳定ID>]
119
+ [social_profile=<Profile>]
120
+ [query=<搜索词>]
121
+ [candidate_name=<昵称>]
122
+ [candidate_douyin_id=<抖音号或 unavailable>]
123
+ [candidate_verification=<认证或 none>]
124
+ [candidate_profile_url=<主页URL>]
125
+ [profile_screenshot_sent=true]
126
+ ```
127
+
128
+ 账号确认后、详情采集前返回:
129
+
130
+ ```text
131
+ [state=WAIT_CANDIDATES_CONFIRM]
132
+ [task_id=<稳定ID>]
133
+ [requested_works=20]
134
+ [profile_works_display=<主页作品数>]
135
+ [direct_card_nodes=<已加载直属卡片数>]
136
+ [detected_grid_columns=<当前响应式列数>]
137
+ [candidate_works=<数量>]
138
+ [unique_candidate_works=<数量>]
139
+ [video_works=<数量>]
140
+ [note_works=<数量>]
141
+ [unresolved_candidates=<数量>]
142
+ [candidates_json=<路径>]
143
+ [candidate_evidence_sent=true|false]
144
+ ```
145
+
146
+ 完成后返回:
147
+
148
+ ```text
149
+ [state=COLLECTION_COMPLETE|PARTIAL_COMPLETE|COLLECTION_FAILED]
150
+ [task_id=<稳定ID>]
151
+ [competitor_confirmed=true]
152
+ [requested_works=20]
153
+ [candidate_works=<数量>]
154
+ [unique_candidate_works=<数量>]
155
+ [video_works=<数量>]
156
+ [note_works=<数量>]
157
+ [unresolved_candidates=<数量>]
158
+ [collected_works=<数量>]
159
+ [complete_works=<数量>]
160
+ [partial_works=<数量>]
161
+ [failed_works=<数量>]
162
+ [insufficient_public_works=true|false]
163
+ [account_fields_complete=true|false]
164
+ [account_profile_screenshot_included=true|false]
165
+ [account_json=<路径>]
166
+ [candidates_json=<路径>]
167
+ [works_jsonl=<路径>]
168
+ [works_csv=<路径>]
169
+ [evidence_screenshots=<数量>]
170
+ [identity_mismatches=<数量>]
171
+ [evidence_binding_mismatches=<数量>]
172
+ [attachments_sent=true|false]
173
+ [browser_process_remaining=0]
174
+ [lock_remaining=0]
175
+ ```
176
+
177
+ 允许的等待或错误状态包括:`LOGIN_REQUIRED`、`PROFILE_LOCKED`、`WAIT_COMPETITOR_CONFIRM`、`WAIT_CANDIDATES_CONFIRM`、`COMPETITOR_REJECTED`、`ACCOUNT_CHANGED`、`WAIT_MANUAL_ACTION`、`PAGE_STRUCTURE_UNKNOWN`、`SESSION_LOST` 和 `PARTIAL_COMPLETE`。
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "抖音竞品账号采集"
3
+ short_description: "搜索并确认竞品账号,采集主页前20个作品的公开数据与证据"
4
+ default_prompt: "使用 $douyin-competitor-collect 搜索指定抖音竞品账号,等待我确认后从同一卡片节点读取 video 与 note 作品,按各自详情布局采集,严格取主页作品网格前20个;不足20个时采集全部。"