Files
MediaCrawler/mac-agent-os-main/PLANS/AUDIO_LIPSYNC_PLAN.md
T
butubb 2112c1a870
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s
feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。

**目前能用的(真环境实测,非推断)**:

    profile/other : 200, 7075 字节  —— 博主主页指标(粉丝/获赞/作品数/昵称)
    aweme/detail  : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)

**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
  1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
     带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
     同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
     挑中的恰好是「批量拉作品列表」这个最敏感的动作。
  2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
     代价,过几小时要重测)。

  所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。

**排查中控住变量后得到的两条事实**(都写进注释了):
  · `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
    UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
    (我先前猜的 sec-ch-ua 不是关键。)
  · 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
    从 CDP 取齐 cookie + UA + hints,而不是各自写死。

「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。

测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
2026-10-10 17:12:25 +08:00

147 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 声音 / 口型 完整方案(v1 草案)
> 建立:2026-10-03 · 状态:**待用户最终确认后实施**
> 关联:`composer/dubbing.py`(配音引擎·已上线)、`composer/lipsync.py`(待改造为可灵版)
---
## 一、目标
让成片的**声音完整、口型对得上、节奏跟得上**:
1. 主角出镜说台词的镜头 → **口型同步**
2. 旁白 / 空镜 → 正常配音(不做口型)
3. 同一角色**音色全片一致**(不管画面怎么变)
4. 台词时长决定镜头时长(**画面跟着声音走**)
---
## 二、用户已确认的决策
| # | 决策 | 说明 |
|---|---|---|
| 1 | **只对有台词的镜头做口型** | 成本最低;其余镜头不做 |
| 2 | **音色必须一致** | 一个角色 = 一个固定 `voice_id`;音色库管理 |
| 3 | **音频先行** | 先 TTS 得到真实音频时长 → 按它定镜头时长 → 再生成画面 |
| 4 | **旁白标记 = 混合(c)** | 默认自动判定(无出场人物=旁白),分镜卡片可手动改 |
| 5 | 一句话拆两镜 | 按**语义停顿**切分(**先自动分,需要时手动调**),每段独立 TTS + 对口型 |
| 6 | 对口型失败兜底 | 用原片段(不影响出片) |
| 7 | 成本测试 | **改用 20 秒测试片**:1 个空镜(素材库免费素材)+ 2 个 5 秒角色说话镜头(做口型)——"该省省,该花花" |
| 8 | **双人同框对策 = 参数** | 正反打/过肩镜头做成本可控制的**参数**(默认关,未来有能力再启用,不影响创作) |
---
## 二·五、待补充的**基础能力**(用户要求:补在基础层,其他流程可复用)
> 原则:**补在基础能力层**(`capabilities/` / `composer/`),而非某个流程专属实现 —— 这样分镜、口播、混剪等流程都能复用。
| # | 能力 | 用途 | 现状 |
|---|---|---|---|
| B1 | **首尾帧衔接** | 镜头间无缝续接 / 镜头内首尾帧控制 | 底层已具备(可灵 `image_tail`),**上层未接通** |
| B2 | **多参考图** | 多角色同框各保人脸 | ❌ 可灵不支持;待专业方案(ComfyUI 多参考 / IP-Adapter) |
| B3 | **微表情 + 口型核对** | 生成后校验表情/口型是否符合预期(质量门) | ❌ 无(可结合视觉模型做检测) |
---
## 三、技术方案
### 3.1 声音分四轨
```
一条片子的声音 = 旁白轨 + 角色人声轨 + 环境音轨 + BGM轨
```
### 3.2 镜头按声音需求分三类
| 类型 | 特征 | 画面 | 声音 |
|---|---|---|---|
| **A 角色说话** | 有台词 + 有出场人物 | 图生视频(绑角色,保人脸) | 角色音色 TTS + **对口型** |
| **B 旁白解说** | 有台词、无出场人物(或手动标旁白) | 空镜 / 场景 | 旁白音色 TTS,不做口型 |
| **C 无台词** | 空镜 / 氛围 | 场景 | 环境音铺底(或静音) |
### 3.3 工作流(音频先行)
```
① 分镜定稿(每镜:台词 + 出场人物 + 旁白标记)
↓
② 【音频先行】逐镜 TTS
· A 类 → 该角色音色(voice_id 固定)
· B 类 → 旁白音色
· C 类 → 无
→ 得到每段**真实音频时长**
↓
③ 【画面跟随】按音频时长定镜头时长 → 生成画面
· 绑角色 → 图生视频(保人脸一致性)← 2026-10-03 已修复
· 未绑 → 文生视频
↓
④ 【对口型】仅 A 类镜头:
镜头视频 + 台词音频 → 可灵 lip-sync → 替换片段(失败则用原片段)
↓
⑤ 【混流】人声轨 + 环境音 + BGM + 字幕
```
### 3.4 音色一致性机制
- **一个角色 = 一个固定 voice_id**(演员表 `CastMember.voice_id` 绑定)
- 未指定 → 按角色代号 hash 从路人池**稳定分配**(同代号永远同音色)
- CosyVoice 同一 voice_id 合成结果音色确定(仅语气/语速随文本微变)
- **旁白与角色音色可以不同**(解说员 vs 画面人物,观众接受且更自然)
### 3.5 可灵 lip-sync 接口(已实测探明,2026-10-03)
```
POST /v1/videos/lip-sync
{
"input": {
"mode": "audio2video", // 或 text2video(需 voice_language)
"video_url": "..." | "video_id": "...", // 二选一(video_id 可用我们生成的镜头)
"audio_type": "url",
"audio_url": "..."
}
}
GET /v1/videos/lip-sync ← 任务列表查询
```
✅ **用现有 kling key 即可,不需要 fal.ai**(现有 `lipsync.py` 是 fal.ai 版 → 改造为可灵版)
⚠️ 单价未知(文档站为 SPA 抓不到)→ 按用户决策:先跑 1 个 5 秒镜头实测
---
## 四、实施步骤(建议顺序)
| 阶段 | 内容 | 依赖 |
|---|---|---|
| **P1** | 音频先行:出片流程加「先 TTS → 按音频时长定镜头时长」(音频存盘供混流复用,**不重复 TTS**) | 无 |
| **P2** | 演员表音色绑定 + 旁白标记(前端 UI + schema) | 无 |
| **P3** | `lipsync.py` 改造为可灵版 + 接入出片流程(仅 A 类镜头,失败用原片段) | P1 |
| **P4** | **20 秒测试片**:1 空镜(免费素材)+ 2 个 5 秒角色说话 → 实测 lip-sync 单价 → 用户决定是否全量 | P3 |
| **P5** | 首尾帧衔接(接通 `image_tail`)→ 补进**基础能力层**(B1) | 独立 |
| **P6** | 双人同框 → 正反打**参数**(默认关,用户可控;未来 B2 到位后可启用) | 独立 |
| **B 系列** | 基础能力补充:B1 首尾帧 / B2 多参考 / B3 微表情口型核对(补在基础层,全流程复用) | 见二·五 |
---
## 五、成本估算(粗略,待实测)
| 项 | 单价 | 说明 |
|---|---|---|
| TTS(CosyVoice) | 极低(按字数) | 几十字台词 ≈ 几分钱 |
| 可灵 lip-sync | **待实测** | 参考 fal.ai 版注释 ¥0.1/秒 |
| 粗估 | 每部短片 2~3 个台词镜头 × 5 秒 ≈ **¥1~2/部** | 月产 20 分钟 ≈ 十数量级 |
---
## 六、已知局限(诚实标注)
1. **多角色同框**:图生视频只能喂一张参考图 → 只保主角(替代:正反打 / 合成参考图 / 等专业能力)
2. **跨镜头口型连贯**:一句话拆两镜时,语气可能有轻微断裂(缓解:切分点落在语义停顿)
3. **已生成素材**:本方案只对新生成生效(旧镜头需重新出片)
---
## 七、待确认
- [ ] 用户确认"按默认"(第 2/3/4 点)→ 即可开工 P1
- [ ] 优先级:**A 声音链先做**(建议),B 一致性增强随后