{"id":"84297c78-4cc0-4f96-a9c7-e5eeb3acc79f","entityType":"agent","slug":"clawhub-tars1230-douyin-creator-insight","name":"douyin-creator-insight","canonicalUrl":"https://www.xpersona.co/agent/clawhub-tars1230-douyin-creator-insight","canonicalPath":"/agent/clawhub-tars1230-douyin-creator-insight","generatedAt":"2026-10-12T09:25:07.796Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T23:58:08.863Z","emptyReason":null},"description":"分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。 Skill: douyin-creator-insight Owner: tars1230 Summary: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。 Tags: latest:1.3.6 Version history: v1.3.6 | 2026-08-05T12:42:37.389Z | user setup/缺Key强制三步：推荐注册页→控制台建Key→export；交互可打开 https://cloud.siliconflow.cn/i/1srulim9 v1.3.5 | 2026-08-05T09:53:13.121Z | user ASR 简化为单一路径：只下 video_url → ffmpeg 抽音 → SenseVoice；去掉 audio_url 优先分支","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 972 downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s174ad9z7a9pq8vt2njhqm0hk983qfsw:douyin-creator-insight","sourceUrl":"https://clawhub.ai/tars1230/douyin-creator-insight","homepage":"https://clawhub.ai/tars1230/skills/douyin-creator-insight","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/tars1230/douyin-creator-insight","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/tars1230/skills/douyin-creator-insight","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。 Skill: douyin-creator-insight Owner: tars1230 Summary: 分析公开抖音创作"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:58:08.863Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:58:08.863Z","emptyReason":null},"stars":null,"forks":null,"downloads":972,"likes":null,"task":null,"library":null,"packageName":null,"latestVersion":"1.3.6","tractionLabel":"972 downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T23:58:08.854Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T23:58:08.863Z","lastCrawledAt":"2026-10-11T23:58:08.854Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T23:58:08.854Z","lastVerifiedAt":null,"highlights":[{"version":"1.3.6","createdAt":"2026-08-05T12:42:37.389Z","changelog":"setup/缺Key强制三步：推荐注册页→控制台建Key→export；交互可打开 https://cloud.siliconflow.cn/i/1srulim9","fileCount":40,"zipByteSize":99838},{"version":"1.3.5","createdAt":"2026-08-05T09:53:13.121Z","changelog":"ASR 简化为单一路径：只下 video_url → ffmpeg 抽音 → SenseVoice；去掉 audio_url 优先分支","fileCount":40,"zipByteSize":98791},{"version":"1.3.4","createdAt":"2026-08-05T09:06:09.864Z","changelog":"audio-first ASR + configurable bitrate","fileCount":40,"zipByteSize":98743},{"version":"1.3.3","createdAt":"2026-08-05T08:37:58.506Z","changelog":"SiliconFlow 注册推荐链接","fileCount":40,"zipByteSize":97572},{"version":"1.3.2","createdAt":"2026-08-05T08:30:43.433Z","changelog":"SenseVoice 官方价标注免费","fileCount":40,"zipByteSize":97385},{"version":"1.3.1","createdAt":"2026-08-05T08:18:16.126Z","changelog":"SiliconFlow default for Douyin CDN ASR","fileCount":40,"zipByteSize":96964},{"version":"1.2.3","createdAt":"2026-08-01T14:58:47.361Z","changelog":"v1.2.3 removes an internal task_plan.md process artifact from the public package; functional v1.2.2 first-run setup remains unchanged.","fileCount":40,"zipByteSize":93512},{"version":"1.2.2","createdAt":"2026-08-01T14:45:13.617Z","changelog":"v1.2.2 adds first-run setup for cloud/local/index modes, safe missing DASHSCOPE_API_KEY handling, and read-only coexistence detection for douyin-favorites-to-knowledge.","fileCount":41,"zipByteSize":94116}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s174ad9z7a9pq8vt2njhqm0hk983qfsw:douyin-creator-insight","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-12T09:25:07.792Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tars1230-douyin-creator-insight/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T23:58:08.863Z","emptyReason":null},"readme":"Skill: douyin-creator-insight\n\nOwner: tars1230\n\nSummary: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。\n\nTags: latest:1.3.6\n\nVersion history:\n\nv1.3.6 | 2026-08-05T12:42:37.389Z | user\n\nsetup/缺Key强制三步：推荐注册页→控制台建Key→export；交互可打开 https://cloud.siliconflow.cn/i/1srulim9\n\nv1.3.5 | 2026-08-05T09:53:13.121Z | user\n\nASR 简化为单一路径：只下 video_url → ffmpeg 抽音 → SenseVoice；去掉 audio_url 优先分支\n\nv1.3.4 | 2026-08-05T09:06:09.864Z | user\n\naudio-first ASR + configurable bitrate\n\nv1.3.3 | 2026-08-05T08:37:58.506Z | user\n\nSiliconFlow 注册推荐链接\n\nv1.3.2 | 2026-08-05T08:30:43.433Z | user\n\nSenseVoice 官方价标注免费\n\nv1.3.1 | 2026-08-05T08:18:16.126Z | user\n\nSiliconFlow default for Douyin CDN ASR\n\nv1.2.3 | 2026-08-01T14:58:47.361Z | user\n\nv1.2.3 removes an internal task_plan.md process artifact from the public package; functional v1.2.2 first-run setup remains unchanged.\n\nv1.2.2 | 2026-08-01T14:45:13.617Z | user\n\nv1.2.2 adds first-run setup for cloud/local/index modes, safe missing DASHSCOPE_API_KEY handling, and read-only coexistence detection for douyin-favorites-to-knowledge.\n\nv1.2.1 | 2026-08-01T13:38:31.303Z | user\n\nv1.2.1 finalizes the runtime-env hardening package across GitHub, Gitee, and ClawHub. It auto-loads ASR/browser profile config from a narrow env whitelist for Hermes/agent launches, keeps cloud ASR as the default, and includes regression tests for cloud/local direct entrypoints and env parsing.\n\nv1.2.0 | 2026-08-01T09:41:12.961Z | user\n\n独立安装；默认 cloud ASR；新增 local Whisper 与 index-only 模式；共享 profile 冲突探测；临时媒体自动清理；完善小账号质量门、采集对账与自适应转写选择。\n\nv1.1.0 | 2026-07-30T09:12:46.574Z | user\n\nBrowser-first public creator collection; share links and sec_uid supported; Apify is now an explicit fallback.\n\nArchive index:\n\nArchive v1.3.6: 40 files, 99838 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (8466b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (11909b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (20941b), scripts/browser_collector.py (13558b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8189b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (19377b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (8821b), scripts/setup.py (8431b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2869b), SKILL.md (10332b), tests/test_pipeline.py (18901b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nFile v1.3.6:SKILL.md\n\n---\nname: douyin-creator-insight\nversion: 1.3.6\ndescription: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。\n---\n\n# Douyin Creator Insight\n\n## 使用条件\n\n仅分析公开可访问数据。默认真实抓取使用已授权的本地浏览器 profile，不依赖 Apify key；Apify 仅是显式 fallback。不要在对话、脚本、报告或仓库中输出 token、cookie、浏览器 profile、私人绝对路径或未公开内容。\n\n## 安装与共享配置\n\n`douyin-creator-insight` 可独立安装和运行，`douyin-favorites-to-knowledge`（旧名/旧目录可能是 `douyin-knowledge-base-pipeline`）不是前置依赖。若两者都存在，本 skill 只复用已登录的 persistent browser profile 和 ASR 环境变量，绝不读取收藏记录、修改增量 metadata，或加入收藏 skill 的 23:00 任务。\n\n首次运行先执行 `python3 scripts/setup.py`。它只写非敏感偏好：`cloud`（云端 ASR）/ `local`（Whisper）/ `index`（只索引），以及可选 profile/output 位置；不保存 API key、cookie 或 token。若检测到已安装 `douyin-favorites-to-knowledge`，优先复用其已登录浏览器 profile 和转录偏好，但状态、账本、输出和 23:00 任务仍完全隔离。缺 Key 时 setup 会打印 **①②③ 逐步指引**，交互终端可询问是否**打开推荐注册页**。\n\n**云端 ASR 真相（抖音）**：抖音 CDN（`*.douyinvod.com` 等）带防盗链，**阿里云百炼 URL-ASR 服务端拉不到媒体**，会稳定失败——不是用户 Key 配错。公开 skill 的默认可用路径是：\n\n1. **推荐 `SILICONFLOW_API_KEY`**：本机用浏览器式 `Referer: https://www.douyin.com/` 临时下载 → 抽音频 → 上传 SiliconFlow `FunAudioLLM/SenseVoiceSmall` → 立即清理临时文件。\n2. **可选 `DASHSCOPE_API_KEY`**：仅当媒体 URL 是第三方可公网直链时走百炼 URL-ASR；对抖音 CDN **默认跳过**（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n3. 至少配置上述之一才允许 `cloud` 真跑；**两者都缺**时停止，不下载、不静默切 Whisper。\n4. 云端都失败且用户允许 local fallback 时才进 Whisper；`index` 永不 ASR。\n\n**新用户拿 Key（必须按序，别自己乱搜）：**\n\n1. 打开推荐注册/登录页：https://cloud.siliconflow.cn/i/1srulim9  \n2. 控制台创建 API Key：https://cloud.siliconflow.cn/account/ak  \n3. `export SILICONFLOW_API_KEY='…'` 或写入 `~/.hermes/.env` / 仓库 `.env.local`，**重启 Agent**  \n4. 价格参考：https://siliconflow.cn/pricing（SenseVoiceSmall 可能标免费，以账单为准）\n\n百炼说明（可选）：`https://help.aliyun.com/zh/model-studio/get-api-key`。Key 放本机环境变量/Secret Manager，不要发聊天或进仓库。skill 自动读 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local`。运行前 `python3 scripts/integration.py`；共享 profile 被占用必须等待。报告写入独立 `<output-root>/creator-insight/`。\n\n> **ASR 费用（默认 SenseVoiceSmall）**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。\n\n- **SiliconFlow 注册推荐链接**：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n\nActor 的价格、配额、可用性和 schema 会变化。运行前查看当前 Actor 页面；任何费用或耗时只能作为本次运行的实测结果陈述，不能沿用固定承诺。\n\n## 输入\n\n从用户原话提取：\n\n- `creator_query`：优先主页 URL、`sec_uid`，或包含 `v.douyin.com` 的完整分享消息；脚本会提取短链接。\n- `max_videos`：默认 1000；用户要求省资源或试跑时降低。超过上限时结果必须标为 `partial`。\n- `transcript_count`：未指定时按作品数自动分档；用户显式指定时优先遵从。\n- `transcript_max_duration_minutes`：默认 5，用于候选筛选。\n- `transcript_mode`：`cloud`（默认）/ `local` / `index`。\n- `output_formats`：默认 `html`、`md`、`json`。\n- `output_dir`：默认当前任务的专用输出目录。\n\n主页 URL、分享短链接或 `sec_uid` 最稳定。昵称和抖音号只可用于候选确认，不能自动选择同名账号；搜索验证码或模糊结果时要求用户改贴主页/分享链接。\n\n## 流程\n\n1. 用 `scripts/resolver.py` 判断输入类型，并从分享消息提取短链接。\n2. 对 URL/短链接/`sec_uid`，优先运行 `scripts/run_pipeline.py --browser`。它在现有 persistent profile 的页面上下文读取公开作品分页，并验证每条返回视频的作者 `sec_uid`。\n3. 昵称或抖音号不可自动选人；搜索触发验证码、无候选或多个候选时停止并请求主页/分享链接。\n4. 用 `scripts/parser.py` 标准化字段，再执行 `quality_gate.py`。门禁失败时停止，不生成伪完整报告。\n5. `index` 模式跳过转写，只保留全量作品信息；其他模式用 `selector.py` 选择候选：30 条及以下全量转写；31-100 条按点赞前 50；更大账号按点赞、收藏和近期作品分层去重抽样（上限 100 条）。\n6. `cloud`（默认）对抖音 CDN 媒体：**优先 SiliconFlow 上传 ASR**（Referer 下载 + 抽音频 + 上传 + 清理）；**不把抖音 CDN URL 默认丢给百炼**。非抖音可公网媒体才先试百炼 URL-ASR。云端都失败才进入 `local` Whisper。`douyin-mcp` 不是依赖。再用 `categorizer.py` 分类、`report_builder.py` 输出真实 provider 状态与错误。\n\n## Tool 调用契约\n\nProfile actor 输入：\n\n```json\n{\n  \"maxPostsPerProfile\": 1000,\n  \"profileUrls\": [\"https://www.douyin.com/user/<sec_uid>\"]\n}\n```\n\n浏览器模式默认最多采集 1000 条；Apify 的实际上限、配额和字段以运行时 Actor schema 为准。任何触发上限、分页未完成或声明数无法对账的结果，都必须在报告的 `collection` 字段标为 `partial` 或 `reconciliation: unavailable`，不得写成全量完成。\n\nActor ID、输入字段和 fallback 以 [references/apify-douyin-actors.md](references/apify-douyin-actors.md) 为准。不要假设文档中的历史 actor 永久可用；调用失败时先核对 Actor 页面和返回 schema。\n\n## 质量门\n\n- 身份必须 matched，且含 `sec_uid` 或抖音号。\n- 视频列表不能为空；少于质量门默认阈值时阻断。\n- 超过一半的视频缺少标题与描述时阻断。\n- 转写成功率低于门槛时，报告必须明确降级或停止。\n- 低置信度身份不得自动选择。\n\n## 运行脚本\n\nAgent 已经完成采集后，可直接复用 `scripts/` 中的解析、筛选和报告函数。独立 CLI 必须显式选择一种模式：\n\n```bash\n# 非联网验证\npython3 scripts/run_pipeline.py --creator <profile_url> --dry-run\n\n# 默认真实路径：已登录浏览器中的公开主页接口\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py --creator '<share_or_profile_url>' --browser\n\n# 明确选择本地 Whisper 或纯信息索引\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode local\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode index\n\n# 使用显式 adapter 真实运行\npython3 scripts/run_pipeline.py \\\n  --creator <profile_url> \\\n  --adapter my_adapter:call_actor \\\n  --output-dir ./output\n```\n\n没有 `--dry-run`、`--browser` 或 `--adapter` 时，CLI 必须失败；不得把 dry-run 返回当成真实报告。\n\n## 失败处理\n\n| 场景 | 行为 |\n|---|---|\n| 找不到账号 | 返回候选或要求更稳定的主页 URL |\n| 浏览器 profile 未登录、主页接口失败 | 不要求复制 cookie；提示在已有 profile 中恢复登录或稍后重试 |\n| 昵称搜索验证码/同名 | 不绕过验证码，不自动选人；要求主页或分享链接 |\n| Profile actor 失败 | 核对 schema 后使用记录在 reference 中的 fallback |\n| 视频不足或字段异常 | 质量门阻断，保留原始响应供排查 |\n| 未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` | 停止真实转写；提示 SiliconFlow（抖音推荐）与可选百炼入口；不自动下载或切 Whisper |\n| 仅有 `DASHSCOPE_API_KEY`、无 SiliconFlow | 允许启动但告警：抖音 CDN 转写大概率失败 |\n| Cloud ASR 失败 | 仅在云端已配置但真实调用失败时记录错误，再回退本地 Whisper；`--no-local-fallback` 时只报告失败 |\n| 本地 Whisper 失败 | 清理临时媒体并标记 `failed` 或 `empty_transcript` |\n| 配额不足 | 停止真实调用，建议用户缩小样本或稍后重试 |\n| 输出写入失败 | 返回非成功状态和明确路径，不宣称完成 |\n\n## 验证\n\n修改 Skill 或脚本后必须运行：\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nfixture E2E 通过只证明本地编排契约正确，不证明第三方 Actor 当前可用。真实发布说明必须把两类证据分开。\n\n## 相关文档\n\n- `references/apify-douyin-actors.md`：Actor 与 fallback\n- `references/data-schema.md`：字段映射\n- `references/creator-resolution-playbook.md`：身份确认\n- `references/categorization-taxonomy.md`：分类规则\n- `references/report-rubric.md`：报告质量\n- `references/failure-playbook.md`：失败恢复\n- `SECURITY.md`：凭据与漏洞报告\n\n### ASR 媒体与码率（1.3.5+）\n- **单一路径**：下载 `video_url` → `ffmpeg -vn` 抽音 → 上传 SenseVoice。\n- **不再优先** `audio_url` / `music.play_url`（常为商业 BGM，多分支易踩坑）。\n- `DOUYIN_ASR_AUDIO_BITRATE`（默认 64k）、`DOUYIN_ASR_SAMPLE_RATE`（默认 16000）。\n- 推荐注册：https://cloud.siliconflow.cn/i/1srulim9\n\nFile v1.3.6:assets/README.md\n\n# Assets · 模板文件\n\n本目录存放报告生成所需的静态资源。\n\n## 文件清单\n\n- `README.md`：本说明\n- `report_template.html`：HTML 报告模板（参考用）\n- `report_style.css`：报告样式（参考用）\n- `creator_card_template.html`：博主封面卡片模板（参考用）\n\n## 当前实现\n\n**注意**：当前 `scripts/report_builder.py` 使用内置 Python 字符串模板，**不依赖** assets/ 目录。\nassets/ 中的文件仅作为参考 / 自定义起点。\n\n## 自定义指南\n\n如果需要自定义样式：\n\n### 方式 1：直接修改内置模板\n\n编辑 `scripts/report_builder.py::HTML_TEMPLATE`，调整 CSS 部分。\n\n### 方式 2：使用 jinja2 渲染\n\n1. 安装：`pip install jinja2`\n2. 把内置 HTML_TEMPLATE 复制到 `assets/report_template.html`\n3. 用 jinja2 渲染\n\n```python\nfrom jinja2 import Environment, FileSystemLoader\n\nenv = Environment(loader=FileSystemLoader('assets'))\ntemplate = env.get_template('report_template.html')\nhtml = template.render(\n    nickname=nickname,\n    followers=followers,\n    ...\n)\n```\n\n### 方式 3：完全重写\n\n如果需要差异化设计（如杂志风、暗色模式），可以：\n\n1. 创建新文件 `assets/report_template_magazine.html`\n2. 在 `scripts/report_builder.py` 中加 `build_html_report_magazine()`\n3. 调用方选择用哪个模板\n\n## 配色参考\n\n| 风格 | 配色 |\n|---|---|\n| 默认（深紫蓝） | `#1e3a8a → #5b21b6` |\n| 杂志风（暖色） | `#b45309 → #d97706` |\n| 暗色模式 | `#0f172a → #1e293b` |\n| 极简（白底） | `#f8fafc → #f1f5f9` |\n\n## 示例模板\n\n### 默认模板（已在 report_builder.py）\n\n```html\n<header class=\"hero\">\n    <h1>{{ nickname }} · 抖音内容洞察报告</h1>\n    <div class=\"creator-stats\">\n        <div class=\"stat\"><span class=\"num\">{{ followers }}</span></div>\n        ...\n    </div>\n</header>\n```\n\n### 杂志风模板（待创建）\n\n参考 `guizang-ppt-skill` 的杂志风风格。\n\nFile v1.3.6:README.md\n\n# Douyin Creator Insight\n\n从公开抖音主页、分享短链接或 `sec_uid` 出发，生成可审计的创作者内容洞察报告。默认使用已登录的本地浏览器 profile 读取公开作品；Apify 是可选 fallback。输出包含 HTML、Markdown 和 JSON。\n\n[![CI](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml/badge.svg)](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n\n## 能做什么\n\n- 解析主页 URL、`sec_uid` 和完整分享文案中的短链接；昵称或抖音号只用于人工候选确认，不自动选择同名账号。\n- 标准化不同数据源的视频字段。\n- 按账号规模自动选择转写候选：小账号全量转写，大账号以点赞、收藏和近期作品分层抽样。\n- 对解析、视频数量和转写质量执行阻断式质量门。\n- 生成 HTML、Markdown、JSON 三种报告。\n\n本项目只处理公开数据，不绕过登录、隐私或平台访问控制。\n\n## 安装与分发入口\n\n- Agent 一键安装：[ClawHub douyin-creator-insight](https://clawhub.ai/tars1230/skills/douyin-creator-insight)\n- 国内源码镜像：[Gitee tars123/douyin-creator-insight](https://gitee.com/tars123/douyin-creator-insight)\n- 源码与版本发布：[GitHub tars1230/douyin-creator-insight](https://github.com/tars1230/douyin-creator-insight)\n\n## 运行方式\n\n### 独立运行，可选复用收藏 skill\n\n本 skill 可以独立安装。第一次运行先执行 `python3 scripts/setup.py`，明确选择：\n\n- `cloud`：云端 ASR（默认）。**抖音场景推荐配置 `SILICONFLOW_API_KEY`**（本机带 Referer 临时下载 → 上传 SenseVoice → 清理）。\n- `local`：本地 Whisper。只有用户明确选择时才临时下载视频，结束后清理。\n- `index`：只索引标题、描述、互动数据和链接，不调用 ASR。\n\n### 云端 ASR 重要说明（请先读）\n\n抖音播放地址在 `*.douyinvod.com` 等 CDN 上，带防盗链。**阿里云百炼的 URL-ASR 无法从服务端下载这些地址**，会稳定返回 download 失败——这不是 API Key 坏了，也不是“测通了百炼就等于抖音能转写”。\n\n| Key | 是否抖音刚需 | 作用 |\n|---|---|---|\n| **`SILICONFLOW_API_KEY`** | **是（推荐）** | 下载（`Referer: https://www.douyin.com/`）+ 上传 `FunAudioLLM/SenseVoiceSmall` |\n| `DASHSCOPE_API_KEY` | 否（可选） | 仅对**可公网直链**媒体做 URL-ASR；对抖音 CDN 默认跳过 |\n\n- SiliconFlow 控制台：[创建 API Key](https://cloud.siliconflow.cn/account/ak)\n- 百炼说明（可选）：[如何获取 API Key](https://help.aliyun.com/zh/model-studio/get-api-key)\n\n两者都缺时，`cloud` 真跑会安全停止，不下载、不静默切 Whisper。只有 `DASHSCOPE`、没有 SiliconFlow 时会告警。Key 放环境变量/Secret Manager，不要发聊天或进仓库。\n\nskill 会自动读取当前 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local` 中的相关配置，Hermes 没透传环境也能继续走 cloud 默认。\n\n同时安装 `douyin-favorites-to-knowledge` 时，setup 会探测并优先复用它的已登录浏览器 profile 和转录偏好，但状态、输出和调度完全隔离：Creator Insight 默认写入 `./output/creator-insight/`，不读取收藏 metadata，也不加入 23:00 收藏任务。运行前执行 `python3 scripts/integration.py`；若共享 profile 已被占用，等待当前流程结束即可。`douyin-mcp` 是可选诊断工具，不是安装或运行依赖。\n\n### 1. 本地浏览器模式（默认推荐）\n\n首次独立使用时，本 skill 会使用中性的共享浏览器 profile；登录一次抖音即可。若已安装收藏 skill，则自动复用它现有的已登录 profile。之后可直接粘贴主页、`sec_uid`，或包含 `https://v.douyin.com/.../` 的完整分享消息：\n\n```bash\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py \\\n  --creator '长按复制此条消息，打开抖音搜索 https://v.douyin.com/xxxx/ ...' \\\n  --browser --max-videos 50 --output-dir ./output\n```\n\n该模式只读取公开作品列表，逐页验证每条作品作者的 `sec_uid`，不复制 cookie、不输出 profile、不绕过验证码。抖音媒体默认走 SiliconFlow 上传 ASR（Referer 下载后清理）；非抖音公网媒体可走百炼 URL ASR；全部云端失败才回退本地 Whisper。\n\n非交互环境可以显式配置：\n\n```bash\n# 云端：保存选择；若 Key 尚未配置，真实运行会安全停止并给出申请入口\npython3 scripts/setup.py --transcript-mode cloud\n\n# 本地：只有明确选择 local 后，真实运行才允许临时下载视频\npython3 scripts/setup.py --transcript-mode local\n\n# 索引：不转录、不下载视频\npython3 scripts/setup.py --transcript-mode index\n```\n\n首次使用需要可选依赖：\n\n```bash\npython3 -m pip install playwright\npython3 -m playwright install chromium\n```\n\n### 2. 作为 Agent Skill 或 Apify fallback\n\n安装到支持 `SKILL.md` 的 agent 环境后，优先走浏览器模式；没有已授权浏览器或浏览器接口异常时，才使用 Apify MCP 或下述 adapter。真实 token 必须由环境变量或宿主 secret store 提供，不要提交到仓库。\n\n### 3. 作为 CLI adapter\n\nCLI 不会猜测凭据，也不会把“未抓取”伪装成成功。必须显式选择以下一种模式：\n\n```bash\n# 非联网检查：只解析输入，不生成真实报告\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --dry-run\n\n# 真实执行：由使用者提供 module:function adapter\nPYTHONPATH=/path/to/adapters:$PYTHONPATH \\\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --adapter my_adapter:call_actor \\\n  --max-videos 50 \\\n  --transcript-count 3 \\\n  --output-dir ./output\n```\n\nAdapter 必须实现以下调用契约：\n\n```python\ndef call_actor(*, actor: str, input: dict, wait_secs: int):\n    \"\"\"Return a list of dataset items or {'datasetItems': [...]} for profile calls.\"\"\"\n```\n\n昵称或抖音号还需要搜索 adapter：\n\n```bash\npython3 scripts/run_pipeline.py \\\n  --creator <nickname> \\\n  --adapter my_adapter:call_actor \\\n  --browser-adapter my_adapter:search_creator\n```\n\n`search_creator(*, query: str, max_results: int)` 应返回包含公开主页 URL 的文本、列表或字典。\n\n## 参数\n\n| 参数 | 说明 | 默认值 |\n|---|---|---|\n| `--creator` | 主页 URL、`sec_uid`、完整分享消息；adapter 模式也可接受抖音号或昵称 | 必填 |\n| `--dry-run` | 非联网解析检查 | 与 `--browser`、`--adapter` 三选一 |\n| `--browser` | 使用已授权浏览器 profile 采集公开主页 | 与 `--dry-run`、`--adapter` 三选一 |\n| `--browser-profile` | 可选的 Playwright persistent profile 目录 | 默认复用 favorites profile |\n| `--headed` | 显示浏览器窗口，用于诊断登录/验证码 | 默认隐藏 |\n| `--adapter` | Apify 或其他外部真实采集 adapter，`module:function` | 与 `--dry-run`、`--browser` 三选一 |\n| `--browser-adapter` | 昵称/抖音号搜索 adapter | 可选 |\n| `--max-videos` | 请求的视频上限 | 1000 |\n| `--transcript-count` | 请求的转写候选数；指定时覆盖自动分档 | 按账号规模自动选择 |\n| `--transcript-mode` | `cloud` 默认 SiliconFlow 上传 ASR（抖音 CDN）+ 可选百炼公网直链 + local fallback；`local` Whisper；`index` 只做信息索引 | setup 选择，未配置时为 `cloud` |\n| `--no-local-fallback` | 云端 ASR 全部失败时不回退本地 Whisper | 关闭 |\n| `--max-duration` | 选择阶段的时长上限，分钟 | 5 |\n| `--output-dir` | Creator Insight 专用报告目录 | `./output/creator-insight` |\n| `--format` | `html json md` 的任意组合 | 全部 |\n\n## 本地验证\n\n测试完全使用 fixtures，不调用抖音或 Apify，也不需要 token。\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nCI 在 Python 3.10 和 3.12 上执行同一套测试。测试覆盖：\n\n- CLI 显式模式契约和退出码；\n- dry-run 不写输出；\n- 10 条 fixture 视频到三格式报告的端到端链路；\n- Skill 元数据、私人绝对路径和常见 secret 模式扫描。\n\n## 数据源与成本\n\n浏览器模式不需要 Apify key，边界是用户已授权浏览器可访问的公开主页。默认 cloud ASR：抖音 CDN 走 SiliconFlow `SenseVoiceSmall`；百炼 `qwen3-asr-flash` 仅公网直链媒体；**费用**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。 其它（如 Apify）价格、地域和免费额度会变化，实际扣费以所用平台（SiliconFlow / 百炼）控制台账单为准。默认 actor 和 fallback 见 [references/apify-douyin-actors.md](references/apify-douyin-actors.md)。Actor 的可用性、输入 schema、价格和账户额度会变化；运行前应在对应 Apify Actor 页面核验，并先用小样本测试。仓库不承诺固定耗时、费用或免费额度。\n\n## 输出与示例\n\n| 文件 | 用途 |\n|---|---|\n| [docs/sample-report.html](docs/sample-report.html) | HTML 报告示例 |\n| [docs/sample-report.md](docs/sample-report.md) | Markdown 摘要示例 |\n| [docs/sample-report.json](docs/sample-report.json) | 结构化数据示例 |\n\n报告中的互动排序是研究启发式，不代表推荐系统权重，也不构成商业、投资或平台增长保证。\n\n## 已知边界\n\n- 上游字段或 Actor 行为变化可能导致质量门阻断。\n- 昵称搜索可能触发验证码，也可能产生同名候选；浏览器模式不会搜索或自动选择，需改贴主页或分享链接。\n- 无旁白、纯音乐、未配置云端 Key 或上游转写失败的视频可能没有 transcript。未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` 时真实运行会安全停止并提示官方申请入口，不会自动下载视频。\n- 未指定 `--transcript-count` 时：30 条及以下全量转写；31-100 条按点赞前 50；101-300 条选 60 条；301-800 条选 80 条；更大账号最多选 100 条。大账号样本按点赞、收藏与近期作品分层去重，避免只偏向历史爆款。\n- 浏览器模式会记录主页声明作品数、实际采集数和分页状态。达到请求上限而尚有下一页时，结果为 `partial`，不能作为全量结论。\n- 收藏 skill 是可选共享底座，不是前置依赖；同时安装时先运行 `scripts/integration.py` 探测 profile 占用和输出布局。浏览器模式不会读取或导出 cookie。\n- 私密账号、绕过访问控制和未授权批量采集不在支持范围内。\n\n## 安全与贡献\n\n安全问题请按 [SECURITY.md](SECURITY.md) 私下报告。开发与 PR 约定见 [CONTRIBUTING.md](CONTRIBUTING.md)。\n\n## License\n\n[MIT](LICENSE)\n\n## SiliconFlow\n\n- 注册推荐链接：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n### ASR 媒体与码率（1.3.5+）\n- **单一路径**：下载 `video_url` → `ffmpeg -vn` 抽音 → 上传 SenseVoice。\n- **不再优先** `audio_url` / `music.play_url`（常为商业 BGM）。\n- `DOUYIN_ASR_AUDIO_BITRATE`（默认 64k）、`DOUYIN_ASR_SAMPLE_RATE`（默认 16000）。\n- 推荐注册：https://cloud.siliconflow.cn/i/1srulim9\n\nFile v1.3.6:_meta.json\n\n{\n  \"ownerId\": \"kn7fgfkjyfqbz673wvzymh5e1x821vpk\",\n  \"slug\": \"douyin-creator-insight\",\n  \"version\": \"1.3.6\",\n  \"publishedAt\": 1785933757389\n}\n\nFile v1.3.6:references/apify-douyin-actors.md\n\n# Apify Douyin Actors 对照表\n\n## 三个核心 actor\n\n### 1. `zen-studio/douyin-profile-scraper` ⭐ 主用\n\n**用途**：抓取指定博主的所有视频列表\n\n**输入**：\n```json\n{\n  \"maxPostsPerProfile\": 200,\n  \"profileUrls\": [\"https://www.douyin.com/user/MS4w...\"]\n}\n```\n\n**输出字段**：\n```json\n[\n  {\n    \"id\": \"7600998358588812742\",\n    \"text\": \"视频文案/描述\",\n    \"title\": \"标题\",\n    \"createTime\": 1737638400,\n    \"createDate\": \"2025-01-23\",\n    \"statistics\": {\n      \"diggCount\": 12345,\n      \"commentCount\": 678,\n      \"shareCount\": 90,\n      \"collectCount\": 234,\n      \"playCount\": 567890\n    },\n    \"videoMeta\": {\n      \"duration\": 120000,\n      \"cover\": \"https://...\"\n    },\n    \"hashtags\": [{\"name\": \"...\"}],\n    \"series\": {\"name\": \"...\"},\n    \"shareUrl\": \"https://...\",\n    \"authorMeta\": {\n      \"name\": \"...\",\n      \"signature\": \"...\",\n      \"followersCount\": 333000,\n      \"heartCount\": 2672708,\n      \"awemeCount\": 200\n    }\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。公开视频、README 和教程里不要承诺固定成本；第一次建议先小样本验证。\n\n**限制**：maxPostsPerProfile 上限 200\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-profile-scraper\",\n    input={\n        \"maxPostsPerProfile\": 200,\n        \"profileUrls\": [profile_url]\n    },\n    wait_secs=45\n)\n```\n\n### 2. `zen-studio/douyin-transcripts-scraper` ⭐ 主用转写\n\n**用途**：抓取视频语音转写；当前限制以 Actor 页面为准\n\n**输入**：\n```json\n{\n  \"targetLanguage\": \"zh\",\n  \"videoUrls\": [\"https://www.douyin.com/video/7575296454722398441\", ...]\n}\n```\n\n**输出**：\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"...\",\n    \"text\": \"完整转写文本...\",\n    \"duration\": 812,\n    \"segments\": [{\"start\": 0, \"end\": 5.2, \"text\": \"...\"}, ...]\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-transcripts-scraper\",\n    input={\n        \"targetLanguage\": \"zh\",\n        \"videoUrls\": [video_url1, video_url2, ...]\n    },\n    wait_secs=45\n)\n```\n\n### 3. `apple_yang/douyin-transcripts-scraper` 备选\n\n**用途**：备用转写服务\n\n**输入**：\n```json\n{\n  \"videoUrl\": \"https://www.douyin.com/video/...\"\n}\n```\n\n**输出**：同上\n\n**限制**：历史测试中长视频支持不稳定；当前限制以 Actor 页面为准\n\n**价格**：以 Apify Actor 当前页面为准。\n\n## 备选 actor（不推荐）\n\n### `bovi/douyin-scraper`\n- 优点：功能多\n- 缺点：`user_videos` 模式 2026 起需要登录 cookies，已验证空结果\n- 不推荐\n\n### `sian.agency/douyin-scraper`\n- 优点：支持 userVideos\n- 缺点：可能排队较久，且可能需要登录 cookies\n- 不推荐\n\n### `apify--rag-web-browser`\n- 用途：网页搜索 + 渲染\n- 兜底方案：当 profile scraper 失败时用此搜索主页\n- 调用示例：\n```python\napify_browser(\n    query=\"https://www.douyin.com/user/MS4w...\",\n    max_results=1\n)\n```\n\n## 经验教训\n\n1. **优先用 zen-studio 系列**，但运行前核对当前访问要求与输入 schema\n2. **user_videos 模式 = 需要登录**（2026 现状）→ 慎用 bovi/sian.agency\n3. **转写超时**：降低样本或候选时长，并核对 Actor 当前限制\n4. **TOON 格式**：Apify 返回的是 TOON 格式，需要手动解析（见 `data-schema.md`）\n5. **字段 schema 不稳定**：不同 actor 返回字段名差异大，需要多别名解析（见 `parser.py::_extract_field`）\n\n## 失败兜底顺序\n\n```\nzen-studio profile scraper (主)\n  ↓ 失败\napify--rag-web-browser 渲染主页\n  ↓ 失败\nWebSearch + 用户手动提供数据\n```\n\n```\nzen-studio transcripts scraper (主)\n  ↓ 失败\napple_yang transcripts scraper (备用，限制以当前 Actor 页面为准)\n  ↓ 失败\n跳过该视频，继续下一个\n```\n\nFile v1.3.6:references/categorization-taxonomy.md\n\n# Categorization Taxonomy · 内容分类体系\n\n## 规则标签关键词（`categorizer.py::CATEGORY_KEYWORDS`）\n\n### 进外企方法\n- `进外企` / `如何进入` / `外企面试` / `外企推荐` / `简历` / `英文` / `雅思` / `BEC` / `外企 title`\n\n### 外企清单\n- `外企清单` / `小而美` / `推荐名单` / `十大城市` / `十个城市` / `城市知名` / `最佳雇主` / `福布斯`\n\n### 福利揭秘\n- `福利` / `待遇` / `15 天年假` / `年假` / `加班` / `年终奖` / `六险一金` / `补充医疗`\n\n### 跳槽/转行\n- `跳槽` / `转型` / `转行` / `准备` / `实操` / `拿下`\n\n### 英语学习\n- `英语` / `英文` / `口语` / `听力` / `职场英语` / `BEC`\n\n### 认知/成长\n- `认知` / `成长` / `心法` / `建议` / `格局`\n\n### 母婴/育儿\n- `母婴` / `育儿` / `宝宝` / `宝贝` / `妈妈`\n\n### 宠物/动物\n- `宠物` / `猫` / `狗` / `皇家` / `玛氏`\n\n### 美食/食品\n- `美食` / `食品` / `食谱` / `厨房`\n\n### 数码/3C\n- `数码` / `3C` / `手机` / `电脑` / `评测`\n\n## 标签来源\n\n| source | 说明 | 示例 |\n|---|---|---|\n| `rule` | 规则关键词匹配 | `进外企方法` |\n| `hashtag` | 来自视频 hashtag | `#外企` → 进外企方法 |\n| `series` | 来自合集名 | `英语学习与提升` → 合集: 英语学习与提升 |\n| `llm` | LLM 主题分类 | 由 LLM 补充 |\n\n## LLM 分类提示词\n\n`categorizer.py::build_categorization_prompt` 生成的提示词：\n\n```python\nprompt = \"\"\"你是一个抖音内容分析专家。请基于以下 {N} 个视频的信息，把它们分到合适的类别。\n\n# 任务\n1. 输出主分类（每个视频 1 个）：进外企方法 / 外企清单 / 福利揭秘 / 跳槽转行 / 英语学习 / 母婴/育儿 / 其他\n2. 提取关键洞察：\n   - 博主主要面向谁（年龄/性别/职业）\n   - 3 个核心主题\n   - 5 条最有价值的视频标题\n   - 选题公式（爆款标题的共同特征）\n\n# 输出格式（JSON）\n{\n  \"main_categories\": [\"...\"],\n  \"audience\": \"...\",\n  \"core_themes\": [\"...\", \"...\", \"...\"],\n  \"top_5_videos\": [\"标题1\", \"标题2\", ...],\n  \"title_formula\": \"...\",\n  \"insights\": \"...\"\n}\n\"\"\"\n```\n\n## 扩展指南\n\n要新增分类：\n1. 在 `CATEGORY_KEYWORDS` 字典中添加新类别 + 关键词列表\n2. 重跑 `categorize_videos()` 即可\n\n要改 LLM 提示词：\n1. 修改 `build_categorization_prompt()` 函数\n2. 调用方传更多视频元数据\n\n## 实战经验\n\n- 史蒂文不做牛马账号的分类分布（200 条视频）：\n  - 英语学习与提升：42 条（合集）\n  - 职业规划与发展：36 条（合集）\n  - 认知与成长合集：5 条（合集）\n  - 外企清单散装：12+ 条\n  - 进外企方法散装：10+ 条\n  - 福利揭秘：5+ 条\n- 建议给 LLM 提供至少 10 条样本视频做分类\n- 主题分类后建议人工复核 TOP 5，确保准确\n\nFile v1.3.6:references/creator-resolution-playbook.md\n\n# Creator Resolution Playbook · 博主识别策略\n\n## 输入类型判定\n\n`resolver.py::parse_input_type` 判定逻辑：\n\n| 类型 | 正则 | 示例 |\n|---|---|---|\n| douyin_id | `^\\d{6,12}$` | `<douyin_id>`（如 `12345678`） |\n| sec_uid | `MS4w...` | `MS4wLjABAAA...` |\n| url | `https://(www\\.)?douyin\\.com/user/MS4w...` | `https://www.douyin.com/user/MS4wLjABAAA...` |\n| nickname | 含中英文 | `史蒂文不做牛马` |\n\n## 精准 vs 模糊匹配\n\n### 精准匹配（confidence ≥ 0.9）\n\nsec_uid 直接确认，不需问用户。\n\n```\n输入: MS4wLjABAAAA...<sec_uid>...   # 抖音内部唯一 ID\n→ 解析: sec_uid = MS4w...\n→ confidence = 0.95\n→ matched = True\n→ profile_url = https://www.douyin.com/user/MS4w...\n```\n\n### 模糊匹配（confidence < 0.9）\n\n用 `apify--rag-web-browser` 搜索：\n- query: `抖音 {creator_query}`\n- 解析搜索结果的 markdown\n- 提取候选人列表（昵称 + 简介 + 粉丝数）\n\n```\n输入: {nickname}                 # 示例：史蒂文不做牛马\n→ 搜索: 抖音 {nickname}\n→ 候选 1: {nickname} · {signature} · {followers} → confidence 0.95\n→ 候选 2: 其他同名账号\n→ 选 #1，自动继续\n```\n\n## 失败处理\n\n### 找不到任何人\n\n```\n输入: 不存在的昵称\n→ 搜索: 返回空\n→ matched = False\n→ AskUserQuestion 让用户重新输入\n```\n\n### 找到多个相似\n\n```\n输入: 小李\n→ 候选 5 个相似账号\n→ AskUserQuestion 让用户选\n→ 用户选 #3 → 用 sec_uid 继续\n```\n\n## 实战经验\n\n### 抖音号和 sec_uid 的区别\n\n- **抖音号**（douyin_id）：纯数字，用户可改，6-12 位\n  - 例：`<douyin_id>`（如 `12345678`）\n- **sec_uid**：抖音内部唯一 ID，MS4w 开头，不可改\n  - 例：`MS4wLjABAAAA...`（约 60 字符长）\n\n**profile scraper 必须用 sec_uid**，不能用抖音号。\n\n### 已知搜不到的输入\n\n- 短链（`v.douyin.com/xxx`）需要先 WebFetch 解析\n- 长 URL（带 modal_id 参数）可能是视频 ID\n- 纯数字 < 6 位大概率不是抖音号\n\n### 实战踩坑\n\n1. **抖音号搜不到人**：用户可能改了 douyin_id，但 sec_uid 不变。永远用 sec_uid。\n2. **同名账号**：很多用户取相似昵称，需要看签名 + 粉丝数判定。\n3. **博主已注销**：可能抓不到视频。提示用户确认。\n\n## 关键代码\n\n`scripts/resolver.py`：\n- `parse_input_type(user_input)`: 识别输入类型\n- `resolve_creator_via_apify(...)`: 主入口\n- `_resolve_via_apify_search(...)`: 模糊匹配逻辑\n- `format_resolution_for_question(...)`: 转 AskUserQuestion 选项\n\nFile v1.3.6:references/data-schema.md\n\n# Data Schema · 字段映射\n\n## Apify profile scraper → 标准化字段\n\n不同 actor 字段名差异（已实测）：\n\n| 标准化字段 | zen-studio | bovi | sian.agency | TOON 解析后 |\n|---|---|---|---|---|\n| aweme_id | id | aweme_id | videoId | id |\n| title | title | (空) | (空) | title |\n| desc | text | desc | desc | text |\n| create_time | createTime | create_time | timestamp | createTime |\n| duration_ms | videoMeta.duration | video.duration | duration | videoMeta.duration |\n| cover_url | videoMeta.cover | video.cover | coverUrl | videoMeta.cover |\n| share_url | shareUrl | share_url | url | shareUrl |\n| hashtags | hashtags[].name | (空) | (空) | hashtags.name |\n| series_name | series.name | (空) | (空) | series.name |\n| digg_count | statistics.diggCount | aweme_stats.digg_count | stats.like | statistics.diggCount |\n| comment_count | statistics.commentCount | aweme_stats.comment_count | stats.comment | statistics.commentCount |\n| share_count | statistics.shareCount | aweme_stats.share_count | stats.share | statistics.shareCount |\n| collect_count | statistics.collectCount | aweme_stats.collect_count | stats.favorite | statistics.collectCount |\n| play_count | statistics.playCount | aweme_stats.play_count | stats.view | statistics.playCount |\n\n## TOON 格式示例\n\nApify `get_dataset_items` 返回的是 TOON 格式（不是 JSON）：\n\n```toon\nitems[200]:\n  - id: \"7600998358588812742\"\n    text: \"进外企真的不难\"\n    createTime: 1737638400\n    statistics:\n      diggCount: 42451\n      commentCount: 1500\n      shareCount: 800\n      collectCount: 24647\n    videoMeta:\n      duration: 240000\n      cover: \"https://...\"\n    hashtags:\n      - name: \"外企\"\n      - name: \"求职\"\n    authorMeta:\n      name: \"史蒂文不做牛马\"\n      signature: \"在七种不同国别外企混迹的牛马一枚\"\n      followersCount: 333000\n      heartCount: 2672708\n```\n\n## 解析规则\n\n`scripts/parser.py::parse_toon_output` 实现：\n1. 用 `items[N]:` 作为块起点\n2. 用 `\\n  - id:` 作为分隔符切分 item\n3. 每行按 4 空格缩进解析 key-value\n4. 多层缩进（如 `statistics.diggCount`）用 `.` 合并为路径\n\n## transcripts scraper 输出\n\nzen-studio transcripts 返回格式：\n\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"视频标题\",\n    \"text\": \"完整转写文本\",\n    \"duration\": 812,\n    \"segments\": [\n      {\"start\": 0.0, \"end\": 5.2, \"text\": \"...\"},\n      ...\n    ],\n    \"errMsg\": null\n  }\n]\n```\n\n## 字段映射实现位置\n\n`scripts/parser.py::_extract_field()` 支持多路径：\n\n```python\n_extract_field(item, [\n    \"statistics.diggCount\",  # zen-studio\n    \"aweme_stats.digg_count\",  # bovi\n    \"stats.diggCount\",  # sian.agency\n])\n```\n\n按顺序尝试，找到第一个非空值。\n\nFile v1.3.6:references/failure-playbook.md\n\n# Failure Playbook · 失败场景手册\n\n## 1. 用户输入的抖音号找不到人\n\n**症状**：`resolve_creator_via_apify` 返回 `matched=False`\n\n**主策略**：\n- 用 `apify--rag-web-browser` 搜索 \"抖音 {creator_query}\"\n- 解析搜索结果，提取候选人列表\n\n**兜底**：\n- AskUserQuestion 列出 3-5 个候选，让用户确认\n- 用户确认后用 sec_uid 重新调用\n\n**关键代码位置**：`resolver.py::_resolve_via_apify_search`\n\n## 2. 视频列表抓不到 / 返回 0 条\n\n**症状**：`parse_actor_dataset` 返回空列表\n\n**原因**：\n- 用户输入的不是用户主页（可能是视频 URL）\n- Apify 账号额度耗尽\n- 抖音 API 反爬\n\n**主策略**：\n- 检查 `maxPostsPerProfile` 是否过大（> 500 容易失败）\n- 重试 + 减小数量\n\n**兜底**：\n- 用 `apify--rag-web-browser` 渲染主页，手动解析\n- 提示用户上传原始 JSON，走离线模式\n\n**关键代码位置**：`run_pipeline.py` Step 2\n\n## 3. 视频列表字段大量为空\n\n**症状**：parse 后大部分 video.title 或 stats 为空\n\n**原因**：\n- actor schema 变化\n- 字段别名没覆盖\n\n**主策略**：\n- 在 `parser.py::_extract_field` 增加新别名\n- 检查 TOON 解析是否有 bug\n\n**兜底**：\n- 保留 raw JSON，下次重试时直接复用\n- 用 `quality_gate.py::check_videos` 检测\n\n## 4. 语音转写全部失败\n\n**症状**：`fetch_transcripts` 返回空或全部 failed\n\n**主策略**：\n- 检查视频时长和 Actor 当前限制\n- 切换备用 actor（apple_yang）\n\n**兜底**：\n- 仅用标题 + 描述 + 互动数据分析，不依赖转写\n- 报告标注 \"transcripts_unavailable\"\n\n## 5. 视频没有旁白（音乐/纯画面）\n\n**症状**：transcript 返回空字符串\n\n**判断**：transcript text 长度 < 10 → 标记 `empty_transcript`\n\n**主策略**：\n- 跳过该视频的转写\n- 改用 title + desc + hashtags 做内容分析\n\n**兜底**：\n- 报告里标注\"无旁白视频\"\n- 用 B 站 / YouTube 等替代来源\n\n## 6. Apify 账号额度耗尽\n\n**症状**：所有 actor 调用都返回 4xx 错误\n\n**主策略**：\n- 减小 `max_videos` 和 `transcript_count`\n- 提示用户充值\n\n**兜底**：\n- 完全离线模式：用户上传历史 raw JSON，skill 仅做分析和报告\n- 使用用户提供的、已获授权的公开数据快照\n\n## 7. 字段 schema 突然变化\n\n**症状**：解析后大量字段为 None\n\n**主策略**：\n- 增加字段别名（参考 `data-schema.md`）\n- 保留 raw 字段，下次回放时排查\n\n**兜底**：\n- 用 `WebFetch` 抓主页 HTML 作为补充\n- 让用户手动提供关键视频 URL\n\n## 8. 时间相关问题\n\n- **createTime 是毫秒还是秒**？不同 actor 不同\n  - `parser.py::_format_date` 自动判断：> 10^12 是毫秒\n- **时长过滤**：默认筛选上限为 5 分钟，可按 Actor 当前限制调整\n  - `selector.py::apply_duration_penalty` 自动惩罚\n\n## 9. 网络/TLS 错误\n\n**症状**：MCP 调用超时或连接失败\n\n**主策略**：\n- 重试（最多 3 次）\n- 切换备用 actor\n\n**兜底**：\n- WebSearch 抓搜索结果页（`apify--rag-web-browser`）\n- 让用户提供手动数据\n\n## 10. 报告生成失败\n\n**症状**：`save_reports` 报错\n\n**主策略**：\n- 检查磁盘空间\n- 检查文件权限\n\n**兜底**：\n- 只生成 JSON 格式（最小输出）\n- 用 `cat > output.json` 直接写文件\n\n## 通用诊断流程\n\n```\n1. 检查 Apify token 是否有效\n2. 检查网络连接（clash verge / proxy）\n3. 用 `quality_gate.run_quality_gate` 检测哪阶段失败\n4. 查本 playbook 找对应失败场景\n5. 实施主策略\n6. 如果失败，启用兜底\n7. 报告失败原因给用户\n```\n\n## 关键代码位置速查\n\n| 失败阶段 | 主要函数 | 兜底函数 |\n|---|---|---|\n| 解析博主 | `resolver.resolve_creator_via_apify` | `_resolve_via_apify_search` |\n| 抓视频 | `parser.parse_actor_dataset` | `apify_browser` |\n| 字段解析 | `parser._extract_field` | 保留 raw |\n| 选精华 | `selector.select_essentials` | 仅按点赞排序 |\n| 转写 | `transcript.fetch_transcripts` | 切换 actor |\n| 报告 | `report_builder.save_reports` | 单独保存 |\n\nFile v1.3.6:references/pre-questions.md\n\n# Pre-questions · AskUserQuestion 模板\n\n## 问询原则\n\n自然语言优先。只有用户没有给目标账号、昵称搜索出现多个候选、或用户要求控制规模/成本时，才提问。默认参数不要逐项打断用户。\n\n推荐输入优先级：\n\n1. 抖音主页 URL\n2. `sec_uid`\n3. 抖音号 / ID\n4. 昵称\n\n昵称支持搜索，但同名账号较多；如果置信度不够，需要让用户确认候选。\n\n## 必填信息\n\n### Q1: 用户输入（creator_query）\n\n```\n\"请提供抖音号 / 昵称 / 主页 URL\"\n```\n\n接受输入格式：\n- 抖音号（纯数字 6-12 位）：如 `<douyin_id>`（如 `12345678`）\n- sec_uid（MS4w 开头）：如 `MS4wLjABAAA...`\n- 昵称：如 `史蒂文不做牛马`\n- 主页 URL：如 `https://www.douyin.com/user/MS4w...`\n\n如果用户已经在一句话里给出上述任意信息，不需要再问 Q1。\n\n## 条件必填（仅当模糊匹配时）\n\n### Q2: 候选博主确认\n\n```\n\"找到几个相似的博主，请确认哪个是您要的：\"\n```\n\n- option1: <nickname1> <signature1> · 粉丝 X 万\n- option2: <nickname2> <signature2> · 粉丝 Y 万\n- ...\n\n## 默认参数（通常不问，直接采用）\n\n### Q3: 抓取视频条数\n\n```\n\"要抓取多少条最新视频？\"\n- 推荐（200 条）\n- 深度（500 条）\n- 快速（50 条）\n```\n\n默认：200\n\n### Q4: 语音转写条数\n\n```\n\"要抓取多少条精华视频的语音转写？\"\n- 5 条（推荐）\n- 10 条\n- 全部精华（可能耗时）\n```\n\n默认：5\n\n### Q5: 转写时长上限（分钟）\n\n```\n\"转写候选的视频时长上限？\"\n- 5 分钟（默认，用于控制样本规模）\n- 10 分钟\n- 不限（可能显著增加资源消耗）\n```\n\n默认：5\n\n### Q6: 研究目标\n\n```\n\"主要研究目标？\"\n- 综合洞察（推荐）\n- 选题拆解\n- 爆款分析\n```\n\n默认：综合洞察\n\n### Q7: 输出格式\n\n```\n\"输出哪些格式的报告？\"\n- HTML（可视化）\n- Markdown（快读）\n- JSON（数据分析）\n```\n\n默认：全部\n\n### Q8: 输出目录\n\n```\n\"报告保存到哪里？\"\n```\n\n默认：当前工作目录 `./output/`\n\n## 什么时候主动改成小样本\n\n用户出现这些意图时，建议先小样本：\n\n- “先试一下”\n- “省额度”\n- “先看看能不能跑通”\n- “教程演示”\n\n推荐小样本：`max_videos=50`、`transcript_count=1`。如果用户明确说完整分析或未指定规模，则使用默认 `max_videos=200`、`transcript_count=5`。\n\n## 完整调用示例\n\n```python\nfrom AskUserQuestion import ask_user_questions\n\nquestions = [\n    {\n        \"key\": \"creator_query\",\n        \"question\": \"请提供抖音号 / 昵称 / 主页 URL\",\n        \"required\": True,\n    },\n    {\n        \"key\": \"max_videos\",\n        \"question\": \"要抓取多少条最新视频？\",\n        \"default\": 200,\n        \"options\": [50, 100, 200, 500],\n    },\n    # ...\n]\n\nanswers = ask_user_questions(questions)\n```\n\nFile v1.3.6:references/report-rubric.md\n\n# Report Rubric · 报告标准\n\n## 报告结构\n\n### HTML 报告章节\n\n```\n1. Hero（封面）\n   - 博主头像 + 昵称 + sec_uid\n   - 4 个数据卡片：粉丝/获赞/视频数/转写数\n   - 个人简介（signature）\n\n2. 摘要\n   - 报告基于 N 条视频 + M 条转写\n   - 报告时点\n\n3. 主题分类（如有）\n   - 每个分类：名称 + 视频数 + TOP 5 视频列表\n\n4. 精华视频语音转写\n   - 每条视频卡片：\n     - 创建日期\n     - 互动数据（点赞/收藏）\n     - 转写状态（success/empty/failed）\n     - 标题\n     - 完整转写（可折叠）\n\n5. 互动 TOP 视频（表格）\n   - 列：# / 标题 / 日期 / 👍 / ⭐ / 💬\n   - 默认 TOP 40\n\n6. 数据来源 + 方法\n   - Apify actor 列表\n   - 互动分公式\n   - 报告生成时间\n```\n\n### Markdown 报告章节\n\n```\n1. # 标题\n2. ## 📊 账号概况（表格）\n3. ## 🏷️ 主题分类（每类列表）\n4. ## 🎙️ 精华视频语音转写（每条）\n5. ## 🏆 互动 TOP 视频（表格）\n6. ## 📖 数据来源\n```\n\n### JSON 数据包结构\n\n```json\n{\n  \"creator\": {...},\n  \"videos\": [...],\n  \"transcripts\": [...],\n  \"categories\": {...},\n  \"top_videos\": [...],\n  \"research_goal\": \"creator_insight\",\n  \"generated_at\": \"ISO 8601\"\n}\n```\n\n## 视觉规范\n\n### 配色\n\n| 用途 | 颜色 |\n|---|---|\n| 主背景 | 渐变 `#f5f7fa → #e8ecf3` |\n| 头部 | 渐变 `#1e3a8a → #5b21b6`（深紫蓝） |\n| 标题色 | `#1e293b` |\n| 强调色 | `#5b21b6` |\n| 链接色 | `#3730a3` |\n| 警告色 | `#f59e0b` |\n| 转写框 | `#fffbeb`（米黄） |\n| 点赞数 | `#ef4444`（红） |\n| 收藏数 | `#f59e0b`（橙） |\n\n### 字号\n\n| 元素 | 字号 |\n|---|---|\n| Hero h1 | 32px |\n| section h2 | 26px |\n| section h3 | 20px |\n| section h4 | 17px |\n| 正文 | 16px |\n| 视频元信息 | 13px |\n\n### 间距\n\n- section padding: 50px 40px\n- 卡片 padding: 14-22px\n- 段落间距: 12-18px\n\n## 数据准确度标准\n\n### 必须保留的字段\n\n- `aweme_id`（必填）\n- `stats.digg_count` / `comment_count` / `share_count` / `collect_count`\n- `create_date`（YYYY-MM-DD 格式）\n- `duration_seconds`（如可用）\n\n### 应当标注的状态\n\n- 转写状态：`success` / `failed` / `empty_transcript` / `skipped`\n- 匹配度：5★ / 4★ / 3★\n- 数据来源：zen-studio / apple_yang / bovi 等\n\n## 输出文件命名\n\n```\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.html\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.md\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.json\n```\n\n例：`史蒂文不做牛马_douyin_insight_20260709_093200.html`\n\n## 性能记录\n\n不设置未经基准测试的固定耗时。每次真实运行应记录样本量、Actor、开始/结束时间、失败数和输出大小；不同账号、网络、Actor 队列和上游 schema 下的结果不可直接类推。\n\n## 测试用例\n\n使用 `tests/test_pipeline.py` 中的合成 fixture 作为可重复测试。真实公开账号报告只作为展示样例，不作为性能基准。\n\n## 复用模板\n\n`scripts/report_builder.py` 内置 HTML/MD 模板，无需额外 assets/ 依赖。\n\n如果需要自定义样式：\n1. 复制 `HTML_TEMPLATE` 到 `assets/report_template.html`\n2. 修改后用 `jinja2` 或其他模板引擎渲染\n3. 当前实现用纯 Python `str.format()`，无 jinja 依赖\n\nFile v1.3.6:CHANGELOG.md\n\n# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [1.3.6] - 2026-08-05\n\n### Changed\n- setup / run 缺 Key 时输出 ①推荐注册页 → ②控制台建 Key → ③export 三步指引；交互终端可询问并打开 `https://cloud.siliconflow.cn/i/1srulim9`。\n\n## [1.3.5] - 2026-08-05\n\n### Changed\n- ASR 简化为单一稳定路径：只下 `video_url` → ffmpeg 抽音 → SenseVoice；去掉 `audio_url` 优先分支（常为 BGM）。\n\n## [1.3.4] - 2026-08-05\n\n### Changed\n- ASR：优先 `audio_url`，失败回退 `video_url`；`DOUYIN_ASR_AUDIO_BITRATE` / `DOUYIN_ASR_SAMPLE_RATE` 可配。\n- 采集：仅原创音写入 `audioUrl`，避免商业 BGM 误当口播。\n\n## [1.3.3] - 2026-08-05\n\n### Changed\n- 文档加入 SiliconFlow 注册推荐链接：https://cloud.siliconflow.cn/i/1srulim9\n\n## [1.3.2] - 2026-08-05\n\n### Changed\n- 文档补齐 SiliconFlow 费用说明：截至 2026-08-05 官方价格页 `FunAudioLLM/SenseVoiceSmall` 标注**免费**（https://siliconflow.cn/pricing；会变，以账单为准，不承诺永久免费）。\n\n## [1.3.1] - 2026-08-05\n\n### Fixed\n- 清除 README / CLI help / mcp.json.example 中残留的「cloud 默认百炼」表述，与 1.3.0 SiliconFlow 主路径对齐。\n\n## [Unreleased]\n\n## [1.3.0] - 2026-08-05\n\n### Fixed（面向公开用户的关键纠错）\n\n- **抖音 CDN 云端转写默认路径错误**：此前文档与 setup 将「阿里云百炼 URL-ASR」宣传为推荐主路径。实测百炼服务端无法拉取 `*.douyinvod.com`，会稳定失败；公开用户按文档只配 `DASHSCOPE_API_KEY` 时几乎转不出文案。\n- **硬闸只认百炼 Key**：`run_pipeline` 在已配置 `SILICONFLOW_API_KEY` 时仍因缺少 `DASHSCOPE_API_KEY` 直接退出。\n- **媒体下载 403**：云端上传 / 本地 Whisper 下载缺少 `Referer: https://www.douyin.com/`，导致 SiliconFlow 回退也失败。\n\n### Changed\n\n- 抖音保护媒体：**优先 SiliconFlow 上传 ASR**；默认跳过百炼 URL（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n- `cloud` 就绪条件：`SILICONFLOW_API_KEY` **或** `DASHSCOPE_API_KEY`。\n- setup / README / SKILL：明确推荐 SiliconFlow 为抖音路径；百炼降为可选公网 URL 路径。\n- `cloud_asr_configured` 同时探测两种 Key。\n\n### Notes\n\n- 两家不是同一模型：百炼默认 `qwen3-asr-flash`；SiliconFlow 默认 `FunAudioLLM/SenseVoiceSmall`；账单分离。\n\n\n## [1.2.3] - 2026-08-01\n\n### Removed\n- Removed the internal `task_plan.md` process artifact from the public package.\n\n## [1.2.2] - 2026-08-01\n\n### Added\n- First-run `scripts/setup.py` for explicit `cloud` / `local` / `index` selection, with non-secret config persistence.\n- Setup and integration detection for existing `douyin-favorites-to-knowledge` installs, shared browser profiles, and reusable transcription preference.\n- Bailian API Key guidance when `DASHSCOPE_API_KEY` is missing.\n\n### Fixed\n- Missing cloud ASR credentials no longer trigger an implicit local Whisper fallback or video download; users must explicitly choose `local`.\n\n## [1.2.1] - 2026-08-01\n\n### Added\n- Adaptive transcript selection: accounts with 30 or fewer videos use all-video transcription; larger accounts use bounded, deduplicated layers of likes, saves, and recent posts.\n- Selection metadata is included in JSON results and summarized in HTML and Markdown reports.\n- Browser collection records declared work count, collected count, and pagination completion; capped collections return `partial`.\n- Independent `cloud`, `local`, and `index` transcript modes. Cloud is the default, local Whisper is a final fallback, and index mode never invokes ASR.\n- Non-mutating integration probe, neutral browser profile for standalone installs, shared-profile busy detection, and isolated Creator Insight output.\n\n### Fixed\n- Skill runtime now auto-loads ASR/browser profile config from standard local env files, so Hermes launcher env gaps no longer collapse cloud ASR into `not_configured`.\n- Profile metadata extraction now prefers exact `sec_uid` matches over sec_uid-less wrapper objects.\n- Profile API author metadata now wins over per-post author fields when merging declared counts and account stats.\n- Timed-out or error-shaped transcript payloads are marked failed and excluded from report text.\n- Missing transcript actor results now receive an explicit per-video failure status.\n- Transcript quality failures return `degraded` instead of ordinary success, with provider and quality details in the result.\n\n### Changed\n- `douyin-knowledge-base-pipeline` and `douyin-mcp` are optional integrations, not installation or runtime dependencies.\n- Cloud ASR first attempts DashScope URL recognition, then an optional temporary-audio cloud upload for large media; temporary media is always cleaned.\n- Reissued the final runtime-env hardening package as `v1.2.1` because ClawHub had already accepted an earlier `1.2.0` package and does not allow overwriting an existing version.\n\n## [1.1.0] - 2026-07-30\n\n### Added\n- Browser-first public creator collection: accepts profile URLs, `sec_uid`, and complete Douyin share messages containing `v.douyin.com` links.\n- `--browser`, `--browser-profile`, and `--headed` CLI options. The collector reuses the existing favorites persistent profile, fetches public post pages in browser context, locally caps and deduplicates results, and verifies every item's author `sec_uid`.\n\n### Changed\n- Apify is an explicit adapter fallback, not a default dependency for public creator collection.\n- Nickname and Douyin-ID searches never auto-select an account; the workflow asks for a stable profile/share link when search is ambiguous or blocked by CAPTCHA.\n- Reports state their actual collection and transcript sources. Browser-mode reports explicitly mark transcript candidates as skipped when no transcription provider is configured.\n\n## [1.0.2] - 2026-07-25\n\n### Changed\n- Updated official GitHub Actions to their Node 24 releases to remove hosted-runner deprecation warnings.\n\n## [1.0.1] - 2026-07-25\n\n### Fixed\n- CLI now requires explicit `--dry-run` or `--adapter module:function`; a real-looking command can no longer silently return a dry-run result.\n- Added fixture-based end-to-end tests and subprocess tests for CLI exit behavior.\n- Removed unbenchmarked timing, cost, quota, and free-tier promises from current documentation.\n\n### Added\n- GitHub Actions on Python 3.10 and 3.12.\n- Repository checks for Skill metadata, private absolute paths, and common live-secret patterns.\n- Security policy and explicit credential-handling guidance.\n\n## [1.0.0] - 2026-07-15\n\n### Added\n- 🎉 **首次公开发布**\n- 5 阶段 pipeline：resolver → parser → selector → transcript → categorizer → report_builder\n- 9 个核心脚本（schemas / resolver / parser / selector / transcript / categorizer / report_builder / quality_gate / run_pipeline）\n- 7 份 references 文档（pre-questions / apify-douyin-actors / data-schema / creator-resolution-playbook / categorization-taxonomy / report-rubric / failure-playbook）\n- 3 套 assets 模板（report_template.html / report_style.css / creator_card_template.html）\n- 三格式输出：HTML（可视化）+ Markdown（快读）+ JSON（数据分析）\n- 智能精华选择：互动分公式 `log(点赞)*1 + log(评论)*2.5 + log(分享)*3 + log(收藏)*2`\n- 多 actor 兜底：zen-studio 主用 → sian.agency 备选 → apify--rag-web-browser 渲染\n- 模糊匹配候选：置信度 < 0.9 时返回 3-5 个候选让用户确认\n\n### Documentation\n- README.md 加 4 大徽章（License / Python 版本 / 零依赖 / Apify 必需）\n- 加 demo 报告区（docs/sample-report.{html,md,json}）\n- 加初版额度预估表（因缺少可复现实验依据，已在 v1.0.1 删除）\n- 加 6 条 FAQ（覆盖 dry-run / 额度 / 输入选择 / empty_transcript / 私密账号 / 与 douyin-workflow 区别）\n- 加环境自检脚本\n- SKILL.md 加\"⚠️ 前置条件\"章节（4 步检查清单）\n- SKILL.md 加\"⚡ 失败兜底速查\"表格（5 行版本）\n\n### Notes\n- 零 Python 三方依赖（用 dataclasses + 标准库）\n- 需要 Apify token + Apify MCP（详见 mcp.json.example）\n- 初版包含固定额度估算；v1.0.1 起改为运行前核对 Actor 页面并以本次实测为准\n\nArchive v1.3.5: 40 files, 98791 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (8248b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (11909b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (20941b), scripts/browser_collector.py (13558b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8189b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (19121b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (8099b), scripts/setup.py (7202b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2825b), SKILL.md (9868b), tests/test_pipeline.py (18901b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nFile v1.3.5:SKILL.md\n\n---\nname: douyin-creator-insight\nversion: 1.3.5\ndescription: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。\n---\n\n# Douyin Creator Insight\n\n## 使用条件\n\n仅分析公开可访问数据。默认真实抓取使用已授权的本地浏览器 profile，不依赖 Apify key；Apify 仅是显式 fallback。不要在对话、脚本、报告或仓库中输出 token、cookie、浏览器 profile、私人绝对路径或未公开内容。\n\n## 安装与共享配置\n\n`douyin-creator-insight` 可独立安装和运行，`douyin-favorites-to-knowledge`（旧名/旧目录可能是 `douyin-knowledge-base-pipeline`）不是前置依赖。若两者都存在，本 skill 只复用已登录的 persistent browser profile 和 ASR 环境变量，绝不读取收藏记录、修改增量 metadata，或加入收藏 skill 的 23:00 任务。\n\n首次运行先执行 `python3 scripts/setup.py`。它只写非敏感偏好：`cloud`（云端 ASR）/ `local`（Whisper）/ `index`（只索引），以及可选 profile/output 位置；不保存 API key、cookie 或 token。若检测到已安装 `douyin-favorites-to-knowledge`，优先复用其已登录浏览器 profile 和转录偏好，但状态、账本、输出和 23:00 任务仍完全隔离。\n\n**云端 ASR 真相（抖音）**：抖音 CDN（`*.douyinvod.com` 等）带防盗链，**阿里云百炼 URL-ASR 服务端拉不到媒体**，会稳定失败——不是用户 Key 配错。公开 skill 的默认可用路径是：\n\n1. **推荐 `SILICONFLOW_API_KEY`**：本机用浏览器式 `Referer: https://www.douyin.com/` 临时下载 → 抽音频 → 上传 SiliconFlow `FunAudioLLM/SenseVoiceSmall` → 立即清理临时文件。\n2. **可选 `DASHSCOPE_API_KEY`**：仅当媒体 URL 是第三方可公网直链时走百炼 URL-ASR；对抖音 CDN **默认跳过**（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n3. 至少配置上述之一才允许 `cloud` 真跑；**两者都缺**时停止，不下载、不静默切 Whisper。\n4. 云端都失败且用户允许 local fallback 时才进 Whisper；`index` 永不 ASR。\n\nSiliconFlow 控制台：`https://cloud.siliconflow.cn/account/ak`。百炼说明（可选）：`https://help.aliyun.com/zh/model-studio/get-api-key`。Key 放本机环境变量/Secret Manager，不要发聊天或进仓库。skill 自动读 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local`。运行前 `python3 scripts/integration.py`；共享 profile 被占用必须等待。报告写入独立 `<output-root>/creator-insight/`。\n\n> **ASR 费用（默认 SenseVoiceSmall）**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。\n\n\n- **SiliconFlow 注册推荐链接**：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n\nActor 的价格、配额、可用性和 schema 会变化。运行前查看当前 Actor 页面；任何费用或耗时只能作为本次运行的实测结果陈述，不能沿用固定承诺。\n\n## 输入\n\n从用户原话提取：\n\n- `creator_query`：优先主页 URL、`sec_uid`，或包含 `v.douyin.com` 的完整分享消息；脚本会提取短链接。\n- `max_videos`：默认 1000；用户要求省资源或试跑时降低。超过上限时结果必须标为 `partial`。\n- `transcript_count`：未指定时按作品数自动分档；用户显式指定时优先遵从。\n- `transcript_max_duration_minutes`：默认 5，用于候选筛选。\n- `transcript_mode`：`cloud`（默认）/ `local` / `index`。\n- `output_formats`：默认 `html`、`md`、`json`。\n- `output_dir`：默认当前任务的专用输出目录。\n\n主页 URL、分享短链接或 `sec_uid` 最稳定。昵称和抖音号只可用于候选确认，不能自动选择同名账号；搜索验证码或模糊结果时要求用户改贴主页/分享链接。\n\n## 流程\n\n1. 用 `scripts/resolver.py` 判断输入类型，并从分享消息提取短链接。\n2. 对 URL/短链接/`sec_uid`，优先运行 `scripts/run_pipeline.py --browser`。它在现有 persistent profile 的页面上下文读取公开作品分页，并验证每条返回视频的作者 `sec_uid`。\n3. 昵称或抖音号不可自动选人；搜索触发验证码、无候选或多个候选时停止并请求主页/分享链接。\n4. 用 `scripts/parser.py` 标准化字段，再执行 `quality_gate.py`。门禁失败时停止，不生成伪完整报告。\n5. `index` 模式跳过转写，只保留全量作品信息；其他模式用 `selector.py` 选择候选：30 条及以下全量转写；31-100 条按点赞前 50；更大账号按点赞、收藏和近期作品分层去重抽样（上限 100 条）。\n6. `cloud`（默认）对抖音 CDN 媒体：**优先 SiliconFlow 上传 ASR**（Referer 下载 + 抽音频 + 上传 + 清理）；**不把抖音 CDN URL 默认丢给百炼**。非抖音可公网媒体才先试百炼 URL-ASR。云端都失败才进入 `local` Whisper。`douyin-mcp` 不是依赖。再用 `categorizer.py` 分类、`report_builder.py` 输出真实 provider 状态与错误。\n\n## Tool 调用契约\n\nProfile actor 输入：\n\n```json\n{\n  \"maxPostsPerProfile\": 1000,\n  \"profileUrls\": [\"https://www.douyin.com/user/<sec_uid>\"]\n}\n```\n\n浏览器模式默认最多采集 1000 条；Apify 的实际上限、配额和字段以运行时 Actor schema 为准。任何触发上限、分页未完成或声明数无法对账的结果，都必须在报告的 `collection` 字段标为 `partial` 或 `reconciliation: unavailable`，不得写成全量完成。\n\nActor ID、输入字段和 fallback 以 [references/apify-douyin-actors.md](references/apify-douyin-actors.md) 为准。不要假设文档中的历史 actor 永久可用；调用失败时先核对 Actor 页面和返回 schema。\n\n## 质量门\n\n- 身份必须 matched，且含 `sec_uid` 或抖音号。\n- 视频列表不能为空；少于质量门默认阈值时阻断。\n- 超过一半的视频缺少标题与描述时阻断。\n- 转写成功率低于门槛时，报告必须明确降级或停止。\n- 低置信度身份不得自动选择。\n\n## 运行脚本\n\nAgent 已经完成采集后，可直接复用 `scripts/` 中的解析、筛选和报告函数。独立 CLI 必须显式选择一种模式：\n\n```bash\n# 非联网验证\npython3 scripts/run_pipeline.py --creator <profile_url> --dry-run\n\n# 默认真实路径：已登录浏览器中的公开主页接口\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py --creator '<share_or_profile_url>' --browser\n\n# 明确选择本地 Whisper 或纯信息索引\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode local\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode index\n\n# 使用显式 adapter 真实运行\npython3 scripts/run_pipeline.py \\\n  --creator <profile_url> \\\n  --adapter my_adapter:call_actor \\\n  --output-dir ./output\n```\n\n没有 `--dry-run`、`--browser` 或 `--adapter` 时，CLI 必须失败；不得把 dry-run 返回当成真实报告。\n\n## 失败处理\n\n| 场景 | 行为 |\n|---|---|\n| 找不到账号 | 返回候选或要求更稳定的主页 URL |\n| 浏览器 profile 未登录、主页接口失败 | 不要求复制 cookie；提示在已有 profile 中恢复登录或稍后重试 |\n| 昵称搜索验证码/同名 | 不绕过验证码，不自动选人；要求主页或分享链接 |\n| Profile actor 失败 | 核对 schema 后使用记录在 reference 中的 fallback |\n| 视频不足或字段异常 | 质量门阻断，保留原始响应供排查 |\n| 未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` | 停止真实转写；提示 SiliconFlow（抖音推荐）与可选百炼入口；不自动下载或切 Whisper |\n| 仅有 `DASHSCOPE_API_KEY`、无 SiliconFlow | 允许启动但告警：抖音 CDN 转写大概率失败 |\n| Cloud ASR 失败 | 仅在云端已配置但真实调用失败时记录错误，再回退本地 Whisper；`--no-local-fallback` 时只报告失败 |\n| 本地 Whisper 失败 | 清理临时媒体并标记 `failed` 或 `empty_transcript` |\n| 配额不足 | 停止真实调用，建议用户缩小样本或稍后重试 |\n| 输出写入失败 | 返回非成功状态和明确路径，不宣称完成 |\n\n## 验证\n\n修改 Skill 或脚本后必须运行：\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nfixture E2E 通过只证明本地编排契约正确，不证明第三方 Actor 当前可用。真实发布说明必须把两类证据分开。\n\n## 相关文档\n\n- `references/apify-douyin-actors.md`：Actor 与 fallback\n- `references/data-schema.md`：字段映射\n- `references/creator-resolution-playbook.md`：身份确认\n- `references/categorization-taxonomy.md`：分类规则\n- `references/report-rubric.md`：报告质量\n- `references/failure-playbook.md`：失败恢复\n- `SECURITY.md`：凭据与漏洞报告\n\n### ASR 媒体与码率（1.3.5+）\n- **单一路径**：下载 `video_url` → `ffmpeg -vn` 抽音 → 上传 SenseVoice。\n- **不再优先** `audio_url` / `music.play_url`（常为商业 BGM，多分支易踩坑）。\n- `DOUYIN_ASR_AUDIO_BITRATE`（默认 64k）、`DOUYIN_ASR_SAMPLE_RATE`（默认 16000）。\n- 推荐注册：https://cloud.siliconflow.cn/i/1srulim9\n\nFile v1.3.5:assets/README.md\n\n# Assets · 模板文件\n\n本目录存放报告生成所需的静态资源。\n\n## 文件清单\n\n- `README.md`：本说明\n- `report_template.html`：HTML 报告模板（参考用）\n- `report_style.css`：报告样式（参考用）\n- `creator_card_template.html`：博主封面卡片模板（参考用）\n\n## 当前实现\n\n**注意**：当前 `scripts/report_builder.py` 使用内置 Python 字符串模板，**不依赖** assets/ 目录。\nassets/ 中的文件仅作为参考 / 自定义起点。\n\n## 自定义指南\n\n如果需要自定义样式：\n\n### 方式 1：直接修改内置模板\n\n编辑 `scripts/report_builder.py::HTML_TEMPLATE`，调整 CSS 部分。\n\n### 方式 2：使用 jinja2 渲染\n\n1. 安装：`pip install jinja2`\n2. 把内置 HTML_TEMPLATE 复制到 `assets/report_template.html`\n3. 用 jinja2 渲染\n\n```python\nfrom jinja2 import Environment, FileSystemLoader\n\nenv = Environment(loader=FileSystemLoader('assets'))\ntemplate = env.get_template('report_template.html')\nhtml = template.render(\n    nickname=nickname,\n    followers=followers,\n    ...\n)\n```\n\n### 方式 3：完全重写\n\n如果需要差异化设计（如杂志风、暗色模式），可以：\n\n1. 创建新文件 `assets/report_template_magazine.html`\n2. 在 `scripts/report_builder.py` 中加 `build_html_report_magazine()`\n3. 调用方选择用哪个模板\n\n## 配色参考\n\n| 风格 | 配色 |\n|---|---|\n| 默认（深紫蓝） | `#1e3a8a → #5b21b6` |\n| 杂志风（暖色） | `#b45309 → #d97706` |\n| 暗色模式 | `#0f172a → #1e293b` |\n| 极简（白底） | `#f8fafc → #f1f5f9` |\n\n## 示例模板\n\n### 默认模板（已在 report_builder.py）\n\n```html\n<header class=\"hero\">\n    <h1>{{ nickname }} · 抖音内容洞察报告</h1>\n    <div class=\"creator-stats\">\n        <div class=\"stat\"><span class=\"num\">{{ followers }}</span></div>\n        ...\n    </div>\n</header>\n```\n\n### 杂志风模板（待创建）\n\n参考 `guizang-ppt-skill` 的杂志风风格。\n\nFile v1.3.5:README.md\n\n# Douyin Creator Insight\n\n从公开抖音主页、分享短链接或 `sec_uid` 出发，生成可审计的创作者内容洞察报告。默认使用已登录的本地浏览器 profile 读取公开作品；Apify 是可选 fallback。输出包含 HTML、Markdown 和 JSON。\n\n[![CI](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml/badge.svg)](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n\n## 能做什么\n\n- 解析主页 URL、`sec_uid` 和完整分享文案中的短链接；昵称或抖音号只用于人工候选确认，不自动选择同名账号。\n- 标准化不同数据源的视频字段。\n- 按账号规模自动选择转写候选：小账号全量转写，大账号以点赞、收藏和近期作品分层抽样。\n- 对解析、视频数量和转写质量执行阻断式质量门。\n- 生成 HTML、Markdown、JSON 三种报告。\n\n本项目只处理公开数据，不绕过登录、隐私或平台访问控制。\n\n## 安装与分发入口\n\n- Agent 一键安装：[ClawHub douyin-creator-insight](https://clawhub.ai/tars1230/skills/douyin-creator-insight)\n- 国内源码镜像：[Gitee tars123/douyin-creator-insight](https://gitee.com/tars123/douyin-creator-insight)\n- 源码与版本发布：[GitHub tars1230/douyin-creator-insight](https://github.com/tars1230/douyin-creator-insight)\n\n## 运行方式\n\n### 独立运行，可选复用收藏 skill\n\n本 skill 可以独立安装。第一次运行先执行 `python3 scripts/setup.py`，明确选择：\n\n- `cloud`：云端 ASR（默认）。**抖音场景推荐配置 `SILICONFLOW_API_KEY`**（本机带 Referer 临时下载 → 上传 SenseVoice → 清理）。\n- `local`：本地 Whisper。只有用户明确选择时才临时下载视频，结束后清理。\n- `index`：只索引标题、描述、互动数据和链接，不调用 ASR。\n\n### 云端 ASR 重要说明（请先读）\n\n抖音播放地址在 `*.douyinvod.com` 等 CDN 上，带防盗链。**阿里云百炼的 URL-ASR 无法从服务端下载这些地址**，会稳定返回 download 失败——这不是 API Key 坏了，也不是“测通了百炼就等于抖音能转写”。\n\n| Key | 是否抖音刚需 | 作用 |\n|---|---|---|\n| **`SILICONFLOW_API_KEY`** | **是（推荐）** | 下载（`Referer: https://www.douyin.com/`）+ 上传 `FunAudioLLM/SenseVoiceSmall` |\n| `DASHSCOPE_API_KEY` | 否（可选） | 仅对**可公网直链**媒体做 URL-ASR；对抖音 CDN 默认跳过 |\n\n- SiliconFlow 控制台：[创建 API Key](https://cloud.siliconflow.cn/account/ak)\n- 百炼说明（可选）：[如何获取 API Key](https://help.aliyun.com/zh/model-studio/get-api-key)\n\n两者都缺时，`cloud` 真跑会安全停止，不下载、不静默切 Whisper。只有 `DASHSCOPE`、没有 SiliconFlow 时会告警。Key 放环境变量/Secret Manager，不要发聊天或进仓库。\n\nskill 会自动读取当前 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local` 中的相关配置，Hermes 没透传环境也能继续走 cloud 默认。\n\n同时安装 `douyin-favorites-to-knowledge` 时，setup 会探测并优先复用它的已登录浏览器 profile 和转录偏好，但状态、输出和调度完全隔离：Creator Insight 默认写入 `./output/creator-insight/`，不读取收藏 metadata，也不加入 23:00 收藏任务。运行前执行 `python3 scripts/integration.py`；若共享 profile 已被占用，等待当前流程结束即可。`douyin-mcp` 是可选诊断工具，不是安装或运行依赖。\n\n### 1. 本地浏览器模式（默认推荐）\n\n首次独立使用时，本 skill 会使用中性的共享浏览器 profile；登录一次抖音即可。若已安装收藏 skill，则自动复用它现有的已登录 profile。之后可直接粘贴主页、`sec_uid`，或包含 `https://v.douyin.com/.../` 的完整分享消息：\n\n```bash\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py \\\n  --creator '长按复制此条消息，打开抖音搜索 https://v.douyin.com/xxxx/ ...' \\\n  --browser --max-videos 50 --output-dir ./output\n```\n\n该模式只读取公开作品列表，逐页验证每条作品作者的 `sec_uid`，不复制 cookie、不输出 profile、不绕过验证码。抖音媒体默认走 SiliconFlow 上传 ASR（Referer 下载后清理）；非抖音公网媒体可走百炼 URL ASR；全部云端失败才回退本地 Whisper。\n\n非交互环境可以显式配置：\n\n```bash\n# 云端：保存选择；若 Key 尚未配置，真实运行会安全停止并给出申请入口\npython3 scripts/setup.py --transcript-mode cloud\n\n# 本地：只有明确选择 local 后，真实运行才允许临时下载视频\npython3 scripts/setup.py --transcript-mode local\n\n# 索引：不转录、不下载视频\npython3 scripts/setup.py --transcript-mode index\n```\n\n首次使用需要可选依赖：\n\n```bash\npython3 -m pip install playwright\npython3 -m playwright install chromium\n```\n\n### 2. 作为 Agent Skill 或 Apify fallback\n\n安装到支持 `SKILL.md` 的 agent 环境后，优先走浏览器模式；没有已授权浏览器或浏览器接口异常时，才使用 Apify MCP 或下述 adapter。真实 token 必须由环境变量或宿主 secret store 提供，不要提交到仓库。\n\n### 3. 作为 CLI adapter\n\nCLI 不会猜测凭据，也不会把“未抓取”伪装成成功。必须显式选择以下一种模式：\n\n```bash\n# 非联网检查：只解析输入，不生成真实报告\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --dry-run\n\n# 真实执行：由使用者提供 module:function adapter\nPYTHONPATH=/path/to/adapters:$PYTHONPATH \\\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --adapter my_adapter:call_actor \\\n  --max-videos 50 \\\n  --transcript-count 3 \\\n  --output-dir ./output\n```\n\nAdapter 必须实现以下调用契约：\n\n```python\ndef call_actor(*, actor: str, input: dict, wait_secs: int):\n    \"\"\"Return a list of dataset items or {'datasetItems': [...]} for profile calls.\"\"\"\n```\n\n昵称或抖音号还需要搜索 adapter：\n\n```bash\npython3 scripts/run_pipeline.py \\\n  --creator <nickname> \\\n  --adapter my_adapter:call_actor \\\n  --browser-adapter my_adapter:search_creator\n```\n\n`search_creator(*, query: str, max_results: int)` 应返回包含公开主页 URL 的文本、列表或字典。\n\n## 参数\n\n| 参数 | 说明 | 默认值 |\n|---|---|---|\n| `--creator` | 主页 URL、`sec_uid`、完整分享消息；adapter 模式也可接受抖音号或昵称 | 必填 |\n| `--dry-run` | 非联网解析检查 | 与 `--browser`、`--adapter` 三选一 |\n| `--browser` | 使用已授权浏览器 profile 采集公开主页 | 与 `--dry-run`、`--adapter` 三选一 |\n| `--browser-profile` | 可选的 Playwright persistent profile 目录 | 默认复用 favorites profile |\n| `--headed` | 显示浏览器窗口，用于诊断登录/验证码 | 默认隐藏 |\n| `--adapter` | Apify 或其他外部真实采集 adapter，`module:function` | 与 `--dry-run`、`--browser` 三选一 |\n| `--browser-adapter` | 昵称/抖音号搜索 adapter | 可选 |\n| `--max-videos` | 请求的视频上限 | 1000 |\n| `--transcript-count` | 请求的转写候选数；指定时覆盖自动分档 | 按账号规模自动选择 |\n| `--transcript-mode` | `cloud` 默认 SiliconFlow 上传 ASR（抖音 CDN）+ 可选百炼公网直链 + local fallback；`local` Whisper；`index` 只做信息索引 | setup 选择，未配置时为 `cloud` |\n| `--no-local-fallback` | 云端 ASR 全部失败时不回退本地 Whisper | 关闭 |\n| `--max-duration` | 选择阶段的时长上限，分钟 | 5 |\n| `--output-dir` | Creator Insight 专用报告目录 | `./output/creator-insight` |\n| `--format` | `html json md` 的任意组合 | 全部 |\n\n## 本地验证\n\n测试完全使用 fixtures，不调用抖音或 Apify，也不需要 token。\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nCI 在 Python 3.10 和 3.12 上执行同一套测试。测试覆盖：\n\n- CLI 显式模式契约和退出码；\n- dry-run 不写输出；\n- 10 条 fixture 视频到三格式报告的端到端链路；\n- Skill 元数据、私人绝对路径和常见 secret 模式扫描。\n\n## 数据源与成本\n\n浏览器模式不需要 Apify key，边界是用户已授权浏览器可访问的公开主页。默认 cloud ASR：抖音 CDN 走 SiliconFlow `SenseVoiceSmall`；百炼 `qwen3-asr-flash` 仅公网直链媒体；**费用**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。 其它（如 Apify）价格、地域和免费额度会变化，实际扣费以所用平台（SiliconFlow / 百炼）控制台账单为准。默认 actor 和 fallback 见 [references/apify-douyin-actors.md](references/apify-douyin-actors.md)。Actor 的可用性、输入 schema、价格和账户额度会变化；运行前应在对应 Apify Actor 页面核验，并先用小样本测试。仓库不承诺固定耗时、费用或免费额度。\n\n## 输出与示例\n\n| 文件 | 用途 |\n|---|---|\n| [docs/sample-report.html](docs/sample-report.html) | HTML 报告示例 |\n| [docs/sample-report.md](docs/sample-report.md) | Markdown 摘要示例 |\n| [docs/sample-report.json](docs/sample-report.json) | 结构化数据示例 |\n\n报告中的互动排序是研究启发式，不代表推荐系统权重，也不构成商业、投资或平台增长保证。\n\n## 已知边界\n\n- 上游字段或 Actor 行为变化可能导致质量门阻断。\n- 昵称搜索可能触发验证码，也可能产生同名候选；浏览器模式不会搜索或自动选择，需改贴主页或分享链接。\n- 无旁白、纯音乐、未配置云端 Key 或上游转写失败的视频可能没有 transcript。未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` 时真实运行会安全停止并提示官方申请入口，不会自动下载视频。\n- 未指定 `--transcript-count` 时：30 条及以下全量转写；31-100 条按点赞前 50；101-300 条选 60 条；301-800 条选 80 条；更大账号最多选 100 条。大账号样本按点赞、收藏与近期作品分层去重，避免只偏向历史爆款。\n- 浏览器模式会记录主页声明作品数、实际采集数和分页状态。达到请求上限而尚有下一页时，结果为 `partial`，不能作为全量结论。\n- 收藏 skill 是可选共享底座，不是前置依赖；同时安装时先运行 `scripts/integration.py` 探测 profile 占用和输出布局。浏览器模式不会读取或导出 cookie。\n- 私密账号、绕过访问控制和未授权批量采集不在支持范围内。\n\n## 安全与贡献\n\n安全问题请按 [SECURITY.md](SECURITY.md) 私下报告。开发与 PR 约定见 [CONTRIBUTING.md](CONTRIBUTING.md)。\n\n## License\n\n[MIT](LICENSE)\n\n## SiliconFlow\n\n- 注册推荐链接：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n### ASR 媒体与码率（1.3.5+）\n- **单一路径**：下载 `video_url` → `ffmpeg -vn` 抽音 → 上传 SenseVoice。\n- **不再优先** `audio_url` / `music.play_url`（常为商业 BGM）。\n- `DOUYIN_ASR_AUDIO_BITRATE`（默认 64k）、`DOUYIN_ASR_SAMPLE_RATE`（默认 16000）。\n- 推荐注册：https://cloud.siliconflow.cn/i/1srulim9\n\nFile v1.3.5:_meta.json\n\n{\n  \"ownerId\": \"kn7fgfkjyfqbz673wvzymh5e1x821vpk\",\n  \"slug\": \"douyin-creator-insight\",\n  \"version\": \"1.3.5\",\n  \"publishedAt\": 1785923593121\n}\n\nFile v1.3.5:references/apify-douyin-actors.md\n\n# Apify Douyin Actors 对照表\n\n## 三个核心 actor\n\n### 1. `zen-studio/douyin-profile-scraper` ⭐ 主用\n\n**用途**：抓取指定博主的所有视频列表\n\n**输入**：\n```json\n{\n  \"maxPostsPerProfile\": 200,\n  \"profileUrls\": [\"https://www.douyin.com/user/MS4w...\"]\n}\n```\n\n**输出字段**：\n```json\n[\n  {\n    \"id\": \"7600998358588812742\",\n    \"text\": \"视频文案/描述\",\n    \"title\": \"标题\",\n    \"createTime\": 1737638400,\n    \"createDate\": \"2025-01-23\",\n    \"statistics\": {\n      \"diggCount\": 12345,\n      \"commentCount\": 678,\n      \"shareCount\": 90,\n      \"collectCount\": 234,\n      \"playCount\": 567890\n    },\n    \"videoMeta\": {\n      \"duration\": 120000,\n      \"cover\": \"https://...\"\n    },\n    \"hashtags\": [{\"name\": \"...\"}],\n    \"series\": {\"name\": \"...\"},\n    \"shareUrl\": \"https://...\",\n    \"authorMeta\": {\n      \"name\": \"...\",\n      \"signature\": \"...\",\n      \"followersCount\": 333000,\n      \"heartCount\": 2672708,\n      \"awemeCount\": 200\n    }\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。公开视频、README 和教程里不要承诺固定成本；第一次建议先小样本验证。\n\n**限制**：maxPostsPerProfile 上限 200\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-profile-scraper\",\n    input={\n        \"maxPostsPerProfile\": 200,\n        \"profileUrls\": [profile_url]\n    },\n    wait_secs=45\n)\n```\n\n### 2. `zen-studio/douyin-transcripts-scraper` ⭐ 主用转写\n\n**用途**：抓取视频语音转写；当前限制以 Actor 页面为准\n\n**输入**：\n```json\n{\n  \"targetLanguage\": \"zh\",\n  \"videoUrls\": [\"https://www.douyin.com/video/7575296454722398441\", ...]\n}\n```\n\n**输出**：\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"...\",\n    \"text\": \"完整转写文本...\",\n    \"duration\": 812,\n    \"segments\": [{\"start\": 0, \"end\": 5.2, \"text\": \"...\"}, ...]\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-transcripts-scraper\",\n    input={\n        \"targetLanguage\": \"zh\",\n        \"videoUrls\": [video_url1, video_url2, ...]\n    },\n    wait_secs=45\n)\n```\n\n### 3. `apple_yang/douyin-transcripts-scraper` 备选\n\n**用途**：备用转写服务\n\n**输入**：\n```json\n{\n  \"videoUrl\": \"https://www.douyin.com/video/...\"\n}\n```\n\n**输出**：同上\n\n**限制**：历史测试中长视频支持不稳定；当前限制以 Actor 页面为准\n\n**价格**：以 Apify Actor 当前页面为准。\n\n## 备选 actor（不推荐）\n\n### `bovi/douyin-scraper`\n- 优点：功能多\n- 缺点：`user_videos` 模式 2026 起需要登录 cookies，已验证空结果\n- 不推荐\n\n### `sian.agency/douyin-scraper`\n- 优点：支持 userVideos\n- 缺点：可能排队较久，且可能需要登录 cookies\n- 不推荐\n\n### `apify--rag-web-browser`\n- 用途：网页搜索 + 渲染\n- 兜底方案：当 profile scraper 失败时用此搜索主页\n- 调用示例：\n```python\napify_browser(\n    query=\"https://www.douyin.com/user/MS4w...\",\n    max_results=1\n)\n```\n\n## 经验教训\n\n1. **优先用 zen-studio 系列**，但运行前核对当前访问要求与输入 schema\n2. **user_videos 模式 = 需要登录**（2026 现状）→ 慎用 bovi/sian.agency\n3. **转写超时**：降低样本或候选时长，并核对 Actor 当前限制\n4. **TOON 格式**：Apify 返回的是 TOON 格式，需要手动解析（见 `data-schema.md`）\n5. **字段 schema 不稳定**：不同 actor 返回字段名差异大，需要多别名解析（见 `parser.py::_extract_field`）\n\n## 失败兜底顺序\n\n```\nzen-studio profile scraper (主)\n  ↓ 失败\napify--rag-web-browser 渲染主页\n  ↓ 失败\nWebSearch + 用户手动提供数据\n```\n\n```\nzen-studio transcripts scraper (主)\n  ↓ 失败\napple_yang transcripts scraper (备用，限制以当前 Actor 页面为准)\n  ↓ 失败\n跳过该视频，继续下一个\n```\n\nFile v1.3.5:references/categorization-taxonomy.md\n\n# Categorization Taxonomy · 内容分类体系\n\n## 规则标签关键词（`categorizer.py::CATEGORY_KEYWORDS`）\n\n### 进外企方法\n- `进外企` / `如何进入` / `外企面试` / `外企推荐` / `简历` / `英文` / `雅思` / `BEC` / `外企 title`\n\n### 外企清单\n- `外企清单` / `小而美` / `推荐名单` / `十大城市` / `十个城市` / `城市知名` / `最佳雇主` / `福布斯`\n\n### 福利揭秘\n- `福利` / `待遇` / `15 天年假` / `年假` / `加班` / `年终奖` / `六险一金` / `补充医疗`\n\n### 跳槽/转行\n- `跳槽` / `转型` / `转行` / `准备` / `实操` / `拿下`\n\n### 英语学习\n- `英语` / `英文` / `口语` / `听力` / `职场英语` / `BEC`\n\n### 认知/成长\n- `认知` / `成长` / `心法` / `建议` / `格局`\n\n### 母婴/育儿\n- `母婴` / `育儿` / `宝宝` / `宝贝` / `妈妈`\n\n### 宠物/动物\n- `宠物` / `猫` / `狗` / `皇家` / `玛氏`\n\n### 美食/食品\n- `美食` / `食品` / `食谱` / `厨房`\n\n### 数码/3C\n- `数码` / `3C` / `手机` / `电脑` / `评测`\n\n## 标签来源\n\n| source | 说明 | 示例 |\n|---|---|---|\n| `rule` | 规则关键词匹配 | `进外企方法` |\n| `hashtag` | 来自视频 hashtag | `#外企` → 进外企方法 |\n| `series` | 来自合集名 | `英语学习与提升` → 合集: 英语学习与提升 |\n| `llm` | LLM 主题分类 | 由 LLM 补充 |\n\n## LLM 分类提示词\n\n`categorizer.py::build_categorization_prompt` 生成的提示词：\n\n```python\nprompt = \"\"\"你是一个抖音内容分析专家。请基于以下 {N} 个视频的信息，把它们分到合适的类别。\n\n# 任务\n1. 输出主分类（每个视频 1 个）：进外企方法 / 外企清单 / 福利揭秘 / 跳槽转行 / 英语学习 / 母婴/育儿 / 其他\n2. 提取关键洞察：\n   - 博主主要面向谁（年龄/性别/职业）\n   - 3 个核心主题\n   - 5 条最有价值的视频标题\n   - 选题公式（爆款标题的共同特征）\n\n# 输出格式（JSON）\n{\n  \"main_categories\": [\"...\"],\n  \"audience\": \"...\",\n  \"core_themes\": [\"...\", \"...\", \"...\"],\n  \"top_5_videos\": [\"标题1\", \"标题2\", ...],\n  \"title_formula\": \"...\",\n  \"insights\": \"...\"\n}\n\"\"\"\n```\n\n## 扩展指南\n\n要新增分类：\n1. 在 `CATEGORY_KEYWORDS` 字典中添加新类别 + 关键词列表\n2. 重跑 `categorize_videos()` 即可\n\n要改 LLM 提示词：\n1. 修改 `build_categorization_prompt()` 函数\n2. 调用方传更多视频元数据\n\n## 实战经验\n\n- 史蒂文不做牛马账号的分类分布（200 条视频）：\n  - 英语学习与提升：42 条（合集）\n  - 职业规划与发展：36 条（合集）\n  - 认知与成长合集：5 条（合集）\n  - 外企清单散装：12+ 条\n  - 进外企方法散装：10+ 条\n  - 福利揭秘：5+ 条\n- 建议给 LLM 提供至少 10 条样本视频做分类\n- 主题分类后建议人工复核 TOP 5，确保准确\n\nFile v1.3.5:references/creator-resolution-playbook.md\n\n# Creator Resolution Playbook · 博主识别策略\n\n## 输入类型判定\n\n`resolver.py::parse_input_type` 判定逻辑：\n\n| 类型 | 正则 | 示例 |\n|---|---|---|\n| douyin_id | `^\\d{6,12}$` | `<douyin_id>`（如 `12345678`） |\n| sec_uid | `MS4w...` | `MS4wLjABAAA...` |\n| url | `https://(www\\.)?douyin\\.com/user/MS4w...` | `https://www.douyin.com/user/MS4wLjABAAA...` |\n| nickname | 含中英文 | `史蒂文不做牛马` |\n\n## 精准 vs 模糊匹配\n\n### 精准匹配（confidence ≥ 0.9）\n\nsec_uid 直接确认，不需问用户。\n\n```\n输入: MS4wLjABAAAA...<sec_uid>...   # 抖音内部唯一 ID\n→ 解析: sec_uid = MS4w...\n→ confidence = 0.95\n→ matched = True\n→ profile_url = https://www.douyin.com/user/MS4w...\n```\n\n### 模糊匹配（confidence < 0.9）\n\n用 `apify--rag-web-browser` 搜索：\n- query: `抖音 {creator_query}`\n- 解析搜索结果的 markdown\n- 提取候选人列表（昵称 + 简介 + 粉丝数）\n\n```\n输入: {nickname}                 # 示例：史蒂文不做牛马\n→ 搜索: 抖音 {nickname}\n→ 候选 1: {nickname} · {signature} · {followers} → confidence 0.95\n→ 候选 2: 其他同名账号\n→ 选 #1，自动继续\n```\n\n## 失败处理\n\n### 找不到任何人\n\n```\n输入: 不存在的昵称\n→ 搜索: 返回空\n→ matched = False\n→ AskUserQuestion 让用户重新输入\n```\n\n### 找到多个相似\n\n```\n输入: 小李\n→ 候选 5 个相似账号\n→ AskUserQuestion 让用户选\n→ 用户选 #3 → 用 sec_uid 继续\n```\n\n## 实战经验\n\n### 抖音号和 sec_uid 的区别\n\n- **抖音号**（douyin_id）：纯数字，用户可改，6-12 位\n  - 例：`<douyin_id>`（如 `12345678`）\n- **sec_uid**：抖音内部唯一 ID，MS4w 开头，不可改\n  - 例：`MS4wLjABAAAA...`（约 60 字符长）\n\n**profile scraper 必须用 sec_uid**，不能用抖音号。\n\n### 已知搜不到的输入\n\n- 短链（`v.douyin.com/xxx`）需要先 WebFetch 解析\n- 长 URL（带 modal_id 参数）可能是视频 ID\n- 纯数字 < 6 位大概率不是抖音号\n\n### 实战踩坑\n\n1. **抖音号搜不到人**：用户可能改了 douyin_id，但 sec_uid 不变。永远用 sec_uid。\n2. **同名账号**：很多用户取相似昵称，需要看签名 + 粉丝数判定。\n3. **博主已注销**：可能抓不到视频。提示用户确认。\n\n## 关键代码\n\n`scripts/resolver.py`：\n- `parse_input_type(user_input)`: 识别输入类型\n- `resolve_creator_via_apify(...)`: 主入口\n- `_resolve_via_apify_search(...)`: 模糊匹配逻辑\n- `format_resolution_for_question(...)`: 转 AskUserQuestion 选项\n\nFile v1.3.5:references/data-schema.md\n\n# Data Schema · 字段映射\n\n## Apify profile scraper → 标准化字段\n\n不同 actor 字段名差异（已实测）：\n\n| 标准化字段 | zen-studio | bovi | sian.agency | TOON 解析后 |\n|---|---|---|---|---|\n| aweme_id | id | aweme_id | videoId | id |\n| title | title | (空) | (空) | title |\n| desc | text | desc | desc | text |\n| create_time | createTime | create_time | timestamp | createTime |\n| duration_ms | videoMeta.duration | video.duration | duration | videoMeta.duration |\n| cover_url | videoMeta.cover | video.cover | coverUrl | videoMeta.cover |\n| share_url | shareUrl | share_url | url | shareUrl |\n| hashtags | hashtags[].name | (空) | (空) | hashtags.name |\n| series_name | series.name | (空) | (空) | series.name |\n| digg_count | statistics.diggCount | aweme_stats.digg_count | stats.like | statistics.diggCount |\n| comment_count | statistics.commentCount | aweme_stats.comment_count | stats.comment | statistics.commentCount |\n| share_count | statistics.shareCount | aweme_stats.share_count | stats.share | statistics.shareCount |\n| collect_count | statistics.collectCount | aweme_stats.collect_count | stats.favorite | statistics.collectCount |\n| play_count | statistics.playCount | aweme_stats.play_count | stats.view | statistics.playCount |\n\n## TOON 格式示例\n\nApify `get_dataset_items` 返回的是 TOON 格式（不是 JSON）：\n\n```toon\nitems[200]:\n  - id: \"7600998358588812742\"\n    text: \"进外企真的不难\"\n    createTime: 1737638400\n    statistics:\n      diggCount: 42451\n      commentCount: 1500\n      shareCount: 800\n      collectCount: 24647\n    videoMeta:\n      duration: 240000\n      cover: \"https://...\"\n    hashtags:\n      - name: \"外企\"\n      - name: \"求职\"\n    authorMeta:\n      name: \"史蒂文不做牛马\"\n      signature: \"在七种不同国别外企混迹的牛马一枚\"\n      followersCount: 333000\n      heartCount: 2672708\n```\n\n## 解析规则\n\n`scripts/parser.py::parse_toon_output` 实现：\n1. 用 `items[N]:` 作为块起点\n2. 用 `\\n  - id:` 作为分隔符切分 item\n3. 每行按 4 空格缩进解析 key-value\n4. 多层缩进（如 `statistics.diggCount`）用 `.` 合并为路径\n\n## transcripts scraper 输出\n\nzen-studio transcripts 返回格式：\n\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"视频标题\",\n    \"text\": \"完整转写文本\",\n    \"duration\": 812,\n    \"segments\": [\n      {\"start\": 0.0, \"end\": 5.2, \"text\": \"...\"},\n      ...\n    ],\n    \"errMsg\": null\n  }\n]\n```\n\n## 字段映射实现位置\n\n`scripts/parser.py::_extract_field()` 支持多路径：\n\n```python\n_extract_field(item, [\n    \"statistics.diggCount\",  # zen-studio\n    \"aweme_stats.digg_count\",  # bovi\n    \"stats.diggCount\",  # sian.agency\n])\n```\n\n按顺序尝试，找到第一个非空值。\n\nFile v1.3.5:references/failure-playbook.md\n\n# Failure Playbook · 失败场景手册\n\n## 1. 用户输入的抖音号找不到人\n\n**症状**：`resolve_creator_via_apify` 返回 `matched=False`\n\n**主策略**：\n- 用 `apify--rag-web-browser` 搜索 \"抖音 {creator_query}\"\n- 解析搜索结果，提取候选人列表\n\n**兜底**：\n- AskUserQuestion 列出 3-5 个候选，让用户确认\n- 用户确认后用 sec_uid 重新调用\n\n**关键代码位置**：`resolver.py::_resolve_via_apify_search`\n\n## 2. 视频列表抓不到 / 返回 0 条\n\n**症状**：`parse_actor_dataset` 返回空列表\n\n**原因**：\n- 用户输入的不是用户主页（可能是视频 URL）\n- Apify 账号额度耗尽\n- 抖音 API 反爬\n\n**主策略**：\n- 检查 `maxPostsPerProfile` 是否过大（> 500 容易失败）\n- 重试 + 减小数量\n\n**兜底**：\n- 用 `apify--rag-web-browser` 渲染主页，手动解析\n- 提示用户上传原始 JSON，走离线模式\n\n**关键代码位置**：`run_pipeline.py` Step 2\n\n## 3. 视频列表字段大量为空\n\n**症状**：parse 后大部分 video.title 或 stats 为空\n\n**原因**：\n- actor schema 变化\n- 字段别名没覆盖\n\n**主策略**：\n- 在 `parser.py::_extract_field` 增加新别名\n- 检查 TOON 解析是否有 bug\n\n**兜底**：\n- 保留 raw JSON，下次重试时直接复用\n- 用 `quality_gate.py::check_videos` 检测\n\n## 4. 语音转写全部失败\n\n**症状**：`fetch_transcripts` 返回空或全部 failed\n\n**主策略**：\n- 检查视频时长和 Actor 当前限制\n- 切换备用 actor（apple_yang）\n\n**兜底**：\n- 仅用标题 + 描述 + 互动数据分析，不依赖转写\n- 报告标注 \"transcripts_unavailable\"\n\n## 5. 视频没有旁白（音乐/纯画面）\n\n**症状**：transcript 返回空字符串\n\n**判断**：transcript text 长度 < 10 → 标记 `empty_transcript`\n\n**主策略**：\n- 跳过该视频的转写\n- 改用 title + desc + hashtags 做内容分析\n\n**兜底**：\n- 报告里标注\"无旁白视频\"\n- 用 B 站 / YouTube 等替代来源\n\n## 6. Apify 账号额度耗尽\n\n**症状**：所有 actor 调用都返回 4xx 错误\n\n**主策略**：\n- 减小 `max_videos` 和 `transcript_count`\n- 提示用户充值\n\n**兜底**：\n- 完全离线模式：用户上传历史 raw JSON，skill 仅做分析和报告\n- 使用用户提供的、已获授权的公开数据快照\n\n## 7. 字段 schema 突然变化\n\n**症状**：解析后大量字段为 None\n\n**主策略**：\n- 增加字段别名（参考 `data-schema.md`）\n- 保留 raw 字段，下次回放时排查\n\n**兜底**：\n- 用 `WebFetch` 抓主页 HTML 作为补充\n- 让用户手动提供关键视频 URL\n\n## 8. 时间相关问题\n\n- **createTime 是毫秒还是秒**？不同 actor 不同\n  - `parser.py::_format_date` 自动判断：> 10^12 是毫秒\n- **时长过滤**：默认筛选上限为 5 分钟，可按 Actor 当前限制调整\n  - `selector.py::apply_duration_penalty` 自动惩罚\n\n## 9. 网络/TLS 错误\n\n**症状**：MCP 调用超时或连接失败\n\n**主策略**：\n- 重试（最多 3 次）\n- 切换备用 actor\n\n**兜底**：\n- WebSearch 抓搜索结果页（`apify--rag-web-browser`）\n- 让用户提供手动数据\n\n## 10. 报告生成失败\n\n**症状**：`save_reports` 报错\n\n**主策略**：\n- 检查磁盘空间\n- 检查文件权限\n\n**兜底**：\n- 只生成 JSON 格式（最小输出）\n- 用 `cat > output.json` 直接写文件\n\n## 通用诊断流程\n\n```\n1. 检查 Apify token 是否有效\n2. 检查网络连接（clash verge / proxy）\n3. 用 `quality_gate.run_quality_gate` 检测哪阶段失败\n4. 查本 playbook 找对应失败场景\n5. 实施主策略\n6. 如果失败，启用兜底\n7. 报告失败原因给用户\n```\n\n## 关键代码位置速查\n\n| 失败阶段 | 主要函数 | 兜底函数 |\n|---|---|---|\n| 解析博主 | `resolver.resolve_creator_via_apify` | `_resolve_via_apify_search` |\n| 抓视频 | `parser.parse_actor_dataset` | `apify_browser` |\n| 字段解析 | `parser._extract_field` | 保留 raw |\n| 选精华 | `selector.select_essentials` | 仅按点赞排序 |\n| 转写 | `transcript.fetch_transcripts` | 切换 actor |\n| 报告 | `report_builder.save_reports` | 单独保存 |\n\nFile v1.3.5:references/pre-questions.md\n\n# Pre-questions · AskUserQuestion 模板\n\n## 问询原则\n\n自然语言优先。只有用户没有给目标账号、昵称搜索出现多个候选、或用户要求控制规模/成本时，才提问。默认参数不要逐项打断用户。\n\n推荐输入优先级：\n\n1. 抖音主页 URL\n2. `sec_uid`\n3. 抖音号 / ID\n4. 昵称\n\n昵称支持搜索，但同名账号较多；如果置信度不够，需要让用户确认候选。\n\n## 必填信息\n\n### Q1: 用户输入（creator_query）\n\n```\n\"请提供抖音号 / 昵称 / 主页 URL\"\n```\n\n接受输入格式：\n- 抖音号（纯数字 6-12 位）：如 `<douyin_id>`（如 `12345678`）\n- sec_uid（MS4w 开头）：如 `MS4wLjABAAA...`\n- 昵称：如 `史蒂文不做牛马`\n- 主页 URL：如 `https://www.douyin.com/user/MS4w...`\n\n如果用户已经在一句话里给出上述任意信息，不需要再问 Q1。\n\n## 条件必填（仅当模糊匹配时）\n\n### Q2: 候选博主确认\n\n```\n\"找到几个相似的博主，请确认哪个是您要的：\"\n```\n\n- option1: <nickname1> <signature1> · 粉丝 X 万\n- option2: <nickname2> <signature2> · 粉丝 Y 万\n- ...\n\n## 默认参数（通常不问，直接采用）\n\n### Q3: 抓取视频条数\n\n```\n\"要抓取多少条最新视频？\"\n- 推荐（200 条）\n- 深度（500 条）\n- 快速（50 条）\n```\n\n默认：200\n\n### Q4: 语音转写条数\n\n```\n\"要抓取多少条精华视频的语音转写？\"\n- 5 条（推荐）\n- 10 条\n- 全部精华（可能耗时）\n```\n\n默认：5\n\n### Q5: 转写时长上限（分钟）\n\n```\n\"转写候选的视频时长上限？\"\n- 5 分钟（默认，用于控制样本规模）\n- 10 分钟\n- 不限（可能显著增加资源消耗）\n```\n\n默认：5\n\n### Q6: 研究目标\n\n```\n\"主要研究目标？\"\n- 综合洞察（推荐）\n- 选题拆解\n- 爆款分析\n```\n\n默认：综合洞察\n\n### Q7: 输出格式\n\n```\n\"输出哪些格式的报告？\"\n- HTML（可视化）\n- Markdown（快读）\n- JSON（数据分析）\n```\n\n默认：全部\n\n### Q8: 输出目录\n\n```\n\"报告保存到哪里？\"\n```\n\n默认：当前工作目录 `./output/`\n\n## 什么时候主动改成小样本\n\n用户出现这些意图时，建议先小样本：\n\n- “先试一下”\n- “省额度”\n- “先看看能不能跑通”\n- “教程演示”\n\n推荐小样本：`max_videos=50`、`transcript_count=1`。如果用户明确说完整分析或未指定规模，则使用默认 `max_videos=200`、`transcript_count=5`。\n\n## 完整调用示例\n\n```python\nfrom AskUserQuestion import ask_user_questions\n\nquestions = [\n    {\n        \"key\": \"creator_query\",\n        \"question\": \"请提供抖音号 / 昵称 / 主页 URL\",\n        \"required\": True,\n    },\n    {\n        \"key\": \"max_videos\",\n        \"question\": \"要抓取多少条最新视频？\",\n        \"default\": 200,\n        \"options\": [50, 100, 200, 500],\n    },\n    # ...\n]\n\nanswers = ask_user_questions(questions)\n```\n\nFile v1.3.5:references/report-rubric.md\n\n# Report Rubric · 报告标准\n\n## 报告结构\n\n### HTML 报告章节\n\n```\n1. Hero（封面）\n   - 博主头像 + 昵称 + sec_uid\n   - 4 个数据卡片：粉丝/获赞/视频数/转写数\n   - 个人简介（signature）\n\n2. 摘要\n   - 报告基于 N 条视频 + M 条转写\n   - 报告时点\n\n3. 主题分类（如有）\n   - 每个分类：名称 + 视频数 + TOP 5 视频列表\n\n4. 精华视频语音转写\n   - 每条视频卡片：\n     - 创建日期\n     - 互动数据（点赞/收藏）\n     - 转写状态（success/empty/failed）\n     - 标题\n     - 完整转写（可折叠）\n\n5. 互动 TOP 视频（表格）\n   - 列：# / 标题 / 日期 / 👍 / ⭐ / 💬\n   - 默认 TOP 40\n\n6. 数据来源 + 方法\n   - Apify actor 列表\n   - 互动分公式\n   - 报告生成时间\n```\n\n### Markdown 报告章节\n\n```\n1. # 标题\n2. ## 📊 账号概况（表格）\n3. ## 🏷️ 主题分类（每类列表）\n4. ## 🎙️ 精华视频语音转写（每条）\n5. ## 🏆 互动 TOP 视频（表格）\n6. ## 📖 数据来源\n```\n\n### JSON 数据包结构\n\n```json\n{\n  \"creator\": {...},\n  \"videos\": [...],\n  \"transcripts\": [...],\n  \"categories\": {...},\n  \"top_videos\": [...],\n  \"research_goal\": \"creator_insight\",\n  \"generated_at\": \"ISO 8601\"\n}\n```\n\n## 视觉规范\n\n### 配色\n\n| 用途 | 颜色 |\n|---|---|\n| 主背景 | 渐变 `#f5f7fa → #e8ecf3` |\n| 头部 | 渐变 `#1e3a8a → #5b21b6`（深紫蓝） |\n| 标题色 | `#1e293b` |\n| 强调色 | `#5b21b6` |\n| 链接色 | `#3730a3` |\n| 警告色 | `#f59e0b` |\n| 转写框 | `#fffbeb`（米黄） |\n| 点赞数 | `#ef4444`（红） |\n| 收藏数 | `#f59e0b`（橙） |\n\n### 字号\n\n| 元素 | 字号 |\n|---|---|\n| Hero h1 | 32px |\n| section h2 | 26px |\n| section h3 | 20px |\n| section h4 | 17px |\n| 正文 | 16px |\n| 视频元信息 | 13px |\n\n### 间距\n\n- section padding: 50px 40px\n- 卡片 padding: 14-22px\n- 段落间距: 12-18px\n\n## 数据准确度标准\n\n### 必须保留的字段\n\n- `aweme_id`（必填）\n- `stats.digg_count` / `comment_count` / `share_count` / `collect_count`\n- `create_date`（YYYY-MM-DD 格式）\n- `duration_seconds`（如可用）\n\n### 应当标注的状态\n\n- 转写状态：`success` / `failed` / `empty_transcript` / `skipped`\n- 匹配度：5★ / 4★ / 3★\n- 数据来源：zen-studio / apple_yang / bovi 等\n\n## 输出文件命名\n\n```\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.html\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.md\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.json\n```\n\n例：`史蒂文不做牛马_douyin_insight_20260709_093200.html`\n\n## 性能记录\n\n不设置未经基准测试的固定耗时。每次真实运行应记录样本量、Actor、开始/结束时间、失败数和输出大小；不同账号、网络、Actor 队列和上游 schema 下的结果不可直接类推。\n\n## 测试用例\n\n使用 `tests/test_pipeline.py` 中的合成 fixture 作为可重复测试。真实公开账号报告只作为展示样例，不作为性能基准。\n\n## 复用模板\n\n`scripts/report_builder.py` 内置 HTML/MD 模板，无需额外 assets/ 依赖。\n\n如果需要自定义样式：\n1. 复制 `HTML_TEMPLATE` 到 `assets/report_template.html`\n2. 修改后用 `jinja2` 或其他模板引擎渲染\n3. 当前实现用纯 Python `str.format()`，无 jinja 依赖\n\nFile v1.3.5:CHANGELOG.md\n\n# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [1.3.5] - 2026-08-05\n\n### Changed\n- ASR 简化为单一稳定路径：只下 `video_url` → ffmpeg 抽音 → SenseVoice；去掉 `audio_url` 优先分支（常为 BGM）。\n\n## [1.3.4] - 2026-08-05\n\n### Changed\n- ASR：优先 `audio_url`，失败回退 `video_url`；`DOUYIN_ASR_AUDIO_BITRATE` / `DOUYIN_ASR_SAMPLE_RATE` 可配。\n- 采集：仅原创音写入 `audioUrl`，避免商业 BGM 误当口播。\n\n## [1.3.3] - 2026-08-05\n\n### Changed\n- 文档加入 SiliconFlow 注册推荐链接：https://cloud.siliconflow.cn/i/1srulim9\n\n## [1.3.2] - 2026-08-05\n\n### Changed\n- 文档补齐 SiliconFlow 费用说明：截至 2026-08-05 官方价格页 `FunAudioLLM/SenseVoiceSmall` 标注**免费**（https://siliconflow.cn/pricing；会变，以账单为准，不承诺永久免费）。\n\n## [1.3.1] - 2026-08-05\n\n### Fixed\n- 清除 README / CLI help / mcp.json.example 中残留的「cloud 默认百炼」表述，与 1.3.0 SiliconFlow 主路径对齐。\n\n## [Unreleased]\n\n## [1.3.0] - 2026-08-05\n\n### Fixed（面向公开用户的关键纠错）\n\n- **抖音 CDN 云端转写默认路径错误**：此前文档与 setup 将「阿里云百炼 URL-ASR」宣传为推荐主路径。实测百炼服务端无法拉取 `*.douyinvod.com`，会稳定失败；公开用户按文档只配 `DASHSCOPE_API_KEY` 时几乎转不出文案。\n- **硬闸只认百炼 Key**：`run_pipeline` 在已配置 `SILICONFLOW_API_KEY` 时仍因缺少 `DASHSCOPE_API_KEY` 直接退出。\n- **媒体下载 403**：云端上传 / 本地 Whisper 下载缺少 `Referer: https://www.douyin.com/`，导致 SiliconFlow 回退也失败。\n\n### Changed\n\n- 抖音保护媒体：**优先 SiliconFlow 上传 ASR**；默认跳过百炼 URL（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n- `cloud` 就绪条件：`SILICONFLOW_API_KEY` **或** `DASHSCOPE_API_KEY`。\n- setup / README / SKILL：明确推荐 SiliconFlow 为抖音路径；百炼降为可选公网 URL 路径。\n- `cloud_asr_configured` 同时探测两种 Key。\n\n### Notes\n\n- 两家不是同一模型：百炼默认 `qwen3-asr-flash`；SiliconFlow 默认 `FunAudioLLM/SenseVoiceSmall`；账单分离。\n\n\n## [1.2.3] - 2026-08-01\n\n### Removed\n- Removed the internal `task_plan.md` process artifact from the public package.\n\n## [1.2.2] - 2026-08-01\n\n### Added\n- First-run `scripts/setup.py` for explicit `cloud` / `local` / `index` selection, with non-secret config persistence.\n- Setup and integration detection for existing `douyin-favorites-to-knowledge` installs, shared browser profiles, and reusable transcription preference.\n- Bailian API Key guidance when `DASHSCOPE_API_KEY` is missing.\n\n### Fixed\n- Missing cloud ASR credentials no longer trigger an implicit local Whisper fallback or video download; users must explicitly choose `local`.\n\n## [1.2.1] - 2026-08-01\n\n### Added\n- Adaptive transcript selection: accounts with 30 or fewer videos use all-video transcription; larger accounts use bounded, deduplicated layers of likes, saves, and recent posts.\n- Selection metadata is included in JSON results and summarized in HTML and Markdown reports.\n- Browser collection records declared work count, collected count, and pagination completion; capped collections return `partial`.\n- Independent `cloud`, `local`, and `index` transcript modes. Cloud is the default, local Whisper is a final fallback, and index mode never invokes ASR.\n- Non-mutating integration probe, neutral browser profile for standalone installs, shared-profile busy detection, and isolated Creator Insight output.\n\n### Fixed\n- Skill runtime now auto-loads ASR/browser profile config from standard local env files, so Hermes launcher env gaps no longer collapse cloud ASR into `not_configured`.\n- Profile metadata extraction now prefers exact `sec_uid` matches over sec_uid-less wrapper objects.\n- Profile API author metadata now wins over per-post author fields when merging declared counts and account stats.\n- Timed-out or error-shaped transcript payloads are marked failed and excluded from report text.\n- Missing transcript actor results now receive an explicit per-video failure status.\n- Transcript quality failures return `degraded` instead of ordinary success, with provider and quality details in the result.\n\n### Changed\n- `douyin-knowledge-base-pipeline` and `douyin-mcp` are optional integrations, not installation or runtime dependencies.\n- Cloud ASR first attempts DashScope URL recognition, then an optional temporary-audio cloud upload for large media; temporary media is always cleaned.\n- Reissued the final runtime-env hardening package as `v1.2.1` because ClawHub had already accepted an earlier `1.2.0` package and does not allow overwriting an existing version.\n\n## [1.1.0] - 2026-07-30\n\n### Added\n- Browser-first public creator collection: accepts profile URLs, `sec_uid`, and complete Douyin share messages containing `v.douyin.com` links.\n- `--browser`, `--browser-profile`, and `--headed` CLI options. The collector reuses the existing favorites persistent profile, fetches public post pages in browser context, locally caps and deduplicates results, and verifies every item's author `sec_uid`.\n\n### Changed\n- Apify is an explicit adapter fallback, not a default dependency for public creator collection.\n- Nickname and Douyin-ID searches never auto-select an account; the workflow asks for a stable profile/share link when search is ambiguous or blocked by CAPTCHA.\n- Reports state their actual collection and transcript sources. Browser-mode reports explicitly mark transcript candidates as skipped when no transcription provider is configured.\n\n## [1.0.2] - 2026-07-25\n\n### Changed\n- Updated official GitHub Actions to their Node 24 releases to remove hosted-runner deprecation warnings.\n\n## [1.0.1] - 2026-07-25\n\n### Fixed\n- CLI now requires explicit `--dry-run` or `--adapter module:function`; a real-looking command can no longer silently return a dry-run result.\n- Added fixture-based end-to-end tests and subprocess tests for CLI exit behavior.\n- Removed unbenchmarked timing, cost, quota, and free-tier promises from current documentation.\n\n### Added\n- GitHub Actions on Python 3.10 and 3.12.\n- Repository checks for Skill metadata, private absolute paths, and common live-secret patterns.\n- Security policy and explicit credential-handling guidance.\n\n## [1.0.0] - 2026-07-15\n\n### Added\n- 🎉 **首次公开发布**\n- 5 阶段 pipeline：resolver → parser → selector → transcript → categorizer → report_builder\n- 9 个核心脚本（schemas / resolver / parser / selector / transcript / categorizer / report_builder / quality_gate / run_pipeline）\n- 7 份 references 文档（pre-questions / apify-douyin-actors / data-schema / creator-resolution-playbook / categorization-taxonomy / report-rubric / failure-playbook）\n- 3 套 assets 模板（report_template.html / report_style.css / creator_card_template.html）\n- 三格式输出：HTML（可视化）+ Markdown（快读）+ JSON（数据分析）\n- 智能精华选择：互动分公式 `log(点赞)*1 + log(评论)*2.5 + log(分享)*3 + log(收藏)*2`\n- 多 actor 兜底：zen-studio 主用 → sian.agency 备选 → apify--rag-web-browser 渲染\n- 模糊匹配候选：置信度 < 0.9 时返回 3-5 个候选让用户确认\n\n### Documentation\n- README.md 加 4 大徽章（License / Python 版本 / 零依赖 / Apify 必需）\n- 加 demo 报告区（docs/sample-report.{html,md,json}）\n- 加初版额度预估表（因缺少可复现实验依据，已在 v1.0.1 删除）\n- 加 6 条 FAQ（覆盖 dry-run / 额度 / 输入选择 / empty_transcript / 私密账号 / 与 douyin-workflow 区别）\n- 加环境自检脚本\n- SKILL.md 加\"⚠️ 前置条件\"章节（4 步检查清单）\n- SKILL.md 加\"⚡ 失败兜底速查\"表格（5 行版本）\n\n### Notes\n- 零 Python 三方依赖（用 dataclasses + 标准库）\n- 需要 Apify token + Apify MCP（详见 mcp.json.example）\n- 初版包含固定额度估算；v1.0.1 起改为运行前核对 Actor 页面并以本次实测为准\n\nArchive v1.3.4: 40 files, 98743 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (8069b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (11870b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (20862b), scripts/browser_collector.py (13558b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8189b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (19121b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (8099b), scripts/setup.py (7202b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (3044b), SKILL.md (9808b), tests/test_pipeline.py (18901b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nFile v1.3.4:SKILL.md\n\n---\nname: douyin-creator-insight\nversion: 1.3.4\ndescription: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。\n---\n\n# Douyin Creator Insight\n\n## 使用条件\n\n仅分析公开可访问数据。默认真实抓取使用已授权的本地浏览器 profile，不依赖 Apify key；Apify 仅是显式 fallback。不要在对话、脚本、报告或仓库中输出 token、cookie、浏览器 profile、私人绝对路径或未公开内容。\n\n## 安装与共享配置\n\n`douyin-creator-insight` 可独立安装和运行，`douyin-favorites-to-knowledge`（旧名/旧目录可能是 `douyin-knowledge-base-pipeline`）不是前置依赖。若两者都存在，本 skill 只复用已登录的 persistent browser profile 和 ASR 环境变量，绝不读取收藏记录、修改增量 metadata，或加入收藏 skill 的 23:00 任务。\n\n首次运行先执行 `python3 scripts/setup.py`。它只写非敏感偏好：`cloud`（云端 ASR）/ `local`（Whisper）/ `index`（只索引），以及可选 profile/output 位置；不保存 API key、cookie 或 token。若检测到已安装 `douyin-favorites-to-knowledge`，优先复用其已登录浏览器 profile 和转录偏好，但状态、账本、输出和 23:00 任务仍完全隔离。\n\n**云端 ASR 真相（抖音）**：抖音 CDN（`*.douyinvod.com` 等）带防盗链，**阿里云百炼 URL-ASR 服务端拉不到媒体**，会稳定失败——不是用户 Key 配错。公开 skill 的默认可用路径是：\n\n1. **推荐 `SILICONFLOW_API_KEY`**：本机用浏览器式 `Referer: https://www.douyin.com/` 临时下载 → 抽音频 → 上传 SiliconFlow `FunAudioLLM/SenseVoiceSmall` → 立即清理临时文件。\n2. **可选 `DASHSCOPE_API_KEY`**：仅当媒体 URL 是第三方可公网直链时走百炼 URL-ASR；对抖音 CDN **默认跳过**（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n3. 至少配置上述之一才允许 `cloud` 真跑；**两者都缺**时停止，不下载、不静默切 Whisper。\n4. 云端都失败且用户允许 local fallback 时才进 Whisper；`index` 永不 ASR。\n\nSiliconFlow 控制台：`https://cloud.siliconflow.cn/account/ak`。百炼说明（可选）：`https://help.aliyun.com/zh/model-studio/get-api-key`。Key 放本机环境变量/Secret Manager，不要发聊天或进仓库。skill 自动读 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local`。运行前 `python3 scripts/integration.py`；共享 profile 被占用必须等待。报告写入独立 `<output-root>/creator-insight/`。\n\n> **ASR 费用（默认 SenseVoiceSmall）**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。\n\n\n- **SiliconFlow 注册推荐链接**：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n\nActor 的价格、配额、可用性和 schema 会变化。运行前查看当前 Actor 页面；任何费用或耗时只能作为本次运行的实测结果陈述，不能沿用固定承诺。\n\n## 输入\n\n从用户原话提取：\n\n- `creator_query`：优先主页 URL、`sec_uid`，或包含 `v.douyin.com` 的完整分享消息；脚本会提取短链接。\n- `max_videos`：默认 1000；用户要求省资源或试跑时降低。超过上限时结果必须标为 `partial`。\n- `transcript_count`：未指定时按作品数自动分档；用户显式指定时优先遵从。\n- `transcript_max_duration_minutes`：默认 5，用于候选筛选。\n- `transcript_mode`：`cloud`（默认）/ `local` / `index`。\n- `output_formats`：默认 `html`、`md`、`json`。\n- `output_dir`：默认当前任务的专用输出目录。\n\n主页 URL、分享短链接或 `sec_uid` 最稳定。昵称和抖音号只可用于候选确认，不能自动选择同名账号；搜索验证码或模糊结果时要求用户改贴主页/分享链接。\n\n## 流程\n\n1. 用 `scripts/resolver.py` 判断输入类型，并从分享消息提取短链接。\n2. 对 URL/短链接/`sec_uid`，优先运行 `scripts/run_pipeline.py --browser`。它在现有 persistent profile 的页面上下文读取公开作品分页，并验证每条返回视频的作者 `sec_uid`。\n3. 昵称或抖音号不可自动选人；搜索触发验证码、无候选或多个候选时停止并请求主页/分享链接。\n4. 用 `scripts/parser.py` 标准化字段，再执行 `quality_gate.py`。门禁失败时停止，不生成伪完整报告。\n5. `index` 模式跳过转写，只保留全量作品信息；其他模式用 `selector.py` 选择候选：30 条及以下全量转写；31-100 条按点赞前 50；更大账号按点赞、收藏和近期作品分层去重抽样（上限 100 条）。\n6. `cloud`（默认）对抖音 CDN 媒体：**优先 SiliconFlow 上传 ASR**（Referer 下载 + 抽音频 + 上传 + 清理）；**不把抖音 CDN URL 默认丢给百炼**。非抖音可公网媒体才先试百炼 URL-ASR。云端都失败才进入 `local` Whisper。`douyin-mcp` 不是依赖。再用 `categorizer.py` 分类、`report_builder.py` 输出真实 provider 状态与错误。\n\n## Tool 调用契约\n\nProfile actor 输入：\n\n```json\n{\n  \"maxPostsPerProfile\": 1000,\n  \"profileUrls\": [\"https://www.douyin.com/user/<sec_uid>\"]\n}\n```\n\n浏览器模式默认最多采集 1000 条；Apify 的实际上限、配额和字段以运行时 Actor schema 为准。任何触发上限、分页未完成或声明数无法对账的结果，都必须在报告的 `collection` 字段标为 `partial` 或 `reconciliation: unavailable`，不得写成全量完成。\n\nActor ID、输入字段和 fallback 以 [references/apify-douyin-actors.md](references/apify-douyin-actors.md) 为准。不要假设文档中的历史 actor 永久可用；调用失败时先核对 Actor 页面和返回 schema。\n\n## 质量门\n\n- 身份必须 matched，且含 `sec_uid` 或抖音号。\n- 视频列表不能为空；少于质量门默认阈值时阻断。\n- 超过一半的视频缺少标题与描述时阻断。\n- 转写成功率低于门槛时，报告必须明确降级或停止。\n- 低置信度身份不得自动选择。\n\n## 运行脚本\n\nAgent 已经完成采集后，可直接复用 `scripts/` 中的解析、筛选和报告函数。独立 CLI 必须显式选择一种模式：\n\n```bash\n# 非联网验证\npython3 scripts/run_pipeline.py --creator <profile_url> --dry-run\n\n# 默认真实路径：已登录浏览器中的公开主页接口\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py --creator '<share_or_profile_url>' --browser\n\n# 明确选择本地 Whisper 或纯信息索引\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode local\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode index\n\n# 使用显式 adapter 真实运行\npython3 scripts/run_pipeline.py \\\n  --creator <profile_url> \\\n  --adapter my_adapter:call_actor \\\n  --output-dir ./output\n```\n\n没有 `--dry-run`、`--browser` 或 `--adapter` 时，CLI 必须失败；不得把 dry-run 返回当成真实报告。\n\n## 失败处理\n\n| 场景 | 行为 |\n|---|---|\n| 找不到账号 | 返回候选或要求更稳定的主页 URL |\n| 浏览器 profile 未登录、主页接口失败 | 不要求复制 cookie；提示在已有 profile 中恢复登录或稍后重试 |\n| 昵称搜索验证码/同名 | 不绕过验证码，不自动选人；要求主页或分享链接 |\n| Profile actor 失败 | 核对 schema 后使用记录在 reference 中的 fallback |\n| 视频不足或字段异常 | 质量门阻断，保留原始响应供排查 |\n| 未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` | 停止真实转写；提示 SiliconFlow（抖音推荐）与可选百炼入口；不自动下载或切 Whisper |\n| 仅有 `DASHSCOPE_API_KEY`、无 SiliconFlow | 允许启动但告警：抖音 CDN 转写大概率失败 |\n| Cloud ASR 失败 | 仅在云端已配置但真实调用失败时记录错误，再回退本地 Whisper；`--no-local-fallback` 时只报告失败 |\n| 本地 Whisper 失败 | 清理临时媒体并标记 `failed` 或 `empty_transcript` |\n| 配额不足 | 停止真实调用，建议用户缩小样本或稍后重试 |\n| 输出写入失败 | 返回非成功状态和明确路径，不宣称完成 |\n\n## 验证\n\n修改 Skill 或脚本后必须运行：\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nfixture E2E 通过只证明本地编排契约正确，不证明第三方 Actor 当前可用。真实发布说明必须把两类证据分开。\n\n## 相关文档\n\n- `references/apify-douyin-actors.md`：Actor 与 fallback\n- `references/data-schema.md`：字段映射\n- `references/creator-resolution-playbook.md`：身份确认\n- `references/categorization-taxonomy.md`：分类规则\n- `references/report-rubric.md`：报告质量\n- `references/failure-playbook.md`：失败恢复\n- `SECURITY.md`：凭据与漏洞报告\n\n### ASR 媒体与码率（1.3.4+）\n- 优先 `audio_url`，失败回退 `video_url`。\n- `DOUYIN_ASR_AUDIO_BITRATE`（默认 64k）、`DOUYIN_ASR_SAMPLE_RATE`（默认 16000）。\n- 抖音 `music.play_url` 仅在原创音时采用，商业 BGM 不用。\n- 推荐注册：https://cloud.siliconflow.cn/i/1srulim9\n\nFile v1.3.4:assets/README.md\n\n# Assets · 模板文件\n\n本目录存放报告生成所需的静态资源。\n\n## 文件清单\n\n- `README.md`：本说明\n- `report_template.html`：HTML 报告模板（参考用）\n- `report_style.css`：报告样式（参考用）\n- `creator_card_template.html`：博主封面卡片模板（参考用）\n\n## 当前实现\n\n**注意**：当前 `scripts/report_builder.py` 使用内置 Python 字符串模板，**不依赖** assets/ 目录。\nassets/ 中的文件仅作为参考 / 自定义起点。\n\n## 自定义指南\n\n如果需要自定义样式：\n\n### 方式 1：直接修改内置模板\n\n编辑 `scripts/report_builder.py::HTML_TEMPLATE`，调整 CSS 部分。\n\n### 方式 2：使用 jinja2 渲染\n\n1. 安装：`pip install jinja2`\n2. 把内置 HTML_TEMPLATE 复制到 `assets/report_template.html`\n3. 用 jinja2 渲染\n\n```python\nfrom jinja2 import Environment, FileSystemLoader\n\nenv = Environment(loader=FileSystemLoader('assets'))\ntemplate = env.get_template('report_template.html')\nhtml = template.render(\n    nickname=nickname,\n    followers=followers,\n    ...\n)\n```\n\n### 方式 3：完全重写\n\n如果需要差异化设计（如杂志风、暗色模式），可以：\n\n1. 创建新文件 `assets/report_template_magazine.html`\n2. 在 `scripts/report_builder.py` 中加 `build_html_report_magazine()`\n3. 调用方选择用哪个模板\n\n## 配色参考\n\n| 风格 | 配色 |\n|---|---|\n| 默认（深紫蓝） | `#1e3a8a → #5b21b6` |\n| 杂志风（暖色） | `#b45309 → #d97706` |\n| 暗色模式 | `#0f172a → #1e293b` |\n| 极简（白底） | `#f8fafc → #f1f5f9` |\n\n## 示例模板\n\n### 默认模板（已在 report_builder.py）\n\n```html\n<header class=\"hero\">\n    <h1>{{ nickname }} · 抖音内容洞察报告</h1>\n    <div class=\"creator-stats\">\n        <div class=\"stat\"><span class=\"num\">{{ followers }}</span></div>\n        ...\n    </div>\n</header>\n```\n\n### 杂志风模板（待创建）\n\n参考 `guizang-ppt-skill` 的杂志风风格。\n\nFile v1.3.4:README.md\n\n# Douyin Creator Insight\n\n从公开抖音主页、分享短链接或 `sec_uid` 出发，生成可审计的创作者内容洞察报告。默认使用已登录的本地浏览器 profile 读取公开作品；Apify 是可选 fallback。输出包含 HTML、Markdown 和 JSON。\n\n[![CI](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml/badge.svg)](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n\n## 能做什么\n\n- 解析主页 URL、`sec_uid` 和完整分享文案中的短链接；昵称或抖音号只用于人工候选确认，不自动选择同名账号。\n- 标准化不同数据源的视频字段。\n- 按账号规模自动选择转写候选：小账号全量转写，大账号以点赞、收藏和近期作品分层抽样。\n- 对解析、视频数量和转写质量执行阻断式质量门。\n- 生成 HTML、Markdown、JSON 三种报告。\n\n本项目只处理公开数据，不绕过登录、隐私或平台访问控制。\n\n## 安装与分发入口\n\n- Agent 一键安装：[ClawHub douyin-creator-insight](https://clawhub.ai/tars1230/skills/douyin-creator-insight)\n- 国内源码镜像：[Gitee tars123/douyin-creator-insight](https://gitee.com/tars123/douyin-creator-insight)\n- 源码与版本发布：[GitHub tars1230/douyin-creator-insight](https://github.com/tars1230/douyin-creator-insight)\n\n## 运行方式\n\n### 独立运行，可选复用收藏 skill\n\n本 skill 可以独立安装。第一次运行先执行 `python3 scripts/setup.py`，明确选择：\n\n- `cloud`：云端 ASR（默认）。**抖音场景推荐配置 `SILICONFLOW_API_KEY`**（本机带 Referer 临时下载 → 上传 SenseVoice → 清理）。\n- `local`：本地 Whisper。只有用户明确选择时才临时下载视频，结束后清理。\n- `index`：只索引标题、描述、互动数据和链接，不调用 ASR。\n\n### 云端 ASR 重要说明（请先读）\n\n抖音播放地址在 `*.douyinvod.com` 等 CDN 上，带防盗链。**阿里云百炼的 URL-ASR 无法从服务端下载这些地址**，会稳定返回 download 失败——这不是 API Key 坏了，也不是“测通了百炼就等于抖音能转写”。\n\n| Key | 是否抖音刚需 | 作用 |\n|---|---|---|\n| **`SILICONFLOW_API_KEY`** | **是（推荐）** | 下载（`Referer: https://www.douyin.com/`）+ 上传 `FunAudioLLM/SenseVoiceSmall` |\n| `DASHSCOPE_API_KEY` | 否（可选） | 仅对**可公网直链**媒体做 URL-ASR；对抖音 CDN 默认跳过 |\n\n- SiliconFlow 控制台：[创建 API Key](https://cloud.siliconflow.cn/account/ak)\n- 百炼说明（可选）：[如何获取 API Key](https://help.aliyun.com/zh/model-studio/get-api-key)\n\n两者都缺时，`cloud` 真跑会安全停止，不下载、不静默切 Whisper。只有 `DASHSCOPE`、没有 SiliconFlow 时会告警。Key 放环境变量/Secret Manager，不要发聊天或进仓库。\n\nskill 会自动读取当前 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local` 中的相关配置，Hermes 没透传环境也能继续走 cloud 默认。\n\n同时安装 `douyin-favorites-to-knowledge` 时，setup 会探测并优先复用它的已登录浏览器 profile 和转录偏好，但状态、输出和调度完全隔离：Creator Insight 默认写入 `./output/creator-insight/`，不读取收藏 metadata，也不加入 23:00 收藏任务。运行前执行 `python3 scripts/integration.py`；若共享 profile 已被占用，等待当前流程结束即可。`douyin-mcp` 是可选诊断工具，不是安装或运行依赖。\n\n### 1. 本地浏览器模式（默认推荐）\n\n首次独立使用时，本 skill 会使用中性的共享浏览器 profile；登录一次抖音即可。若已安装收藏 skill，则自动复用它现有的已登录 profile。之后可直接粘贴主页、`sec_uid`，或包含 `https://v.douyin.com/.../` 的完整分享消息：\n\n```bash\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py \\\n  --creator '长按复制此条消息，打开抖音搜索 https://v.douyin.com/xxxx/ ...' \\\n  --browser --max-videos 50 --output-dir ./output\n```\n\n该模式只读取公开作品列表，逐页验证每条作品作者的 `sec_uid`，不复制 cookie、不输出 profile、不绕过验证码。抖音媒体默认走 SiliconFlow 上传 ASR（Referer 下载后清理）；非抖音公网媒体可走百炼 URL ASR；全部云端失败才回退本地 Whisper。\n\n非交互环境可以显式配置：\n\n```bash\n# 云端：保存选择；若 Key 尚未配置，真实运行会安全停止并给出申请入口\npython3 scripts/setup.py --transcript-mode cloud\n\n# 本地：只有明确选择 local 后，真实运行才允许临时下载视频\npython3 scripts/setup.py --transcript-mode local\n\n# 索引：不转录、不下载视频\npython3 scripts/setup.py --transcript-mode index\n```\n\n首次使用需要可选依赖：\n\n```bash\npython3 -m pip install playwright\npython3 -m playwright install chromium\n```\n\n### 2. 作为 Agent Skill 或 Apify fallback\n\n安装到支持 `SKILL.md` 的 agent 环境后，优先走浏览器模式；没有已授权浏览器或浏览器接口异常时，才使用 Apify MCP 或下述 adapter。真实 token 必须由环境变量或宿主 secret store 提供，不要提交到仓库。\n\n### 3. 作为 CLI adapter\n\nCLI 不会猜测凭据，也不会把“未抓取”伪装成成功。必须显式选择以下一种模式：\n\n```bash\n# 非联网检查：只解析输入，不生成真实报告\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --dry-run\n\n# 真实执行：由使用者提供 module:function adapter\nPYTHONPATH=/path/to/adapters:$PYTHONPATH \\\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --adapter my_adapter:call_actor \\\n  --max-videos 50 \\\n  --transcript-count 3 \\\n  --output-dir ./output\n```\n\nAdapter 必须实现以下调用契约：\n\n```python\ndef call_actor(*, actor: str, input: dict, wait_secs: int):\n    \"\"\"Return a list of dataset items or {'datasetItems': [...]} for profile calls.\"\"\"\n```\n\n昵称或抖音号还需要搜索 adapter：\n\n```bash\npython3 scripts/run_pipeline.py \\\n  --creator <nickname> \\\n  --adapter my_adapter:call_actor \\\n  --browser-adapter my_adapter:search_creator\n```\n\n`search_creator(*, query: str, max_results: int)` 应返回包含公开主页 URL 的文本、列表或字典。\n\n## 参数\n\n| 参数 | 说明 | 默认值 |\n|---|---|---|\n| `--creator` | 主页 URL、`sec_uid`、完整分享消息；adapter 模式也可接受抖音号或昵称 | 必填 |\n| `--dry-run` | 非联网解析检查 | 与 `--browser`、`--adapter` 三选一 |\n| `--browser` | 使用已授权浏览器 profile 采集公开主页 | 与 `--dry-run`、`--adapter` 三选一 |\n| `--browser-profile` | 可选的 Playwright persistent profile 目录 | 默认复用 favorites profile |\n| `--headed` | 显示浏览器窗口，用于诊断登录/验证码 | 默认隐藏 |\n| `--adapter` | Apify 或其他外部真实采集 adapter，`module:function` | 与 `--dry-run`、`--browser` 三选一 |\n| `--browser-adapter` | 昵称/抖音号搜索 adapter | 可选 |\n| `--max-videos` | 请求的视频上限 | 1000 |\n| `--transcript-count` | 请求的转写候选数；指定时覆盖自动分档 | 按账号规模自动选择 |\n| `--transcript-mode` | `cloud` 默认 SiliconFlow 上传 ASR（抖音 CDN）+ 可选百炼公网直链 + local fallback；`local` Whisper；`index` 只做信息索引 | setup 选择，未配置时为 `cloud` |\n| `--no-local-fallback` | 云端 ASR 全部失败时不回退本地 Whisper | 关闭 |\n| `--max-duration` | 选择阶段的时长上限，分钟 | 5 |\n| `--output-dir` | Creator Insight 专用报告目录 | `./output/creator-insight` |\n| `--format` | `html json md` 的任意组合 | 全部 |\n\n## 本地验证\n\n测试完全使用 fixtures，不调用抖音或 Apify，也不需要 token。\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nCI 在 Python 3.10 和 3.12 上执行同一套测试。测试覆盖：\n\n- CLI 显式模式契约和退出码；\n- dry-run 不写输出；\n- 10 条 fixture 视频到三格式报告的端到端链路；\n- Skill 元数据、私人绝对路径和常见 secret 模式扫描。\n\n## 数据源与成本\n\n浏览器模式不需要 Apify key，边界是用户已授权浏览器可访问的公开主页。默认 cloud ASR：抖音 CDN 走 SiliconFlow `SenseVoiceSmall`；百炼 `qwen3-asr-flash` 仅公网直链媒体；**费用**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。 其它（如 Apify）价格、地域和免费额度会变化，实际扣费以所用平台（SiliconFlow / 百炼）控制台账单为准。默认 actor 和 fallback 见 [references/apify-douyin-actors.md](references/apify-douyin-actors.md)。Actor 的可用性、输入 schema、价格和账户额度会变化；运行前应在对应 Apify Actor 页面核验，并先用小样本测试。仓库不承诺固定耗时、费用或免费额度。\n\n## 输出与示例\n\n| 文件 | 用途 |\n|---|---|\n| [docs/sample-report.html](docs/sample-report.html) | HTML 报告示例 |\n| [docs/sample-report.md](docs/sample-report.md) | Markdown 摘要示例 |\n| [docs/sample-report.json](docs/sample-report.json) | 结构化数据示例 |\n\n报告中的互动排序是研究启发式，不代表推荐系统权重，也不构成商业、投资或平台增长保证。\n\n## 已知边界\n\n- 上游字段或 Actor 行为变化可能导致质量门阻断。\n- 昵称搜索可能触发验证码，也可能产生同名候选；浏览器模式不会搜索或自动选择，需改贴主页或分享链接。\n- 无旁白、纯音乐、未配置云端 Key 或上游转写失败的视频可能没有 transcript。未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` 时真实运行会安全停止并提示官方申请入口，不会自动下载视频。\n- 未指定 `--transcript-count` 时：30 条及以下全量转写；31-100 条按点赞前 50；101-300 条选 60 条；301-800 条选 80 条；更大账号最多选 100 条。大账号样本按点赞、收藏与近期作品分层去重，避免只偏向历史爆款。\n- 浏览器模式会记录主页声明作品数、实际采集数和分页状态。达到请求上限而尚有下一页时，结果为 `partial`，不能作为全量结论。\n- 收藏 skill 是可选共享底座，不是前置依赖；同时安装时先运行 `scripts/integration.py` 探测 profile 占用和输出布局。浏览器模式不会读取或导出 cookie。\n- 私密账号、绕过访问控制和未授权批量采集不在支持范围内。\n\n## 安全与贡献\n\n安全问题请按 [SECURITY.md](SECURITY.md) 私下报告。开发与 PR 约定见 [CONTRIBUTING.md](CONTRIBUTING.md)。\n\n## License\n\n[MIT](LICENSE)\n\n## SiliconFlow\n\n- 注册推荐链接：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n### ASR 媒体与码率（1.3.4+）\n- 优先 `audio_url`，失败回退 `video_url`。\n- `DOUYIN_ASR_AUDIO_BITRATE`（默认 64k）、`DOUYIN_ASR_SAMPLE_RATE`（默认 16000）。\n- 抖音 `music.play_url` 仅在原创音时采用，商业 BGM 不用。\n- 推荐注册：https://cloud.siliconflow.cn/i/1srulim9\n\nFile v1.3.4:_meta.json\n\n{\n  \"ownerId\": \"kn7fgfkjyfqbz673wvzymh5e1x821vpk\",\n  \"slug\": \"douyin-creator-insight\",\n  \"version\": \"1.3.4\",\n  \"publishedAt\": 1785920769864\n}\n\nFile v1.3.4:references/apify-douyin-actors.md\n\n# Apify Douyin Actors 对照表\n\n## 三个核心 actor\n\n### 1. `zen-studio/douyin-profile-scraper` ⭐ 主用\n\n**用途**：抓取指定博主的所有视频列表\n\n**输入**：\n```json\n{\n  \"maxPostsPerProfile\": 200,\n  \"profileUrls\": [\"https://www.douyin.com/user/MS4w...\"]\n}\n```\n\n**输出字段**：\n```json\n[\n  {\n    \"id\": \"7600998358588812742\",\n    \"text\": \"视频文案/描述\",\n    \"title\": \"标题\",\n    \"createTime\": 1737638400,\n    \"createDate\": \"2025-01-23\",\n    \"statistics\": {\n      \"diggCount\": 12345,\n      \"commentCount\": 678,\n      \"shareCount\": 90,\n      \"collectCount\": 234,\n      \"playCount\": 567890\n    },\n    \"videoMeta\": {\n      \"duration\": 120000,\n      \"cover\": \"https://...\"\n    },\n    \"hashtags\": [{\"name\": \"...\"}],\n    \"series\": {\"name\": \"...\"},\n    \"shareUrl\": \"https://...\",\n    \"authorMeta\": {\n      \"name\": \"...\",\n      \"signature\": \"...\",\n      \"followersCount\": 333000,\n      \"heartCount\": 2672708,\n      \"awemeCount\": 200\n    }\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。公开视频、README 和教程里不要承诺固定成本；第一次建议先小样本验证。\n\n**限制**：maxPostsPerProfile 上限 200\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-profile-scraper\",\n    input={\n        \"maxPostsPerProfile\": 200,\n        \"profileUrls\": [profile_url]\n    },\n    wait_secs=45\n)\n```\n\n### 2. `zen-studio/douyin-transcripts-scraper` ⭐ 主用转写\n\n**用途**：抓取视频语音转写；当前限制以 Actor 页面为准\n\n**输入**：\n```json\n{\n  \"targetLanguage\": \"zh\",\n  \"videoUrls\": [\"https://www.douyin.com/video/7575296454722398441\", ...]\n}\n```\n\n**输出**：\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"...\",\n    \"text\": \"完整转写文本...\",\n    \"duration\": 812,\n    \"segments\": [{\"start\": 0, \"end\": 5.2, \"text\": \"...\"}, ...]\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-transcripts-scraper\",\n    input={\n        \"targetLanguage\": \"zh\",\n        \"videoUrls\": [video_url1, video_url2, ...]\n    },\n    wait_secs=45\n)\n```\n\n### 3. `apple_yang/douyin-transcripts-scraper` 备选\n\n**用途**：备用转写服务\n\n**输入**：\n```json\n{\n  \"videoUrl\": \"https://www.douyin.com/video/...\"\n}\n```\n\n**输出**：同上\n\n**限制**：历史测试中长视频支持不稳定；当前限制以 Actor 页面为准\n\n**价格**：以 Apify Actor 当前页面为准。\n\n## 备选 actor（不推荐）\n\n### `bovi/douyin-scraper`\n- 优点：功能多\n- 缺点：`user_videos` 模式 2026 起需要登录 cookies，已验证空结果\n- 不推荐\n\n### `sian.agency/douyin-scraper`\n- 优点：支持 userVideos\n- 缺点：可能排队较久，且可能需要登录 cookies\n- 不推荐\n\n### `apify--rag-web-browser`\n- 用途：网页搜索 + 渲染\n- 兜底方案：当 profile scraper 失败时用此搜索主页\n- 调用示例：\n```python\napify_browser(\n    query=\"https://www.douyin.com/user/MS4w...\",\n    max_results=1\n)\n```\n\n## 经验教训\n\n1. **优先用 zen-studio 系列**，但运行前核对当前访问要求与输入 schema\n2. **user_videos 模式 = 需要登录**（2026 现状）→ 慎用 bovi/sian.agency\n3. **转写超时**：降低样本或候选时长，并核对 Actor 当前限制\n4. **TOON 格式**：Apify 返回的是 TOON 格式，需要手动解析（见 `data-schema.md`）\n5. **字段 schema 不稳定**：不同 actor 返回字段名差异大，需要多别名解析（见 `parser.py::_extract_field`）\n\n## 失败兜底顺序\n\n```\nzen-studio profile scraper (主)\n  ↓ 失败\napify--rag-web-browser 渲染主页\n  ↓ 失败\nWebSearch + 用户手动提供数据\n```\n\n```\nzen-studio transcripts scraper (主)\n  ↓ 失败\napple_yang transcripts scraper (备用，限制以当前 Actor 页面为准)\n  ↓ 失败\n跳过该视频，继续下一个\n```\n\nFile v1.3.4:references/categorization-taxonomy.md\n\n# Categorization Taxonomy · 内容分类体系\n\n## 规则标签关键词（`categorizer.py::CATEGORY_KEYWORDS`）\n\n### 进外企方法\n- `进外企` / `如何进入` / `外企面试` / `外企推荐` / `简历` / `英文` / `雅思` / `BEC` / `外企 title`\n\n### 外企清单\n- `外企清单` / `小而美` / `推荐名单` / `十大城市` / `十个城市` / `城市知名` / `最佳雇主` / `福布斯`\n\n### 福利揭秘\n- `福利` / `待遇` / `15 天年假` / `年假` / `加班` / `年终奖` / `六险一金` / `补充医疗`\n\n### 跳槽/转行\n- `跳槽` / `转型` / `转行` / `准备` / `实操` / `拿下`\n\n### 英语学习\n- `英语` / `英文` / `口语` / `听力` / `职场英语` / `BEC`\n\n### 认知/成长\n- `认知` / `成长` / `心法` / `建议` / `格局`\n\n### 母婴/育儿\n- `母婴` / `育儿` / `宝宝` / `宝贝` / `妈妈`\n\n### 宠物/动物\n- `宠物` / `猫` / `狗` / `皇家` / `玛氏`\n\n### 美食/食品\n- `美食` / `食品` / `食谱` / `厨房`\n\n### 数码/3C\n- `数码` / `3C` / `手机` / `电脑` / `评测`\n\n## 标签来源\n\n| source | 说明 | 示例 |\n|---|---|---|\n| `rule` | 规则关键词匹配 | `进外企方法` |\n| `hashtag` | 来自视频 hashtag | `#外企` → 进外企方法 |\n| `series` | 来自合集名 | `英语学习与提升` → 合集: 英语学习与提升 |\n| `llm` | LLM 主题分类 | 由 LLM 补充 |\n\n## LLM 分类提示词\n\n`categorizer.py::build_categorization_prompt` 生成的提示词：\n\n```python\nprompt = \"\"\"你是一个抖音内容分析专家。请基于以下 {N} 个视频的信息，把它们分到合适的类别。\n\n# 任务\n1. 输出主分类（每个视频 1 个）：进外企方法 / 外企清单 / 福利揭秘 / 跳槽转行 / 英语学习 / 母婴/育儿 / 其他\n2. 提取关键洞察：\n   - 博主主要面向谁（年龄/性别/职业）\n   - 3 个核心主题\n   - 5 条最有价值的视频标题\n   - 选题公式（爆款标题的共同特征）\n\n# 输出格式（JSON）\n{\n  \"main_categories\": [\"...\"],\n  \"audience\": \"...\",\n  \"core_themes\": [\"...\", \"...\", \"...\"],\n  \"top_5_videos\": [\"标题1\", \"标题2\", ...],\n  \"title_formula\": \"...\",\n  \"insights\": \"...\"\n}\n\"\"\"\n```\n\n## 扩展指南\n\n要新增分类：\n1. 在 `CATEGORY_KEYWORDS` 字典中添加新类别 + 关键词列表\n2. 重跑 `categorize_videos()` 即可\n\n要改 LLM 提示词：\n1. 修改 `build_categorization_prompt()` 函数\n2. 调用方传更多视频元数据\n\n## 实战经验\n\n- 史蒂文不做牛马账号的分类分布（200 条视频）：\n  - 英语学习与提升：42 条（合集）\n  - 职业规划与发展：36 条（合集）\n  - 认知与成长合集：5 条（合集）\n  - 外企清单散装：12+ 条\n  - 进外企方法散装：10+ 条\n  - 福利揭秘：5+ 条\n- 建议给 LLM 提供至少 10 条样本视频做分类\n- 主题分类后建议人工复核 TOP 5，确保准确\n\nFile v1.3.4:references/creator-resolution-playbook.md\n\n# Creator Resolution Playbook · 博主识别策略\n\n## 输入类型判定\n\n`resolver.py::parse_input_type` 判定逻辑：\n\n| 类型 | 正则 | 示例 |\n|---|---|---|\n| douyin_id | `^\\d{6,12}$` | `<douyin_id>`（如 `12345678`） |\n| sec_uid | `MS4w...` | `MS4wLjABAAA...` |\n| url | `https://(www\\.)?douyin\\.com/user/MS4w...` | `https://www.douyin.com/user/MS4wLjABAAA...` |\n| nickname | 含中英文 | `史蒂文不做牛马` |\n\n## 精准 vs 模糊匹配\n\n### 精准匹配（confidence ≥ 0.9）\n\nsec_uid 直接确认，不需问用户。\n\n```\n输入: MS4wLjABAAAA...<sec_uid>...   # 抖音内部唯一 ID\n→ 解析: sec_uid = MS4w...\n→ confidence = 0.95\n→ matched = True\n→ profile_url = https://www.douyin.com/user/MS4w...\n```\n\n### 模糊匹配（confidence < 0.9）\n\n用 `apify--rag-web-browser` 搜索：\n- query: `抖音 {creator_query}`\n- 解析搜索结果的 markdown\n- 提取候选人列表（昵称 + 简介 + 粉丝数）\n\n```\n输入: {nickname}                 # 示例：史蒂文不做牛马\n→ 搜索: 抖音 {nickname}\n→ 候选 1: {nickname} · {signature} · {followers} → confidence 0.95\n→ 候选 2: 其他同名账号\n→ 选 #1，自动继续\n```\n\n## 失败处理\n\n### 找不到任何人\n\n```\n输入: 不存在的昵称\n→ 搜索: 返回空\n→ matched = False\n→ AskUserQuestion 让用户重新输入\n```\n\n### 找到多个相似\n\n```\n输入: 小李\n→ 候选 5 个相似账号\n→ AskUserQuestion 让用户选\n→ 用户选 #3 → 用 sec_uid 继续\n```\n\n## 实战经验\n\n### 抖音号和 sec_uid 的区别\n\n- **抖音号**（douyin_id）：纯数字，用户可改，6-12 位\n  - 例：`<douyin_id>`（如 `12345678`）\n- **sec_uid**：抖音内部唯一 ID，MS4w 开头，不可改\n  - 例：`MS4wLjABAAAA...`（约 60 字符长）\n\n**profile scraper 必须用 sec_uid**，不能用抖音号。\n\n### 已知搜不到的输入\n\n- 短链（`v.douyin.com/xxx`）需要先 WebFetch 解析\n- 长 URL（带 modal_id 参数）可能是视频 ID\n- 纯数字 < 6 位大概率不是抖音号\n\n### 实战踩坑\n\n1. **抖音号搜不到人**：用户可能改了 douyin_id，但 sec_uid 不变。永远用 sec_uid。\n2. **同名账号**：很多用户取相似昵称，需要看签名 + 粉丝数判定。\n3. **博主已注销**：可能抓不到视频。提示用户确认。\n\n## 关键代码\n\n`scripts/resolver.py`：\n- `parse_input_type(user_input)`: 识别输入类型\n- `resolve_creator_via_apify(...)`: 主入口\n- `_resolve_via_apify_search(...)`: 模糊匹配逻辑\n- `format_resolution_for_question(...)`: 转 AskUserQuestion 选项\n\nFile v1.3.4:references/data-schema.md\n\n# Data Schema · 字段映射\n\n## Apify profile scraper → 标准化字段\n\n不同 actor 字段名差异（已实测）：\n\n| 标准化字段 | zen-studio | bovi | sian.agency | TOON 解析后 |\n|---|---|---|---|---|\n| aweme_id | id | aweme_id | videoId | id |\n| title | title | (空) | (空) | title |\n| desc | text | desc | desc | text |\n| create_time | createTime | create_time | timestamp | createTime |\n| duration_ms | videoMeta.duration | video.duration | duration | videoMeta.duration |\n| cover_url | videoMeta.cover | video.cover | coverUrl | videoMeta.cover |\n| share_url | shareUrl | share_url | url | shareUrl |\n| hashtags | hashtags[].name | (空) | (空) | hashtags.name |\n| series_name | series.name | (空) | (空) | series.name |\n| digg_count | statistics.diggCount | aweme_stats.digg_count | stats.like | statistics.diggCount |\n| comment_count | statistics.commentCount | aweme_stats.comment_count | stats.comment | statistics.commentCount |\n| share_count | statistics.shareCount | aweme_stats.share_count | stats.share | statistics.shareCount |\n| collect_count | statistics.collectCount | aweme_stats.collect_count | stats.favorite | statistics.collectCount |\n| play_count | statistics.playCount | aweme_stats.play_count | stats.view | statistics.playCount |\n\n## TOON 格式示例\n\nApify `get_dataset_items` 返回的是 TOON 格式（不是 JSON）：\n\n```toon\nitems[200]:\n  - id: \"7600998358588812742\"\n    text: \"进外企真的不难\"\n    createTime: 1737638400\n    statistics:\n      diggCount: 42451\n      commentCount: 1500\n      shareCount: 800\n      collectCount: 24647\n    videoMeta:\n      duration: 240000\n      cover: \"https://...\"\n    hashtags:\n      - name: \"外企\"\n      - name: \"求职\"\n    authorMeta:\n      name: \"史蒂文不做牛马\"\n      signature: \"在七种不同国别外企混迹的牛马一枚\"\n      followersCount: 333000\n      heartCount: 2672708\n```\n\n## 解析规则\n\n`scripts/parser.py::parse_toon_output` 实现：\n1. 用 `items[N]:` 作为块起点\n2. 用 `\\n  - id:` 作为分隔符切分 item\n3. 每行按 4 空格缩进解析 key-value\n4. 多层缩进（如 `statistics.diggCount`）用 `.` 合并为路径\n\n## transcripts scraper 输出\n\nzen-studio transcripts 返回格式：\n\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"视频标题\",\n    \"text\": \"完整转写文本\",\n    \"duration\": 812,\n    \"segments\": [\n      {\"start\": 0.0, \"end\": 5.2, \"text\": \"...\"},\n      ...\n    ],\n    \"errMsg\": null\n  }\n]\n```\n\n## 字段映射实现位置\n\n`scripts/parser.py::_extract_field()` 支持多路径：\n\n```python\n_extract_field(item, [\n    \"statistics.diggCount\",  # zen-studio\n    \"aweme_stats.digg_count\",  # bovi\n    \"stats.diggCount\",  # sian.agency\n])\n```\n\n按顺序尝试，找到第一个非空值。\n\nFile v1.3.4:references/failure-playbook.md\n\n# Failure Playbook · 失败场景手册\n\n## 1. 用户输入的抖音号找不到人\n\n**症状**：`resolve_creator_via_apify` 返回 `matched=False`\n\n**主策略**：\n- 用 `apify--rag-web-browser` 搜索 \"抖音 {creator_query}\"\n- 解析搜索结果，提取候选人列表\n\n**兜底**：\n- AskUserQuestion 列出 3-5 个候选，让用户确认\n- 用户确认后用 sec_uid 重新调用\n\n**关键代码位置**：`resolver.py::_resolve_via_apify_search`\n\n## 2. 视频列表抓不到 / 返回 0 条\n\n**症状**：`parse_actor_dataset` 返回空列表\n\n**原因**：\n- 用户输入的不是用户主页（可能是视频 URL）\n- Apify 账号额度耗尽\n- 抖音 API 反爬\n\n**主策略**：\n- 检查 `maxPostsPerProfile` 是否过大（> 500 容易失败）\n- 重试 + 减小数量\n\n**兜底**：\n- 用 `apify--rag-web-browser` 渲染主页，手动解析\n- 提示用户上传原始 JSON，走离线模式\n\n**关键代码位置**：`run_pipeline.py` Step 2\n\n## 3. 视频列表字段大量为空\n\n**症状**：parse 后大部分 video.title 或 stats 为空\n\n**原因**：\n- actor schema 变化\n- 字段别名没覆盖\n\n**主策略**：\n- 在 `parser.py::_extract_field` 增加新别名\n- 检查 TOON 解析是否有 bug\n\n**兜底**：\n- 保留 raw JSON，下次重试时直接复用\n- 用 `quality_gate.py::check_videos` 检测\n\n## 4. 语音转写全部失败\n\n**症状**：`fetch_transcripts` 返回空或全部 failed\n\n**主策略**：\n- 检查视频时长和 Actor 当前限制\n- 切换备用 actor（apple_yang）\n\n**兜底**：\n- 仅用标题 + 描述 + 互动数据分析，不依赖转写\n- 报告标注 \"transcripts_unavailable\"\n\n## 5. 视频没有旁白（音乐/纯画面）\n\n**症状**：transcript 返回空字符串\n\n**判断**：transcript text 长度 < 10 → 标记 `empty_transcript`\n\n**主策略**：\n- 跳过该视频的转写\n- 改用 title + desc + hashtags 做内容分析\n\n**兜底**：\n- 报告里标注\"无旁白视频\"\n- 用 B 站 / YouTube 等替代来源\n\n## 6. Apify 账号额度耗尽\n\n**症状**：所有 actor 调用都返回 4xx 错误\n\n**主策略**：\n- 减小 `max_videos` 和 `transcript_count`\n- 提示用户充值\n\n**兜底**：\n- 完全离线模式：用户上传历史 raw JSON，skill 仅做分析和报告\n- 使用用户提供的、已获授权的公开数据快照\n\n## 7. 字段 schema 突然变化\n\n**症状**：解析后大量字段为 None\n\n**主策略**：\n- 增加字段别名（参考 `data-schema.md`）\n- 保留 raw 字段，下次回放时排查\n\n**兜底**：\n- 用 `WebFetch` 抓主页 HTML 作为补充\n- 让用户手动提供关键视频 URL\n\n## 8. 时间相关问题\n\n- **createTime 是毫秒还是秒**？不同 actor 不同\n  - `parser.py::_format_date` 自动判断：> 10^12 是毫秒\n- **时长过滤**：默认筛选上限为 5 分钟，可按 Actor 当前限制调整\n  - `selector.py::apply_duration_penalty` 自动惩罚\n\n## 9. 网络/TLS 错误\n\n**症状**：MCP 调用超时或连接失败\n\n**主策略**：\n- 重试（最多 3 次）\n- 切换备用 actor\n\n**兜底**：\n- WebSearch 抓搜索结果页（`apify--rag-web-browser`）\n- 让用户提供手动数据\n\n## 10. 报告生成失败\n\n**症状**：`save_reports` 报错\n\n**主策略**：\n- 检查磁盘空间\n- 检查文件权限\n\n**兜底**：\n- 只生成 JSON 格式（最小输出）\n- 用 `cat > output.json` 直接写文件\n\n## 通用诊断流程\n\n```\n1. 检查 Apify token 是否有效\n2. 检查网络连接（clash verge / proxy）\n3. 用 `quality_gate.run_quality_gate` 检测哪阶段失败\n4. 查本 playbook 找对应失败场景\n5. 实施主策略\n6. 如果失败，启用兜底\n7. 报告失败原因给用户\n```\n\n## 关键代码位置速查\n\n| 失败阶段 | 主要函数 | 兜底函数 |\n|---|---|---|\n| 解析博主 | `resolver.resolve_creator_via_apify` | `_resolve_via_apify_search` |\n| 抓视频 | `parser.parse_actor_dataset` | `apify_browser` |\n| 字段解析 | `parser._extract_field` | 保留 raw |\n| 选精华 | `selector.select_essentials` | 仅按点赞排序 |\n| 转写 | `transcript.fetch_transcripts` | 切换 actor |\n| 报告 | `report_builder.save_reports` | 单独保存 |\n\nFile v1.3.4:references/pre-questions.md\n\n# Pre-questions · AskUserQuestion 模板\n\n## 问询原则\n\n自然语言优先。只有用户没有给目标账号、昵称搜索出现多个候选、或用户要求控制规模/成本时，才提问。默认参数不要逐项打断用户。\n\n推荐输入优先级：\n\n1. 抖音主页 URL\n2. `sec_uid`\n3. 抖音号 / ID\n4. 昵称\n\n昵称支持搜索，但同名账号较多；如果置信度不够，需要让用户确认候选。\n\n## 必填信息\n\n### Q1: 用户输入（creator_query）\n\n```\n\"请提供抖音号 / 昵称 / 主页 URL\"\n```\n\n接受输入格式：\n- 抖音号（纯数字 6-12 位）：如 `<douyin_id>`（如 `12345678`）\n- sec_uid（MS4w 开头）：如 `MS4wLjABAAA...`\n- 昵称：如 `史蒂文不做牛马`\n- 主页 URL：如 `https://www.douyin.com/user/MS4w...`\n\n如果用户已经在一句话里给出上述任意信息，不需要再问 Q1。\n\n## 条件必填（仅当模糊匹配时）\n\n### Q2: 候选博主确认\n\n```\n\"找到几个相似的博主，请确认哪个是您要的：\"\n```\n\n- option1: <nickname1> <signature1> · 粉丝 X 万\n- option2: <nickname2> <signature2> · 粉丝 Y 万\n- ...\n\n## 默认参数（通常不问，直接采用）\n\n### Q3: 抓取视频条数\n\n```\n\"要抓取多少条最新视频？\"\n- 推荐（200 条）\n- 深度（500 条）\n- 快速（50 条）\n```\n\n默认：200\n\n### Q4: 语音转写条数\n\n```\n\"要抓取多少条精华视频的语音转写？\"\n- 5 条（推荐）\n- 10 条\n- 全部精华（可能耗时）\n```\n\n默认：5\n\n### Q5: 转写时长上限（分钟）\n\n```\n\"转写候选的视频时长上限？\"\n- 5 分钟（默认，用于控制样本规模）\n- 10 分钟\n- 不限（可能显著增加资源消耗）\n```\n\n默认：5\n\n### Q6: 研究目标\n\n```\n\"主要研究目标？\"\n- 综合洞察（推荐）\n- 选题拆解\n- 爆款分析\n```\n\n默认：综合洞察\n\n### Q7: 输出格式\n\n```\n\"输出哪些格式的报告？\"\n- HTML（可视化）\n- Markdown（快读）\n- JSON（数据分析）\n```\n\n默认：全部\n\n### Q8: 输出目录\n\n```\n\"报告保存到哪里？\"\n```\n\n默认：当前工作目录 `./output/`\n\n## 什么时候主动改成小样本\n\n用户出现这些意图时，建议先小样本：\n\n- “先试一下”\n- “省额度”\n- “先看看能不能跑通”\n- “教程演示”\n\n推荐小样本：`max_videos=50`、`transcript_count=1`。如果用户明确说完整分析或未指定规模，则使用默认 `max_videos=200`、`transcript_count=5`。\n\n## 完整调用示例\n\n```python\nfrom AskUserQuestion import ask_user_questions\n\nquestions = [\n    {\n        \"key\": \"creator_query\",\n        \"question\": \"请提供抖音号 / 昵称 / 主页 URL\",\n        \"required\": True,\n    },\n    {\n        \"key\": \"max_videos\",\n        \"question\": \"要抓取多少条最新视频？\",\n        \"default\": 200,\n        \"options\": [50, 100, 200, 500],\n    },\n    # ...\n]\n\nanswers = ask_user_questions(questions)\n```\n\nFile v1.3.4:references/report-rubric.md\n\n# Report Rubric · 报告标准\n\n## 报告结构\n\n### HTML 报告章节\n\n```\n1. Hero（封面）\n   - 博主头像 + 昵称 + sec_uid\n   - 4 个数据卡片：粉丝/获赞/视频数/转写数\n   - 个人简介（signature）\n\n2. 摘要\n   - 报告基于 N 条视频 + M 条转写\n   - 报告时点\n\n3. 主题分类（如有）\n   - 每个分类：名称 + 视频数 + TOP 5 视频列表\n\n4. 精华视频语音转写\n   - 每条视频卡片：\n     - 创建日期\n     - 互动数据（点赞/收藏）\n     - 转写状态（success/empty/failed）\n     - 标题\n     - 完整转写（可折叠）\n\n5. 互动 TOP 视频（表格）\n   - 列：# / 标题 / 日期 / 👍 / ⭐ / 💬\n   - 默认 TOP 40\n\n6. 数据来源 + 方法\n   - Apify actor 列表\n   - 互动分公式\n   - 报告生成时间\n```\n\n### Markdown 报告章节\n\n```\n1. # 标题\n2. ## 📊 账号概况（表格）\n3. ## 🏷️ 主题分类（每类列表）\n4. ## 🎙️ 精华视频语音转写（每条）\n5. ## 🏆 互动 TOP 视频（表格）\n6. ## 📖 数据来源\n```\n\n### JSON 数据包结构\n\n```json\n{\n  \"creator\": {...},\n  \"videos\": [...],\n  \"transcripts\": [...],\n  \"categories\": {...},\n  \"top_videos\": [...],\n  \"research_goal\": \"creator_insight\",\n  \"generated_at\": \"ISO 8601\"\n}\n```\n\n## 视觉规范\n\n### 配色\n\n| 用途 | 颜色 |\n|---|---|\n| 主背景 | 渐变 `#f5f7fa → #e8ecf3` |\n| 头部 | 渐变 `#1e3a8a → #5b21b6`（深紫蓝） |\n| 标题色 | `#1e293b` |\n| 强调色 | `#5b21b6` |\n| 链接色 | `#3730a3` |\n| 警告色 | `#f59e0b` |\n| 转写框 | `#fffbeb`（米黄） |\n| 点赞数 | `#ef4444`（红） |\n| 收藏数 | `#f59e0b`（橙） |\n\n### 字号\n\n| 元素 | 字号 |\n|---|---|\n| Hero h1 | 32px |\n| section h2 | 26px |\n| section h3 | 20px |\n| section h4 | 17px |\n| 正文 | 16px |\n| 视频元信息 | 13px |\n\n### 间距\n\n- section padding: 50px 40px\n- 卡片 padding: 14-22px\n- 段落间距: 12-18px\n\n## 数据准确度标准\n\n### 必须保留的字段\n\n- `aweme_id`（必填）\n- `stats.digg_count` / `comment_count` / `share_count` / `collect_count`\n- `create_date`（YYYY-MM-DD 格式）\n- `duration_seconds`（如可用）\n\n### 应当标注的状态\n\n- 转写状态：`success` / `failed` / `empty_transcript` / `skipped`\n- 匹配度：5★ / 4★ / 3★\n- 数据来源：zen-studio / apple_yang / bovi 等\n\n## 输出文件命名\n\n```\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.html\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.md\n{nickname}_douyin_insight_{YYYYMMDD_HHMMSS}.json\n```\n\n例：`史蒂文不做牛马_douyin_insight_20260709_093200.html`\n\n## 性能记录\n\n不设置未经基准测试的固定耗时。每次真实运行应记录样本量、Actor、开始/结束时间、失败数和输出大小；不同账号、网络、Actor 队列和上游 schema 下的结果不可直接类推。\n\n## 测试用例\n\n使用 `tests/test_pipeline.py` 中的合成 fixture 作为可重复测试。真实公开账号报告只作为展示样例，不作为性能基准。\n\n## 复用模板\n\n`scripts/report_builder.py` 内置 HTML/MD 模板，无需额外 assets/ 依赖。\n\n如果需要自定义样式：\n1. 复制 `HTML_TEMPLATE` 到 `assets/report_template.html`\n2. 修改后用 `jinja2` 或其他模板引擎渲染\n3. 当前实现用纯 Python `str.format()`，无 jinja 依赖\n\nFile v1.3.4:CHANGELOG.md\n\n# Changelog\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## [1.3.4] - 2026-08-05\n\n### Changed\n- ASR：优先 `audio_url`，失败回退 `video_url`；`DOUYIN_ASR_AUDIO_BITRATE` / `DOUYIN_ASR_SAMPLE_RATE` 可配。\n- 采集：仅原创音写入 `audioUrl`，避免商业 BGM 误当口播。\n\n## [1.3.3] - 2026-08-05\n\n### Changed\n- 文档加入 SiliconFlow 注册推荐链接：https://cloud.siliconflow.cn/i/1srulim9\n\n## [1.3.2] - 2026-08-05\n\n### Changed\n- 文档补齐 SiliconFlow 费用说明：截至 2026-08-05 官方价格页 `FunAudioLLM/SenseVoiceSmall` 标注**免费**（https://siliconflow.cn/pricing；会变，以账单为准，不承诺永久免费）。\n\n## [1.3.1] - 2026-08-05\n\n### Fixed\n- 清除 README / CLI help / mcp.json.example 中残留的「cloud 默认百炼」表述，与 1.3.0 SiliconFlow 主路径对齐。\n\n## [Unreleased]\n\n## [1.3.0] - 2026-08-05\n\n### Fixed（面向公开用户的关键纠错）\n\n- **抖音 CDN 云端转写默认路径错误**：此前文档与 setup 将「阿里云百炼 URL-ASR」宣传为推荐主路径。实测百炼服务端无法拉取 `*.douyinvod.com`，会稳定失败；公开用户按文档只配 `DASHSCOPE_API_KEY` 时几乎转不出文案。\n- **硬闸只认百炼 Key**：`run_pipeline` 在已配置 `SILICONFLOW_API_KEY` 时仍因缺少 `DASHSCOPE_API_KEY` 直接退出。\n- **媒体下载 403**：云端上传 / 本地 Whisper 下载缺少 `Referer: https://www.douyin.com/`，导致 SiliconFlow 回退也失败。\n\n### Changed\n\n- 抖音保护媒体：**优先 SiliconFlow 上传 ASR**；默认跳过百炼 URL（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n- `cloud` 就绪条件：`SILICONFLOW_API_KEY` **或** `DASHSCOPE_API_KEY`。\n- setup / README / SKILL：明确推荐 SiliconFlow 为抖音路径；百炼降为可选公网 URL 路径。\n- `cloud_asr_configured` 同时探测两种 Key。\n\n### Notes\n\n- 两家不是同一模型：百炼默认 `qwen3-asr-flash`；SiliconFlow 默认 `FunAudioLLM/SenseVoiceSmall`；账单分离。\n\n\n## [1.2.3] - 2026-08-01\n\n### Removed\n- Removed the internal `task_plan.md` process artifact from the public package.\n\n## [1.2.2] - 2026-08-01\n\n### Added\n- First-run `scripts/setup.py` for explicit `cloud` / `local` / `index` selection, with non-secret config persistence.\n- Setup and integration detection for existing `douyin-favorites-to-knowledge` installs, shared browser profiles, and reusable transcription preference.\n- Bailian API Key guidance when `DASHSCOPE_API_KEY` is missing.\n\n### Fixed\n- Missing cloud ASR credentials no longer trigger an implicit local Whisper fallback or video download; users must explicitly choose `local`.\n\n## [1.2.1] - 2026-08-01\n\n### Added\n- Adaptive transcript selection: accounts with 30 or fewer videos use all-video transcription; larger accounts use bounded, deduplicated layers of likes, saves, and recent posts.\n- Selection metadata is included in JSON results and summarized in HTML and Markdown reports.\n- Browser collection records declared work count, collected count, and pagination completion; capped collections return `partial`.\n- Independent `cloud`, `local`, and `index` transcript modes. Cloud is the default, local Whisper is a final fallback, and index mode never invokes ASR.\n- Non-mutating integration probe, neutral browser profile for standalone installs, shared-profile busy detection, and isolated Creator Insight output.\n\n### Fixed\n- Skill runtime now auto-loads ASR/browser profile config from standard local env files, so Hermes launcher env gaps no longer collapse cloud ASR into `not_configured`.\n- Profile metadata extraction now prefers exact `sec_uid` matches over sec_uid-less wrapper objects.\n- Profile API author metadata now wins over per-post author fields when merging declared counts and account stats.\n- Timed-out or error-shaped transcript payloads are marked failed and excluded from report text.\n- Missing transcript actor results now receive an explicit per-video failure status.\n- Transcript quality failures return `degraded` instead of ordinary success, with provider and quality details in the result.\n\n### Changed\n- `douyin-knowledge-base-pipeline` and `douyin-mcp` are optional integrations, not installation or runtime dependencies.\n- Cloud ASR first attempts DashScope URL recognition, then an optional temporary-audio cloud upload for large media; temporary media is always cleaned.\n- Reissued the final runtime-env hardening package as `v1.2.1` because ClawHub had already accepted an earlier `1.2.0` package and does not allow overwriting an existing version.\n\n## [1.1.0] - 2026-07-30\n\n### Added\n- Browser-first public creator collection: accepts profile URLs, `sec_uid`, and complete Douyin share messages containing `v.douyin.com` links.\n- `--browser`, `--browser-profile`, and `--headed` CLI options. The collector reuses the existing favorites persistent profile, fetches public post pages in browser context, locally caps and deduplicates results, and verifies every item's author `sec_uid`.\n\n### Changed\n- Apify is an explicit adapter fallback, not a default dependency for public creator collection.\n- Nickname and Douyin-ID searches never auto-select an account; the workflow asks for a stable profile/share link when search is ambiguous or blocked by CAPTCHA.\n- Reports state their actual collection and transcript sources. Browser-mode reports explicitly mark transcript candidates as skipped when no transcription provider is configured.\n\n## [1.0.2] - 2026-07-25\n\n### Changed\n- Updated official GitHub Actions to their Node 24 releases to remove hosted-runner deprecation warnings.\n\n## [1.0.1] - 2026-07-25\n\n### Fixed\n- CLI now requires explicit `--dry-run` or `--adapter module:function`; a real-looking command can no longer silently return a dry-run result.\n- Added fixture-based end-to-end tests and subprocess tests for CLI exit behavior.\n- Removed unbenchmarked timing, cost, quota, and free-tier promises from current documentation.\n\n### Added\n- GitHub Actions on Python 3.10 and 3.12.\n- Repository checks for Skill metadata, private absolute paths, and common live-secret patterns.\n- Security policy and explicit credential-handling guidance.\n\n## [1.0.0] - 2026-07-15\n\n### Added\n- 🎉 **首次公开发布**\n- 5 阶段 pipeline：resolver → parser → selector → transcript → categorizer → report_builder\n- 9 个核心脚本（schemas / resolver / parser / selector / transcript / categorizer / report_builder / quality_gate / run_pipeline）\n- 7 份 references 文档（pre-questions / apify-douyin-actors / data-schema / creator-resolution-playbook / categorization-taxonomy / report-rubric / failure-playbook）\n- 3 套 assets 模板（report_template.html / report_style.css / creator_card_template.html）\n- 三格式输出：HTML（可视化）+ Markdown（快读）+ JSON（数据分析）\n- 智能精华选择：互动分公式 `log(点赞)*1 + log(评论)*2.5 + log(分享)*3 + log(收藏)*2`\n- 多 actor 兜底：zen-studio 主用 → sian.agency 备选 → apify--rag-web-browser 渲染\n- 模糊匹配候选：置信度 < 0.9 时返回 3-5 个候选让用户确认\n\n### Documentation\n- README.md 加 4 大徽章（License / Python 版本 / 零依赖 / Apify 必需）\n- 加 demo 报告区（docs/sample-report.{html,md,json}）\n- 加初版额度预估表（因缺少可复现实验依据，已在 v1.0.1 删除）\n- 加 6 条 FAQ（覆盖 dry-run / 额度 / 输入选择 / empty_transcript / 私密账号 / 与 douyin-workflow 区别）\n- 加环境自检脚本\n- SKILL.md 加\"⚠️ 前置条件\"章节（4 步检查清单）\n- SKILL.md 加\"⚡ 失败兜底速查\"表格（5 行版本）\n\n### Notes\n- 零 Python 三方依赖（用 dataclasses + 标准库）\n- 需要 Apify token + Apify MCP（详见 mcp.json.example）\n- 初版包含固定额度估算；v1.0.1 起改为运行前核对 Actor 页面并以本次实测为准\n\nArchive v1.3.3: 40 files, 97572 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (7836b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (11558b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (18470b), scripts/browser_collector.py (13103b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (19121b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (8099b), scripts/setup.py (7202b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2882b), SKILL.md (9496b), tests/test_pipeline.py (18901b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nFile v1.3.3:SKILL.md\n\n---\nname: douyin-creator-insight\nversion: 1.3.3\ndescription: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。\n---\n\n# Douyin Creator Insight\n\n## 使用条件\n\n仅分析公开可访问数据。默认真实抓取使用已授权的本地浏览器 profile，不依赖 Apify key；Apify 仅是显式 fallback。不要在对话、脚本、报告或仓库中输出 token、cookie、浏览器 profile、私人绝对路径或未公开内容。\n\n## 安装与共享配置\n\n`douyin-creator-insight` 可独立安装和运行，`douyin-favorites-to-knowledge`（旧名/旧目录可能是 `douyin-knowledge-base-pipeline`）不是前置依赖。若两者都存在，本 skill 只复用已登录的 persistent browser profile 和 ASR 环境变量，绝不读取收藏记录、修改增量 metadata，或加入收藏 skill 的 23:00 任务。\n\n首次运行先执行 `python3 scripts/setup.py`。它只写非敏感偏好：`cloud`（云端 ASR）/ `local`（Whisper）/ `index`（只索引），以及可选 profile/output 位置；不保存 API key、cookie 或 token。若检测到已安装 `douyin-favorites-to-knowledge`，优先复用其已登录浏览器 profile 和转录偏好，但状态、账本、输出和 23:00 任务仍完全隔离。\n\n**云端 ASR 真相（抖音）**：抖音 CDN（`*.douyinvod.com` 等）带防盗链，**阿里云百炼 URL-ASR 服务端拉不到媒体**，会稳定失败——不是用户 Key 配错。公开 skill 的默认可用路径是：\n\n1. **推荐 `SILICONFLOW_API_KEY`**：本机用浏览器式 `Referer: https://www.douyin.com/` 临时下载 → 抽音频 → 上传 SiliconFlow `FunAudioLLM/SenseVoiceSmall` → 立即清理临时文件。\n2. **可选 `DASHSCOPE_API_KEY`**：仅当媒体 URL 是第三方可公网直链时走百炼 URL-ASR；对抖音 CDN **默认跳过**（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n3. 至少配置上述之一才允许 `cloud` 真跑；**两者都缺**时停止，不下载、不静默切 Whisper。\n4. 云端都失败且用户允许 local fallback 时才进 Whisper；`index` 永不 ASR。\n\nSiliconFlow 控制台：`https://cloud.siliconflow.cn/account/ak`。百炼说明（可选）：`https://help.aliyun.com/zh/model-studio/get-api-key`。Key 放本机环境变量/Secret Manager，不要发聊天或进仓库。skill 自动读 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local`。运行前 `python3 scripts/integration.py`；共享 profile 被占用必须等待。报告写入独立 `<output-root>/creator-insight/`。\n\n> **ASR 费用（默认 SenseVoiceSmall）**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。\n\n\n- **SiliconFlow 注册推荐链接**：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n\nActor 的价格、配额、可用性和 schema 会变化。运行前查看当前 Actor 页面；任何费用或耗时只能作为本次运行的实测结果陈述，不能沿用固定承诺。\n\n## 输入\n\n从用户原话提取：\n\n- `creator_query`：优先主页 URL、`sec_uid`，或包含 `v.douyin.com` 的完整分享消息；脚本会提取短链接。\n- `max_videos`：默认 1000；用户要求省资源或试跑时降低。超过上限时结果必须标为 `partial`。\n- `transcript_count`：未指定时按作品数自动分档；用户显式指定时优先遵从。\n- `transcript_max_duration_minutes`：默认 5，用于候选筛选。\n- `transcript_mode`：`cloud`（默认）/ `local` / `index`。\n- `output_formats`：默认 `html`、`md`、`json`。\n- `output_dir`：默认当前任务的专用输出目录。\n\n主页 URL、分享短链接或 `sec_uid` 最稳定。昵称和抖音号只可用于候选确认，不能自动选择同名账号；搜索验证码或模糊结果时要求用户改贴主页/分享链接。\n\n## 流程\n\n1. 用 `scripts/resolver.py` 判断输入类型，并从分享消息提取短链接。\n2. 对 URL/短链接/`sec_uid`，优先运行 `scripts/run_pipeline.py --browser`。它在现有 persistent profile 的页面上下文读取公开作品分页，并验证每条返回视频的作者 `sec_uid`。\n3. 昵称或抖音号不可自动选人；搜索触发验证码、无候选或多个候选时停止并请求主页/分享链接。\n4. 用 `scripts/parser.py` 标准化字段，再执行 `quality_gate.py`。门禁失败时停止，不生成伪完整报告。\n5. `index` 模式跳过转写，只保留全量作品信息；其他模式用 `selector.py` 选择候选：30 条及以下全量转写；31-100 条按点赞前 50；更大账号按点赞、收藏和近期作品分层去重抽样（上限 100 条）。\n6. `cloud`（默认）对抖音 CDN 媒体：**优先 SiliconFlow 上传 ASR**（Referer 下载 + 抽音频 + 上传 + 清理）；**不把抖音 CDN URL 默认丢给百炼**。非抖音可公网媒体才先试百炼 URL-ASR。云端都失败才进入 `local` Whisper。`douyin-mcp` 不是依赖。再用 `categorizer.py` 分类、`report_builder.py` 输出真实 provider 状态与错误。\n\n## Tool 调用契约\n\nProfile actor 输入：\n\n```json\n{\n  \"maxPostsPerProfile\": 1000,\n  \"profileUrls\": [\"https://www.douyin.com/user/<sec_uid>\"]\n}\n```\n\n浏览器模式默认最多采集 1000 条；Apify 的实际上限、配额和字段以运行时 Actor schema 为准。任何触发上限、分页未完成或声明数无法对账的结果，都必须在报告的 `collection` 字段标为 `partial` 或 `reconciliation: unavailable`，不得写成全量完成。\n\nActor ID、输入字段和 fallback 以 [references/apify-douyin-actors.md](references/apify-douyin-actors.md) 为准。不要假设文档中的历史 actor 永久可用；调用失败时先核对 Actor 页面和返回 schema。\n\n## 质量门\n\n- 身份必须 matched，且含 `sec_uid` 或抖音号。\n- 视频列表不能为空；少于质量门默认阈值时阻断。\n- 超过一半的视频缺少标题与描述时阻断。\n- 转写成功率低于门槛时，报告必须明确降级或停止。\n- 低置信度身份不得自动选择。\n\n## 运行脚本\n\nAgent 已经完成采集后，可直接复用 `scripts/` 中的解析、筛选和报告函数。独立 CLI 必须显式选择一种模式：\n\n```bash\n# 非联网验证\npython3 scripts/run_pipeline.py --creator <profile_url> --dry-run\n\n# 默认真实路径：已登录浏览器中的公开主页接口\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py --creator '<share_or_profile_url>' --browser\n\n# 明确选择本地 Whisper 或纯信息索引\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode local\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode index\n\n# 使用显式 adapter 真实运行\npython3 scripts/run_pipeline.py \\\n  --creator <profile_url> \\\n  --adapter my_adapter:call_actor \\\n  --output-dir ./output\n```\n\n没有 `--dry-run`、`--browser` 或 `--adapter` 时，CLI 必须失败；不得把 dry-run 返回当成真实报告。\n\n## 失败处理\n\n| 场景 | 行为 |\n|---|---|\n| 找不到账号 | 返回候选或要求更稳定的主页 URL |\n| 浏览器 profile 未登录、主页接口失败 | 不要求复制 cookie；提示在已有 profile 中恢复登录或稍后重试 |\n| 昵称搜索验证码/同名 | 不绕过验证码，不自动选人；要求主页或分享链接 |\n| Profile actor 失败 | 核对 schema 后使用记录在 reference 中的 fallback |\n| 视频不足或字段异常 | 质量门阻断，保留原始响应供排查 |\n| 未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` | 停止真实转写；提示 SiliconFlow（抖音推荐）与可选百炼入口；不自动下载或切 Whisper |\n| 仅有 `DASHSCOPE_API_KEY`、无 SiliconFlow | 允许启动但告警：抖音 CDN 转写大概率失败 |\n| Cloud ASR 失败 | 仅在云端已配置但真实调用失败时记录错误，再回退本地 Whisper；`--no-local-fallback` 时只报告失败 |\n| 本地 Whisper 失败 | 清理临时媒体并标记 `failed` 或 `empty_transcript` |\n| 配额不足 | 停止真实调用，建议用户缩小样本或稍后重试 |\n| 输出写入失败 | 返回非成功状态和明确路径，不宣称完成 |\n\n## 验证\n\n修改 Skill 或脚本后必须运行：\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nfixture E2E 通过只证明本地编排契约正确，不证明第三方 Actor 当前可用。真实发布说明必须把两类证据分开。\n\n## 相关文档\n\n- `references/apify-douyin-actors.md`：Actor 与 fallback\n- `references/data-schema.md`：字段映射\n- `references/creator-resolution-playbook.md`：身份确认\n- `references/categorization-taxonomy.md`：分类规则\n- `references/report-rubric.md`：报告质量\n- `references/failure-playbook.md`：失败恢复\n- `SECURITY.md`：凭据与漏洞报告\n\nFile v1.3.3:assets/README.md\n\n# Assets · 模板文件\n\n本目录存放报告生成所需的静态资源。\n\n## 文件清单\n\n- `README.md`：本说明\n- `report_template.html`：HTML 报告模板（参考用）\n- `report_style.css`：报告样式（参考用）\n- `creator_card_template.html`：博主封面卡片模板（参考用）\n\n## 当前实现\n\n**注意**：当前 `scripts/report_builder.py` 使用内置 Python 字符串模板，**不依赖** assets/ 目录。\nassets/ 中的文件仅作为参考 / 自定义起点。\n\n## 自定义指南\n\n如果需要自定义样式：\n\n### 方式 1：直接修改内置模板\n\n编辑 `scripts/report_builder.py::HTML_TEMPLATE`，调整 CSS 部分。\n\n### 方式 2：使用 jinja2 渲染\n\n1. 安装：`pip install jinja2`\n2. 把内置 HTML_TEMPLATE 复制到 `assets/report_template.html`\n3. 用 jinja2 渲染\n\n```python\nfrom jinja2 import Environment, FileSystemLoader\n\nenv = Environment(loader=FileSystemLoader('assets'))\ntemplate = env.get_template('report_template.html')\nhtml = template.render(\n    nickname=nickname,\n    followers=followers,\n    ...\n)\n```\n\n### 方式 3：完全重写\n\n如果需要差异化设计（如杂志风、暗色模式），可以：\n\n1. 创建新文件 `assets/report_template_magazine.html`\n2. 在 `scripts/report_builder.py` 中加 `build_html_report_magazine()`\n3. 调用方选择用哪个模板\n\n## 配色参考\n\n| 风格 | 配色 |\n|---|---|\n| 默认（深紫蓝） | `#1e3a8a → #5b21b6` |\n| 杂志风（暖色） | `#b45309 → #d97706` |\n| 暗色模式 | `#0f172a → #1e293b` |\n| 极简（白底） | `#f8fafc → #f1f5f9` |\n\n## 示例模板\n\n### 默认模板（已在 report_builder.py）\n\n```html\n<header class=\"hero\">\n    <h1>{{ nickname }} · 抖音内容洞察报告</h1>\n    <div class=\"creator-stats\">\n        <div class=\"stat\"><span class=\"num\">{{ followers }}</span></div>\n        ...\n    </div>\n</header>\n```\n\n### 杂志风模板（待创建）\n\n参考 `guizang-ppt-skill` 的杂志风风格。\n\nFile v1.3.3:README.md\n\n# Douyin Creator Insight\n\n从公开抖音主页、分享短链接或 `sec_uid` 出发，生成可审计的创作者内容洞察报告。默认使用已登录的本地浏览器 profile 读取公开作品；Apify 是可选 fallback。输出包含 HTML、Markdown 和 JSON。\n\n[![CI](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml/badge.svg)](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n\n## 能做什么\n\n- 解析主页 URL、`sec_uid` 和完整分享文案中的短链接；昵称或抖音号只用于人工候选确认，不自动选择同名账号。\n- 标准化不同数据源的视频字段。\n- 按账号规模自动选择转写候选：小账号全量转写，大账号以点赞、收藏和近期作品分层抽样。\n- 对解析、视频数量和转写质量执行阻断式质量门。\n- 生成 HTML、Markdown、JSON 三种报告。\n\n本项目只处理公开数据，不绕过登录、隐私或平台访问控制。\n\n## 安装与分发入口\n\n- Agent 一键安装：[ClawHub douyin-creator-insight](https://clawhub.ai/tars1230/skills/douyin-creator-insight)\n- 国内源码镜像：[Gitee tars123/douyin-creator-insight](https://gitee.com/tars123/douyin-creator-insight)\n- 源码与版本发布：[GitHub tars1230/douyin-creator-insight](https://github.com/tars1230/douyin-creator-insight)\n\n## 运行方式\n\n### 独立运行，可选复用收藏 skill\n\n本 skill 可以独立安装。第一次运行先执行 `python3 scripts/setup.py`，明确选择：\n\n- `cloud`：云端 ASR（默认）。**抖音场景推荐配置 `SILICONFLOW_API_KEY`**（本机带 Referer 临时下载 → 上传 SenseVoice → 清理）。\n- `local`：本地 Whisper。只有用户明确选择时才临时下载视频，结束后清理。\n- `index`：只索引标题、描述、互动数据和链接，不调用 ASR。\n\n### 云端 ASR 重要说明（请先读）\n\n抖音播放地址在 `*.douyinvod.com` 等 CDN 上，带防盗链。**阿里云百炼的 URL-ASR 无法从服务端下载这些地址**，会稳定返回 download 失败——这不是 API Key 坏了，也不是“测通了百炼就等于抖音能转写”。\n\n| Key | 是否抖音刚需 | 作用 |\n|---|---|---|\n| **`SILICONFLOW_API_KEY`** | **是（推荐）** | 下载（`Referer: https://www.douyin.com/`）+ 上传 `FunAudioLLM/SenseVoiceSmall` |\n| `DASHSCOPE_API_KEY` | 否（可选） | 仅对**可公网直链**媒体做 URL-ASR；对抖音 CDN 默认跳过 |\n\n- SiliconFlow 控制台：[创建 API Key](https://cloud.siliconflow.cn/account/ak)\n- 百炼说明（可选）：[如何获取 API Key](https://help.aliyun.com/zh/model-studio/get-api-key)\n\n两者都缺时，`cloud` 真跑会安全停止，不下载、不静默切 Whisper。只有 `DASHSCOPE`、没有 SiliconFlow 时会告警。Key 放环境变量/Secret Manager，不要发聊天或进仓库。\n\nskill 会自动读取当前 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local` 中的相关配置，Hermes 没透传环境也能继续走 cloud 默认。\n\n同时安装 `douyin-favorites-to-knowledge` 时，setup 会探测并优先复用它的已登录浏览器 profile 和转录偏好，但状态、输出和调度完全隔离：Creator Insight 默认写入 `./output/creator-insight/`，不读取收藏 metadata，也不加入 23:00 收藏任务。运行前执行 `python3 scripts/integration.py`；若共享 profile 已被占用，等待当前流程结束即可。`douyin-mcp` 是可选诊断工具，不是安装或运行依赖。\n\n### 1. 本地浏览器模式（默认推荐）\n\n首次独立使用时，本 skill 会使用中性的共享浏览器 profile；登录一次抖音即可。若已安装收藏 skill，则自动复用它现有的已登录 profile。之后可直接粘贴主页、`sec_uid`，或包含 `https://v.douyin.com/.../` 的完整分享消息：\n\n```bash\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py \\\n  --creator '长按复制此条消息，打开抖音搜索 https://v.douyin.com/xxxx/ ...' \\\n  --browser --max-videos 50 --output-dir ./output\n```\n\n该模式只读取公开作品列表，逐页验证每条作品作者的 `sec_uid`，不复制 cookie、不输出 profile、不绕过验证码。抖音媒体默认走 SiliconFlow 上传 ASR（Referer 下载后清理）；非抖音公网媒体可走百炼 URL ASR；全部云端失败才回退本地 Whisper。\n\n非交互环境可以显式配置：\n\n```bash\n# 云端：保存选择；若 Key 尚未配置，真实运行会安全停止并给出申请入口\npython3 scripts/setup.py --transcript-mode cloud\n\n# 本地：只有明确选择 local 后，真实运行才允许临时下载视频\npython3 scripts/setup.py --transcript-mode local\n\n# 索引：不转录、不下载视频\npython3 scripts/setup.py --transcript-mode index\n```\n\n首次使用需要可选依赖：\n\n```bash\npython3 -m pip install playwright\npython3 -m playwright install chromium\n```\n\n### 2. 作为 Agent Skill 或 Apify fallback\n\n安装到支持 `SKILL.md` 的 agent 环境后，优先走浏览器模式；没有已授权浏览器或浏览器接口异常时，才使用 Apify MCP 或下述 adapter。真实 token 必须由环境变量或宿主 secret store 提供，不要提交到仓库。\n\n### 3. 作为 CLI adapter\n\nCLI 不会猜测凭据，也不会把“未抓取”伪装成成功。必须显式选择以下一种模式：\n\n```bash\n# 非联网检查：只解析输入，不生成真实报告\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --dry-run\n\n# 真实执行：由使用者提供 module:function adapter\nPYTHONPATH=/path/to/adapters:$PYTHONPATH \\\npython3 scripts/run_pipeline.py \\\n  --creator https://www.douyin.com/user/<sec_uid> \\\n  --adapter my_adapter:call_actor \\\n  --max-videos 50 \\\n  --transcript-count 3 \\\n  --output-dir ./output\n```\n\nAdapter 必须实现以下调用契约：\n\n```python\ndef call_actor(*, actor: str, input: dict, wait_secs: int):\n    \"\"\"Return a list of dataset items or {'datasetItems': [...]} for profile calls.\"\"\"\n```\n\n昵称或抖音号还需要搜索 adapter：\n\n```bash\npython3 scripts/run_pipeline.py \\\n  --creator <nickname> \\\n  --adapter my_adapter:call_actor \\\n  --browser-adapter my_adapter:search_creator\n```\n\n`search_creator(*, query: str, max_results: int)` 应返回包含公开主页 URL 的文本、列表或字典。\n\n## 参数\n\n| 参数 | 说明 | 默认值 |\n|---|---|---|\n| `--creator` | 主页 URL、`sec_uid`、完整分享消息；adapter 模式也可接受抖音号或昵称 | 必填 |\n| `--dry-run` | 非联网解析检查 | 与 `--browser`、`--adapter` 三选一 |\n| `--browser` | 使用已授权浏览器 profile 采集公开主页 | 与 `--dry-run`、`--adapter` 三选一 |\n| `--browser-profile` | 可选的 Playwright persistent profile 目录 | 默认复用 favorites profile |\n| `--headed` | 显示浏览器窗口，用于诊断登录/验证码 | 默认隐藏 |\n| `--adapter` | Apify 或其他外部真实采集 adapter，`module:function` | 与 `--dry-run`、`--browser` 三选一 |\n| `--browser-adapter` | 昵称/抖音号搜索 adapter | 可选 |\n| `--max-videos` | 请求的视频上限 | 1000 |\n| `--transcript-count` | 请求的转写候选数；指定时覆盖自动分档 | 按账号规模自动选择 |\n| `--transcript-mode` | `cloud` 默认 SiliconFlow 上传 ASR（抖音 CDN）+ 可选百炼公网直链 + local fallback；`local` Whisper；`index` 只做信息索引 | setup 选择，未配置时为 `cloud` |\n| `--no-local-fallback` | 云端 ASR 全部失败时不回退本地 Whisper | 关闭 |\n| `--max-duration` | 选择阶段的时长上限，分钟 | 5 |\n| `--output-dir` | Creator Insight 专用报告目录 | `./output/creator-insight` |\n| `--format` | `html json md` 的任意组合 | 全部 |\n\n## 本地验证\n\n测试完全使用 fixtures，不调用抖音或 Apify，也不需要 token。\n\n```bash\npython3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v\n```\n\nCI 在 Python 3.10 和 3.12 上执行同一套测试。测试覆盖：\n\n- CLI 显式模式契约和退出码；\n- dry-run 不写输出；\n- 10 条 fixture 视频到三格式报告的端到端链路；\n- Skill 元数据、私人绝对路径和常见 secret 模式扫描。\n\n## 数据源与成本\n\n浏览器模式不需要 Apify key，边界是用户已授权浏览器可访问的公开主页。默认 cloud ASR：抖音 CDN 走 SiliconFlow `SenseVoiceSmall`；百炼 `qwen3-asr-flash` 仅公网直链媒体；**费用**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。 其它（如 Apify）价格、地域和免费额度会变化，实际扣费以所用平台（SiliconFlow / 百炼）控制台账单为准。默认 actor 和 fallback 见 [references/apify-douyin-actors.md](references/apify-douyin-actors.md)。Actor 的可用性、输入 schema、价格和账户额度会变化；运行前应在对应 Apify Actor 页面核验，并先用小样本测试。仓库不承诺固定耗时、费用或免费额度。\n\n## 输出与示例\n\n| 文件 | 用途 |\n|---|---|\n| [docs/sample-report.html](docs/sample-report.html) | HTML 报告示例 |\n| [docs/sample-report.md](docs/sample-report.md) | Markdown 摘要示例 |\n| [docs/sample-report.json](docs/sample-report.json) | 结构化数据示例 |\n\n报告中的互动排序是研究启发式，不代表推荐系统权重，也不构成商业、投资或平台增长保证。\n\n## 已知边界\n\n- 上游字段或 Actor 行为变化可能导致质量门阻断。\n- 昵称搜索可能触发验证码，也可能产生同名候选；浏览器模式不会搜索或自动选择，需改贴主页或分享链接。\n- 无旁白、纯音乐、未配置云端 Key 或上游转写失败的视频可能没有 transcript。未配置 `SILICONFLOW_API_KEY` 且未配置 `DASHSCOPE_API_KEY` 时真实运行会安全停止并提示官方申请入口，不会自动下载视频。\n- 未指定 `--transcript-count` 时：30 条及以下全量转写；31-100 条按点赞前 50；101-300 条选 60 条；301-800 条选 80 条；更大账号最多选 100 条。大账号样本按点赞、收藏与近期作品分层去重，避免只偏向历史爆款。\n- 浏览器模式会记录主页声明作品数、实际采集数和分页状态。达到请求上限而尚有下一页时，结果为 `partial`，不能作为全量结论。\n- 收藏 skill 是可选共享底座，不是前置依赖；同时安装时先运行 `scripts/integration.py` 探测 profile 占用和输出布局。浏览器模式不会读取或导出 cookie。\n- 私密账号、绕过访问控制和未授权批量采集不在支持范围内。\n\n## 安全与贡献\n\n安全问题请按 [SECURITY.md](SECURITY.md) 私下报告。开发与 PR 约定见 [CONTRIBUTING.md](CONTRIBUTING.md)。\n\n## License\n\n[MIT](LICENSE)\n\n## SiliconFlow\n\n- 注册推荐链接：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\nFile v1.3.3:_meta.json\n\n{\n  \"ownerId\": \"kn7fgfkjyfqbz673wvzymh5e1x821vpk\",\n  \"slug\": \"douyin-creator-insight\",\n  \"version\": \"1.3.3\",\n  \"publishedAt\": 1785919078506\n}\n\nFile v1.3.3:references/apify-douyin-actors.md\n\n# Apify Douyin Actors 对照表\n\n## 三个核心 actor\n\n### 1. `zen-studio/douyin-profile-scraper` ⭐ 主用\n\n**用途**：抓取指定博主的所有视频列表\n\n**输入**：\n```json\n{\n  \"maxPostsPerProfile\": 200,\n  \"profileUrls\": [\"https://www.douyin.com/user/MS4w...\"]\n}\n```\n\n**输出字段**：\n```json\n[\n  {\n    \"id\": \"7600998358588812742\",\n    \"text\": \"视频文案/描述\",\n    \"title\": \"标题\",\n    \"createTime\": 1737638400,\n    \"createDate\": \"2025-01-23\",\n    \"statistics\": {\n      \"diggCount\": 12345,\n      \"commentCount\": 678,\n      \"shareCount\": 90,\n      \"collectCount\": 234,\n      \"playCount\": 567890\n    },\n    \"videoMeta\": {\n      \"duration\": 120000,\n      \"cover\": \"https://...\"\n    },\n    \"hashtags\": [{\"name\": \"...\"}],\n    \"series\": {\"name\": \"...\"},\n    \"shareUrl\": \"https://...\",\n    \"authorMeta\": {\n      \"name\": \"...\",\n      \"signature\": \"...\",\n      \"followersCount\": 333000,\n      \"heartCount\": 2672708,\n      \"awemeCount\": 200\n    }\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。公开视频、README 和教程里不要承诺固定成本；第一次建议先小样本验证。\n\n**限制**：maxPostsPerProfile 上限 200\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-profile-scraper\",\n    input={\n        \"maxPostsPerProfile\": 200,\n        \"profileUrls\": [profile_url]\n    },\n    wait_secs=45\n)\n```\n\n### 2. `zen-studio/douyin-transcripts-scraper` ⭐ 主用转写\n\n**用途**：抓取视频语音转写；当前限制以 Actor 页面为准\n\n**输入**：\n```json\n{\n  \"targetLanguage\": \"zh\",\n  \"videoUrls\": [\"https://www.douyin.com/video/7575296454722398441\", ...]\n}\n```\n\n**输出**：\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"...\",\n    \"text\": \"完整转写文本...\",\n    \"duration\": 812,\n    \"segments\": [{\"start\": 0, \"end\": 5.2, \"text\": \"...\"}, ...]\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-transcripts-scraper\",\n    input={\n        \"targetLanguage\": \"zh\",\n        \"videoUrls\": [video_url1, video_url2, ...]\n    },\n    wait_secs=45\n)\n```\n\n### 3. `apple_yang/douyin-transcripts-scraper` 备选\n\n**用途**：备用转写服务\n\n**输入**：\n```json\n{\n  \"videoUrl\": \"https://www.douyin.com/video/...\"\n}\n```\n\n**输出**：同上\n\n**限制**：历史测试中长视频支持不稳定；当前限制以 Actor 页面为准\n\n**价格**：以 Apify Actor 当前页面为准。\n\n## 备选 actor（不推荐）\n\n### `bovi/douyin-scraper`\n- 优点：功能多\n- 缺点：`user_videos` 模式 2026 起需要登录 cookies，已验证空结果\n- 不推荐\n\n### `sian.agency/douyin-scraper`\n- 优点：支持 userVideos\n- 缺点：可能排队较久，且可能需要登录 cookies\n- 不推荐\n\n### `apify--rag-web-browser`\n- 用途：网页搜索 + 渲染\n- 兜底方案：当 profile scraper 失败时用此搜索主页\n- 调用示例：\n```python\napify_browser(\n    query=\"https://www.douyin.com/user/MS4w...\",\n    max_results=1\n)\n```\n\n## 经验教训\n\n1. **优先用 zen-studio 系列**，但运行前核对当前访问要求与输入 schema\n2. **user_videos 模式 = 需要登录**（2026 现状）→ 慎用 bovi/sian.agency\n3. **转写超时**：降低样本或候选时长，并核对 Actor 当前限制\n4. **TOON 格式**：Apify 返回的是 TOON 格式，需要手动解析（见 `data-schema.md`）\n5. **字段 schema 不稳定**：不同 actor 返回字段名差异大，需要多别名解析（见 `parser.py::_extract_field`）\n\n## 失败兜底顺序\n\n```\nzen-studio profile scraper (主)\n  ↓ 失败\napify--rag-web-browser 渲染主页\n  ↓ 失败\nWebSearch + 用户手动提供数据\n```\n\n```\nzen-studio transcripts scraper (主)\n  ↓ 失败\napple_yang transcripts scraper (备用，限制以当前 Actor 页面为准)\n  ↓ 失败\n跳过该视频，继续下一个\n```\n\nFile v1.3.3:references/categorization-taxonomy.md\n\n# Categorization Taxonomy · 内容分类体系\n\n## 规则标签关键词（`categorizer.py::CATEGORY_KEYWORDS`）\n\n### 进外企方法\n- `进外企` / `如何进入` / `外企面试` / `外企推荐` / `简历` / `英文` / `雅思` / `BEC` / `外企 title`\n\n### 外企清单\n- `外企清单` / `小而美` / `推荐名单` / `十大城市` / `十个城市` / `城市知名` / `最佳雇主` / `福布斯`\n\n### 福利揭秘\n- `福利` / `待遇` / `15 天年假` / `年假` / `加班` / `年终奖` / `六险一金` / `补充医疗`\n\n### 跳槽/转行\n- `跳槽` / `转型` / `转行` / `准备` / `实操` / `拿下`\n\n### 英语学习\n- `英语` / `英文` / `口语` / `听力` / `职场英语` / `BEC`\n\n### 认知/成长\n- `认知` / `成长` / `心法` / `建议` / `格局`\n\n### 母婴/育儿\n- `母婴` / `育儿` / `宝宝` / `宝贝` / `妈妈`\n\n### 宠物/动物\n- `宠物` / `猫` / `狗` / `皇家` / `玛氏`\n\n### 美食/食品\n- `美食` / `食品` / `食谱` / `厨房`\n\n### 数码/3C\n- `数码` / `3C` / `手机` / `电脑` / `评测`\n\n## 标签来源\n\n| source | 说明 | 示例 |\n|---|---|---|\n| `rule` | 规则关键词匹配 | `进外企方法` |\n| `hashtag` | 来自视频 hashtag | `#外企` → 进外企方法 |\n| `series` | 来自合集名 | `英语学习与提升` → 合集: 英语学习与提升 |\n| `llm` | LLM 主题分类 | 由 LLM 补充 |\n\n## LLM 分类提示词\n\n`categorizer.py::build_categorization_prompt` 生成的提示词：\n\n```python\nprompt = \"\"\"你是一个抖音内容分析专家。请基于以下 {N} 个视频的信息，把它们分到合适的类别。\n\n# 任务\n1. 输出主分类（每个视频 1 个）：进外企方法 / 外企清单 / 福利揭秘 / 跳槽转行 / 英语学习 / 母婴/育儿 / 其他\n2. 提取关键洞察：\n   - 博主主要面向谁（年龄/性别/职业）\n   - 3 个核心主题\n   - 5 条最有价值的视频标题\n   - 选题公式（爆款标题的共同特征）\n\n# 输出格式（JSON）\n{\n  \"main_categories\": [\"...\"],\n  \"audience\": \"...\",\n  \"core_themes\": [\"...\", \"...\", \"...\"],\n  \"top_5_videos\": [\"标题1\", \"标题2\", ...],\n  \"title_formula\": \"...\",\n  \"insights\": \"...\"\n}\n\"\"\"\n```\n\n## 扩展指南\n\n要新增分类：\n1. 在 `CATEGORY_KEYWORDS` 字典中添加新类别 + 关键词列表\n2. 重跑 `categorize_videos()` 即可\n\n要改 LLM 提示词：\n1. 修改 `build_categorization_prompt()` 函数\n2. 调用方传更多视频元数据\n\n## 实战经验\n\n- 史蒂文不做牛马账号的分类分布（200 条视频）：\n  - 英语学习与提升：42 条（合集）\n  - 职业规划与发展：36 条（合集）\n  - 认知与成长合集：5 条（合集）\n  - 外企清单散装：12+ 条\n  - 进外企方法散装：10+ 条\n  - 福利揭秘：5+ 条\n- 建议给 LLM 提供至少 10 条样本视频做分类\n- 主题分类后建议人工复核 TOP 5，确保准确\n\nFile v1.3.3:references/creator-resolution-playbook.md\n\n# Creator Resolution Playbook · 博主识别策略\n\n## 输入类型判定\n\n`resolver.py::parse_input_type` 判定逻辑：\n\n| 类型 | 正则 | 示例 |\n|---|---|---|\n| douyin_id | `^\\d{6,12}$` | `<douyin_id>`（如 `12345678`） |\n| sec_uid | `MS4w...` | `MS4wLjABAAA...` |\n| url | `https://(www\\.)?douyin\\.com/user/MS4w...` | `https://www.douyin.com/user/MS4wLjABAAA...` |\n| nickname | 含中英文 | `史蒂文不做牛马` |\n\n## 精准 vs 模糊匹配\n\n### 精准匹配（confidence ≥ 0.9）\n\nsec_uid 直接确认，不需问用户。\n\n```\n输入: MS4wLjABAAAA...<sec_uid>...   # 抖音内部唯一 ID\n→ 解析: sec_uid = MS4w...\n→ confidence = 0.95\n→ matched = True\n→ profile_url = https://www.douyin.com/user/MS4w...\n```\n\n### 模糊匹配（confidence < 0.9）\n\n用 `apify--rag-web-browser` 搜索：\n- query: `抖音 {creator_query}`\n- 解析搜索结果的 markdown\n- 提取候选人列表（昵称 + 简介 + 粉丝数）\n\n```\n输入: {nickname}                 # 示例：史蒂文不做牛马\n→ 搜索: 抖音 {nickname}\n→ 候选 1: {nickname} · {signature} · {followers} → confidence 0.95\n→ 候选 2: 其他同名账号\n→ 选 #1，自动继续\n```\n\n## 失败处理\n\n### 找不到任何人\n\n```\n输入: 不存在的昵称\n→ 搜索: 返回空\n→ matched = False\n→ AskUserQuestion 让用户重新输入\n```\n\n### 找到多个相似\n\n```\n输入: 小李\n→ 候选 5 个相似账号\n→ AskUserQuestion 让用户选\n→ 用户选 #3 → 用 sec_uid 继续\n```\n\n## 实战经验\n\n### 抖音号和 sec_uid 的区别\n\n- **抖音号**（douyin_id）：纯数字，用户可改，6-12 位\n  - 例：`<douyin_id>`（如 `12345678`）\n- **sec_uid**：抖音内部唯一 ID，MS4w 开头，不可改\n  - 例：`MS4wLjABAAAA...`（约 60 字符长）\n\n**profile scraper 必须用 sec_uid**，不能用抖音号。\n\n### 已知搜不到的输入\n\n- 短链（`v.douyin.com/xxx`）需要先 WebFetch 解析\n- 长 URL（带 modal_id 参数）可能是视频 ID\n- 纯数字 < 6 位大概率不是抖音号\n\n### 实战踩坑\n\n1. **抖音号搜不到人**：用户可能改了 douyin_id，但 sec_uid 不变。永远用 sec_uid。\n2. **同名账号**：很多用户取相似昵称，需要看签名 + 粉丝数判定。\n3. **博主已注销**：可能抓不到视频。提示用户确认。\n\n## 关键代码\n\n`scripts/resolver.py`：\n- `parse_input_type(user_input)`: 识别输入类型\n- `resolve_creator_via_apify(...)`: 主入口\n- `_resolve_via_apify_search(...)`: 模糊匹配逻辑\n- `format_resolution_for_question(...)`: 转 AskUserQuestion 选项\n\nFile v1.3.3:references/data-schema.md\n\n# Data Schema · 字段映射\n\n## Apify profile scraper → 标准化字段\n\n不同 actor 字段名差异（已实测）：\n\n| 标准化字段 | zen-studio | bovi | sian.agency | TOON 解析后 |\n|---|---|---|---|---|\n| aweme_id | id | aweme_id | videoId | id |\n| title | title | (空) | (空) | title |\n| desc | text | desc | desc | text |\n| create_time | createTime | create_time | timestamp | createTime |\n| duration_ms | videoMeta.duration | video.duration | duration | videoMeta.duration |\n| cover_url | videoMeta.cover | video.cover | coverUrl | videoMeta.cover |\n| share_url | shareUrl | share_url | url | shareUrl |\n| hashtags | hashtags[].name | (空) | (空) | hashtags.name |\n| series_name | series.name | (空) | (空) | series.name |\n| digg_count | statistics.diggCount | aweme_stats.digg_count | stats.like | statistics.diggCount |\n| comment_count | statistics.commentCount | aweme_stats.comment_count | stats.comment | statistics.commentCount |\n| share_count | statistics.shareCount | aweme_stats.share_count | stats.share | statistics.shareCount |\n| collect_count | statistics.collectCount | aweme_stats.collect_count | stats.favorite | statistics.collectCount |\n| play_count | statistics.playCount | aweme_stats.play_count | stats.view | statistics.playCount |\n\n## TOON 格式示例\n\nApify `get_dataset_items` 返回的是 TOON 格式（不是 JSON）：\n\n```toon\nitems[200]:\n  - id: \"7600998358588812742\"\n    text: \"进外企真的不难\"\n    createTime: 1737638400\n    statistics:\n      diggCount: 42451\n      commentCount: 1500\n      shareCount: 800\n      collectCount: 24647\n    videoMeta:\n      duration: 240000\n      cover: \"https://...\"\n    hashtags:\n      - name: \"外企\"\n      - name: \"求职\"\n    authorMeta:\n      name: \"史蒂文不做牛马\"\n      signature: \"在七种不同国别外企混迹的牛马一枚\"\n      followersCount: 333000\n      heartCount: 2672708\n```\n\n## 解析规则\n\n`scripts/parser.py::parse_toon_output` 实现：\n1. 用 `items[N]:` 作为块起点\n2. 用 `\\n  - id:` 作为分隔符切分 item\n3. 每行按 4 空格缩进解析 key-value\n4. 多层缩进（如 `statistics.diggCount`）用 `.` 合并为路径\n\n## transcripts scraper 输出\n\nzen-studio transcripts 返回格式：\n\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"视频标题\",\n    \"text\": \"完整转写文本\",\n    \"duration\": 812,\n    \"segments\": [\n      {\"start\": 0.0, \"end\": 5.2, \"text\": \"...\"},\n      ...\n    ],\n    \"errMsg\": null\n  }\n]\n```\n\n## 字段映射实现位置\n\n`scripts/parser.py::_extract_field()` 支持多路径：\n\n```python\n_extract_field(item, [\n    \"statistics.diggCount\",  # zen-studio\n    \"aweme_stats.digg_count\",  # bovi\n    \"stats.diggCount\",  # sian.agency\n])\n```\n\n按顺序尝试，找到第一个非空值。\n\nFile v1.3.3:references/failure-playbook.md\n\n# Failure Playbook · 失败场景手册\n\n## 1. 用户输入的抖音号找不到人\n\n**症状**：`resolve_creator_via_apify` 返回 `matched=False`\n\n**主策略**：\n- 用 `apify--rag-web-browser` 搜索 \"抖音 {creator_query}\"\n- 解析搜索结果，提取候选人列表\n\n**兜底**：\n- AskUserQuestion 列出 3-5 个候选，让用户确认\n- 用户确认后用 sec_uid 重新调用\n\n**关键代码位置**：`resolver.py::_resolve_via_apify_search`\n\n## 2. 视频列表抓不到 / 返回 0 条\n\n**症状**：`parse_actor_dataset` 返回空列表\n\n**原因**：\n- 用户输入的不是用户主页（可能是视频 URL）\n- Apify 账号额度耗尽\n- 抖音 API 反爬\n\n**主策略**：\n- 检查 `maxPostsPerProfile` 是否过大（> 500 容易失败）\n- 重试 + 减小数量\n\n**兜底**：\n- 用 `apify--rag-web-browser` 渲染主页，手动解析\n- 提示用户上传原始 JSON，走离线模式\n\n**关键代码位置**：`run_pipeline.py` Step 2\n\n## 3. 视频列表字段大量为空\n\n**症状**：parse 后大部分 video.title 或 stats 为空\n\n**原因**：\n- actor schema 变化\n- 字段别名没覆盖\n\n**主策略**：\n- 在 `parser.py::_extract_field` 增加新别名\n- 检查 TOON 解析是否有 bug\n\n**兜底**：\n- 保留 raw JSON，下次重试时直接复用\n- 用 `quality_gate.py::check_videos` 检测\n\n## 4. 语音转写全部失败\n\n**症状**：`fetch_transcripts` 返回空或全部 failed\n\n**主策略**：\n- 检查视频时长和 Actor 当前限制\n- 切换备用 actor（apple_yang）\n\n**兜底**：\n- 仅用标题 + 描述 + 互动数据分析，不依赖转写\n- 报告标注 \"transcripts_unavailable\"\n\n## 5. 视频没有旁白（音乐/纯画面）\n\n**症状**：transcript 返回空字符串\n\n**判断**：transcript text 长度 < 10 → 标记 `empty_transcript`\n\n**主策略**：\n- 跳过该视频的转写\n- 改用 title + desc + hashtags 做内容分析\n\n**兜底**：\n- 报告里标注\"无旁白视频\"\n- 用 B 站 / YouTube 等替代来源\n\n## 6. Apify 账号额度耗尽\n\n**症状**：所有 actor 调用都返回 4xx 错误\n\n**主策略**：\n- 减小 `max_videos` 和 `transcript_count`\n- 提示用户充值\n\n**兜底**：\n- 完全离线模式：用户上传历史 raw JSON，skill 仅做分析和报告\n- 使用用户提供的、已获授权的公开数据快照\n\n## 7. 字段 schema 突然变化\n\n**症状**：解析后大量字段为 None\n\n**主策略**：\n- 增加字段别名（参考 `data-schema.md`）\n- 保留 raw 字段，下次回放时排查\n\n**兜底**：\n- 用 `WebFetch` 抓主页 HTML 作为补充\n- 让用户手动提供关键视频 URL\n\n## 8. 时间相关问题\n\n- **createTime 是毫秒还是秒**？不同 actor 不同\n  - `parser.py::_format_date` 自动判断：> 10^12 是毫秒\n- **时长过滤**：默认筛选上限为 5 分钟，可按 Actor 当前限制调整\n  - `selector.py::apply_duration_penalty` 自动惩罚\n\n## 9. 网络/TLS 错误\n\n**症状**：MCP 调用超时或连接失败\n\n**主策略**：\n- 重试（最多 3 次）\n- 切换备用 actor\n\n**兜底**：\n- WebSearch 抓搜索结果页（`apify--rag-web-browser`）\n- 让用户提供手动数据\n\n## 10. 报告生成失败\n\n**症状**：`save_reports` 报错\n\n**主策略**：\n- 检查磁盘空间\n- 检查文件权限\n\n**兜底**：\n- 只生成 JSON 格式（最小输出）\n- 用 `cat > output.json` 直接写文件\n\n## 通用诊断流程\n\n```\n1. 检查 Apify token 是否有效\n2. 检查网络连接（clash verge / proxy）\n3. 用 `quality_gate.run_quality_gate` 检测哪阶段失败\n4. 查本 playbook 找对应失败场景\n5. 实施主策略\n6. 如果失败，启用兜底\n7. 报告失败原因给用户\n```\n\n## 关键代码位置速查\n\n| 失败阶段 | 主要函数 | 兜底函数 |\n|---|---|---|\n| 解析博主 | `resolver.resolve_creator_via_apify` | `_resolve_via_apify_search` |\n| 抓视频 | `parser.parse_actor_dataset` | `apify_browser` |\n| 字段解析 | `parser._extract_field` | 保留 raw |\n| 选精华 | `selector.select_essentials` | 仅按点赞排序 |\n| 转写 | `transcript.fetch_transcripts` | 切换 actor |\n| 报告 | `report_builder.save_reports` | 单独保存 |\n\nFile v1.3.3:references/pre-questions.md\n\n# Pre-questions · AskUserQuestion 模板\n\n## 问询原则\n\n自然语言优先。只有用户没有给目标账号、昵称搜索出现多个候选、或用户要求控制规模/成本时，才提问。默认参数不要逐项打断用户。\n\n推荐输入优先级：\n\n1. 抖音主页 URL\n2. `sec_uid`\n3. 抖音号 / ID\n4. 昵称\n\n昵称支持搜索，但同名账号较多；如果置信度不够，需要让用户确认候选。\n\n## 必填信息\n\n### Q1: 用户输入（creator_query）\n\n```\n\"请提供抖音号 / 昵称 / 主页 URL\"\n```\n\n接受输入格式：\n- 抖音号（纯数字 6-12 位）：如 `<douyin_id>`（如 `12345678`）\n- sec_uid（MS4w 开头）：如 `MS4wLjABAAA...`\n- 昵称：如 `史蒂文不做牛马`\n- 主页 URL：如 `https://www.douyin.com/user/MS4w...`\n\n如果用户已经在一句话里给出上述任意信息，不需要再问 Q1。\n\n## 条件必填（仅当模糊匹配时）\n\n### Q2: 候选博主确认\n\n```\n\"找到几个相似的博主，请确认哪个是您要的：\"\n```\n\n- option1: <nickname1> <signature1> · 粉丝 X 万\n- option2: <nickname2> <signature2> · 粉丝 Y 万\n- ...\n\n## 默认参数（通常不问，直接采用）\n\n### Q3: 抓取视频条数\n\n```\n\"要抓取多少条最新视频？\"\n- 推荐（200 条）\n- 深度（500 条）\n- 快速（50 条）\n```\n\n默认：200\n\n### Q4: 语音转写条数\n\n```\n\"要抓取多少条精华视频的语音转写？\"\n- 5 条（推荐）\n- 10 条\n- 全部精华（可能耗时）\n```\n\n默认：5\n\n### Q5: 转写时长上限（分钟）\n\n```\n\"转写候选的视频时长上限？\"\n- 5 分钟（默认，用于控制样本规模）\n- 10 分钟\n- 不限（可能显著增加资源消耗）\n```\n\n默认：5\n\n### Q6: 研究目标\n\n```\n\"主要研究目标？\"\n- 综合洞察（推荐）\n- 选题拆解\n- 爆款分析\n```\n\n默认：综合洞察\n\n### Q7: 输出格式\n\n```\n\"输出哪些格式的报告？\"\n- HTML（可视化）\n- Markdown（快读）\n- JSON（数据分析）\n```\n\n默认：全部\n\n### Q8: 输出目录\n\n```\n\"报告保存到哪里？\"\n```\n\n默认：当前工作目录 `./output/`\n\n## 什么时候主动改成小样本\n\n用户出现这些意图时，建议先小样本：\n\n- “先试一下”\n- “省额度”\n- “先看看能不能跑通”\n- “教程演示”\n\n推荐小样本：`max_videos=50`、`transcript_count=1`。如果用户明确说完整分析或未指定规模，则使用默认 `max_videos=200`、`transcript_count=5`。\n\n## 完整调用示例\n\n```python\nfrom AskUserQuestion import ask_user_questions\n\nquestions = [\n    {\n        \"key\": \"creator_query\",\n        \"question\": \"请提供抖音号 / 昵称 / 主页 URL\",\n        \"required\": True,\n    },\n    {\n        \"ke\n\nArchive v1.3.2: 40 files, 97385 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (7710b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (11334b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (18470b), scripts/browser_collector.py (13103b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (19121b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (8099b), scripts/setup.py (7202b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2869b), SKILL.md (9271b), tests/test_pipeline.py (18901b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nArchive v1.3.1: 40 files, 96964 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (7459b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (10887b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (18470b), scripts/browser_collector.py (13103b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (19121b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (8099b), scripts/setup.py (7202b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (3185b), SKILL.md (8809b), tests/test_pipeline.py (18901b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nArchive v1.2.3: 40 files, 93512 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (6128b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (10258b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (15175b), scripts/browser_collector.py (13103b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (18530b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (7687b), scripts/setup.py (5423b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2976b), SKILL.md (8547b), tests/test_pipeline.py (16617b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nArchive v1.2.2: 41 files, 94116 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (6010b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (10258b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (15175b), scripts/browser_collector.py (13103b), scripts/categorizer.py (4204b), scripts/integration.py (3838b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (18530b), scripts/runtime_env.py (4450b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/setup_config.py (7687b), scripts/setup.py (5423b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2908b), SKILL.md (8547b), task_plan.md (741b), tests/test_pipeline.py (16617b), tests/test_repository.py (1463b), tests/test_runtime_env.py (10472b), _meta.json (141b)\n\nArchive v1.2.1: 39 files, 86219 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (5306b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (8489b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (14368b), scripts/browser_collector.py (12955b), scripts/categorizer.py (4204b), scripts/integration.py (3345b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (17185b), scripts/runtime_env.py (4414b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (2949b), SKILL.md (7863b), task_plan.md (921b), tests/test_pipeline.py (14404b), tests/test_repository.py (1413b), tests/test_runtime_env.py (6756b), _meta.json (141b)\n\nArchive v1.2.0: 37 files, 82565 bytes\n\nFiles: assets/README.md (1961b), assets/report_style.css (2990b), assets/report_template.html (1229b), CHANGELOG.md (5112b), CONTRIBUTING.md (3575b), docs/sample-report.html (8743b), docs/sample-report.json (2404b), docs/sample-report.md (2240b), LICENSE (1085b), README.md (8331b), references/apify-douyin-actors.md (3869b), references/categorization-taxonomy.md (2861b), references/creator-resolution-playbook.md (2571b), references/data-schema.md (2773b), references/failure-playbook.md (4132b), references/pre-questions.md (2889b), references/report-rubric.md (3282b), requirements.txt (2264b), scripts/asr.py (14250b), scripts/browser_collector.py (12887b), scripts/categorizer.py (4204b), scripts/integration.py (3345b), scripts/parser.py (8130b), scripts/quality_gate.py (5152b), scripts/report_builder.py (15329b), scripts/resolver.py (9716b), scripts/run_pipeline.py (17185b), scripts/schemas.py (5944b), scripts/selector.py (5604b), scripts/transcript.py (6599b), SECURITY.md (613b), skill-card.md (3046b), SKILL.md (7705b), task_plan.md (921b), tests/test_pipeline.py (14404b), tests/test_repository.py (1413b), _meta.json (141b)","readmeExcerpt":"Skill: douyin-creator-insight Owner: tars1230 Summary: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。 Tags: latest:1.3.6 Version history: v1.3.6 | 2026-08-05T12:42:37.389Z | user setup/缺Key强制三步：推荐注册页→控制台建Key→export；交互可打开 https://cloud.siliconflow.cn/i/1srulim9 v1.3.5 | 2026-08-05T09:53:13.121Z | user ASR 简化为单一路径：只下 video_url → ffmpeg 抽音 → SenseVoice；去掉 audio_url 优先分支 ","codeSnippets":[],"executableExamples":[{"language":"json","snippet":"{\n  \"maxPostsPerProfile\": 1000,\n  \"profileUrls\": [\"https://www.douyin.com/user/<sec_uid>\"]\n}"},{"language":"bash","snippet":"# 非联网验证\npython3 scripts/run_pipeline.py --creator <profile_url> --dry-run\n\n# 默认真实路径：已登录浏览器中的公开主页接口\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py --creator '<share_or_profile_url>' --browser\n\n# 明确选择本地 Whisper 或纯信息索引\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode local\npython3 scripts/run_pipeline.py --creator '<profile_url>' --browser --transcript-mode index\n\n# 使用显式 adapter 真实运行\npython3 scripts/run_pipeline.py \\\n  --creator <profile_url> \\\n  --adapter my_adapter:call_actor \\\n  --output-dir ./output"},{"language":"bash","snippet":"python3 -m compileall -q scripts tests\npython3 -m unittest discover -s tests -v"},{"language":"python","snippet":"from jinja2 import Environment, FileSystemLoader\n\nenv = Environment(loader=FileSystemLoader('assets'))\ntemplate = env.get_template('report_template.html')\nhtml = template.render(\n    nickname=nickname,\n    followers=followers,\n    ...\n)"},{"language":"html","snippet":"<header class=\"hero\">\n    <h1>{{ nickname }} · 抖音内容洞察报告</h1>\n    <div class=\"creator-stats\">\n        <div class=\"stat\"><span class=\"num\">{{ followers }}</span></div>\n        ...\n    </div>\n</header>"},{"language":"bash","snippet":"python3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py \\\n  --creator '长按复制此条消息，打开抖音搜索 https://v.douyin.com/xxxx/ ...' \\\n  --browser --max-videos 50 --output-dir ./output"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: douyin-creator-insight\nversion: 1.3.6\ndescription: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。\n---\n\n# Douyin Creator Insight\n\n## 使用条件\n\n仅分析公开可访问数据。默认真实抓取使用已授权的本地浏览器 profile，不依赖 Apify key；Apify 仅是显式 fallback。不要在对话、脚本、报告或仓库中输出 token、cookie、浏览器 profile、私人绝对路径或未公开内容。\n\n## 安装与共享配置\n\n`douyin-creator-insight` 可独立安装和运行，`douyin-favorites-to-knowledge`（旧名/旧目录可能是 `douyin-knowledge-base-pipeline`）不是前置依赖。若两者都存在，本 skill 只复用已登录的 persistent browser profile 和 ASR 环境变量，绝不读取收藏记录、修改增量 metadata，或加入收藏 skill 的 23:00 任务。\n\n首次运行先执行 `python3 scripts/setup.py`。它只写非敏感偏好：`cloud`（云端 ASR）/ `local`（Whisper）/ `index`（只索引），以及可选 profile/output 位置；不保存 API key、cookie 或 token。若检测到已安装 `douyin-favorites-to-knowledge`，优先复用其已登录浏览器 profile 和转录偏好，但状态、账本、输出和 23:00 任务仍完全隔离。缺 Key 时 setup 会打印 **①②③ 逐步指引**，交互终端可询问是否**打开推荐注册页**。\n\n**云端 ASR 真相（抖音）**：抖音 CDN（`*.douyinvod.com` 等）带防盗链，**阿里云百炼 URL-ASR 服务端拉不到媒体**，会稳定失败——不是用户 Key 配错。公开 skill 的默认可用路径是：\n\n1. **推荐 `SILICONFLOW_API_KEY`**：本机用浏览器式 `Referer: https://www.douyin.com/` 临时下载 → 抽音频 → 上传 SiliconFlow `FunAudioLLM/SenseVoiceSmall` → 立即清理临时文件。\n2. **可选 `DASHSCOPE_API_KEY`**：仅当媒体 URL 是第三方可公网直链时走百炼 URL-ASR；对抖音 CDN **默认跳过**（可用 `DOUYIN_FORCE_DASHSCOPE_URL=1` 强行试）。\n3. 至少配置上述之一才允许 `cloud` 真跑；**两者都缺**时停止，不下载、不静默切 Whisper。\n4. 云端都失败且用户允许 local fallback 时才进 Whisper；`index` 永不 ASR。\n\n**新用户拿 Key（必须按序，别自己乱搜）：**\n\n1. 打开推荐注册/登录页：https://cloud.siliconflow.cn/i/1srulim9  \n2. 控制台创建 API Key：https://cloud.siliconflow.cn/account/ak  \n3. `export SILICONFLOW_API_KEY='…'` 或写入 `~/.hermes/.env` / 仓库 `.env.local`，**重启 Agent**  \n4. 价格参考：https://siliconflow.cn/pricing（SenseVoiceSmall 可能标免费，以账单为准）\n\n百炼说明（可选）：`https://help.aliyun.com/zh/model-studio/get-api-key`。Key 放本机环境变量/Secret Manager，不要发聊天或进仓库。skill 自动读 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local`。运行前 `python3 scripts/integration.py`；共享 profile 被占用必须等待。报告写入独立 `<output-root>/creator-insight/`。\n\n> **ASR 费用（默认 SenseVoiceSmall）**：截至 **2026-08-05**，硅基流动[官方价格页](https://siliconflow.cn/pricing)将 `FunAudioLLM/SenseVoiceSmall` 标注为 **免费**（同页 `TeleSpeechASR` 亦免费；TTS 另计）。需要 `SILICONFLOW_API_KEY`。价格会变，**不承诺永久免费**；以价格页与控制台账单为准。可选百炼 `qwen3-asr-flash` 另计费（与 SiliconFlow 账单分离），且对抖音 CDN 常失败。\n\n- **SiliconFlow 注册推荐链接**：[https://cloud.siliconflow.cn/i/1srulim9](https://cloud.siliconflow.cn/i/1srulim9)\n- Key 控制台：[https://cloud.siliconflow.cn/account/ak](https://cloud.siliconflow.cn/account/ak)\n\n\nActor 的价格、配额、可用性和 schema 会变化。运行前查看当前 Actor 页面；任何费用或耗时只能作为本次运行的实测结果陈述，不能沿用固定承诺。\n\n## 输入\n\n从用户原话提取：\n\n- `creator_query`：优先主页 URL、`sec_uid`，或包含 `v.douyin.com` 的完整分享消息；脚本会提取短链接。\n- `max_videos`：默认 1000；用户要求省资源或试跑时降低。超过上限时结果必须标为 `partial`。\n- `transcript_count`：未指定时按作品数自动分档；用户显式指定时优先遵从。\n- `transcript_max_duration_minutes`：默认 5，用于候选筛选。\n- `transcript_mode`：`cloud`（默认）/ `local` / `index`。\n- `output_formats`：默认 `html`、`md`、`json`。\n- `output_dir`：默认当前任务的专用输出目录。\n\n主页 URL、分享短链接或 `sec_uid` 最稳定。昵称和抖音号只可用于候选确认，不能自动选择同名账号；搜索验证码或模糊结果时要求用户改贴主页/分享链接。\n\n## 流程\n\n1. 用 `scripts/resolver.py` 判断输入类型，并从分享消息提取短链接。\n2. 对 URL/短链接/`sec_uid`，优"},{"path":"assets/README.md","content":"# Assets · 模板文件\n\n本目录存放报告生成所需的静态资源。\n\n## 文件清单\n\n- `README.md`：本说明\n- `report_template.html`：HTML 报告模板（参考用）\n- `report_style.css`：报告样式（参考用）\n- `creator_card_template.html`：博主封面卡片模板（参考用）\n\n## 当前实现\n\n**注意**：当前 `scripts/report_builder.py` 使用内置 Python 字符串模板，**不依赖** assets/ 目录。\nassets/ 中的文件仅作为参考 / 自定义起点。\n\n## 自定义指南\n\n如果需要自定义样式：\n\n### 方式 1：直接修改内置模板\n\n编辑 `scripts/report_builder.py::HTML_TEMPLATE`，调整 CSS 部分。\n\n### 方式 2：使用 jinja2 渲染\n\n1. 安装：`pip install jinja2`\n2. 把内置 HTML_TEMPLATE 复制到 `assets/report_template.html`\n3. 用 jinja2 渲染\n\n```python\nfrom jinja2 import Environment, FileSystemLoader\n\nenv = Environment(loader=FileSystemLoader('assets'))\ntemplate = env.get_template('report_template.html')\nhtml = template.render(\n    nickname=nickname,\n    followers=followers,\n    ...\n)\n```\n\n### 方式 3：完全重写\n\n如果需要差异化设计（如杂志风、暗色模式），可以：\n\n1. 创建新文件 `assets/report_template_magazine.html`\n2. 在 `scripts/report_builder.py` 中加 `build_html_report_magazine()`\n3. 调用方选择用哪个模板\n\n## 配色参考\n\n| 风格 | 配色 |\n|---|---|\n| 默认（深紫蓝） | `#1e3a8a → #5b21b6` |\n| 杂志风（暖色） | `#b45309 → #d97706` |\n| 暗色模式 | `#0f172a → #1e293b` |\n| 极简（白底） | `#f8fafc → #f1f5f9` |\n\n## 示例模板\n\n### 默认模板（已在 report_builder.py）\n\n```html\n<header class=\"hero\">\n    <h1>{{ nickname }} · 抖音内容洞察报告</h1>\n    <div class=\"creator-stats\">\n        <div class=\"stat\"><span class=\"num\">{{ followers }}</span></div>\n        ...\n    </div>\n</header>\n```\n\n### 杂志风模板（待创建）\n\n参考 `guizang-ppt-skill` 的杂志风风格。"},{"path":"README.md","content":"# Douyin Creator Insight\n\n从公开抖音主页、分享短链接或 `sec_uid` 出发，生成可审计的创作者内容洞察报告。默认使用已登录的本地浏览器 profile 读取公开作品；Apify 是可选 fallback。输出包含 HTML、Markdown 和 JSON。\n\n[![CI](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml/badge.svg)](https://github.com/tars1230/douyin-creator-insight/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)\n\n## 能做什么\n\n- 解析主页 URL、`sec_uid` 和完整分享文案中的短链接；昵称或抖音号只用于人工候选确认，不自动选择同名账号。\n- 标准化不同数据源的视频字段。\n- 按账号规模自动选择转写候选：小账号全量转写，大账号以点赞、收藏和近期作品分层抽样。\n- 对解析、视频数量和转写质量执行阻断式质量门。\n- 生成 HTML、Markdown、JSON 三种报告。\n\n本项目只处理公开数据，不绕过登录、隐私或平台访问控制。\n\n## 安装与分发入口\n\n- Agent 一键安装：[ClawHub douyin-creator-insight](https://clawhub.ai/tars1230/skills/douyin-creator-insight)\n- 国内源码镜像：[Gitee tars123/douyin-creator-insight](https://gitee.com/tars123/douyin-creator-insight)\n- 源码与版本发布：[GitHub tars1230/douyin-creator-insight](https://github.com/tars1230/douyin-creator-insight)\n\n## 运行方式\n\n### 独立运行，可选复用收藏 skill\n\n本 skill 可以独立安装。第一次运行先执行 `python3 scripts/setup.py`，明确选择：\n\n- `cloud`：云端 ASR（默认）。**抖音场景推荐配置 `SILICONFLOW_API_KEY`**（本机带 Referer 临时下载 → 上传 SenseVoice → 清理）。\n- `local`：本地 Whisper。只有用户明确选择时才临时下载视频，结束后清理。\n- `index`：只索引标题、描述、互动数据和链接，不调用 ASR。\n\n### 云端 ASR 重要说明（请先读）\n\n抖音播放地址在 `*.douyinvod.com` 等 CDN 上，带防盗链。**阿里云百炼的 URL-ASR 无法从服务端下载这些地址**，会稳定返回 download 失败——这不是 API Key 坏了，也不是“测通了百炼就等于抖音能转写”。\n\n| Key | 是否抖音刚需 | 作用 |\n|---|---|---|\n| **`SILICONFLOW_API_KEY`** | **是（推荐）** | 下载（`Referer: https://www.douyin.com/`）+ 上传 `FunAudioLLM/SenseVoiceSmall` |\n| `DASHSCOPE_API_KEY` | 否（可选） | 仅对**可公网直链**媒体做 URL-ASR；对抖音 CDN 默认跳过 |\n\n- SiliconFlow 控制台：[创建 API Key](https://cloud.siliconflow.cn/account/ak)\n- 百炼说明（可选）：[如何获取 API Key](https://help.aliyun.com/zh/model-studio/get-api-key)\n\n两者都缺时，`cloud` 真跑会安全停止，不下载、不静默切 Whisper。只有 `DASHSCOPE`、没有 SiliconFlow 时会告警。Key 放环境变量/Secret Manager，不要发聊天或进仓库。\n\nskill 会自动读取当前 shell、`~/.hermes/.env`、仓库 `.env` / `.env.local` 中的相关配置，Hermes 没透传环境也能继续走 cloud 默认。\n\n同时安装 `douyin-favorites-to-knowledge` 时，setup 会探测并优先复用它的已登录浏览器 profile 和转录偏好，但状态、输出和调度完全隔离：Creator Insight 默认写入 `./output/creator-insight/`，不读取收藏 metadata，也不加入 23:00 收藏任务。运行前执行 `python3 scripts/integration.py`；若共享 profile 已被占用，等待当前流程结束即可。`douyin-mcp` 是可选诊断工具，不是安装或运行依赖。\n\n### 1. 本地浏览器模式（默认推荐）\n\n首次独立使用时，本 skill 会使用中性的共享浏览器 profile；登录一次抖音即可。若已安装收藏 skill，则自动复用它现有的已登录 profile。之后可直接粘贴主页、`sec_uid`，或包含 `https://v.douyin.com/.../` 的完整分享消息：\n\n```bash\npython3 scripts/setup.py\npython3 scripts/integration.py\npython3 scripts/run_pipeline.py \\\n  --creator '长按复制此条消息，打开抖音搜索 https://v.douyin.com/xxxx/ ...' \\\n  --browser --max-videos 50 --output-dir ./output\n```\n\n该模式只读取公开作品列表，逐页验证每条作品作者的 `sec_uid`，不复制 cookie、不输出 profile、不绕过验证码。抖音媒体默认走 SiliconFlow 上传 ASR（Referer 下载后清理）；非抖音公网媒体可走百炼 URL ASR；全部云端失败才回退本地 Whisper。\n\n非交互环境可以显式配置：\n\n```bash\n# 云端：保存选择；若 Key 尚未配置，真实运行会安全停止并给出申请入口\npython3 scripts/setup.py --transcript-mode cloud\n\n# 本地：只有明确选择 local 后，真实运行才允许临时下载视频\npython3 scripts/setu"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7fgfkjyfqbz673wvzymh5e1x821vpk\",\n  \"slug\": \"douyin-creator-insight\",\n  \"version\": \"1.3.6\",\n  \"publishedAt\": 1785933757389\n}"},{"path":"references/apify-douyin-actors.md","content":"# Apify Douyin Actors 对照表\n\n## 三个核心 actor\n\n### 1. `zen-studio/douyin-profile-scraper` ⭐ 主用\n\n**用途**：抓取指定博主的所有视频列表\n\n**输入**：\n```json\n{\n  \"maxPostsPerProfile\": 200,\n  \"profileUrls\": [\"https://www.douyin.com/user/MS4w...\"]\n}\n```\n\n**输出字段**：\n```json\n[\n  {\n    \"id\": \"7600998358588812742\",\n    \"text\": \"视频文案/描述\",\n    \"title\": \"标题\",\n    \"createTime\": 1737638400,\n    \"createDate\": \"2025-01-23\",\n    \"statistics\": {\n      \"diggCount\": 12345,\n      \"commentCount\": 678,\n      \"shareCount\": 90,\n      \"collectCount\": 234,\n      \"playCount\": 567890\n    },\n    \"videoMeta\": {\n      \"duration\": 120000,\n      \"cover\": \"https://...\"\n    },\n    \"hashtags\": [{\"name\": \"...\"}],\n    \"series\": {\"name\": \"...\"},\n    \"shareUrl\": \"https://...\",\n    \"authorMeta\": {\n      \"name\": \"...\",\n      \"signature\": \"...\",\n      \"followersCount\": 333000,\n      \"heartCount\": 2672708,\n      \"awemeCount\": 200\n    }\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。公开视频、README 和教程里不要承诺固定成本；第一次建议先小样本验证。\n\n**限制**：maxPostsPerProfile 上限 200\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-profile-scraper\",\n    input={\n        \"maxPostsPerProfile\": 200,\n        \"profileUrls\": [profile_url]\n    },\n    wait_secs=45\n)\n```\n\n### 2. `zen-studio/douyin-transcripts-scraper` ⭐ 主用转写\n\n**用途**：抓取视频语音转写；当前限制以 Actor 页面为准\n\n**输入**：\n```json\n{\n  \"targetLanguage\": \"zh\",\n  \"videoUrls\": [\"https://www.douyin.com/video/7575296454722398441\", ...]\n}\n```\n\n**输出**：\n```json\n[\n  {\n    \"id\": \"7575296454722398441\",\n    \"caption\": \"...\",\n    \"text\": \"完整转写文本...\",\n    \"duration\": 812,\n    \"segments\": [{\"start\": 0, \"end\": 5.2, \"text\": \"...\"}, ...]\n  }\n]\n```\n\n**价格**：以 Apify Actor 当前页面为准。\n\n**调用示例**：\n```python\napify_caller(\n    actor=\"zen-studio/douyin-transcripts-scraper\",\n    input={\n        \"targetLanguage\": \"zh\",\n        \"videoUrls\": [video_url1, video_url2, ...]\n    },\n    wait_secs=45\n)\n```\n\n### 3. `apple_yang/douyin-transcripts-scraper` 备选\n\n**用途**：备用转写服务\n\n**输入**：\n```json\n{\n  \"videoUrl\": \"https://www.douyin.com/video/...\"\n}\n```\n\n**输出**：同上\n\n**限制**：历史测试中长视频支持不稳定；当前限制以 Actor 页面为准\n\n**价格**：以 Apify Actor 当前页面为准。\n\n## 备选 actor（不推荐）\n\n### `bovi/douyin-scraper`\n- 优点：功能多\n- 缺点：`user_videos` 模式 2026 起需要登录 cookies，已验证空结果\n- 不推荐\n\n### `sian.agency/douyin-scraper`\n- 优点：支持 userVideos\n- 缺点：可能排队较久，且可能需要登录 cookies\n- 不推荐\n\n### `apify--rag-web-browser`\n- 用途：网页搜索 + 渲染\n- 兜底方案：当 profile scraper 失败时用此搜索主页\n- 调用示例：\n```python\napify_browser(\n    query=\"https://www.douyin.com/user/MS4w...\",\n    max_results=1\n)\n```\n\n## 经验教训\n\n1. **优先用 zen-studio 系列**，但运行前核对当前访问要求与输入 schema\n2. **user_videos 模式 = 需要登录**（2026 现状）→ 慎用 bovi/sian.agency\n3. **转写超时**：降低样本或候选时长，并核对 Actor 当前限制\n4. **TOON 格式**：Apify 返回的是 TOON 格式，需要手动解析（见 `data-schema.md`）\n5. **字段 schema 不稳定**：不同 actor 返回字段名差异大，需要多别名解析（见 `parser.py::_extract_field`）\n\n## 失败兜底顺序\n\n```\nzen-studio profile scraper (主)\n  ↓ 失败\napify--rag-web-browser 渲染主页\n  ↓ 失败\nWebSearch + 用户手动提供数据\n```\n\n```\nzen-studio transcripts scraper (主)\n  ↓ 失败\napple_yang transcripts scraper (备用，限制以当前 Actor 页面为准)\n  ↓ 失败\n跳过该视频，继续下一个\n```"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。 Skill: douyin-creator-insight Owner: tars1230 Summary: 分析公开抖音创作者的视频主题、互动结构和代表内容，并输出 HTML、Markdown、JSON 报告。适用于研究某个抖音博主、拆解选题和内容结构；不用于收藏夹同步、私密账号或绕过平台访问控制。 Tags: latest:1.3.6 Version history: v1.3.6 | 2026-08-05T12:42:37.389Z | user setup/缺Key强制三步：推荐注册页→控制台建Key→export；交互可打开 https://cloud.siliconflow.cn/i/1srulim9 v1.3.5 | 2026-08-05T09:53:13.121Z | user ASR 简化为单一路径：只下 video_url → ffmpeg 抽音 → SenseVoice；去掉 audio_url 优先分支","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1026,"uniquenessScore":46,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T23:58:08.863Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T23:58:08.863Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-12T09:25:07.796Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}