feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

移植自 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 带网关原话 / 正常返回)。
This commit is contained in:
2026-10-10 17:12:25 +08:00
parent 21ff01b894
commit 2112c1a870
1601 changed files with 367425 additions and 0 deletions
@@ -0,0 +1,146 @@
# 声音 / 口型 完整方案(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 一致性增强随后
@@ -0,0 +1,130 @@
# Dashboard 五层架构合规审计报告 v1.0
> 日期: 2026-06-19
> 审计范围: 所有 33 个前端视图 + 4 个内联模块
---
## 一、五层架构标准
```
Layer 5: 前端视图 (Vite views/*.js) → 调 API
Layer 4: API 路由 (routes/*.py) → 调 CommandBus
Layer 3: 命令总线 (CommandBus) → 调 MachineSession
Layer 2: 执行引擎 (mc run / mc task) → 调 原子操作
Layer 1: 浏览器 (Camoufox) → 执行操作
```
**通过标准**: 前端 API 调用 → 后端路由 → CommandBus.dispatch() → 子进程执行
---
## 二、账户操作视图 (必须走 CommandBus)
### ✅ 已合规 (7个)
| 视图 | 操作 | API 调用 | 后端路径 |
|:-----|:------|:---------|:---------|
| **养号执行** | 启动养号 | `POST /api/ops/run` | → CommandBus → `mc run` |
| **联邦指挥台** | 执行操作 | `POST /api/ops/run` | → CommandBus → `mc run` |
| **信息采集** | 批量采集 | `POST /api/ops/run {type:'collect'}` | → CommandBus `CMD_REGISTRY` → `mc run --blueprints=auto` |
| **信息采集** | 单账号采集 | `POST /api/ops/run {type:'collect'}` | → CommandBus `CMD_REGISTRY` → `mc run --blueprints=auto` |
| **定向评论** | 执行评论 | `POST /api/ops/run {type:'comment'}` | → CommandBus `CMD_REGISTRY` → `mc task comment` |
| **收藏点赞** | 执行点赞 | `POST /api/ops/run {type:'like'}` | → CommandBus `CMD_REGISTRY` → `mc run --blueprints=douyin_daily` |
| **登录** (账号管理/各视图🔑) | 打开浏览器 | `POST /api/ops/run {type:'login'}` | → CommandBus `CMD_REGISTRY` → `mc smart-login` |
| **CMD_REGISTRY 注册表** | 统一 cmd_type → 命令模板 | 在 command_bus.py 定义 | 新增操作只需加一行,不需改 dispatch |
### ℹ️ 系统运维操作 (不走 CommandBus 是合理的)
| 视图 | 操作 | API | 原因 |
|:-----|:------|:----|:------|
| **远程Shell** | 在远端执行命令 | `POST /api/federation/exec` | 系统管理工具, 非账号操作 |
| **对账检查** | ORACLE 宪法对账 | `POST /api/fleet/reconcile` | 系统健康检查 |
| **一键同步** | Git 同步所有机器 | `POST /api/fleet/sync` | 系统运维 |
### 📊 只读数据视图 (无操作, 无需 CommandBus)
| 视图 | API | 说明 |
|:-----|:----|:------|
| machines | `/api/machines` | 机器状态, 只读 |
| matrix-accounts | `/api/matrix/accounts` | 账号列表, 只读 |
| matrix-blueprints | `/api/matrix/blueprints`, `/api/matrix/atom-ops` | 蓝图列表+原子操作, 只读 |
| matrix-atom-ops | `/api/matrix/atom-ops` | 原子操作列表, 只读 |
| matrix-corpus | `/api/matrix/corpus` | 语料库, 只读 |
| matrix-summary | `/api/matrix/cross-machines`, `/api/matrix/system-info` | 多机总览, 只读 |
| matrix-sms-proxy | `/api/matrix/sms/*` | SMS 代理配置, 只读 |
| matrix-schedule | `/api/matrix/schedules` | 定时任务, 只读 |
| capabilities | `/api/capabilities` | 能力目录, 只读 |
| costs | `/api/summary`, `/api/costs/breakdown` | 费用统计, 只读 |
| productions | `/api/matrix/sms/accounts` | 生产列表, 只读 |
| assets | `/api/assets` | 资产库, 只读 |
### ❌ 14行占位符 (无功能)
| 视图 | 状态 |
|:-----|:------|
| ave-render, ave-script, ave-materials, ave-templates | 占位符 |
| crawl-history, crawl-sources | 占位符 |
| serve-dashboard, serve-mcp, serve-schedule | 占位符 |
| matrix-login | 跳转到采集 |
| matrix-publish | "开发中..." |
| workflow | 占位符 |
---
## 三、远程执行路径 (federation API)
`recording.js` 中 `_routeOperation()` 对远程机器分发走 federation API:
| 操作 | Federation 端点 | 现状 |
|:-----|:----------------|:------|
| login(远程) | `POST /api/federation/login` | ⚠️ 直接 SSH 执行 |
| logout(远程) | `POST /api/federation/logout` | ⚠️ 直接 SSH 执行 |
| comment(远程) | `POST /api/federation/comment` | ⚠️ 直接 SSH 执行 |
| nurture(远程) | `POST /api/federation/nurture` | ⚠️ 直接 SSH 执行 |
| collect(远程) | `POST /api/federation/collect` | ⚠️ 直接 SSH 执行 |
**这些 federation 端点应该也改为走 CommandBus**, 否则远程操作不经过命令总线的 preflight/冷却/并发控制。
---
## 四、ORACLE 合规检查规则
### 4.1 账号→机器映射表
`ORACLE.yaml` 是账号→机器的**宪法级**映射表。CommandBus 执行前自动校验:
```
请求: account=douyin_test, machine=5kechengdeAir
→ ORACLE 查 douyin_test → 应属于 chengzigedeAir
→ 发出警告: "douyin_test 按 ORACLE 应在 chengzigedeAir,实际发往 5kechengdeAir"
→ 仍然允许执行(可能是临时调配)
```
### 4.2 三种结果
| 检查结果 | 行为 | 前端显示 |
|:---------|:-----|:---------|
| 匹配 | 正常执行 | ✅ 绿色 |
| 不匹配 | 执行 + 警告 | ⚠️ 橙色警告 |
| 未登记 | 执行 + 警告 | ⚠️ 建议 git pull 后 fleet_reconcile |
### 4.3 规则存证
- `ORACLE.yaml` — 宪法文件,账号机器映射的 source of truth
- `command_bus.py` — 运行时校验,每次 dispatch 自动检查
- `fleet_reconcile` — 对账工具,检查实际状态是否符合 ORACLE
---
## 五、总结
| 类别 | 数量 | 状态 |
|:-----|:-----|:------|
| 账户操作视图 | **7** | ✅ **全部已合规**(走 CommandBus) |
| 系统运维视图 | **3** | ℹ️ 合理不走 CommandBus |
| 只读数据视图 | **12** | ℹ️ 无操作 |
| 占位符视图 | **11** | ❌ 无功能 |
| 远程分发端点 | **5** | ⚠️ 待改造 |
**当前优先级**: 远程端点(federation)改造 → 占位符填充 → 旧模块清理
@@ -0,0 +1,144 @@
# 基础能力治理与补强方案(提案)
> 2026-10-03 · 状态:待用户拍板
> 背景:用户提问"接着补基础能力,怎么加,也涉及以后基础能力如何增加调整"
---
## 一、诊断:能力体系已"半脱节"
### 已有基础(做得好的)
| 模块 | 位置 | 作用 |
|---|---|---|
| 能力登记 | `05_tools/09_ave/config/capabilities.yaml` | 25 个能力,含 io / params_schema / providers |
| 缺口声明 | `05_tools/09_ave/config/feasibility_rules.yaml` | 30 条可行性规则 + 10 个能力缺口映射 + 三色红线 |
| 匹配器 | `05_tools/09_ave/scripts/capability_matcher.py` | 需求→能力匹配 + 目录指纹 + 升级检测 |
| 前端 | 导演台技术预检弹窗 | 显示每个镜头的技术预检与缺口汇总 |
### ⚠️ 实测发现的 5 处"清单 ≠ 实际"
| 能力 | 清单写的 | 实际 | 影响 |
|---|---|---|---|
| `lipsync` 对口型 | providers: fal / volcano / d_id · partial | 已用**百炼 videoretalk** 跑通 | 清单 provider 错误,无法据此排障 |
| `person_swap` 人物置换 | partial | **已实测跑通** | 状态偏保守 |
| `vfx_apply` 特效 | planned | 可灵 `camera_control` **已可用** | 状态偏保守 |
| `frame_chain` 首尾帧 | **missing** | `kling_video.py:152` **已实现 image_tail** | **把已有能力报成缺口** |
| `voice_lock` 声线锁 | cap_id=**None** | 音色库已实现 | 未挂到能力,统计丢失 |
**根因**:能力登记、代码实现、缺口声明**三者无联动** ——
加了功能忘登记、登记了没实现、实现了却仍报"缺失"。
---
## 二、机制方案:能力生命周期(4 步 + 1 台账)
```
① 登记 capabilities.yaml(唯一真相源)
新增字段:
cost: {unit: "元/秒", price: 0.08, note: "走免费额度优先"}
limits: ["正面近景 2~120s", "边长 640~2048"]
self_test: "python -m capabilities.selftest lipsync"
last_verified: "2026-10-03"
provider.state: ready | needs_key | broken
② 自检 scripts/capability_doctor.py(新)
一条命令验证"清单说的 ready 是不是真能跑"
--list 列出全部能力与最近验证状态
--capability X 单查(api_key 配置 / provider 可达 / limits 校验)
--live 真跑最小样例(产生费用,需显式开启)
--update 把验证结果写回 capabilities.yaml 的 last_verified
③ 接入 标准 4 步(写成 docs/CAPABILITY_GUIDE.md)
a. capabilities.yaml 登记(id/name/category/io/schema/provider/cost/limits)
b. 实现 provider(scripts/capabilities/<name>.py 或既有模块)
c. 写自检样例(让 doctor --live 能跑)
d. feasibility_rules.yaml 声明"什么技术需求触发它"
—— 与导演系统的"接新导演 3 步"对称
④ 台账 runtime/ave/capability_gaps.json(新)
缺口不再散落在规则里,而是有状态:
{id, name, first_seen, occurrences, affected_shots[], status,
blocking, resolved_at, resolved_by}
status: open → planned → in_progress → resolved
+ 能力升级 → 指纹变化 → 已出片方案自动提示"可重新生成更好版本"
```
**设计取舍**:先做 ①②(对账 + 体检),台账 ④ 可后置。
理由是 ①② 立刻消除"清单不可信"这个根本问题;④ 是统计增项。
---
## 三、本轮补什么(按性价比排序)
### 🥇 P0 能力对账 + 体检脚本(零成本 · 约 1 天)
- 修正上述 5 处脱节(尤其 `frame_chain` 从 missing → ready)
- 补 `cost` / `limits` 字段(为报价与预算打基础)
- 写 `capability_doctor.py`(`--list` 与单查;`--live` 可选)
- **产出**:一份可信的能力清单 + 一键体检
### 🥈 P1 首尾帧衔接 `frame_chain`(能力已有,只差接线)
- **前提**:可灵 `image_tail` 参数**代码已实现**(`capabilities/kling_video.py:143-152`)
- **做**:分镜 `tech_requirements.chain_from_prev` → 生成时自动把上一镜尾帧作为本镜尾帧/首帧
- 抽尾帧:ffmpeg 取上一镜最后一帧 → 存 `chain/{shot_id}_tail.jpg`
- 生成时:`tail_image_path=上镜尾帧`
- **效果**:长镜头分段生成无缝衔接;跨镜人物/光线不漂移
- **成本**:0(只多一个参数;抽帧是本地 ffmpeg)
### 🥉 P2 多角色同框一致性(已发现的真实问题)
现状:图生视频只喂**一张**参考图 → 双人同框时只有主角保脸,配角随机。
| 方案 | 做法 | 成本 | 我的评价 |
|---|---|---|---|
| **a. 首帧合成** | 生成前把多角色合成到一张首帧图 → 图生视频 | 一次图生图 | 效果最好,稍复杂 |
| **b. 导演层规避** | 提示词要求避免"多角色同框近景",改用正反打/过肩 | **0** | **零成本先上**,且更符合真实拍摄 |
| c. 多参考图 | 查即梦/万相是否支持多图输入 | ? | 需先验证 |
**建议**:先 b(零成本、马上见效)→ 再评估 a。
### P3 表情微管理 `expression_consistency`
- 轻量:分镜 `expression_detail`(已有)+ 跨镜一致性提示词强化
- 中量:角色资产加"表情参考图"槽位 → 图生视频时带上
### P4 口型质检辅助(用户提过的"微表情口型核对")
- 出片后自动抽关键帧 → 拼对比图 → 人工快速核对
- 进阶:接人脸检测,粗判嘴部开合与音频包络是否吻合
---
## 四、推荐执行顺序
```
P0 对账 + 体检脚本 ← 地基,零成本,先做
↓
P1 首尾帧接线 ← 能力已有,投入产出比最高
↓
P2b 多角色规避(提示词)→ P2a 首帧合成
↓
P3 表情 / P4 口型质检
```
---
## 五、待用户拍板
1. **P0 治理机制**是否认可?(登记 + 自检 + 台账三件套;可精简为"对账 + doctor")
2. **P1 首尾帧**是否本轮做?
3. **P2 多角色**:先用提示词规避够不够,还是直接上首帧合成?
---
## 附:执行时需动的文件(预告)
- `05_tools/09_ave/config/capabilities.yaml`(对账 + 补字段)
- `05_tools/09_ave/config/feasibility_rules.yaml`(缺口状态修正)
- `05_tools/09_ave/scripts/capability_doctor.py`(新建)
- `05_tools/09_ave/scripts/capability_matcher.py`(缺口台账读写)
- `05_tools/09_ave/scripts/composer/pipeline.py`(首尾帧接线)
- `05_tools/09_ave/scripts/directors/*.py`(多角色规避提示词)
- `05_tools/10_dashboard/routes/ave.py` + 前端(缺口台账展示,可选)
+55
View File
@@ -0,0 +1,55 @@
# 命令传导治理——改动清单与范围
> 日期: 2026-06-25 | 目标版本: 4.2.1
> 改动后由用户全面审计
---
## 改动范围总览
### 前端视图(4个文件)
| 文件 | 当前问题 | 改为 | 工作量 |
|:-----|:---------|:-----|:-------|
| `views/matrix-like.js` | 用旧路由 `/matrix/task/run` + 双重循环逐个发 | `POST /api/ops/run {type:'like', accounts:全部}` | 中 |
| `views/matrix-sms-proxy.js` | 用已删除的路由 `/matrix/collect-homepage` | `POST /api/ops/run {type:'collect', accounts}` | 小 |
| `views/matrix-accounts.js` | 单账号采集/登录逐个发 | 一次性提交 + 显示结果 | 中 |
| `views/matrix-comment.js` | — | 审计确认是否需要改 | 小 |
### 后端路由(1个文件)
| 路由 | 处理方式 |
|:-----|:---------|
| `routes/matrix.py:/task/run` (POST) | 删除(已改由 `/api/ops/run` 替代) |
| `routes/matrix.py:/nurture/start` (POST) | 删除(已改由 `/api/ops/run` 替代) |
| `routes/matrix.py:/collect-homepage/*` (POST) | ✅ 已删除 |
### 旧模块(modules/ 中的残留引用)
| 模块 | 引用 | 处理 |
|:-----|:------|:------|
| `modules/collect.js:92` | `/api/matrix/task/run` | 改为 `/api/ops/run` |
| `modules/recording.js:137,149` | `/matrix/collect-homepage/phone` + `/status` | 删除或改为新路由 |
| `modules/nurture.js:109,122,153,165` | `/matrix/collect-homepage` + `/status` | 删除或改为新路由 |
### CMD_REGISTRY
| 条目 | 当前 | 改为 |
|:-----|:-----|:-----|
| `nurture.runner` | 定义了但 dispatch 未使用 | dispatch 使用 runner 字段 |
| `comment` 模板 | 含 `{direction}` 可能缺失 | 去掉 direction 或设默认值 |
---
## 实施顺序
```
Step 1: 改 matrix-like.js(旧路由,最高优先级)
Step 2: 改 matrix-sms-proxy.js(旧路由已删除,会404)
Step 3: 改 matrix-accounts.js(逐个发送问题)
Step 4: 改 modules/*.js 旧引用
Step 5: 删除后端旧路由 + 清理 CMD_REGISTRY
Step 6: 构建前端 + 重启 Dashboard
Step 7: git push + 同步远程
Step 8: 提供改动清单供用户审计
```
+191
View File
@@ -0,0 +1,191 @@
# AgentOS 联邦系统 — 代码合并与清理方案 v1.0
> 目标:消除重复/歧义/新旧版本并存问题,留下一套统一清晰的代码
---
## 一、CLI 合并:`mc` + `matrix` → `mc` 统一
### 1.1 现状
| 功能 | `mc` (当前主入口) | `matrix` (旧入口) |
|:-----|:-----------------|:-----------------|
| 账号列表 | ✅ `mc account list` | ✅ `matrix account list`(读不同yaml) |
| 账号状态 | ✅ `mc account status` | ✅ `matrix account status`(不同判断方式) |
| 账号登录 | ✅ `mc account login` | ✅ `matrix account login`(代码相同) |
| **账号创建** | ❌ **没有** | ✅ `matrix account create` → `create_identity.py` |
| 账号导出 | ✅ `mc account export` | ❌ |
| 账号导入 | ✅ `mc account import` | ❌ |
| 蓝图列表 | ✅ `mc blueprint list` | ✅ `matrix config blueprint list` |
| **养号执行** | ✅ `mc run` (**BatchEngine**) | ✅ `matrix nurture run` (**nurture_multi**) |
| 定时任务 | ✅ `mc task` | ❌ |
| 语料库 | ✅ `mc corpus` | ❌ |
| 代理 | ✅ `mc proxy` (预留) | ❌ |
| SMS | ✅ `mc sms` (预留) | ❌ |
| 全局状态 | ✅ `mc status` | ✅ `matrix status` |
| **config展示** | ❌ | ✅ `matrix config show` |
### 1.2 关键问题
**问题1:`matrix account create` 是 mc 没有的**
`mc` 缺少创建身份功能。需要把 `create_identity.py` 的调用移植过来。
**问题2:`mc account list` 和 `matrix account list` 读不同的 yaml**
- `mc account list` → 读 `config/accounts.yaml`(mc配置)
- `matrix account list` → 也读 `config/accounts.yaml`(其实是同一个文件)
- 这里其实不冲突,只是 `matrix` 把所有 enabled 账号都列出来
**问题3:养号执行有两套路径**
- `mc run` → `BatchEngine` → CDPConnector → DouyinOps/XhsOps → JSON 蓝图
- `matrix nurture run` → `nurture_multi` / `nurture_xhs_loop` → `runner.py` → `nurture_blueprint.py` (Python步列表)
这两套是**完全不同的执行逻辑**!`mc run` 走 JSON 蓝图,`matrix nurture` 走 Python 步列表。
### 1.3 合并方案
**目标:只保留 `mc`,`matrix.py` 移入 `archive/`。**
| 要加的功能 | 加到 `mc` 哪里 | 代码来源 |
|:----------|:-------------|:---------|
| `mc account create <name>` | `mc/cli.py:cmd_account` → 新增 action="create" | 从 `matrix.py:cmd_account_create` 搬 |
| `mc config show` | `mc/cli.py` → 新增子命令 | 从 `matrix.py:cmd_config_show` 搬 |
**养号执行路径统一**:
- **保留 `mc run`**(走 BatchEngine + JSON 蓝图)
- **删除 `matrix nurture run`**
- `runner.py` 中的 `nurture_multi` / `nurture_xhs_loop` 保留备查,但不再通过 CLI 直接调用
---
## 二、Ops 合并:抖音 → 统一 DouyinOps
### 2.1 现状:抖音有三套操作代码
| 实现 | 文件 | 形式 | 状态 |
|:-----|:------|:------|:------|
| **A: DouyinOps 完整类** | `douyin_ops.py` (210行) | 完整类,20个操作 | ✅ **当前使用** (engine.py 调这个) |
| **B: ops/douyin/ 拆分布** | `ops/douyin/browse.py` + `interact.py` (70行) | 独立函数,5个操作 | ❌ 轻量版、不完整、未使用 |
| **C: runner.py 内联执行** | `runner.py:_execute_op()` | 内联函数,10个操作 | ❌ 旧养号路径在用 |
**ops/douyin/browse.py + interact.py = 冗余代码**。只有 5 个操作(goto_home, goto_video, scroll_feed, like, collect, comment, next_video),而且和 DouyinOps 功能完全重叠。
### 2.2 小红书情况
| 实现 | 文件 | 状态 |
|:-----|:------|:------|
| **XhsOps** | `ops/xhs_ops.py` | ✅ 当前使用 (engine.py 调这个) |
| **runner.py 内联** | `runner.py` 中 `nurture_xhs_loop` | ❌ 旧养号路径在用 |
小红书只有一套 XhsOps,没有冗余问题。
### 2.3 Ops 合并方案
| 操作 | 当前方案 |
|:-----|:---------|
| `douyin_ops.py` DouyinOps | ✅ **保留为主入口** |
| `ops/douyin/browse.py` | **归档**到 `archive/` |
| `ops/douyin/interact.py` | **归档**到 `archive/` |
| `ops/douyin/` 目录 | **删除**(已被 DouyinOps 完整覆盖) |
| `runner.py` 中的 `_execute_op()` | 保持不动(旧养号路径还在用,等迁移完再删) |
---
## 三、工具 vs 蓝图:厘清职责
### 3.1 当前散落的独立工具
| 文件 | 功能 | 应该归类 |
|:-----|:------|:---------|
| `collect_homepage_info.py` | 采集用户主页信息(昵称/粉丝/关注) | **走蓝图** (现有 `douyin_read_profile` + `xiaohongshu_read_profile`) |
| `collect_batch_runner.py` | 批量采集多个账号 | **走蓝图** + `mc run` 批量执行 |
| `publish_video.py` | 视频发布(Camoufox浏览器上传,可选调外部sau CLI) | **Camoufox模式→走蓝图**(加4个发布操作到Ops);sau模式保持独立工具 |
| `login_identity.py` | 身份登录 | **走 mc account login** |
| `create_identity.py` | 创建新身份 | **走 mc account create** |
| `guardd.py` | 系统守护进程 | **不是蓝图**,保持独立 |
### 3.2 蓝图 vs 工具的定义
| | 蓝图 (Blueprint) | 工具 (Tool) |
|:--|:----------------|:------------|
| **做什么** | 操作账号(登录/点赞/评论/采集/发布) | 维护系统(创建身份/管理代理/启动daemon) |
| **执行方式** | 被 `mc run` 调用,走浏览器 + 原子操作 | 直接 CLI 调用,不涉及浏览器 |
| **定义位置** | `blueprints/*.json` | `scripts/*.py` 或 `mc/*.py` |
| **例子** | `douyin_daily`, `douyin_comment`, `xhs_daily` | `create_identity.py`, `guardd.py`, `cdp_connector.py` |
**结论**:`collect_homepage_info.py` 的功能应该通过 `mc run --blueprint=douyin_read_profile` 来实现。它有独立的 `douyin_read_profile` 蓝图(9步)和 `xiaohongshu_read_profile` 蓝图(8步),只是原来没有通过 `mc run` 统一入口调用。应该改成:
```bash
# 原来: python collect_homepage_info.py --single phone_xxx
# 改为: mc run --accounts=douyin_test --blueprints=douyin_read_profile --rounds=1
```
---
## 四、完整合并行动清单
### Phase 1: CLI 合并(30分钟)
| # | 任务 | 改动文件 | 说明 |
|:-:|:-----|:---------|:------|
| 1 | `mc account create` | `mc/cli.py` | 新增 action="create", 调 create_identity.py |
| 2 | `mc config show` | `mc/cli.py` | 新增子命令,搬 matrix.py 的 cmd_config_show |
| 3 | `matrix.py` 移入 archive | 删除原文件 | 标记废弃 |
### Phase 2: Ops 清理(15分钟)
| # | 任务 | 说明 |
|:-:|:-----|:------|
| 1 | `ops/douyin/` 目录归档 | browse.py + interact.py 功能完全被 douyin_ops.py 覆盖 |
| 2 | 确认 engine.py 只引用 douyin_ops.py | 当前已经是这样,不改 |
### Phase 3: 工具→蓝图迁移(辅助标注)
| # | 任务 | 说明 | 操作 |
|:-:|:-----|:------|:-----|
| 1 | `collect_homepage_info.py` 迁移 | 提取函数(extract_douyin/extract_xiaohongshu)被collect_batch_runner复用 | 保留不动,新增 blueprints 内数据输出能力后自然废弃 |
| 2 | `collect_batch_runner.py` 迁移 | 有独特的分批管理/输出格式逻辑,暂不能直接取代 | 保留,待BlueprintEngine支持结构化输出后再迁移 |
| 3 | **LoginStateMachine** | ✅ 这才是真正要写的核心模块 | 立即开始写 |
> **实际优先级调整**:工具→蓝图迁移是清理任务,可延后。
> 当下最有价值的是写 `login_state_machine.py`,嵌入到现有的 BatchEngine 执行流中。
### Phase 4: 废弃代码归档
| 文件 | 处理 |
|:-----|:------|
| `matrix.py` (整个) | → `archive/` |
| `ops/douyin/browse.py` | → `archive/` |
| `ops/douyin/interact.py` | → `archive/` |
| `atom_ops.py` | → `archive/` |
| `yanghao_runner.py` | → `archive/` |
| `orchestrator.py` | → `archive/` |
| `step_by_step_v2.py` | → `archive/` |
| `step_by_step_v3.py` | → `archive/` |
| `xhs_session_test.py` | 删除(测试文件) |
| `watch_session.py` | 删除(测试文件) |
---
## 五、合并后架构
```
mc CLI (统一入口)
├── mc account list|create|login|status|export|import
├── mc run --accounts --blueprints --rounds ← 唯一执行入口
├── mc blueprint list|show
├── mc task comment
├── mc corpus list|add|select
├── mc proxy list|test|set
├── mc sms config|test
├── mc status all|accounts|browsers
└── mc config show ← 新增
执行路径 (唯一):
mc run → BatchEngine → CDPConnector → Camoufox → DouyinOps / XhsOps → JSON蓝图步
独立工具 (不通过蓝图, 直接CLI调用):
cdp_connector.py 浏览器连接管理
create_identity.py 创建身份
guardd.py 系统守护进程
vision_bridge.py oMLX视觉分析
```
@@ -0,0 +1,220 @@
# AgentOS 命令传导统一治理方案 v1.0
> 日期: 2026-06-25
> 版本: 4.2.1 规划
> 状态: 规划中 → 逐步落地中
> 主线: 消除调用链路打架,CommandBus 成为唯一执行入口
---
## 一、背景与问题
### 1.1 当前问题清单
看板经过多次改造迁移,积累了大量不一致的调用路径。扫描发现:
| # | 问题 | 涉及文件 | 严重程度 |
|:-:|:-----|:---------|:---------|
| ① | 采集有 **6 条入口路径**,5 条有问题 | `routes/matrix.py`、`services/command_bus.py`、`platforms/`、`mc/cli.py` | P0 |
| ② | CommandBus 的 cmd_type 映射散落在 dispatch() 中,不一致 | `services/command_bus.py:698-719` | P0 |
| ③ | `platforms/` 插件层引用已归档脚本 | `platforms/douyin/plugin.py`、`platforms/xiaohongshu/plugin.py` | P1 |
| ④ | 前端视图参数格式不统一(account_ids vs accounts) | `matrix-collect.js`、`matrix-accounts.js` | P1 |
| ⑤ | `routes/matrix.py` 中有路由绕过 CommandBus | `/collect-homepage/phone`、`/nurture/start` | P1 |
| ⑥ | `mc collect --all` 无参数时提示退出不执行 | `mc/cli.py:641-652` | P2 |
| ⑦ | `agents/plugins/matrix.py` 引用存档脚本 | `agentos/plugins/matrix.py:191` | P2 |
### 1.2 根因
```
看板改造迁移过程中:
旧路径(routes/matrix.py + 直接subprocess)← 未删除
新路径(routes/ops.py + CommandBus) ← 新增
platforms/ 插件层(引用存档脚本) ← 未同步更新
前端视图(分两批迁移,参数格式未统一) ← 未统一
```
---
## 二、治理目标
### 2.1 核心原则
```
┌──────────────────────────────────────────────┐
│ L5 前端视图(薄层) │
│ 统一发 {type, accounts, params} │
│ 统一走 POST /api/ops/run │
├──────────────────────────────────────────────┤
│ L4 API 路由(薄层转发) │
│ routes/ops.py 是唯一的执行入口 │
│ routes/matrix.py 中的执行类路由全部删除 │
├──────────────────────────────────────────────┤
│ L3 CommandBus(注册表驱动) │
│ CMD_REGISTRY 统一映射 cmd_type → 命令 │
│ 新增操作只需加一行注册表 │
├──────────────────────────────────────────────┤
│ L2-L0 mc 引擎 + 原子操作(唯一执行层) │
│ 所有命令最终走到同一套引擎 │
└──────────────────────────────────────────────┘
```
### 2.2 治理后
| 维度 | 治理前 | 治理后 |
|:-----|:-------|:-------|
| 采集入口 | 6 个(5 个坏) | 2 个(前端 `/api/ops/run` + CLI `mc collect`)|
| 命令映射 | 散落在 dispatch() 中硬编码 | 注册表 `CMD_REGISTRY` |
| 前端调用格式 | `account_ids` / `accounts` 混用 | 统一 `{type, accounts, params}` |
| 新增操作类型 | 改 CommandBus 代码 | 加一行注册表 |
| 平台层 | 两层(PlatformOps + Platform) | 一层(mc 引擎 + 原子操作)|
| archive 引用 | 多处 | 零 |
---
## 三、实施步骤
### Phase 0: 方案文档(当前)
- [x] 创建 `PLANS/COMMAND_UNIFICATION_PLAN.md`(本文档)
- [x] 更新 `01_core/VERSION` → 4.2.1
- [x] 更新 `CHANGELOG.md`
### Phase 1: CommandBus 加操作注册表(P0) ✅
- [x] 在 `services/command_bus.py` 新建 `CMD_REGISTRY` 注册表
- [x] 注册表包含:nurture / collect / login / logout / comment / like
- [x] collect 默认 `--blueprints` 根据账号平台自动选择
- [ ] 验证:所有入口命令格式一致(等启动 Dashboard 后验证)
**修改文件**:`services/command_bus.py` ✅
### Phase 2: 前端统一调用路径(P1) ✅
- [x] `matrix-collect.js` 改走 `POST /api/ops/run {type:'collect', accounts, params}`
- [x] 删除 `routes/matrix.py` 中:
- `/collect-homepage`
- `/collect-homepage/phone`
- `/collect-homepage/cancel`
- `/collect-homepage/status`
- [ ] 验证:信息采集页批量采集功能正常(等启动 Dashboard 后验证)
**修改文件**:`frontend/src/views/matrix-collect.js` ✅、`routes/matrix.py` ✅
### Phase 3: CLI mc collect 修复(P2) ✅
- [x] `mc/cli.py:cmd_collect()` 支持 `--all` 参数
- [x] 按手机号采集改为先查账号ID再执行(修复直接传phone的bug)
- [x] 新增 `--status` 显示采集状态
- [x] 删除废弃提示
- [ ] 验证:CLI `mc collect --all` 正常(等实际执行时验证)
**修改文件**:`mc/cli.py` ✅
### Phase 4: 标记 platforms/ 为 deprecated(P1) ✅
- [x] `platforms/douyin/plugin.py` 的 `collect()` 方法不再引用 archive 脚本
- [x] `platforms/xiaohongshu/plugin.py` 同上
- [x] 添加 deprecated 注释说明替代方案
- [ ] 注册到 99_system/INDEX.md(待定,取决于 platforms/ 是否记录在 INDEX)
**修改文件**:`platforms/*/plugin.py` ✅
### Phase 5: 更新 AUDIT_5LAYER_REPORT.md(P2) ✅
- [x] 更新信息采集的审计状态(从 `/matrix/collect-homepage` 改为 `/api/ops/run`)
- [x] 添加 CommandBus 注册表审计项
**修改文件**:`PLANS/AUDIT_5LAYER_REPORT.md` ✅
---
## 四、关键设计决策
### 4.1 CMD_REGISTRY 注册表设计
```python
CMD_REGISTRY = {
"nurture": {
"runner": "nurture_runner.sh", # shell 包装器
"defaults": {"blueprint": "douyin_daily", "rounds": 10},
"auto_blueprint": False,
},
"collect": {
"template": "mc run --accounts={ids} --blueprints={blueprint} --rounds={rounds}",
"defaults": {"rounds": 1},
"auto_blueprint": True,
"blueprint_map": {
"douyin": "douyin_read_profile",
"xiaohongshu": "xiaohongshu_read_profile",
},
},
"login": {
"template": "mc smart-login {ids}",
"single_account": True,
},
"logout": {
"template": "mc run --accounts={ids} --blueprints=douyin_daily --rounds=1",
},
"comment": {
"template": "mc task comment --account={ids} --url={url}",
"required_params": ["url"],
},
"like": {
"template": "mc run --accounts={ids} --blueprints=douyin_daily --rounds=1",
},
}
```
### 4.2 前端统一调用格式
```javascript
// ✅ 所有操作统一格式
await apiRequest('/api/ops/run', {
method: 'POST',
body: JSON.stringify({
type: 'collect', // nurture / collect / login / logout / comment / like
accounts: ['douyin_01'], // 账号ID列表
params: { // 操作参数(可选,不传则用注册表默认值)
rounds: 1,
// blueprint 由服务端根据账号平台自动推断
},
}),
});
```
### 4.3 与现有架构的关系
```
现有架构:
routes/matrix.py → 多个执行入口(需要干掉)
routes/ops.py → 统一执行入口(需要保留并做强)
CommandBus → 转发层(加注册表)
mc CLI → 直接调执行引擎
治理后:
所有执行操作 → routes/ops.py → CommandBus(注册表) → mc 引擎
routes/matrix.py 只保留读操作(GET)
CLI 直接调 mc 引擎(与 CommandBus 共享执行层)
```
---
## 五、版本更新
| 组件 | 当前版本 | 目标版本 | 变更 |
|:-----|:---------|:---------|:-----|
| AgentOS 框架 | 4.2.0 | **4.2.1** | 命令传导统一治理 |
| guardd | 2.3.0 | 2.3.0 | 无变更 |
| ORACLE schema | 1.0 | 1.0 | 无变更 |
---
## 六、验证清单
每阶段完成后验证:
- [ ] Phase 1: CommandBus 注册表生效,collect 命令带 `--blueprints`
- [ ] Phase 2: 信息采集页批量采集功能正常,`/api/matrix/collect-homepage` 路由已删除
- [ ] Phase 3: CLI `mc collect --all` 执行所有账号采集
- [ ] Phase 4: platforms/plugin 不再引用 archive 脚本
- [ ] Phase 5: 审计报告已更新
@@ -0,0 +1,295 @@
# AgentOS 前端看板调整方案
> 版本: 1.0 | 日期: 2026-07-04
> 后端改动: Phase 1 三队列 + Phase 2 语料重组 + Phase 3 智能评论
---
## 一、调整总览
| 视图 | 文件 | 行数 | 当前状态 | 需要调整 |
|:-----|:------|:-----|:---------|:---------|
| **指挥台** | `ops-command.js` | 413 | ✅ P0/P1/P2 过滤 + 初始化按钮 | 小修 |
| **定向评论** | `matrix-comment.js` | 99 | ❌ 只支持旧 comment 类型 | **大改** |
| **语料库** | `matrix-corpus.js` | 573 | ❌ 无行业/accessible 显示 | **大改** |
| **账号中心** | `accounts-center.js` | 797 | ❌ 无 smart_comment + industry 显示 | **中改** |
| **互动操作** | `matrix-interact.js` | 500 | ⚠️ 有 corpus 浏览但无行业池 | 小修 |
| **执行管道** | `execution-pipeline.js` | 300 | ❌ 未被任何视图引用 | 可废弃 |
| **命令历史** | `matrix-commands.js` | 221 | ⚠️ 需确认状态展示一致 | 小修 |
---
## 二、每项调整详述
### 2.1 指挥台(ops-command.js)— 小修
**当前已有功能** ✅
- P0/P1/P2 过滤器 ✅
- 机器下拉选择 ✅
- 初始化/重置全部按钮 ✅
- 活动任务网格 + 队列详情 ✅
**需要补充**:
| 补充项 | 原因 | 工作量 |
|:-------|:------|:-------|
| 在队列详情中区分 smart_comment 任务来源 | 当前 P0 任务只显示优先级,不区分是评论还是智能评论 | ~10行 |
| 添加视频分析状态显示(如果是 smart_comment) | VideoAnalyzer 的 `asyncio.run()` 可能执行较久,用户需要知道分析进度 | ~30行 |
| 队列详情增加 industry 过滤 | 让用户只看 health 或 general 账号的任务 | ~15行 |
---
### 2.2 定向评论(matrix-comment.js)— ❌ 需要大改
**当前问题**:
1. 只支持 `type:'comment'`,不支持 `smart_comment`
2. 没有视频分析预览 — 填了链接直接执行,用户不知道会发什么评论
3. 语料选择只有硬编码的下拉("通用/科技/生活/美食/娱乐"),不反映后端实际的行业池
4. 每个视频×每个账号发一次 `/ops/run`,效率低(N 个账号×M 个链接 = N×M 次 API 调用)
**需要改为**:
```
┌───────────────────────────────────────────────────┐
│ 💬 智能评论(新版) │
│ │
│ [账号选择器] │
│ │
│ 视频链接: [textarea 每行一个] │
│ │
│ 方向: [称赞/提问/共鸣/感慨] 语料: [自动/行业/万能] │
│ │
│ [▶️ 分析视频] [▶️ 直接执行] │
│ │
│ ── 分析结果预览 ── │
│ url1 → [health] "医生讲得很清楚..." [✏️ 修改] │
│ url2 → [general] "博主说得很对..." [✏️ 修改] │
│ url3 → [health] "这个方子很实用..." [✏️ 修改] │
│ │
│ 全部 3 个视频分析完成,预计分发 20 个账号 │
│ [✅ 确认并分发] │
└───────────────────────────────────────────────────┘
```
**具体改动**:
| 改动 | 说明 | 工作量 |
|:-----|:------|:-------|
| 新增分析按钮 + 预览区 | 先调 `smart_comment` 只分析不分发,返回预览 | ~80行 |
| 预评论可编辑 | 用户可在预览区修改每条评论后确认 | ~30行 |
| 行业标签显示 | 每个视频分析后显示 `[health]` 或 `[general]` 标签 | ~10行 |
| 语料下拉从后端动态加载 | 从 `/matrix/corpus` 接口读取实际分类列表 | ~15行 |
| 批量提交 | 分析完的一次性 `POST /ops/run` 全部账号×全部URL | ~20行 |
| **合计** | | **~155行** |
---
### 2.3 语料库(matrix-corpus.js)— ❌ 需要大改
**当前现状**:
- 573 行,三标签(1D 分类 / 2D 场景 / 3D 多轮)
- 分类显示:分类名 + 权重 + 启用状态 + 评论列表
- 添加/批量导入/删除
- **缺少**:`accessible` 行业标签显示和管理
**需要改为**:
```
┌───────────────────────────────────────────────────┐
│ 📚 语料库 │
│ 8 个分类 · 2 个行业池 · 156 条评论 │
│ │
│ ┌─ 行业过滤 ──────────────────────────────────────────┐
│ │ [全部] [万能池] [大健康池] [科技池] [美食池] │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌─ 大健康称赞 ──── accessible: [health] ───────────┐ │
│ │ weight: 30 | enabled: true │ │
│ │ "医生讲得很清楚,通俗易懂" [编辑] [删除] │ │
│ │ "这个方子很实用,收藏了" [编辑] [删除] │ │
│ │ [+ 添加评论] │ │
│ └────────────────────────────────────────────────────┘ │
```
**具体改动**:
| 改动 | 说明 | 工作量 |
|:-----|:------|:-------|
| 行业池过滤标签 | 在分类列表上方加 accessible 过滤按钮 | ~20行 |
| accessible 标记显示 | 每个分类显示 `accessible: ["health"]` 或 `accessible: ["*"]` | ~15行 |
| 行业池管理入口 | 添加/编辑分类时可选"允许哪些行业访问" | ~30行 |
| 行业池 vs 万能池分离显示 | 万能池标签(称赞/提问/共鸣)显示在独立区域 | ~20行 |
| 删除功能修复 | 当前删除按钮可能不工作(查下 delete 端点) | ~10行 |
| **合计** | | **~95行** |
---
### 2.4 账号中心(accounts-center.js)— 中改
**当前现状**:
- 797 行,账号列表 + 批量操作 + 状态汇总
- 批量操作:采集/登录/评论/养号
- 评论按钮跳转到 `matrix-comment.js`
- **缺少**:industry 字段显示、smart_comment 批量操作
**需要改为**:
| 改动 | 说明 | 工作量 |
|:-----|:------|:-------|
| 账号列表增加 industry 列 | 显示 health/general 标签 | ~15行 |
| 按 industry 过滤 | 下拉选择 health/general/全部 | ~15行 |
| 批量操作新增"智能评论" | 弹出链接输入+方向+分析预览对话框 | ~60行 |
| **合计** | | **~90行** |
---
### 2.5 互动操作(matrix-interact.js)— 小修
**当前现状**:
- 500 行,有三个 tab(评论/点赞/关注)
- 评论 tab 有 corpus 浏览器 + 关键词匹配
- 评论模式下拉:`comment` / `search_browse` / `reply`
- **缺少**:smart_comment 模式
| 改动 | 说明 | 工作量 |
|:-----|:------|:-------|
| smart_comment 模式选择 | 在模式下拉加"智能评论"选项 | ~10行 |
| 方向选择与行业匹配 | 如果选了行业池,自动过滤可选方向 | ~15行 |
| **合计** | | **~25行** |
---
### 2.6 执行管道组件(execution-pipeline.js)— ❌ 废弃
**当前现状**:
- 300 行,但 **不被任何视图引用**
- 搜索 `execution-pipeline.js` 的引用:0 个视图 import
- 有 double `/api` 前缀 bug(line 20 `const API = '/api'`,line 146 `api('/api/ops/...')` → `/api/api/ops/...`)
| 处理 | 说明 |
|:-----|:------|
| 标记为废弃 | 不移除文件,但在顶部加注释说明 |
| 保留未来用 | 如有重构计划可复用,但当前不需要修 |
---
### 2.7 命令历史(matrix-commands.js)— 小修
**当前现状**:
- 221 行,显示历史命令列表
- 调 `/ops/status` 获取
| 改动 | 说明 | 工作量 |
|:-----|:------|:-------|
| 显示 priority 列 | 区分 P0/P1/P2 任务 | ~10行 |
| 显示 industry 列 | 如果任务包含 industry 信息 | ~5行 |
| **合计** | | **~15行** |
---
## 三、修改优先级
| 优先级 | 视图 | 工作量 | 原因 |
|:-------|:------|:-------|:-----|
| **P0** | `matrix-comment.js` | ~155行 | **核心功能**: 智能评论的前端入口,用户直接交互 |
| **P1** | `matrix-corpus.js` | ~95行 | **体验提升**: 行业池管理,让用户能自定义语料 |
| **P1** | `accounts-center.js` | ~90行 | **效率提升**: 批量智能评论入口 |
| **P2** | `matrix-interact.js` | ~25行 | 补充优化 |
| **P2** | `ops-command.js` | ~55行 | 已有基础功能,补细节 |
| **P2** | `matrix-commands.js` | ~15行 | 显示优化 |
| - | `execution-pipeline.js` | 0 | 废弃不修 |
**总计工作量**: ~435 行改动。
---
## 四、smart_comment 前端交互流程
```
用户进入「定向评论」页面
│
├─ 选择账号(账户选择器)
├─ 填写视频链接(textarea,每行一个)
├─ 选择方向(称赞/提问/共鸣)
└─ 选择语料(自动/行业匹配/指定分类)
│
▼
点击「分析视频」
│
▼
前端调 POST /api/ops/run {type:"smart_comment", accounts: [只取1个], params:{urls, direction, preview:true}}
↓ 后端 VideoAnalyzer 分析
↓ 返回 {url: {title, industry, comment}}
│
▼
前端显示分析结果预览
┌─────────────────────────────────────────┐
│ url1 → [health] "医生讲得很清楚..." [✏️]│
│ url2 → [general] "博主说得很对..." [✏️]│
└─────────────────────────────────────────┘
用户可逐条修改预评论
│
▼
点击「确认并分发」
│
▼
调 POST /api/ops/run {type:"smart_comment", accounts:[全部], params:{urls, direction, comments:{url:预评论}}}
↓
后端直接拆解 → 打包 → API 分发到各机 guardd
│
▼
前端切换到指挥台,显示各机队列状态
```
---
## 五、预审/修改流程的关键设计
**关键设计点:用户在分发前可以看到并修改每条预评论**
```javascript
// 分析结果数据结构(前端存储)
let previewData = {
urls: {
"https://v.douyin.com/xxx": {
title: "胃镜到底疼不疼",
industry: "health",
comment: "医生讲得很清楚,通俗易懂" // 用户可编辑
},
"https://v.douyin.com/yyy": {
title: "苏州美食探店",
industry: "general",
comment: "博主说得很对" // 用户可编辑
}
}
};
// 用户编辑预评论后,确认分发
async function confirmDistribute() {
// 收集所有预评论(含用户修改后的)
const comments = {};
for (const [url, data] of Object.entries(previewData.urls)) {
comments[url] = data.comment;
}
// 一次性分发
await apiRequest('/ops/run', {
method: 'POST',
body: JSON.stringify({
type: 'smart_comment',
accounts: selectedAccounts,
params: { urls: Object.keys(comments), comments, direction }
})
});
}
```
---
## 六、调整汇总工作量
| 视图 | 当前行数 | 新增行数 | 总行数 |
|:-----|:---------|:---------|:-------|
| `matrix-comment.js` | 99 | +155 | 254 |
| `matrix-corpus.js` | 573 | +95 | 668 |
| `accounts-center.js` | 797 | +90 | 887 |
| `ops-command.js` | 413 | +55 | 468 |
| `matrix-interact.js` | 500 | +25 | 525 |
| `matrix-commands.js` | 221 | +15 | 236 |
| **Total** | **2603** | **+435** | **~3038** |
@@ -0,0 +1,54 @@
# 实施进度跟踪
> 最后更新: 2026-07-16 17:30
## ✅ Phase 1 — guardd 调度引擎
| 任务 | 提交 |
|:-----|:------|
| 1a guardd modules/ 目录拆分 | 015b0579 |
| 1b TaskStore + PriorityQueue | 015b0579 |
| 1c 孤儿浏览器清理 | 015b0579 |
| 1d BrowserSlotManager + 心跳增强 | f36b39cd |
| 1e 调度主循环 + Executor + guardd集成 | f36b39cd |
## ✅ Phase 2 — 联邦指挥台
| 任务 | 提交 |
|:-----|:------|
| 2a CommandBus 读写分离 + 任务拆解 | daaf19a2 |
| 2b API路由 + 指挥台前端 | 44d561d |
| 2c 跨机依赖事件推送 | fffeef6c |
## ✅ Phase 3 — 高级功能
| 任务 | 提交 |
|:-----|:------|
| 3a 指挥台操作(停止/排序按钮)| 7c0f00a |
| 3b ORACLE 定时任务同步 | 015b0579 |
| 3c 三级接力蓝图 | fffeef6c |
| 3d 告警中心 | fffeef6c |
| 3e 超时熔断 | fffeef6c |
| 账号健康度面板 | 本次 |
| 远程机器 launchd 自启 | 本次 |
| 拖拽排序按钮 | 本次 |
## ✅ Phase 4 — 抖追踪 + CDP 采集引擎 (2026-07-15/16)
| 任务 | 提交 |
|:-----|:------|
| 4a mediacrawler_adapter — CDP 采集引擎 | 90b3042c |
| 4b 抖追踪前端 UI(导入/采集/跟踪/全选) | 90b3042c |
| 4c 跟踪专项页 + 评论展开 + 刷新全部 | 38d3ba2f |
| 4d 复制链接(单条/已选/全部) | 38d3ba2f |
| 4e Chrome debug launchd 自启 | 90b3042c |
| 4f KeepAlive true,崩溃自动重启 | e7bb8767 |
| 4g 评论工作台粘贴解析「标题+链接」配对 | 7c372bec |
| 4h 双行排版标题+网址 | 1b26d235 |
| 4i 浏览器标题跟随路由切换 | 7e4a789a |
## 待做(低优先级)
- 拖拽排序后端API(目前只有前端按钮)
- 三级接力端到端人机验证
- 指挥台UI美化
@@ -0,0 +1,67 @@
# Dashboard 集成审计报告
> 日期: 2026-06-27 | 基于当前代码状态
## 执行路径总览
```
前端视图 → POST /api/ops/run {type, accounts, params}
→ CommandBus.dispatch()
→ 按机器分组
→ _send_local() / _send_remote()
→ guardd /scheduler/submit (新路径 ✅)
→ guardd /task (旧路径降级)
→ subprocess / SSH (最终降级)
```
## 各视图集成状态
### ✅ 已走新路径(CommandBus → guardd 调度引擎)
| 视图 | 操作类型 | 提交方式 |
|:-----|:---------|:---------|
| `matrix-accounts.js` | collect, login | `fetch('/api/ops/run')` → 新路径 |
| `matrix-collect.js` | collect | `apiRequest('/api/ops/run')` → 新路径 |
| `matrix-nurture.js` | nurture | `apiRequest('/api/ops/run')` → 新路径 |
| `matrix-comment.js` | comment | `apiRequest('/api/ops/run')` → 新路径 |
| `matrix-interact.js` | interact | `apiRequest('/api/ops/run')` → 新路径 |
| `matrix-like.js` | like | `apiRequest('/api/ops/run')` → 新路径 |
| `ops-command.js` | 联邦指挥台 | 读 `/api/ops/queue` + `/api/ops/machines` |
### 🔶 需要注意的点
| 问题 | 说明 |
|:-----|:------|
| **账号管理页采集不显示在指挥台** | 已修复: `_send_local()` 优先走 scheduler,旧路径降级 |
| **指挥台只读不写** | 目前指挥台只能"看"不能"操作"(Phase 3a 实现) |
| **旧 `/task` 路径仍保留** | 作为降级方案,guardd 不可用时自动 fallback |
| **nurture_runner.sh 未集成到调度器** | 养号任务仍走旧 nurture_runner.sh 路径(通过 /task 降级) |
### ⏳ 待实现(Phase 3)
| 功能 | 优先级 |
|:-----|:-------|
| 指挥台操作按钮(取消/暂停/重排) | P0 |
| 告警中心(封号/登录失败高亮) | P1 |
| 三级接力 | P2 |
| 任务超时熔断自动恢复 | P1 |
## 当前数据流
```
用户点击"采集"
↓
matrix-accounts.js → POST /api/ops/run
↓
CommandBus.dispatch("collect", [account_id], params)
↓
_send_local() → guardd /scheduler/submit
↓
guardd scheduler → 15s循环 → executor.execute()
↓
指挥台每15秒 poll /api/ops/queue → 看到任务
```
## 测试方法
在账号管理页点"采集" → 等15秒 → 刷新指挥台 → 应该能看到任务出现在队列中
@@ -0,0 +1,551 @@
# 评论互动系统 — 详细规划
> 版本: v1.0-draft | 日期: 2026-06-25
> 范围: 定向评论 + 收藏点赞 → 合并为"评论互动"全功能
> 基于: AgentOS 联邦多机协同 + CommandBus 分发 + 现有蓝图引擎
---
## 一、功能全景
### 1.1 核心能力
| 能力 | 说明 |
|:-----|:------|
| **定向评论** | 给指定视频/博主评论,多个账号参与 |
| **三级接力评论** | A评→B回复A→C回复B,形成互动链 |
| **点赞互动** | 点赞视频/评论/关注评论者 |
| **定时错开** | 跨小时/跨天的评论时间编排 |
| **跨机协同** | 三台机器之间任务分配与排队 |
| **语料集成** | 现有语料库(L1-L4)复用 + 上下文感知 |
| **评论载体** | 文字 + emoji + 图片(预留) |
### 1.2 用户场景
```
用户输入:
博主/视频链接: https://www.douyin.com/video/xxx
或博主主页: https://www.douyin.com/user/xxx
互动策略: 热评互动 / 三级接力 / 点赞关注
时间窗口: 2小时 / 跨天
参与账号: douyin_136, xhs_7 (自动分配给7kecheng)
douyin_01, xhs_01 (自动分配给5kechengdeAir)
系统输出:
自动编排 → 按机器+时间分配任务
→ 机器1 13:00 douyin_136 发评论A
→ 机器2 13:05 douyin_01 回复A
→ 机器1 13:10 xhs_7 回复B
→ 全部完成后汇总报告
```
---
## 二、架构设计
### 2.1 系统分层
```
L5 看板层 ── 评论互动视图 (matrix-interact.js)
│ POST /api/ops/run {type:'interact', accounts, params:{...}}
L4 路由层 ── routes/ops.py (已存在,复用)
│ → CommandBus.dispatch('interact', ...)
L3 分发层 ── CommandBus + CMD_REGISTRY (已存在,扩展)
│ → 按机器分组 → 每机一条 interact 命令
│ → 高级编排: InteractOrchestrator
L2 编排层 ── InteractOrchestrator (新增)
│ ├── 解析互动策略
│ ├── 生成时间线 (谁在什么时间做什么)
│ ├── 拆解为原子任务 (每个账号每个时间点一条)
│ └── 写入跨机任务队列
L1 执行层 ── 现有 mc run + 蓝图引擎 (复用)
│ 新增互动蓝图: interact_chain, interact_like, interact_comment
│ 复用现有: douyin_ops.py, xhs_ops.py (post_comment, like, follow)
L0 浏览器层 ── Camoufox (已有,不变)
```
### 2.2 新增模块
```
05_tools/07_matrix/
├── scripts/
│ ├── mc/
│ │ ├── cli.py ← 新增: interact 子命令
│ │ ├── interact.py ← [新增] 互动引擎 (InteractOrchestrator)
│ │ │ ├── InteractOrchestrator — 主编排器
│ │ │ ├── InteractionPlan — 互动计划
│ │ │ ├── TimeLine — 时间线
│ │ │ └── ChainStrategy — 接力策略
│ │ └── engine.py ← 扩展: 支持互动蓝图的 resolve_args
│ ├── matrix_modules/
│ │ └── interact/ ← [新增] 互动模块
│ │ ├── __init__.py
│ │ ├── chain.py — 三级接力逻辑
│ │ ├── timeline.py — 时间线生成
│ │ └── strategy.py — 互动策略选择
├── blueprints/
│ ├── interact_chain.json ← [新增] 三级接力蓝图
│ ├── interact_comment.json ← [新增] 定向评论蓝图
│ ├── interact_like.json ← [新增] 点赞互动蓝图
│ └── interact_hot.json ← [新增] 热评互动蓝图
```
---
## 三、蓝图设计
### 3.1 定向评论蓝图 (interact_comment)
```json
{
"id": "interact_comment",
"name": "互动-定向评论",
"description": "给指定视频发评论(含语料库+表情)",
"version": "1.0",
"platform": "douyin",
"steps": [
{"step_id": 1, "op": "goto_url", "args": {"url": "@url"}},
{"step_id": 2, "op": "wait_watch", "args": {"seconds": null}},
{"step_id": 3, "op": "open_comments", "args": {}},
{"step_id": 4, "op": "post_comment", "args": {"text": "@comment_text"}},
{"step_id": 5, "op": "close_comments", "args": {}}
],
"args_schema": {
"url": {"type": "string", "required": true, "desc": "视频链接"},
"comment_text": {"type": "string", "required": true, "desc": "评论内容,支持@corpus从语料库取"}
}
}
```
### 3.2 三级接力蓝图 (interact_chain)
```json
{
"id": "interact_chain",
"name": "互动-三级接力",
"description": "A评→B回复A→C回复B,形成互动链",
"version": "1.0",
"platform": "douyin",
"steps": [
{"step_id": 1, "op": "goto_url", "args": {"url": "@url"}},
{"step_id": 2, "op": "wait_watch", "args": {"seconds": null}},
{"step_id": 3, "op": "open_comments", "args": {}},
{"step_id": 4, "op": "post_comment", "args": {"text": "@comment_text"}},
{"step_id": 5, "op": "close_comments", "args": {}},
{"step_id": 6, "op": "reply_to_comment", "args": {"target": "@reply_to", "text": "@reply_text"}}
],
"args_schema": {
"url": {"required": true},
"comment_text": {"desc": "一级评论内容"},
"reply_to": {"desc": "回复目标的评论ID或用户名"},
"reply_text": {"desc": "回复内容"},
"chain_position": {"enum": ["first", "reply", "second_reply"]}
}
}
```
蓝图不分三级为三个独立的蓝图。**用同一个蓝图 + 不同参数**,InteractOrchestrator 根据 `chain_position` 决定每个账号执行哪一步。
### 3.3 点赞互动蓝图 (interact_like)
```json
{
"id": "interact_like",
"name": "互动-点赞互动",
"description": "点赞视频+点赞评论+关注评论者",
"version": "1.0",
"platform": "douyin",
"steps": [
{"step_id": 1, "op": "goto_url", "args": {"url": "@url"}},
{"step_id": 2, "op": "wait_watch", "args": {"seconds": null}},
{"step_id": 3, "op": "like", "args": {}},
{"step_id": 4, "op": "open_comments", "args": {}},
{"step_id": 5, "op": "like_comment", "args": {"target": "@target_comment"}},
{"step_id": 6, "op": "follow_user", "args": {"target": "@target_user"}},
{"step_id": 7, "op": "close_comments", "args": {}}
]
}
```
### 3.4 热评互动蓝图 (interact_hot)
组合评论 + 点赞 + 回复热评:
```json
{
"id": "interact_hot",
"name": "互动-热评互动",
"description": "在热门评论下回复,提升曝光",
"version": "1.0",
"platform": "douyin",
"steps": [
{"step_id": 1, "op": "goto_url", "args": {"url": "@url"}},
{"step_id": 2, "op": "open_comments", "args": {}},
{"step_id": 3, "op": "scroll_to_hot_comment", "args": {}},
{"step_id": 4, "op": "like_comment", "args": {"target": "first_hot"}},
{"step_id": 5, "op": "reply_to_comment", "args": {"text": "@reply_text"}},
{"step_id": 6, "op": "close_comments", "args": {}}
]
}
```
---
## 四、任务编排引擎 (InteractOrchestrator)
### 4.1 核心流程
```
用户输入:
{url, strategy, accounts, time_window}
InteractOrchestrator.plan()
│
├── 1. 解析互动策略
│ strategy="chain" → 生成三级接力计划
│ strategy="comment" → 生成批量评论计划
│ strategy="like" → 生成点赞互动计划
│ strategy="hot" → 生成热评互动计划
│
├── 2. 生成时间线
│ 根据 time_window + interval 计算每个账号的执行时间
│ 例: 3账号 × 三级接力
│ 账号A 13:00 发评论 → 间隔5分钟
│ 账号B 13:05 回复A → 间隔5分钟
│ 账号C 13:10 回复B → 完成
│
├── 3. 拆解为原子任务
│ 每个 (账号, 时间, 蓝图, 参数) = 一条原子任务
│ 每台机器独占一条(机器级别串行,账号级别串行)
│
├── 4. 写入任务队列
│ 通过 CommandBus 分发到各台机器
│ → 不立即执行,先写入任务数据库(带时间戳)
│ → guardd 或守护线程按时触发
│
└── 5. 返回计划
{plan: [...], status: "scheduled"}
```
### 4.2 时间线生成算法
```
输入: accounts=[A, B, C], strategy="chain", window={start: "13:00", end: "15:00"}
chain 策略:
A 在 13:00 → 发评论 (first)
B 在 13:00 + offset1 → 回复A (reply, reply_to=A)
C 在 13:00 + offset1 + offset2 → 回复B (second_reply, reply_to=B)
其中 offset = random(300, 600) 秒 (5-10分钟)
支持跨小时: offset 累加可以到 next hour
batch 策略:
A 在 13:00 → 评论 (内容1)
B 在 13:00 + random(300,900) → 评论 (内容2)
C 在 13:00 + random(600,1800) → 评论 (内容3)
like 策略:
A 在 13:00 → 点赞视频+关注博主
B 在 13:00 + random(120,600) → 点赞视频+点赞热评
```
### 4.3 跨机任务排队
```
CommandBus.dispatch("interact", all_accounts, params)
→ 按 machine 分组
→ 每台机器构建一条 InteractOrchestrator 任务
每台机器上:
MachineSession 串行队列
[interact_任务A] → 执行A → 完成后
[等待中到13:05] → 定时器触发
[interact_任务B] → 执行B → 完成后
...
```
**关键**:定时触发不是由 CommandBus 的 poll 守卫做,而是由 **InteractOrchestrator 在机器本地启动一个延迟协程**。
执行流程:
```python
class InteractOrchestrator:
async def execute_plan(self, plan: InteractionPlan):
"""按时间线顺序执行所有子任务"""
for step in plan.timeline:
# 等待到指定时间
wait_seconds = (step.scheduled_at - datetime.now()).total_seconds()
if wait_seconds > 0:
await asyncio.sleep(wait_seconds)
# 执行当前步骤
result = await self._execute_step(step)
step.result = result
```
---
## 五、看板集成 (Dashboard)
### 5.1 新视图: 评论互动 (matrix-interact.js)
参照现在 `matrix-collect.js` 和 `matrix-nurture.js` 的模式:
```javascript
// 使用已有 account-selector 组件
// ① 选择账号
// ② 输入互动参数(URL/博主/策略/时间)
// ③ 提交 → POST /api/ops/run {type:'interact', accounts, params}
```
**交互流程**:
```
┌─────────────────────────────────────────────┐
│ 💬 评论互动 │
│ │
│ 账号选择器 (复用 createAccountSelector) │
│ ┌─────────────────────────────────────────┐ │
│ │ ☑ douyin_136 🎵 7kecheng │ │
│ │ ☑ xhs_7 📕 7kecheng │ │
│ │ ☑ douyin_01 🎵 5kechengdeAir │ │
│ │ ... │ │
│ └─────────────────────────────────────────┘ │
│ │
│ 互动参数: │
│ 视频链接 [________________________] 📋 │
│ 互动策略 [热评互动 ▼] [三级接力] [点赞] │
│ 时间窗口 [13:00] ~ [15:00] │
│ 延迟间隔 [5-10] 分钟 / 步 │
│ 语料分类 [美食 ▼] [旅行] [通用] │
│ │
│ [🔍 预检] [🚀 提交互动] │
│ │
│ 执行计划预览: │
│ ┌─────────────────────────────────────────┐ │
│ │ 13:00 douyin_136 → 发评论 "看着就很有.." │ │
│ │ 13:05 xhs_7 → 回复 ↑ "同意!.." │ │
│ │ 13:12 douyin_01 → 回复 xhs_7 "... " │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```
### 5.2 API 路由
复用现有 `POST /api/ops/run`,新增 type `interact`:
```json
POST /api/ops/run
{
"type": "interact",
"accounts": ["douyin_136", "xhs_7", "douyin_01"],
"params": {
"strategy": "chain",
"url": "https://www.douyin.com/video/xxx",
"time_window": {"start": "13:00", "end": "15:00"},
"interval": {"min": 300, "max": 600},
"corpus_category": "food",
"chain_position": {
"douyin_136": "first",
"xhs_7": "reply",
"douyin_01": "second_reply"
},
"dry_run": true // 预检模式:只返回计划不执行
}
}
```
### 5.3 CMD_REGISTRY 扩展
```python
CMD_REGISTRY = {
...,
"interact": {
"runner": None, # 不走 nurture_runner.sh,直接调 InteractOrchestrator
"defaults": {"rounds": 1},
"single_account": False,
},
}
```
---
## 六、现有代码复用清单
### 6.1 可直接复用的
| 组件 | 用途 |
|:-----|:------|
| `account-selector.js` | 账号选择器(不改) |
| `routes/ops.py` | API 路由(扩展 type=interact) |
| `CommandBus` | 按机器分发、排队(复用) |
| `MachineSession` | 串行队列(复用) |
| `douyin_ops.post_comment(text)` | 评论发送(复用) |
| `douyin_ops.like()` | 点赞(复用) |
| `douyin_ops.follow()` | 关注(复用) |
| `xhs_ops.xhs_comment(text)` | 小红书评论(复用) |
| `corpus.py` | 语料库(复用) |
| `ai_generator.py` | AI 评论生成(复用) |
| `nurture_runner.sh` | 执行包装器(可选复用,interact 可能直接走 mc run) |
### 6.2 需要新增/扩展的
| 组件 | 说明 |
|:-----|:------|
| `mc/interact.py` | InteractOrchestrator 编排引擎 |
| `mc/cli.py` | 新增 `mc interact` 子命令 |
| `blueprints/interact_*.json` | 互动蓝图 |
| `matrix_modules/interact/` | 互动模块(chain、timeline、strategy)|
| `douyin_ops.reply_to_comment()` | 回复评论原子操作 **(新增)** |
| `douyin_ops.like_comment()` | 点赞评论原子操作 **(新增)** |
| `douyin_ops.scroll_to_hot_comment()` | 滚动到热评(新增) |
| `frontend/src/views/matrix-interact.js` | 看板视图 |
### 6.3 新增原子操作
```python
# douyin_ops.py
async def reply_to_comment(self, page, target: str, text: str) -> bool:
"""回复指定评论。target 可以是评论序号或评论者用户名"""
# 1. 找到目标评论的回复按钮
# 2. 点击"回复"
# 3. 输入框聚焦
# 4. 填入回复内容
# 5. 发送
pass
async def like_comment(self, page, target: str = "first_hot") -> bool:
"""点赞评论。target=first_hot / 指定序号"""
# 1. 找到目标评论
# 2. 找到点赞按钮(大拇指/心形)
# 3. 点击
pass
async def follow_user(self, page, target: str) -> bool:
"""关注指定用户(从评论区)"""
pass
```
---
## 七、语料库增强(三级互动语料)
现有语料库是单条评论。三级互动需要**配对语料**:
```python
# 新增: interact_corpus.py 或扩展 corpus.py
# 三级互动语料对
CHAIN_CORPUS = {
"food": {
"first": "看着就很有食欲,周末去试试",
"reply": "同意!上次吃过一次确实不错",
"second_reply": "我也去过!他家那个招牌菜绝了"
},
"tech": {
"first": "这个技术分析很透彻,学到了",
"reply": "对,特别是第三点我之前完全没想到",
"second_reply": "是的,按照这个方法试了效果很好"
},
"travel": {
"first": "这个地方太美了,已加入旅行清单",
"reply": "去年去过,风景确实很好,值得二刷",
"second_reply": "求攻略!准备下个月去"
},
...
}
```
每套三级语料包含三个层次的评论,形成一个自然的对话流。
---
## 八、实施路线图
### Phase 1(基础能力)— 2天
| 任务 | 产出 |
|:-----|:------|
| 新增 `douyin_ops.reply_to_comment()` | 原子操作 |
| 新增 `douyin_ops.like_comment()` | 原子操作 |
| 编写 3 个互动蓝图 JSON | blueprints |
| 扩展 `corpus.py` 增加三级接力语料 | 语料库 |
| 构建 `matrix-interact.js` 基础视图 | 看板 |
| 扩展 CMD_REGISTRY 增加 interact 类型 | 后端 |
### Phase 2(编排引擎)— 2天
| 任务 | 产出 |
|:-----|:------|
| 实现 `InteractOrchestrator` 核心 | mc/interact.py |
| 时间线生成算法 | timeline.py |
| 跨机任务队列 | interact 走 CommandBus |
| 预检功能 (dry_run) | 返回计划预览 |
### Phase 3(高级功能)— 2天
| 任务 | 产出 |
|:-----|:------|
| 三级接力全流程联调 | chain 端到端 |
| 跨小时定时触发 | asyncio sleep / guardd定时 |
| 看板计划预览 | 前端展示时间线 |
| 执行进度跟踪 | status API |
### Phase 4(增强)— 持续
| 任务 | 产出 |
|:-----|:------|
| 图片/表情包评论 | 蓝图扩展 |
| AI 生成评论(oMLX) | 对接现有 ai_generator |
| 互动效果分析 | 看板统计 |
| 自动策略推荐 | 基于账号健康度 |
---
## 九、关键设计决策
| 决策 | 选择 | 理由 |
|:-----|:------|:------|
| 蓝图复用 vs 新建 | 新建互动蓝图系列 | 避免污染现有养号蓝图 |
| 定时触发方式 | InteractOrchestrator 内部 sleep | 简单可靠,不依赖外部调度 |
| 三级接力实现 | 同一个蓝图+chain_position 参数 | 减少蓝图数量,参数化驱动 |
| 跨机协同 | 复用 CommandBus 队列 | 已有成熟的分发/排队机制 |
| 看板视图 | 新建 matrix-interact.js | 功能独立,不与现有视图耦合 |
| CMD_REGISTRY 扩展 | 新增 type=interact | 统一入口,不走硬编码分支 |
---
## 十、与现有系统的关系
```
现有系统 新增系统
──────── ────────
养号 (nurture) 评论互动 (interact)
├── 日常浏览 ├── 定向评论
├── 随机点赞/评论 ├── 三级接力
├── asyncio.gather ├── 时间线编排
└── 蓝图 douyin_daily └── 互动蓝图系列
采集 (collect) 点赞 (like) → 并入 interact
├── 读主页信息
└── 写 profiles.json
登录 (login) 评论 (comment) → 并入 interact
├── smart-login
└── 状态检测
```
**合并策略**:`like` 和 `comment` 类型的 `CMD_REGISTRY` 保留向后兼容,但前端视图统一到 `matrix-interact.js`,不再使用独立的 `matrix-comment.js` 和 `matrix-like.js`。
---
## 十一、风险与对策
| 风险 | 概率 | 影响 | 对策 |
|:-----|:----:|:----:|:------|
| 回复评论 DOM 结构变化 | 高 | 中 | CSS 选择器 + JS 多兜底 |
| 跨小时 sleep 被中断 | 中 | 高 | 使用 guardd 持久化定时器 |
| 同一时间多账号冲突 | 中 | 中 | MachineSession 队列保证单线程 |
| 抖音限流/封号 | 低 | 高 | 不超过每天10条/账号 |
| 三级接力找不到目标评论 | 中 | 中 | fallback 到独立评论 |
@@ -0,0 +1,221 @@
# AgentOS 命令传导与采集系统——全面优化规划 v2.0
> 日期: 2026-06-25 | 版本: 4.2.1
> 基于: CONSTITUTION.md、FEDERATION_GUIDE.md、AUDIT_5LAYER_REPORT.md、COMMAND_UNIFICATION_PLAN.md
> 覆盖: 命令传导全链路 + 信息采集全链路 + 远程执行 + 数据持久化 + 封号检测
---
## 一、当前架构全景
```
L5 前端视图 (12个操作视图)
│ 统一格式: {type, accounts, params}
│ 统一入口: POST /api/ops/run
▼
L4 API 路由
├── routes/ops.py ← ✅ 统一执行入口(已治理)
└── routes/matrix.py ← ✅ 只保留 GET 读操作(已治理)
▼
L3 CommandBus
├── CMD_REGISTRY ← ✅ 注册表(已治理)
├── dispatch() ← ✅ 注册表驱动(已治理)
├── MachineSession ← ✅ 每机队列(已治理)
├── CMD_POLL_STRATEGY ← ✅ 按类型策略(已治理)
└── poll守卫线程 ← ✅ 15s自动检测(已治理)
▼
L2 mc 引擎
├── nurture_runner.sh ← ⚠️ 远程参数默认值已修
├── BatchEngine ← ✅ 支持封号标记
└── LoginStateMachine ← ✅ 支持banned状态
▼
L1 平台原子操作
├── douyin_ops.py ← ✅ 封号检测+同步写homepage_info
└── ops/xhs_ops.py ← ✅ 封号检测+同步写homepage_info
▼
L0 Camoufox 浏览器
```
---
## 二、剩余问题清单(按优先级)
### P0 —— 必须修(功能阻断)
| # | 问题 | 发现时间 | 涉及文件 |
|:-:|:-----|:---------|:---------|
| ① | **远程 nurture 空值参数导致参数错位** | 2026-06-25 | `command_bus.py:_send_remote` ✅ **已修复** |
| ② | **前端批量账号逐个发送**(matrix-nurture) | 2026-06-25 | `matrix-nurture.js` ✅ **已修复** |
| — | 以上两个问题已修复并推送 | — | — |
### P1 —— 应修(影响体验/一致性和正确性)
| # | 问题 | 涉及文件 | 说明 |
|:-:|:-----|:---------|:------|
| ③ | **`routes/matrix.py` 中 `/nurture/start` 和 `/nurture/preview` 绕过 CommandBus** | `routes/matrix.py:333-443` | 约100行 POST 代码直接调引擎,不走 CommandBus |
| ④ | **`routes/matrix.py` 中 `/task/run` 路由绕过 CommandBus** | `routes/matrix.py:757-790` | 任务执行直接 subprocess |
| ⑤ | **`matrix-accounts.js` 单账号采集(`_actCol`)+登录(`_actLogin`)逐个发送** | `matrix-accounts.js:121-145` | 和修复前的 `_nurtureExec` 一样的问题 |
| ⑥ | **`matrix-comment.js` 评论执行逐个发送** | `matrix-comment.js` | 需要审计 |
| ⑦ | **`matrix-like.js` 收藏点赞逐个发送** | `matrix-like.js` | 需要审计 |
| ⑧ | **CMD_REGISTRY 中 comment 的模板含 `{direction}`,可能缺失** | `command_bus.py:631` | 前端可能不传 direction |
| ⑨ | **nurture 在 CMD_REGISTRY 中定义了 `runner` 字段但 dispatch 未使用** | `command_bus.py:640` | 注册表与实际逻辑不一致 |
### P2 —— 可修(清理/优化/后续)
| # | 问题 | 涉及文件 | 说明 |
|:-:|:-----|:---------|:------|
| ⑩ | **`platforms/` 目录已标记 deprecated 但代码还存在** | `platforms/` | 等待最终清理 |
| ⑪ | **`agentos/plugins/matrix.py` 引用存档脚本** | `agentos/plugins/matrix.py:189-192` | 依然引用 `collect_batch_runner.py` |
| ⑫ | **`scripts/archive/` 中的旧脚本可移出** | `scripts/archive/` | 确认无引用后移除 |
| ⑬ | **`routes/matrix.py` 中 `/nurture/preview`(GET读操作)可保留但需要文档说明** | `routes/matrix.py:333` | 仅预览功能 |
| ⑭ | **联邦机器 `fleet_collector` 缓存过期后 Dashboard 读到旧数据** | `services/fleet_collector.py` | 需要自动刷新机制 |
| ⑮ | **Dashboard 信息采集页展示多渠道数据聚合时的去重** | `routes/matrix.py` | 多台机器有同一个账号时重复显示 |
| ⑯ | **`crawl-tasks.js`、`crawl-sources.js` 等占位符视图无功能** | `views/crawl-*.js` | 11个占位符 |
### P3 —— 远期(架构优化)
| # | 问题 | 说明 |
|:-:|:-----|:------|
| ⑰ | **nurture_runner.sh 和 _send_remote 参数传递方式不同** | 本地传数组、远程传 shell 字符串,应统一 |
| ⑱ | **远程结果回传路径不一致** | nurture 结果在 `/tmp/`,collect 结果在 `runtime/results/` |
| ⑲ | **CMD_REGISTRY 从 dict 改为 dataclass** | 类型安全+IDE 补全 |
| ⑳ | **`routes/ops.py` 改为 class-based router** | 更好的可维护性 |
---
## 三、信息采集专项优化
### 3.1 当前链路(治理后)
```
前端 matrix-collect.js → POST /api/ops/run {type:'collect', accounts, params}
→ CommandBus CMD_REGISTRY["collect"]
→ auto_blueprint: 按账号平台自动选 douyin_read_profile / xiaohongshu_read_profile
→ 按机器分组 → MachineSession 队列 → _send_local / _send_remote
→ 远程执行 mc run --blueprints=xxx --rounds=1
→ BatchEngine → LoginStateMachine → 原子操作 → 数据提取
→ _save_profiles_json() → 写 profiles.json + homepage_info.json ✅
```
### 3.2 已修复的问题
| 问题 | 修复 |
|:-----|:------|
| profiles.json 和 homepage_info.json 不同步 | ✅ `_save_profiles_json()` 同步写两个文件 |
| 封号检测在采集流程内 | ✅ 登录层也检测封号,直接标记 banned |
| 正则取数字为'?' | ✅ 小红书 e2e 兜底已加 |
| 数据写入了但 Dashboard 不显示 | ✅ fleet_collector 缓存清除已做 |
### 3.3 信息采集的剩余优化
| 优化项 | 说明 | 优先级 |
|:-------|:-----|:-------|
| 采集进度实时反馈到 Dashboard | 目前是"提交后等完成",没有进度条 | P2 |
| 多机采集结果去重 | 同一个 identity_dir 在多台机器都有数据时重复显示 | P2 |
| 采集历史对比(上次 vs 本次) | 方便查看粉丝增长 | P3 |
| homepage_info.json 数据与 ORACLE 账号映射对账 | 自动发现"有账号但未采集" | P2 |
---
## 四、统一命令模板注册表(CMD_REGISTRY)最终设计
```python
CMD_REGISTRY = {
"nurture": {
"template": "mc run --accounts={ids} --blueprints={blueprint} --rounds={rounds}",
"defaults": {"blueprint": "douyin_daily", "rounds": 10},
"runner": "nurture_runner.sh", # shell 包装器(本地用)
"auto_blueprint": False,
},
"collect": {
"template": "mc run --accounts={ids} --blueprints={blueprint} --rounds={rounds}",
"defaults": {"rounds": 1},
"auto_blueprint": True,
"blueprint_map": {
"douyin": "douyin_read_profile",
"xiaohongshu": "xiaohongshu_read_profile",
},
},
"login": {
"template": "mc smart-login {ids}",
"single_account": True,
},
"logout": {
"template": "mc run --accounts={ids} --blueprints=douyin_daily --rounds=1",
},
"comment": {
"template": "mc task comment --account={ids} --url={url}",
"required_params": ["url"],
},
"like": {
"template": "mc run --accounts={ids} --blueprints=douyin_daily --rounds=1",
},
}
```
**核心原则**:
- ✅ 所有操作共用同一套模板渲染引擎
- ✅ 新增操作只需在注册表加一行
- ✅ `auto_blueprint` 让前端不用知道具体蓝图名
- ✅ `required_params` 在 dispatch 时自动校验
---
## 五、实施路线图
### Phase 6: 统一后端执行路由(P1)
| # | 任务 | 文件 | 工作量 |
|:-:|:-----|:-----|:-------|
| 6.1 | 删除 `routes/matrix.py` 中 `/nurture/start` 绕过 CommandBus 的代码 | `routes/matrix.py` | 小 |
| 6.2 | 删除 `/task/run` 绕过 CommandBus 的代码 | `routes/matrix.py` | 小 |
| 6.3 | 确认所有前端视图已改用 `/api/ops/run` | 逐个审计 views/ | 中 |
| 6.4 | 修复 accounts.js 单账号采集逐个发送 | `matrix-accounts.js` | 小 |
### Phase 7: 前端统一调用格式审计(P1)
| # | 任务 | 说明 |
|:-:|:-----|:------|
| 7.1 | 审计所有 views/ 中的 POST 调用,确认格式统一 | 逐个检查 |
| 7.2 | 修复不合规的调用 | 同上 |
| 7.3 | 增加 ESLint 规则或文档约束 | 后续 |
### Phase 8: 远程执行结果回传统一(P2)
| # | 任务 | 说明 |
|:-:|:-----|:------|
| 8.1 | 统一远程命令的结果文件路径 | 目前 `/tmp/` 和 `runtime/results/` 混用 |
| 8.2 | 统一 poll 策略对远程命令的检查方式 | 目前本地和远程各一套逻辑 |
### Phase 9: 清理遗留代码(P2)
| # | 任务 | 文件 |
|:-:|:-----|:------|
| 9.1 | 移除 `platforms/` 目录(或移到 archive) | `platforms/` |
| 9.2 | 修复 `agentos/plugins/matrix.py` 存档引用 | `agentos/plugins/matrix.py` |
| 9.3 | 确认 `scripts/archive/` 无外部引用后移出 | `scripts/archive/` |
| 9.4 | 删除 `routes/matrix.py` 中已废弃的 GET/POST 路由(需逐个确认) | `routes/matrix.py` |
---
## 六、治理后最终状态
```
L5 前端 ── 统一 POST /api/ops/run {type, accounts, params}
L4 路由 ── ops.py 唯一执行入口 | matrix.py 只读查询
L3 总线 ── CMD_REGISTRY 注册表 | 统一模板渲染 | 自动按机器分组
L2 引擎 ── BatchRunner | LoginStateMachine | 封号检测
L1 操作 ── douyin_ops + xhs_ops | 三段式原子操作
L0 浏览器 ── Camoufox | 登录态管理
数据层 ── profiles.json + homepage_info.json 同步写入
封号层 ── 登录检测 + 采集检测 双层判断
```
---
## 七、验证清单
- [ ] Phase 6: 无 POST 路由绕过 CommandBus
- [ ] Phase 7: 所有前端 views POST 调用格式统一
- [ ] Phase 8: 远程结果回传一致,Dashboard 能看到远程执行结果
- [ ] Phase 9: 无 archive 脚本的外部引用
@@ -0,0 +1,309 @@
# AgentOS 队列管理与程序职责框架
> 版本: 1.0 | 日期: 2026-07-04
> 目标: 说清楚"什么程序管什么"、"任务怎么流转"、"三台机器各自干什么"
---
## 一、程序总图:三台机器各自运行什么
```
┌──────────────────────────────────────────┐
│ Master(chengzigedeAir) │
│ │
│ ┌─ Dashboard ───────────────────────────────────────┐ │
│ │ FastAPI :9988 │ │
│ │ 职责: 接收用户请求、展示状态、调度分发 │ │
│ │ 包含: routes/*.py (API层) │ │
│ │ services/command_bus.py (调度层) │ │
│ │ services/video_analyzer.py (视频分析) 🆕 │ │
│ │ frontend/ (前端页面 47个视图) │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ ┌─ guardd :9090 ──────────────────────────────────────┐ │
│ │ 16个模块 + 15秒调度循环 │ │
│ │ 职责: 本地任务排队→执行、心跳上报 │ │
│ └────────────────────────────────────────────────────┘ │
│ │
│ └── 也负责自己的3台账号的养号/评论/采集 ──┘ │
└──────────────────────┬───────────────────────────────┘
│ Tailscale
┌──────────────────────────────────────────┐
│ Worker(5kechengdeAir / 7kecheng) │
│ │
│ ┌─ guardd :9090 ─────────────────────────┐ │
│ │ 只跑 guardd(无 Dashboard) │ │
│ │ 职责: 收大包→拆小包→三队列→3 slot执行 │ │
│ └────────────────────────────────────────┘ │
│ │
│ 账号: 5kecheng=12个, 7kecheng=大量的 │ │
└──────────────────────────────────────────────┘
```
**结论**: Dashboard 只在 Master 跑,Worker 只跑 guardd。
---
## 二、每个程序的具体职责
### 2.1 Dashboard(Master 专用)
| 模块 | 文件 | 职责 |
|:-----|:------|:------|
| **路由层** | `routes/ops.py` | 接收用户提交 → 调 CommandBus |
| **命令分发** | `services/command_bus.py` | 拆解任务→按机器打包→调 guardd API |
| **视频分析** | `services/video_analyzer.py` 🆕 | 浏览器提取标题→分类→选评论 |
| **前端** | `frontend/src/views/*` | 47 个视图,用户操作入口 |
### 2.2 guardd 守护进程(每台机器都有)
| 模块 | 文件位置 | 职责 |
|:-----|:---------|:------|
| **HTTP 服务器** | `guardd.py` line 227-380 | 端口 9090,接收/响应所有 API 请求 |
| **调度引擎** | `modules/scheduler.py` | **三队列管理 + 3 slot 流水线 + 账号互斥** |
| **任务存储** | `modules/task_store.py` | 任务数据持久化(SQLite + 内存双写) |
| **优先级队列** | `modules/priority_queue.py` | heapq 实现,支持按时间调度和取消 |
| **槽位管理器** | `modules/slot_manager.py` | 3 slot 分配/释放,浏览器进程监控 |
| **执行器** | `modules/executor.py` | 子进程执行 `mc run`,解析输出,超时控制 |
| **心跳上报** | `modules/heartbeat.py` | 每15秒收集本地状态→推送给 Dashboard |
| **计划同步** | `modules/schedule_bridge.py` | 每60秒检查 ORACLE 定时任务并提交 |
| **账号监控** | `modules/account_monitor.py` | 实时检查 cookies.sqlite 登录态 |
| **清理维护** | `guardd.py` line 1420-1450 | 9 模块循环每 300 秒执行 |
---
## 三、任务流转全路径:从用户提交到账号执行
### 3.1 场景:用户提交 20 个账号评论 1 个视频
```
你 (Dashboard 浏览器)
│ POST /api/ops/run {type:"smart_comment", accounts:[...20个], params:{urls:["https://..."]}}
▼
┌─ routes/ops.py line 36 ─────────────────────────────────────────────┐
│ api_ops_run() │
│ 数据校验 → CommandBus.dispatch("smart_comment", accounts, params) │
└───────────────────────────┬──────────────────────────────────────────┘
▼
┌─ services/command_bus.py line 908 ──────────────────────────────────┐
│ CommandBus.dispatch() │
│ │
│ STEP 1: 加载 ORACLE.yaml → 按机器分组 │
│ 7kecheng → [12个账号] │
│ 5kechengdeAir → [8个账号] │
│ │
│ STEP 2: smart_comment 分支 (line 1007) │
│ ├─ 新建 VideoAnalyzer → asyncio.run(analyze_batch(urls)) │
│ │ └─ 无头浏览器打开视频 → 提取标题/描述 │
│ │ └─ 关键词匹配 → 行业分类 (health/general) │
│ │ └─ 从行业池或万能池选评论 │
│ │ └─ 返回 {url: {title, industry, comment}} │
│ │ │
│ └─ 拆解: 每个账号×每个URL = 最小单元 │
│ ├─ {douyin_133, comment, "医生讲得很清楚", P0, 7kecheng} │
│ ├─ {douyin_134, comment, "医生讲得很清楚", P0, 7kecheng} │
│ └─ ... × 20 │
│ │
│ STEP 3: 按机器打包 → MachineSession.send() │
│ ├─ POST http://100.65.35.28:9090/scheduler/submit (12个P0任务) │
│ └─ POST http://100.72.182.121:9090/scheduler/submit (8个P0任务) │
└───────────────────────────┬──────────────────────────────────────────┘
▼
┌─ guardd HTTP :9090 (Worker机器) ──────────────────────────────────┐
│ do_POST /scheduler/submit │
│ → api_scheduler_submit() → _init_scheduler() → scheduler.submit() │
│ │
│ submit_task(): │
│ ├─ 账号互斥检查(第1层)→ 同一账号不可同时入队 │
│ ├─ 根据 priority 入对应队列: │
│ │ P0=0 → queue_priority (优先队列) │
│ │ P1=1 → queue_normal (日常队列) │
│ │ P2=2 → queue_filler (劣后队列) │
│ └─ 有空闲 slot → 立即分配 │
└───────────────────────────┬──────────────────────────────────────────┘
▼
┌─ scheduler.run_cycle() 每15秒 ─────────────────────────────────────┐
│ │
│ ① _check_all_active_tasks(): │
│ ├─ slot0: [P1养号 douyin_133] → 还在跑?→ 检查超时 │
│ ├─ slot1: [P1养号 douyin_134] → 已完成!→ _release_slot() │
│ │ └─ 释放 account_slots["douyin_134"] │
│ │ └─ 检查 paused_tasks: 有P0等这个slot? → 推入 queue_priority │
│ └─ slot2: [P2采集 douyin_135] → 还在跑 │
│ │
│ ② _schedule_all_slots(): │
│ ├─ slot0: 忙 → 跳过 │
│ ├─ slot1: 空闲 → _pop_by_priority() │
│ │ ├─ queue_priority pop → 取出 {douyin_134, comment} ← P0 │
│ │ └─ _assign_task() + account_slots["douyin_134"] = slot1 │
│ └─ slot2: 忙 → 跳过 │
│ │
│ ③ slot_manager.check_health(): 监控浏览器进程 │
└─────────────────────────────────────────────────────────────────────┘
```
### 3.2 关键:每台机器的 guardd 独立管理自己的队列
```
7kecheng 的 guardd:
queue_priority: [P0评论×4, P0评论×3] ← 智能评论待执行
queue_normal: [P1养号×22] ← 日常养号排队
queue_filler: [P2采集×8] ← 采集任务有空才做
---------------
slot0: → [P1养号 douyin_133 → P0评论 douyin_183 → 恢复P1 douyin_143]
slot1: → [P1养号 douyin_134 → P0评论 douyin_184 → 恢复P1 douyin_144]
slot2: → [P2采集 douyin_135 → ...]
---------------
account_slots: {"douyin_133":0, "douyin_134":1, "douyin_135":2}
5kechengdeAir 的 guardd:
queue_priority: [P0评论×2]
queue_normal: [P1养号×15]
queue_filler: []
---------------
slot0: → [P1养号 douyin_01 → P0评论 douyin_02 → 恢复P1 douyin_03]
slot1: → [空闲]
slot2: → [空闲]
---------------
account_slots: {"douyin_01":0}
```
**两台机器互不干扰** — 各自管各自的队列和 slot。
---
## 四、谁管队列
### 4.1 一句话回答
| 程序 | 管什么 |
|:-----|:--------|
| **CommandBus**(Master) | 把大任务拆成最小单元 → 按机器打包 → 分发到各机 guardd |
| **guardd scheduler**(每台机器) | 收到包后 → 自己管理三队列 → 分配 3 slot 执行 → 账号互斥 |
| **guardd heartbeat**(每台机器) | 只管 **上报状态** 给 Dashboard — **不参与队列管理** |
### 4.2 详细
```
大任务(20个账号评论1个视频)
│
▼ CommandBus(Dashboard 进程)
拆成 20 个小单元
按机器分成 2 个包: 7kecheng=12个, 5kecheng=8个
│
├──→ 7kecheng guardd:
│ 收到12个P0任务 → 入 queue_priority
│ scheduler: 从queue取 → 分到3个slot → 执行
│
└──→ 5kechengdeAir guardd:
收到8个P0任务 → 入 queue_priority
scheduler: 从queue取 → 分到3个slot → 执行
```
**heartbeat 只做状态上报,不干涉队列。**
---
## 五、三队列详细逻辑
### 5.1 队列类型
| 队列 | 变量名 | 优先级 | 谁来入队 | 何时执行 | 可被抢占 |
|:-----|:--------|:-------|:---------|:---------|:---------|
| P0 优先 | `queue_priority` | 最高 | smart_comment / 定向操作 | 有空闲 slot 立即执行 | ❌(它抢别人) |
| P1 日常 | `queue_normal` | 中 | 养号定时任务 / 日常操作 | P0 都执行完才取 | ✅ 被 P0 打断 |
| P2 劣后 | `queue_filler` | 低 | 批量采集 / 后台同步 | 只有 P0/P1 都空时才做 | ✅ 被 P0/P1 抢占 |
### 5.2 分配算法(`_pop_by_priority`)
```
每次 slot 空闲:
① 先看 queue_priority → 有 P0 → 取出来执行
② queue_priority 空 → 看 queue_normal → 有 P1 → 取出来执行
③ queue_normal 也空 → 看 queue_filler → 有 P2 → 取出来执行
每一步都跳过 busy 账号:
如果任务的账号在 account_slots 表中 → 跳过不取
```
### 5.3 P0 抢占(`insert_priority`)
```
收到 P0 任务 → 检查账号:
├─ 账号空闲 → 直接入 queue_priority
└─ 账号忙碌 → 挂到该 slot 的 paused_slots 列表
slot0: [▶️P1养号 douyin_133] → paused_slots[0] = [P0评论]
↓ 养号完成
_release_slot(0) → 检测到 paused_slots[0] 有 P0
→ P0 入 queue_priority → slot0 立即分配
↓ P0 执行完
→ 恢复被中断的 P1 队列
```
### 5.4 账号互斥表(`account_slots`)
```
account_slots = {
"douyin_133": 0, # douyin_133 在 slot0 运行
"douyin_134": 1, # douyin_134 在 slot1 运行
}
三层防护:
第1层: submit_task() 入队时 → 检查 account_slots
第2层: _pop_by_priority() 分配时 → 跳过 busy 账号
第3层: slot_manager 执行前 → 浏览器级别拦截
```
---
## 六、与旧的 9 模块心跳循环的关系
### 6.1 各自独立运行
```
guardd 进程:
┌─ 主线程: HTTP 服务器 :9090
├─ 调度线程: scheduler.run_cycle() 每15秒
└─ 原文线程: _run_heartbeat_cycle() 每300秒
包含 9 个模块:
1. module_heartbeat_collect
2. module_account_cleanup
3. module_login_check
4. module_results_cleanup
5. module_browser_cleanup
6. module_knowledge_sync ← 知识库同步
7. module_cleanup_ops ← 命令清理
8. module_dashboard_sync ← 看板同步
9. module_sync_checker ← 同步检查
```
**心跳只做辅助工作,不参与调度。** 调度由 `scheduler.run_cycle()` 独立完成。
---
## 七、现有技能体系与本次改造的关系
### 7.1 已归档技能(设计文档,无代码)
| 技能 | 内容 | 与本次改造的关系 |
|:-----|:------|:----------------|
| `web_crawler` | Scrapling + Crawl4AI 爬虫设计 | 实际代码未实现,但 Scrapling 已安装 ✅,可用来增强视频信息提取 |
| `content_processor` | 视频/文章/音频采集设计 | 设计框架可参考,无代码 |
| `auto_collector` | 24小时自动监控设计 | 设计框架可参考,无代码 |
### 7.2 可利用的已安装包
| 包名 | 已安装 | 可用来做什么 |
|:-----|:-------|:------------|
| **scrapling** 0.2.99 | ✅ | HTTP 静态页面抓取(比启动浏览器快) |
| **crawl4ai** | ✅ | LLM 友好的页面内容提取 |
| **cloakbrowser** | ✅ | 高反爬场景(https://www.douyin.com 动态内容) |
| **playwright** | ✅ | 浏览器自动化(当前 VideoAnalyzer 使用) |
### 7.3 可做的增强(不阻塞)
| 增强点 | 当前做法 | 可优化为 | 优先级 |
|:-------|:---------|:---------|:------|
| 视频标题提取 | 启动无头 Playwright | 先用 Scrapling HTTP 请求 meta tag,失败再降级浏览器 | 可优化 |
| 热门评论分析 | 未实现 | 爬虫获取视频页面的 top 评论,分析情感和话题 | 后续 |
| AI 生成评论 | 模板关键词匹配 | 上下文传到本地 oMLX 模型生成个性化评论 | 后续 |
+193
View File
@@ -0,0 +1,193 @@
# 写实感指南(去 AI 感 · 自拍 Vlog)
> 2026-10-03 建立 · 来源:外部方法论学习(`cclank/lanshu-awesome-ai-video-kit` 21 篇方法论 + `smixs/visual-skills`)
> 用途:调提示词、改导演规则、做拍法预设时的**对照规范**
---
## 一、三条最容易踩的坑(我们已实测踩中)
### 坑 1:图生视频却重描述视觉 ✗✗✗
**可灵官方守则**:图生视频时"**只描述运动,不重描述视觉**"——Kling 会重画图中已有内容,
你再描述一遍 = 给它两套冲突指令 → 画面被"重画" → AI 感。
```
❌ A red sports car with chrome wheels on a wet road... the car starts moving
✅ The headlights blaze on and the engine roars to life.
The rear tires spin, spraying water across the wet asphalt.
```
**判定**:镜头有参考图(`image_path` 存在)→ 提示词应**只含动作演化**。
### 坑 2:矛盾约束(写了等于没写)
| ❌ 矛盾组合 | 原因 |
|---|---|
| `胶片感 / film grain` + `4K超清 / ultra sharp` | 胶片感本身是模糊+颗粒 |
| **`电影感` + `纪实手持` 都强写** | 风格相互拉扯(**我们踩过**) |
| `慢动作` + `高速动作` | 速度矛盾 |
| 同时指定多个艺术家风格(>2) | 模型随机取一个 |
| **`画面稳定` + `手持晃动`** | 稳定=三脚架语言(**我们踩过**) |
### 坑 3:抽象情绪词
```
❌ 【情绪目标】紧张 / 好奇 / 悲伤
✅ 手指无意识地攥紧衣角,眼神闪躲,呼吸急促
```
**原则**:视频模型看不懂抽象形容词,**必须外化为身体细节**;每镜只写 1-2 个关键动作(多了稀释焦点)。
---
## 二、写实人像 5 段公式(Dan Kieft / 5M+ 播放教学)
```
① Subject 谁 —— 年龄/种族/妆/服装(具体,不堆形容词)
② Pose 姿态 —— candid shot / 坐着 / 侧看 / 微笑
③ Camera ★ 相机 —— Fujifilm X100V · 35mm · 景深 · bokeh ← 杀手锏
④ Skin ★ 皮肤 —— 真实纹理 · 自然瑕疵 · 不过度磨皮 · 毛孔可见
⑤ Aesthetic 调性 —— Instagram 风 · 暖调 · 自然光 · 城市背景
```
**完整示例(原文)**:
```
Beautiful 20-year-old East Asian woman, minimalist makeup, wearing beige streetwear
jacket, candid moment sitting at a cafe table, looking sideways with soft smile.
Shot on Fujifilm X100V, 35mm film, realistic lighting, natural skin texture,
unfiltered, pores visible, soft background bokeh, Instagram aesthetic,
professional urban street photography, warm tones.
```
**要点**:
- **相机型号是杀手锏** —— 触发模型的"真实摄影"先验(`Fujifilm X100V` / `Leica Q3` / `iPhone 前置`)
- **`unfiltered` + `pores visible`** 是反 AI 塑料感的直接解药
- `Same woman` / 角色名重复 → 锚定同一人物(跨场景一致性)
---
## 三、情绪外化表(10 种,可直接抄)
| 抽象情绪 | 外化为动作与细节 |
|---|---|
| 悲伤 | 低头、肩膀微微颤抖、眼眶泛红、手指无意识攥紧衣角、泪水打转却没落下 |
| 喜悦 | 嘴角抑制不住上扬、眉眼舒展、脚步轻快、哼小曲、忍不住原地转圈 |
| 紧张/焦虑 | 频繁看表、手指敲桌面、呼吸急促、眼神闪躲、无意识啃指甲 |
| 愤怒 | 双拳紧握、下颌线紧绷、胸口起伏、眼神锐利、从牙缝挤话 |
| 释然 | 长舒一口气、肩膀放松、淡淡微笑、抬头望向远方 |
| 恐惧 | 瞳孔放大、后退半步、抓住身边物体、屏息、嘴唇发抖 |
| 疲惫 | 揉太阳穴、靠墙、眼皮下沉、长呼气、动作迟缓 |
| 专注 | 眉头微皱、眼神锁定一点、嘴唇抿紧、身体前倾、手稳定不动 |
| 犹豫 | 张嘴又闭上、视线游移、手悬在半空、踱步、欲言又止 |
| 惊喜 | 眼睛瞬间睁大、嘴巴张开成 O 形、双手捂嘴、向前一步、笑容缓缓绽放 |
**写法对照**:
```
❌ 她终于轻松下来了。
✅ 她长长地舒了一口气,紧绷的肩膀完全放松下来,脸上浮起淡淡的微笑,抬头望向远方。
```
---
## 四、特殊字符规范(结构化标注)
| 信息类型 | 符号 | 示例 |
|---|---|---|
| 音乐 | `( )` | `(背景播放着舒缓的爵士钢琴)` |
| 音效 | `< >` | `<远处传来狗叫声>` |
| 台词 | `{ }` | `她轻声说{好久不见}` |
| 字幕 | `【 】` | `【第二章:重逢】` |
**语言规范**:台词语言统一,外语需标注语种 → `用日语说道{こんにちは}`
> ⚠️ 这是给**支持音频生成的模型**用的(Seedance 2.5 等)。我们当前是"先出画面再配音",
> 此规范可用于**分镜脚本阶段的标注**,便于后续 TTS 分段与音效铺底。
---
## 五、约束词三件套(护栏)
**必加基础**:`不要水印` · `不要 Logo` · `不要字幕`
**画面稳定**:`人物面部稳定不变形` · `动作连贯自然不僵硬` · `无穿模无卡顿无闪烁`
**主体一致性(防"双胞胎")**:
```
视频全程禁止出现外形、着装、配饰完全一致的人物
禁止生成同款分身、双胞胎效果
同一画面中仅保留单个对应人物,不出现人物重复复刻
```
**镜头**:`镜头平稳` / `固定机位` / `避免突然变焦`(**注意与手持风格二选一**)
---
## 六、可灵专属守则(我们用可灵,重点)
1. **中文理解业界最强** → **推荐纯中文提示词**(避免中英混用)
2. **图生视频极强** → 有参考图时**只写动作**(见坑 1)
3. **用 active verbs**:`rockets upward` / `slams into` / `erupts`(不是 `moves`/`goes`)
4. **写时序流**:`抬起刀 → 一刀劈下 → 刀锋反光 → 竹子滑落`(箭头 = 时间节点)
5. **用具体光源**代替笼统词:`闪烁的日光灯管` / `霓虹灯` / `烛光` / `黄金时刻`
(❌ `dramatic lighting` / `自然光,光源有画面依据`)
6. **加触感细节**(tactile details)
7. **原生支持音画同步 + 角色定向发声**("角色A说X,角色B说Y")—— ⚠️ 我们尚未使用
8. 时长:15s(智能分镜可达 2 分钟)—— 我们目前限制 5/10s,可放宽
---
## 七、自拍 Vlog 专项包(核心诉求)
自拍 vlog 的"真",靠这 5 层同时成立:
**① 设备锚点**
```
iPhone 15 Pro 前置摄像头,竖屏 9:16,近距离广角
轻微桶形畸变(前置镜头的特征)
```
**② 手持特征**(⚠️ 不能同时写"画面稳定")
```
手持自拍(手臂长度)、轻微呼吸起伏、偶尔微调构图
```
**③ 生活光**(真实光源 > 形容词)
```
窗光从左侧打在脸上、室内顶灯偏暖、手机屏幕的光在镜片上有反光
背景比人脸暗一档(室外过曝的窗户)
```
**④ 微瑕疵**(AI 最不会自发生成的东西)
```
对焦偶尔漂移、曝光随移动变化、轻微噪点、头发有几缕没梳顺
说话时自然眨眼、吞咽、鼻翼微动、视线偶尔离开镜头
```
**⑤ 声音层**
```
房间混响、远处车流、衣服摩擦声、说话时的换气声
```
---
## 八、落地清单(改系统时对照)
| 位置 | 改什么 |
|---|---|
| `composer/pipeline.py: build_shot_prompt` | 图生视频分支**删视觉重描述**;加写实锚点包(相机型号/皮肤/反塑料感) |
| 同上 | **矛盾自检**:`稳定 vs 手持`、`电影感 vs 纪实` 等成对冲突检测 |
| `directors/*.py` | 情绪**必须外化**(内建情绪外化表);光源必须具体 |
| 拍法预设 | 新增 📱 **自拍 Vlog**(一键带全 5 层锚点) |
| 全局 | 每镜自动附加约束词三件套 |
| 可选 | 试可灵原生音画同步(角色定向发声)替代"事后配音" |
---
## 附:资料存档位置
- 抓取的 7 篇方法论原文:`/tmp/aivideo_kb/`(临时,重启会清)
- `04-情绪外化表.md` · `06-约束词清单.md` · `07-特殊字符规范.md`
- `08-避坑12问.md` · `09-kling-公式.md` · `20-realistic-character-consistency.md`
- `02-进阶公式.md` · `smixs-README.md`
- 上游仓库:`cclank/lanshu-awesome-ai-video-kit`(411 prompts / 21 篇方法论)
+241
View File
@@ -0,0 +1,241 @@
# 改造分析报告:现状 vs 目标架构
> 日期: 2026-07-04 | 基于 `PLANS/TASK_ORCHESTRATION_ARCHITECTURE.md`
> 审计范围: 全部 7 个模块,逐项检查
---
## 一、改造项总览
| # | 模块 | 改造类型 | 优先级 |
|:-:|:-----|:---------|:-------|
| 1 | `scheduler.py` | 🔧 **重写** — 现有逻辑不满足需求 | P0 |
| 2 | `priority_queue.py` | ✅ **不动** — 现有类直接可用 | - |
| 3 | `command_bus.py` | 🆕 **新增** smart_comment 类型 | P1 |
| 4 | `video_analyzer.py` | 🆕 **新建** — 不存在 | P1 |
| 5 | `corpus.py` | 🔧 **改造** — 加行业过滤 + 万能兜底 | P1 |
| 6 | `douyin.yaml` | 🔧 **重构** — 语料分层 | P1 |
| 7 | `profiles.json` | 🔧 **补字段** — 加 industry | P2 |
| 8 | `ops-command.js` | 🆕 **加功能** — 三队列显示 | P3 |
---
## 二、逐项分析
---
### 改造项 1:`scheduler.py` — 🔧 重写
**当前代码**(`guardd/modules/scheduler.py:33-362`):
当前是单队列模式:
```python
class Scheduler:
def __init__(self):
self.queue = PriorityQueue() # ← 一个队列装所有优先级
self.active_tasks: dict[int, dict] # {slot_id: task}
self.paused_tasks: dict[int, dict]
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 队列数量 | **1 个** 混装所有优先级 | **3 个** 独立队列(P0/P1/P2) | ❌ P0不能插队,P2不能填空 |
| `_pop_next_task()` | 遍历所有任务,按`(priority, scheduled_at)`排序后取第一个 | 先看P0→再看P1→再看P2,且跳过 busy 账号 | ❌ 无法实现优先级隔离 |
| 账号互斥 | slot_manager.find_account() 在分配时检查 | 三层检查:入队时+分配时+执行前 | ❌ 入队层不检查,可能重复入队 |
| 账号状态表 | 无 | `account_slots: dict[str, int]` | ❌ 没有快速查询账号状态的能力 |
| P0 抢占 | 无 | 当前任务结束后插队 | ❌ 完全未实现 |
| P2 劣后 | 无 | 只在空闲时执行,可被抢占 | ❌ 完全未实现 |
| 暂停任务暂存 | `paused_tasks` 存在但不被 active 使用 | P0插入时暂停P1,完成后恢复 | ❌ 逻辑不完整 |
**改造原因**:当前逻辑是**功能错误的**。三个优先级的任务混在一个队列里,虽然排序时按 priority 字段,但 `_pop_next_task` 取完第一个任务后就 break 了,不会继续往后看。当高优任务 due 时间还没到时(`scheduled_at > now`),堆顶返回 None,整个调度循环就停了。这导致 P0 任务无法真正插队。
**改动量**:~200行,重写 `Scheduler` 类。
---
### 改造项 2:`priority_queue.py` — ✅ 不动
**当前代码**(`guardd/modules/priority_queue.py:1-79`):
```python
class PriorityQueue:
"""基于 heapq 实现,支持优先级排序 + 时间调度 + 取消/重排"""
```
当前实现完全满足需求。三队列只需创建三个独立实例:
```python
self.queue_priority = PriorityQueue() # P0
self.queue_normal = PriorityQueue() # P1
self.queue_filler = PriorityQueue() # P2
```
无需修改此类。
---
### 改造项 3:`command_bus.py` — 🆕 新增 smart_comment
**当前代码**(`services/command_bus.py:807-842`):
```python
CMD_REGISTRY = {
"nurture": {...},
"collect": {...},
"login": {...},
"logout": {...},
"comment": {...},
"like": {...},
"interact": {...},
"record": {...},
}
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 评论类型 | `comment` / `interact` — 直接传 `mc task comment` | + `smart_comment` — 先分析视频再评论 | ❌ 缺少视频分析环节 |
| 分发逻辑 | 按机器分组后直接发到 guardd | 先调 VideoAnalyzer 分析所有URL,再分组分发 | ❌ 无分析环节 |
**改造原因**:**新功能需求**。现有 comment/interact 可以保留不变,新增 smart_comment 走新的视频分析流程。
**改动量**:~20行,加一条注册表 + dispatch 分支。
---
### 改造项 4:`video_analyzer.py` — 🆕 新建
**当前**:文件不存在。
**需要新建**一个完整的视频分析模块,包含:
- 浏览器打开 URL 提取标题/描述
- 关键词匹配行业分类
- 根据账号 industry 选评论
**改造原因**:**完全是新增功能**,原来是直接传评论或者随机取语料,现在需要先分析视频内容再做匹配。
**改动量**:~150行新文件。
---
### 改造项 5:`corpus.py` — 🔧 改造
**当前代码**(`scripts/mc/corpus.py:51-57`):
```python
KEYWORD_CATEGORY_MAP = [
(["科技", "数码", "手机"], ["称赞", "提问"]),
(["美食", "做饭", "菜"], ["称赞", "共鸣"]),
(["旅游", "风景", "旅行"], ["称赞", "提问"]),
(["情感", "生活", "感悟"], ["共鸣", "安慰"]),
(["知识", "科普", "教育"], ["提问", "补充"]),
]
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 关键词覆盖 | **5组**(科技/美食/旅游/情感/知识) | **9+组**(加上医疗/财经/育儿/汽车等) | ❌ 无医疗关键词,健康类视频无法匹配 |
| 行业过滤 | 无 | 根据账号 industry 过滤语料 | ❌ 医疗账号可能发科技评论 |
| 万能兜底 | `_get_random_comment()` 全域随机 | 从万能池(称赞/提问/共鸣)取 | ❌ 没有万能池概念 |
| 分类→方向映射 | `DIRECTION_TO_CATEGORY` 5个 | 同步扩展 | ❌ 需要对齐 |
**改造原因**:**现有功能不完整**。关键词覆盖太窄,缺少行业过滤机制和万能兜底逻辑。
**改动量**:~50行,改 `KEYWORD_CATEGORY_MAP` + `get_comment_for_video()`。
---
### 改造项 6:`douyin.yaml` — 🔧 重构
**当前结构**(`corpus/douyin.yaml:239行`):
```
categories:
赞美: (30条,通用)
共鸣: (15条,通用)
提问: (15条,通用)
感慨: (15条,通用)
客观: (10条,通用)
补充: (5条,通用)
```
| 功能点 | 现状 | 目标 | 问题 |
|:-------|:-----|:-----|:-----|
| 语料分层 | **平铺**,都在同一层 | **两层**:万能池 + 行业池 | ❌ 无法区分行业 |
| accessible 字段 | 无 | `accessible: "*"` 或 `accessible: ["health"]` | ❌ 无法限制账号使用 |
| match_tags 字段 | 无 | 每个行业池带关键词标签 | ❌ 无法自动匹配视频 |
**改造原因**:**结构设计不满足新需求**。需要按行业分层,加 accessible 和 match_tags 字段。
**改动量**:YAML 结构调整,将现有评论分类到"万能称赞""万能提问""万能共鸣"下,新增"大健康称赞"等行业池。
---
### 改造项 7:`profiles.json` — 🔧 补字段
**当前**(`profiles.json:344行`):
```json
{
"douyin_133": {"nickname":"苏州胃肠体检敏敏", ...},
"douyin_test": {"nickname":"小美养生茶", ...},
}
```
没有一个账号有 `industry` 字段。
**改造原因**:**缺少关键数据**。没有 industry 字段,VideoAnalyzer 无法判断账号该用哪个语料池。
**改动量**:每个账号加一行 `"industry": "health"` 或 `"industry": "general"`,手动配置。
---
### 改造项 8:`ops-command.js` — 🆕 加功能
**当前代码**:
前端已有 P0/P1/P2 的 HTML 筛选 checkbox(第41-43行),但后台 scheduler 返回的队列数据中优先级是混在一起的,前端无法真正按优先级分类展示。
**改造原因**:**新功能需求**。后台改为三队列后,前端需要分开显示三个队列的长度+内容。
**改动量**:~80行,加三个队列的独立展示区域。
---
## 三、改造原因分类
| 类别 | 数量 | 项 |
|:-----|:-----|:----|
| ❌ **功能错误**(现有逻辑有问题) | 1 | scheduler.py — 单队列导致P0/P2无法正常工作 |
| ⚠️ **功能不完整**(有但不够) | 2 | corpus.py 关键词覆盖窄、douyin.yaml 无行业过滤 |
| 🆕 **新功能需求**(完全新增) | 4 | video_analyzer.py、command_bus smart_comment、profiles.json industry、ops-command三队列 |
| ✅ **无需修改** | 1 | priority_queue.py |
---
## 四、按 Phase 的改造详细清单
### Phase 1:队列改造(P0)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| `guardd/modules/scheduler.py` | 362行 | 重写:单队列→三队列 + 账号互斥表 + P0抢插 + P2填空 | ❌ 功能错误,当前单队列无法实现优先级隔离 |
### Phase 2:语料重组(P1)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| `corpus/douyin.yaml` | 239行 | 重构为万能池+行业池 | 🆕 新需求,需要按行业分层 |
| `scripts/mc/corpus.py` | 701行 | 扩展关键词 + 加行业过滤 + 万能兜底 | ⚠️ 关键词覆盖窄,缺少过滤 |
| `profiles.json` | 344行 | 各账号加 industry 字段 | 🆕 新需求,需要标记账号行业 |
### Phase 3:视频分析(P1)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| **新建** `services/video_analyzer.py` | 0 → ~150行 | 视频URL分析+分类+选评论 | 🆕 完全新增 |
| `services/command_bus.py` | 1289行 | CMD_REGISTRY 加 smart_comment | 🆕 新需求 |
### Phase 4:指挥台展示(P2)
| 文件 | 当前行数 | 改动 | 原因 |
|:-----|:---------|:------|:------|
| `frontend/views/ops-command.js` | 413行 | 三队列独立展示 | 🆕 新需求 |
File diff suppressed because it is too large Load Diff
+288
View File
@@ -0,0 +1,288 @@
# 导演工作室 · 重新设计方案
> 2026-10-10 · 基于**实测盘查**(非推测)
> 目标:止住"越改越乱",把现有能力重新收进一个**边界清晰**的结构里
---
## 一、现状诊断(全部实测数据)
### 1.1 规模
| 项 | 数量 | 说明 |
|---|---|---|
| 前端视图 | **85 个** | 视频工厂相关 44 个 |
| 后端路由 | **7 文件 / 145 端点 / 7206 行** | ave(33) · ave_project(30) · ave_keyframe(25) · ave_assets(33) · ave_scene(5) · ave_creatives(16) · ave_docs(3) |
| `ave-director.js` | **112 KB** | 单文件注册 **26 个 `window._dir*` 函数** |
| 项目对象顶层键 | **19 个** | 其中 3 个是从没写过的死键 |
| 运行目录 | **15 个** | 含 5 个测试残留 |
### 1.2 五类具体问题(都对齐到了文件)
**① 空壳页面 4 个**(内容是"功能开发中,敬请期待")
```
ave-script.js 409 B 脚本生成
ave-render.js 409 B 渲染任务
ave-templates.js 406 B 模板
ave-materials.js 409 B 素材库
```
**② 新旧两套流程并存 —— 6 个老流程页在菜单里,但跑不通**
```
ave-flow-short-drama.js 744 B ← 菜单「🎭 短剧创作」
ave-flow-dub.js 647 B ← 菜单「🎙️ 基础口播」
ave-flow-beat.js 579 B ← 菜单「🥁 卡点视频」
ave-flow-narrative.js 668 B ← 菜单「📖 角色叙事」
ave-flow-digital-human.js 611 B ← 菜单「👤 数字人口播」
ave-flow-hybrid.js 564 B ← 菜单「🎞️ 口播+混剪」
```
它们自己的注释写着:**"TTS / 素材 / BGM / 字幕的执行实现仍在接入中(运行时会明确跳过)"**
→ 而工作室那条链路**是通的** → 两套并存,用户不知道点哪个
**③ 工作室内部职责重叠(用户已经混了)**
```
🌍 设定 vs 📋 创意卡 —— 都在"想清楚这个故事"
🖼 关键帧设计 vs 🖼 关键帧 —— 用户明确问过"这两个有什么区别"
```
实测:用户上次说的"关键帧工作台里面是空的",我查了两轮才确认他指的是哪个页面。
**④ 单文件职责超载**
`ave-director.js`(112 KB)一个文件里塞了:
```
<!-- ② 全局设置 --> 导演系统 / 风格 / 演员表 / 场景 / seed
<!-- 📐 全片设定 --> 空间/角色/镜头语言(原故事板并入)
<!-- ③ 按场次生成 --> 段落列表 + 场记板 + 生成
<!-- ④ 分镜表 --> 镜头卡片编辑
<!-- 出片进度 --> 渲染任务轮询
```
**⑤ 数据源分散 + 死键**
```
projects/{pid}/project.json ← 项目对象(19 键,其中 3 键为空)
storyboards/{pid}.json ← 分镜(不在 project.json)
keyframes/{pid}/{sid}/ ← 关键帧图
keyframe_videos/{pid}/{sid}/ ← 视频片段
```
`project.json` 里的 `keyframes` / `videos` / `assets` **三个键从没被写过**(空)。
实测 `_enrich()` 每次读项目时**临时合并**前三个 → 说明它们本该在项目对象里。
---
## 二、根因(为什么会"越改越乱")
三条,都不是技术问题:
1. **加功能时"就地扩"** —— 没有"这一层该管什么"的边界。分镜页越塞越多(演员表、锚点、全片设定、出片设置),因为"顺手就放这了"。
2. **新旧并存不删** —— 怕删坏,就留着旧的。结果路由/菜单/文档里同时存在两套,用户选错就在所难免。
3. **数据"能跑就行"** —— 写在哪方便就写哪。分镜写 `storyboards/`、关键帧写 `keyframes/`,导致"上游带入"读不到(这是之前修过的真 bug)。
---
## 三、新架构
### 3.1 三条主线(先分清楚"这是哪一类东西")
```
📦 原料 🎬 生产 📊 交付
(可复用资产) (做一条片子) (看结果)
角色/场景/道具 导演工作室 生产记录
音色/BGM/音效 (唯一主流程) 费用统计
产品/服装/素材 产物中心
```
**判断规则**:
- 能被**多条片子复用** → 进「原料」
- 属于**某一条片子**的 → 进「生产」
- 是**结果/统计** → 进「交付」
### 3.2 生产主线:工作室 9 阶段 → **7 阶段**
**合并的关键点**:`🖼 关键帧设计` + `🖼 关键帧` → **一个页面**(左设计右图)
```
① 💡 创意 ┐
② 🌍 设定 ├→ ③ 📋 创意卡 → ④ 📝 剧本 → ⑤ 🎬 分镜 → ⑥ 🖼 关键帧 → ⑦ 🎞 视频 → ⑧ 🎙 后期
┘
(素材层) (汇聚层) (执行层)
```
**为什么保留 ①②(不合并)**:
- `💡 创意` = **这个故事的种子**(候选 → 选一句)
- `🌍 设定` = **世界的规则**(可跨故事复用,比如"肛肠科病房"这个世界的规则)
- `📋 创意卡` = **两者合起来 → 这个故事的具体构想**
- 职责不同,但**界面上必须写明各自管什么**(现在的毛病是没写)
**为什么合并 ⑥**:
- 用户已经混了。而且"设计"(决定拆几张)和"生成"(出图)本来就是**同一步的两半** —— 设计完立刻要看图对不对。
### 3.3 每阶段一张「职责卡」(界面顶部固定显示)
这是**治乱的核心**:每个页面顶部明确写三行 —— **我从哪来 / 我产出什么 / 下一步用它做什么**。
| # | 阶段 | 输入(从哪来) | 产出 | 下一步用它做什么 |
|---|---|---|---|---|
| ① | 💡 创意 | 参数选型 | 选中的 1 句话 | 扩写成创意卡 |
| ② | 🌍 设定 | — | 世界规则(可复用) | 创意卡 + 剧本的世界观依据 |
| ③ | 📋 创意卡 | 创意 + 设定 | 故事卡(12 字段) | 剧本的**最高依据** |
| ④ | 📝 剧本 | 创意卡 | 按**段落**的剧本 | 分镜按段落做 |
| ⑤ | 🎬 分镜 | 剧本段落 + 导演/风格/演员 | 镜头(Shot) | 关键帧按镜头做 |
| ⑥ | 🖼 关键帧 | 镜头 + 角色/场景资产 | 帧设计(A/B/C)+ 帧图 | 视频的首/尾帧 |
| ⑦ | 🎞 视频 | 关键帧(选首尾)+ 引擎 | 视频片段(可多段) | 后期拼接 |
| ⑧ | 🎙 后期 | 采用的片段 | 成片(拼接/字幕/混音) | 交付 |
### 3.4 菜单重排
**现状 → 目标**
```
🎬 视频工厂 · 资源库(16 项) → 📦 原料(12 项)
摘掉:素材库(空壳)
保留:创意库 / 角色库 / 角色生成器 / 场景生成器 / 场景库 /
真实场地 / 道具库 / 产品库 / 服装库 / 音色库 / BGM / 音效
说明:环境音库、特效预设 暂藏在「更多」里(当前为空,用不上)
🎬 视频工厂 · 流程(12 项) → 🎬 生产(3 项)
★ 导演工作室(唯一主流程)
🔄 人物置换(独立工具,不属主流程)
🔀 流程画布(高级功能,折叠在「高级」下)
隐藏:6 个 ave-flow-*(老流程,跑不通)+ 新建流程(与流程画布重复)
🎬 视频工厂 · 能力中心(4 项) → 🧩 配置(4 项,不变)
🎬 视频工厂 · 运营(2+ 项) → 📊 交付(3 项)
生产记录 / 费用统计 / 产物中心
```
**净减**:`16+12+4+2 = 34 项` → `12+3+4+3 = 22 项`(-35%)
### 3.5 拆掉 112 KB 的巨物
`ave-director.js` 拆成 3 个视图(各管一件事):
```
views/studio-shots-config.js ← 导演系统 / 风格 / 演员表 / 场景 / 锚点(配置)
views/studio-shots-generate.js ← 段落列表(场记板)/ 生成 / 全片设定(动作)
views/studio-shots-table.js ← 分镜表(结果,可编辑)
```
用户在一个页面里**从上到下**走,但代码是三块,各自可独立改。
---
## 四、数据模型(单一真相源)
### 4.1 原则
> **一条片子的全部数据,只在一个文件里。** 媒体文件(图/视频/音频)仍各自落盘,但**路径登记在项目对象里**。
### 4.2 目标结构
**⚠️ 权衡说明(我先自我修正)**:
我最初想把 `shots`(含关键帧和视频的全部版本记录)塞进 `project.json`。
**但那样会让它膨胀到几百 KB** —— 20 个镜头 × 每镜 3 帧 × 每帧多版本,
每次改一个字都要重写整个文件,性能和并发都会出问题。
**所以改成:单一真相源 = 单一目录,而不是单一文件。**
```
projects/{pid}/ ← ★ 一个项目 = 一个目录(这就是"真相源")
│
├ project.json ← 轻量(< 20 KB):元数据 + 各阶段摘要
│ { "project_id","title","stage","created_at","updated_at",
│ "creative":{...}, // 💡 创意(选中的候选)
│ "setting":{...}, // 🌍 设定
│ "creative_card":{...}, // 📋 创意卡
│ "script":{...}, // 📝 剧本(段落)
│ "film_settings":{...}, // 📐 全片设定
│ "post":{...}, // 🎙 后期(时间线 + 成片路径)
│ "cast":[...], // 演员表
│ "history":[...] } // 变更记录
│
├ shots.json ← 重数据:分镜 + 关键帧 + 视频(可单独读写)
│ [ { "shot_id","paragraph_no","visual","duration","cast_slots", ...,
│ "keyframes": { "plan":{A/B/C 提示词},
│ "frames":[{seq,role,versions:[{v,file,adopted}]}] },
│ "videos": [ {segment, versions:[{v,file,adopted,has_voice}]} ] } ]
│
└ media/ ← 媒体文件(或继续用现目录,只登记路径)
keyframes/shot_01/v1.png
videos/shot_01/s1_v1.mp4
```
**为什么这样更好**:
- `project.json` 保持轻量 → 改设定/剧本不会牵动分镜
- `shots.json` 单独读写 → 生成一镜只改这个文件
- **但对外只有"一个项目目录"** → 备份/复制/迁移 = 复制目录
**取消**:
- `project.json` 里的 `keyframes` / `videos` / `assets` 三个死键 → 删除
- `storyboards/{pid}.json` **作为独立位置** → 并入 `projects/{pid}/shots.json`
(同级目录,不再是"另一个地方")
- 前端不再需要 `_enrich()` 跨目录临时合并
### 4.3 收益
- 「上游带入」天然正确(同一目录,不用跨目录捞)
- 「这个项目的全部产物」一个请求拿到
- 备份/迁移/复制项目 = 复制一个目录
- 删项目 = 删一个目录(现在要删 4 个地方)
---
## 五、迁移路径(现有内容怎么落位)
**原则:不删数据,只搬家。每一步都可回滚(先备份)。**
| 现有 | 去向 |
|---|---|
| `storyboards/{pid}.json` 的 shots | 搬进 `project.json` 的 `shots[]` |
| `keyframes/{pid}/{sid}/*.png` | 文件不动;路径登记到 `shots[i].keyframes` |
| `keyframe_videos/{pid}/{sid}/*.mp4` | 文件不动;路径登记到 `shots[i].videos` |
| `storyboard_paper` | 已是 `film_settings` 的来源(已迁移)→ 删键 |
| 6 个 `ave-flow-*` 视图 | **文件保留**(不删仓库文件),仅从菜单摘掉 |
| 4 个空壳视图 | 同上,从菜单摘掉(它们本来也不在菜单里) |
| 运行目录里的测试残留 | 移到 `_trash/` |
---
## 六、实施顺序(4 批,每批独立可验证)
**批 1 · 止血(零风险,先让界面不乱)**
- 菜单重排(摘掉老流程 + 空壳)
- 每个阶段页顶部加「职责卡」(我产出什么 / 下一步用它做什么)
- 合并 `🖼 关键帧设计` + `🖼 关键帧` 为一个页面
**批 2 · 数据归一(动后端,但只加不改)**
- `shots` 搬进 `project.json`(写入时双写,读取时优先新位置)
- 关键帧/视频的路径登记进 `shots[i]`
- 前端改读新位置(保留旧路径兜底)
**批 3 · 拆巨物**
- `ave-director.js` 拆 3 块(配置 / 生成 / 表)
- 每块独立测试
**批 4 · 清理**
- 删死键、废弃 `_enrich()`、测试残留移 `_trash/`
- 更新文档
---
## 七、待你确认的 5 件事
1. **要不要合并「关键帧设计」和「关键帧」?**(我倾向合并 —— 你已经混过一次)
2. **`ave-flow-*` 那 6 个老流程页,从菜单摘掉可以吗?**(文件保留)
3. **「环境音库」当前是空的 —— 先藏起来,还是保留在菜单里?**
4. **「流程画布」(`workflow`) 你还用吗?**(它是另一套编排方式,功能与工作室重叠)
5. **批 1 的菜单重排,要不要现在就做?**(零风险,改完立刻清爽)
---
## 附:本次盘查用到的命令(可复现)
```bash
# 视图规模
ls -la frontend/src/views/*.js | awk '{print $5, $NF}' | sort -rn
# 空壳识别
for f in views/*.js; do [ $(wc -c < $f) -lt 1000 ] && echo "$f"; done
# 后端端点分布
for f in routes/ave*.py; do echo "$(basename $f) $(grep -cE '^@router\.' $f)"; done
# 项目对象结构
python3 -c "import json;d=json.load(open('.../project.json'));print(list(d.keys()))"
```
@@ -0,0 +1,175 @@
# Task: submission_distill 内容蒸馏任务 🧪
> **用途**: 将 `01_submissions/` 中积压的原始采集内容自动蒸馏为结构化报告
> **建议添加至**: `ORACLE.yaml → tasks:`
> **基于数据**: 2026-05-18 至 06-08 共 70 篇袁本初文章(238KB)
---
## 一、任务定义(YAML 片段)
```yaml
- name: submission_distill
description: "蒸馏 01_submissions 原始文章为分类摘要+元数据报告"
schedule: 0 5 * * 1
# ^ 每周一早5点(赶在 inbox_refine 4点+vector_rebuild 3:30 之前)
on_machines:
- chengzigedeAir
action: distill
params:
source_dir: "01_submissions"
output_dir: "03_knowledge/00_stream"
batch_size: 10
max_age_days: 14
# 摘要模式: llm — 用 AI 写自然语言摘要
# extract — 仅提取关键词和元数据(快速版)
mode: llm
```
也可拆为两个子任务,一个做关键词提取,一个做 AI 摘要:
```yaml
- name: submission_metadata
description: "提取 submissions 元数据和关键词索引(快速,每天跑)"
schedule: 0 5 * * *
on_machines:
- chengzigedeAir
action: distill
params:
mode: extract
source_dir: "01_submissions"
output_dir: "04_memory/long_term"
- name: submission_abstract
description: "提交物 AI 摘要生成(耗时长,每周跑)"
schedule: 0 5 * * 1
on_machines:
- chengzigedeAir
action: distill
params:
mode: llm
source_dir: "01_submissions"
output_dir: "03_knowledge/00_stream"
batch_size: 10
```
---
## 二、运行时数据流
```
01_submissions/*.md
│
├── step 1: extract_metadata (每天)
│ ├── 解析文件名 → {date, author, category, seq}
│ ├── 解析 front matter → {yaml fields}
│ ├── 提取标签 → keywords[]
│ ├── 计算字数、行数
│ └── 更新 keyword_index.json
│
├── step 2: group_by_category (每周)
│ ├── 按分类聚类
│ ├── 按日期排序
│ └── 计算跨分类交叉引用
│
├── step 3: generate_summary (每周)
│ ├── 每个分类读最新一篇代表性文章
│ ├── LLM 生成 200-300 字摘要
│ ├── 提炼核心概念
│ └── 输出到 03_knowledge/00_stream/
│
└── step 4: aggregate (每周)
├── 生成跨分类主题网络
├── 更新统计表
└── 生成 JSON 摘要输出
```
---
## 三、首次执行时的预期输出
| 输出文件 | 内容 |
|:---------|:-----|
| `03_knowledge/00_stream/YYYY-MM_submissions_distillation.md` | 全量蒸馏报告(分类摘要+元数据+主题网络) |
| `04_memory/long_term/keyword_index_YYYYMMDD.json` | 更新后的关键词索引 |
| 同时更新 | `02_skills/kb_manager/` 中的分类知识条目 |
### 首次处理(基于当前 70 篇)统计预期
| 分类 | 篇数 | 预计摘要长度 | 代表标签 |
|:-----|:----:|:-----------:|:---------|
| 社会观察 | 22 | ~2,000字 | 底层逻辑、阶层流动、AI、就业、教育内卷 |
| 政治分析 | 18 | ~1,800字 | 地缘政治、中美关系、大国博弈、社会治理 |
| 经济分析 | 14 | ~1,600字 | 财务自由、资产配置、被动收入、投资 |
| 哲学思考 | 10 | ~1,400字 | 认知升维、思维方式、方法论、阶层跃迁 |
| 历史解读 | 6 | ~1,200字 | 历史周期律、文明升维、制度分析 |
### 跨分类主题网络
```
认知升维 ──→ 社会观察(阶层流动)
│
├──→ 经济分析(财务自由系统)
│
├──→ 政治分析(大国博弈底层逻辑)
│
└──→ 历史解读(文明升维)
```
---
## 四、与现有 ORACLE 任务的依赖关系
| 现有任务 | 时间 | 与 distill 的关系 |
|:---------|:----:|:-----------------|
| `collect_profiles` | 03:00 每天 | ✅ 前置——先采集后蒸馏 |
| `vector_rebuild` | 03:30 每天 | ⚠️ 错峰——distill 改 05:00 |
| `knowledge_inbox_refine` | 04:00 每天 | ⚠️ 错峰——distill 改 05:00 |
| `git_sync` | 每15分钟 | ✅ 独立,不冲突 |
---
## 五、关键技术决策
### 为什么每天 extract 但每周 generate?
- **extract**(元数据提取):纯文本处理,每篇 < 0.1秒,70篇 < 10秒,可以每天跑
- **generate**(AI摘要):每批10篇需要 LLM 调用,10-30秒/批,7批 ~2分钟,每周一次就够了
### batch_size=10 的考量
- 10篇恰好是平均一天的产量
- 一批的 token 量约 35KB * 10 = 350KB,在 LLM 上下文窗口内
- 分批处理可以防止单批次超时
### mode=llm vs mode=extract 的区别
- `extract`:纯文本的 shell 脚本就能完成(提取元数据、关键词、字数)
- `llm`:需要 LLM 调用(写摘要、提炼概念、跨分类分析)
---
## 六、实现建议
distill action 的实现可以放在 `05_tools/07_matrix/scripts/` 下:
```bash
# scripts/distill.sh — 内容蒸馏脚本
# 用法: bash distill.sh <mode> <source_dir> <output_dir> [batch_size]
mode=${1:-extract}
source_dir=${2:-01_submissions}
output_dir=${3:-03_knowledge/00_stream}
batch_size=${4:-10}
case "$mode" in
extract)
# 遍历所有 .md,提取 front matter + 文件名元数据
# 输出 keyword_index.json
;;
llm)
# 按分类聚类 → 每类取最新篇 → LLM 摘要 → 写报告
;;
esac
```
或者封装成 `mc distill` CLI 子命令,统一走 CommandBus。
@@ -0,0 +1,373 @@
# AgentOS 联邦系统 — 全量审计报告 v1.0
> 审计日期: 2026-06-19 | 基于代码实际读取,无推断无虚构
> 审计范围: `05_tools/07_matrix/` 全部代码 + `05_tools/10_dashboard/` 关键代码 + `ORACLE.yaml`
---
## 一、项目状态总览
### 1.1 三台机器角色(来自 ORACLE.yaml)
| 机器 | IP (Tailscale) | 角色 | Dashboard Web | 职责 |
|:-----|:--------------|:-----|:-------------|:------|
| chengzigedeAir | 100.111.43.6 | **master** | ✅ localhost:9988 | 运行Dashboard + 养号 + 知识库 |
| 5kechengdeAir | 100.72.182.121 | worker | ❌ 不跑 | 养号工人机器 |
| 7kecheng | 100.65.35.28 | worker | ❌ 不跑 | 养号工人机器(大量账号) |
**Dashboard 只能通过 chengzigedeAir:9988 访问。** 用户在任意电脑浏览器打开 `http://100.111.43.6:9988` 即可操作。
### 1.2 本机身份(7个)
| 身份目录 | 所属账号 | 跨平台 |
|:---------|:---------|:-------|
| `phone_15370103682` | douyin_test + xhs_01 | ✅ 同身份跨平台 |
| `douyin_133` | douyin_133 | ❌ 仅抖音 |
| `douyin_133_2` | douyin_133_2 | ❌ 仅抖音 |
| `douyin_134` | douyin_134 | ❌ 仅抖音 |
| `douyin_test` | douyin_test | ❌ 仅抖音 |
| `test_login` | (测试) | ❌ |
| `xhs_01` | xhs_01 | ❌ |
**关键发现**: `phone_15370103682` 是唯一个真正"同身份跨平台"的身份——它的 identity_dir 同时绑定了 douyin_test + xhs_01。其他身份尚未启用跨平台模式。
### 1.3 命令执行链(从 Dashboard 到浏览器)
```
Dashboard → POST /api/ops/run (routes/ops.py)
→ CommandBus.dispatch() (services/command_bus.py)
→ MachineSession.send()
→ 本机: _send_local()
→ bash nurture_runner.sh (services/nurture_runner.sh)
→ python -m mc run (mc/cli.py → mc/run.py → mc/engine.py)
→ CDPConnector.launch() (cdp_connector.py → Camoufox)
→ BatchEngine._run_acct_on_conn()
→ DouyinOps / XhsOps (douyin_ops.py / ops/xhs_ops.py)
→ step by step from JSON blueprint
→ 远程: _send_remote()
→ SSH command to remote machine
→ remote executes same mc run flow
```
---
## 二、CLI 体系
### 2.1 `mc`(当前主命令)
定义在: `mc/cli.py` | 入口: `python -m mc`
| 子命令 | 功能 | 代码位置 |
|:-------|:-----|:---------|
| `mc run --accounts=A --blueprints=B --rounds=N` | **批量执行引擎** | `mc/run.py` → `mc/engine.py` |
| `mc account list` | 账号列表 | `mc/cli.py:cmd_account()` |
| `mc account login <name>` | 登录 | → `login_identity.py` |
| `mc account status [name]` | 登录状态 | → `matrix_mgmt.py` |
| `mc account export/import` | 导入导出 | → `matrix_mgmt.py` |
| `mc blueprint list/show` | 蓝图管理 | → `matrix_mgmt.py` |
| `mc task comment --url=...` | 定向评论任务 | → `task_engine.py` |
| `mc corpus list/add/select` | 语料库管理 | → `mc/corpus.py` |
| `mc proxy list/test/set` | 代理管理 | 预留 |
| `mc sms config/test` | SMS 配置 | 预留 |
| `mc status all/accounts/browsers` | 全局状态 | `mc/cli.py` |
### 2.2 `matrix`(旧命令,仍可用但非主入口)
定义在: `matrix.py` | 功能类似于 mc,但接口更老
| 子命令 | 说明 |
|:-------|:------|
| `matrix account list` | 列出账号(读 accounts.yaml) |
| `matrix account create` | 创建新身份 |
| `matrix account login` | 首次登录 |
| `matrix nurture run` | 养号(不同于 mc run 的执行路径) |
### 2.3 其他工具
| 文件 | 说明 |
|:-----|:------|
| `guardd.py` | 系统守护进程:每60s检测孤儿浏览器/磁盘/超时/心跳 |
| `orchestrator.py` | 养号编排器(旧版,engine.py 已替代) |
| `yanghao_runner.py` | 养号运行器(旧版启动方式) |
| `task_engine.py` | `mc task` 调度的任务引擎 |
| `task_scheduler.py` | 定时任务调度器 |
| `atom_ops.py` | 旧版原子操作定义(已废弃,ops/ 已替代) |
| `nurture_blueprint.py` | 抖音养号步序列(Python定义,`nurture_loop` 使用) |
| `cdp_connector.py` | 浏览器连接管理器(Camoufox/Chrome) |
| `browser_utils.py` | GracefulBrowser 浏览器生命周期 |
| `browser_manager.py` | 浏览器管理器(旧版) |
| `collect_homepage_info.py` | 主页信息采集 |
| `collect_batch_runner.py` | 批量采集执行器 |
| `publish_video.py` | 视频发布 |
| `login_identity.py` | 身份登录入口 |
| `vision_bridge.py` | oMLX 视觉分析桥接(2026-06-19 新加) |
| `watch_session.py` | 会话监控(2026-06-19 测试用) |
| `auth_manager.py` | 认证管理 |
| `anti_detection.py` | 反检测工具 |
| `page_state.py` | 页面状态读取 |
| `step_by_step_v2.py` | 分步执行v2(旧版) |
| `step_by_step_v3.py` | 分步执行v3(旧版) |
---
## 三、蓝图系统
### 3.1 蓝图文件(14个 JSON)
位于: `05_tools/07_matrix/blueprints/`
| 蓝图 | 平台 | 步骤数 | 说明 |
|:-----|:------|:------|:-----|
| `douyin_daily` | douyin | 23 | 日常养号:浏览/点赞/收藏/评论循环 |
| `douyin_active_v1` | douyin | 27 | 高活跃养号:多浏览+多点赞+搜索+评论 |
| `douyin_comment` | douyin | 5 | 定向评论:goto_url → watch → comment |
| `douyin_comment_test` | douyin | 5 | 定向评论测试(硬编码URL) |
| `douyin_reply` | douyin | 5 | 回复评论:找到我的评论 → 回复 |
| `douyin_search` | douyin | 14 | 搜索+浏览:搜关键词 → 浏览 → 互动 |
| `douyin_search_browse` | douyin | 7 | 搜索浏览(简版) |
| `douyin_collect` | douyin | 5 | 信息采集:搜索 → 打开主页 → 采集 |
| `douyin_read_profile` | douyin | 9 | 读主页:昵称/抖音号/关注/粉丝/获赞 |
| `xhs_daily` | xiaohongshu | 17 | 小红书日常养号 |
| `xhs_active_v1` | xiaohongshu | 26 | 小红书高活跃 |
| `xiaohongshu_read_profile` | xiaohongshu | 8 | 小红书读主页 |
| `export_douyin_01_*` | douyin | 3 | 导出任务(custom ops) |
| `export_xhs_01_*` | xiaohongshu | 4 | 导出任务(custom ops) |
### 3.2 蓝图步骤格式
```json
{"step_id": 1, "op": "goto_url", "args": {"url": "@url"}}
```
**参数模板系统**(运行时替换):
- `@url` → 从任务参数的 url 字段替换
- `@corpus` → 从语料库取文案
- `@keyword` → 从任务参数的 keyword 字段替换
- `@direction` → 评论方向(正面/提问/共鸣/感慨)
- `@scene` → 场景(first_comment/reply/repeat)
- `@comment_text` → 直接评论文本
- `@reply_text` → 回复文本
### 3.3 蓝图执行方式
**通过 `mc/engine.py` 的 `BatchEngine._run_acct_on_conn()`**:
```
1. 加载 JSON blueprint
2. 按 platform 创建 DouyinOps / XhsOps 实例
3. 导航到平台首页
4. 逐个执行步骤:ops.execute(op, args, step_id)
5. 参数替换由 _resolve_args() 处理
6. 每步间隔 1.5s
```
### 3.4 原生Python蓝图
除了 JSON,还有 `nurture_blueprint.py` 中的 `BLUEPRINT_NURTURE`(Python列表):
```python
BLUEPRINT_NURTURE = [
("进入视频", op_enter_video, {}, 1.0),
("观看", op_watch, {}, 1.0),
("点赞", op_like, {}, 0.4), # ← 概率
...
]
```
这个由 `nurture_loop()` / `nurture_daily.py` 使用。**注意这个和 JSON 蓝图是两套独立的执行路径。**
---
## 四、原子操作体系
### 4.1 当前实现(ops/ 目录)
```
ops/
├── _base.py → PlatformOps 基类 + OpResult
├── xhs_ops.py → XhsOps (16个操作) ← 小红书
└── douyin/
├── __init__.py
├── browse.py → 浏览类操作
└── interact.py → 互动类操作
douyin_ops.py → DouyinOps (20个操作) ← 抖音(另一套实现)
```
**注意**: 抖音有**两套**操作实现:
1. `douyin_ops.py` → 独立完整类(engine.py 当前使用的)
2. `ops/douyin/` → 拆分版(browse.py + interact.py,可能较新)
### 4.2 DouyinOps 支持的20个操作
| 操作 | 说明 |
|:-----|:------|
| goto_home | 回到首页 |
| goto_url | 跳转到指定URL |
| like | 点赞 |
| collect | 收藏 |
| follow | 关注 |
| open_comments | 打开评论区 |
| close_comments | 关闭评论区 |
| post_comment | 发表评论 |
| next_video | 下一个视频(ArrowDown) |
| prev_video | 上一个视频(ArrowUp) |
| search | 搜索关键词 |
| wait_watch | 等待+观看(随机时长) |
| scroll_feed | 滚动瀑布流 |
| open_video | 点开视频 |
| wait | 等待 |
| go_back | 返回 |
| goto_profile | 去用户主页 |
| read_profile_field | 读主页字段 |
| read_my_comments | 读我的评论 |
| reply_comment | 回复评论 |
| search_browse | 搜索+浏览 |
### 4.3 XhsOps 支持的16个操作
| 操作 | 说明 |
|:-----|:------|
| xhs_goto_home | 回到首页 |
| xhs_browse | 浏览(已在首页则跳过) |
| xhs_scroll_feed | 滚动瀑布流 |
| xhs_click_note | 点击笔记 |
| xhs_like | 点赞 |
| xhs_collect | 收藏 |
| xhs_comment | 评论 |
| xhs_post_comment | 发表评论 |
| xhs_follow | 关注 |
| xhs_search | 搜索 |
| xhs_goto_profile | 去用户主页 |
| xhs_read_nickname | 读昵称 |
| xhs_read_user_id | 读用户ID |
| xhs_read_following | 读关注数 |
| xhs_read_fans | 读粉丝数 |
| xhs_read_likes | 读获赞数 |
| xhs_read_bio | 读个人简介 |
### 4.4 平台操作基类接口
```python
class OpResult:
op: str # 操作名
step_id: int # 步骤编号
success: bool
detail: str # 简短描述
elapsed: float # 耗时(秒)
error: str # 失败原因
class PlatformOps(ABC):
async def execute(self, op, args, step_id) -> OpResult # 统一入口,自动重试
async def _do_execute(self, op, args, step_id) -> OpResult # 子类实现
```
---
## 五、命令分发系统
### 5.1 CommandBus (services/command_bus.py)
| 方法 | 功能 |
|:-----|:------|
| `CommandBus.dispatch(type, accounts, params)` | 统一入口,按机器分组 |
| `CommandBus.get_status(machine, account)` | 查询命令状态 |
| `CommandBus.get_all_machines_status()` | 所有机器聚合状态 |
| `CommandBus.cancel(run_id)` | 取消命令 |
**MachineSession** (每机器一个):
| 方法 | 功能 |
|:-----|:------|
| `send(cmd)` | 本地→`_send_local` / 远程→`_send_remote` |
| `preflight()` | SSH可达? 活跃命令<3? 资源检查 |
| `poll(cmd)` | 轮询结果(本地读文件/远程SSH读取) |
| `cancel(cmd)` | 取消命令(本地pkill/远程SSH pkill) |
| `graceful_exit()` | 优雅退出+清理 |
### 5.2 结果文件格式
```
runtime/nurture/results/{run_id}.json
```
```json
{
"run_id": "nurture_1234567890_douyin_test",
"account": "douyin_test",
"blueprint": "douyin_daily",
"status": "completed",
"hostname": "chengzigedeAir",
"steps": {"total": 23, "success": 21, "failed": 2},
"duration_secs": 452
}
```
---
## 六、配置文件体系
| 文件 | 用途 | 覆盖范围 |
|:-----|:------|:---------|
| `ORACLE.yaml`(根目录) | 宪法:机器定义/账号分配/任务计划/全局配置 | 三台机器只读 |
| `accounts_registry.yaml`(07_matrix/) | 账号注册表:每个账号的机器归属/平台/窗口位置 | 三台机器同步 |
| `config_template/accounts.yaml` | 账号配置模板 | 按需部署到 config/ |
| `config_template/sms.yaml` | SMS API 配置模板 | 按需部署到 scripts/config/ |
| `config_template/screen_layout.yaml` | UI 布局参数(评论框坐标等) | 按需部署 |
| `config_template/schedule.yaml` | 定时任务模板 | 按需部署 |
| `scripts/config/sms.yaml` | 实际运行的 SMS 配置 | 本机生效 |
| `scripts/config/schedule.yaml` | 实际运行的定时任务 | 本机生效 |
| `scripts/config/comment_corpus.yaml` | 评论语料库 | 本机生效 |
---
## 七、守护进程
| 进程 | 启动方式 | 功能 |
|:-----|:---------|:-----|
| `guardd` | launchd 守护 | 每60s检测:孤儿浏览器/磁盘<5GB/Dashboard存活/命令超时30min/浏览器数>3 |
| `Dashboard` | launchd 守护 (端口9988) | FastAPI Web服务 |
| `socks5-forwarder` | launchd 守护 (端口10800) | SOCKS5 代理转发 |
guardd 检测结果写入 `runtime/guardd/events.log`,心跳推送到 `localhost:9988/api/push/heartbeat`。
---
## 八、语料库体系
| 文件 | 格式 | 用途 |
|:-----|:------|:------|
| `corpus/douyin.yaml` | YAML | 抖音语料(已定义) |
| `corpus/xiaohongshu.yaml` | YAML | 小红书语料(已定义) |
| `scripts/config/comment_corpus.yaml` | YAML | 运行时评论语料库(实际使用) |
`CorpusManager` 类 (`mc/corpus.py`) 提供:
- `get_comment_for_video(title, direction, account_id)` → 根据视频标题和方向选文案
- `get_comment_for_scene(persona, scene, keyword, round_num)` → 按场景选文案
---
## 九、关键依赖版本
| 组件 | 版本 | 路径 |
|:-----|:------|:------|
| Python | 3.13.12 | `~/.workbuddy/binaries/python/envs/agent-os/bin/python3` |
| Camoufox | 0.4.11 | agent-os venv |
| Playwright | 1.58.0 | agent-os venv |
| FastAPI | (在 requirements.txt) | agent-os venv |
| uvicorn | (在 requirements.txt) | agent-os venv |
---
## 十、代码清理建议
以下文件经检查为**废弃/归档状态**,不应再被主动使用:
| 文件 | 被谁取代 | 建议处理 |
|:-----|:---------|:--------|
| `matrix.py` 整体 | `mc/` | 归档到 `archive/` |
| `atom_ops.py` | `ops/_base.py` + `DouyinOps`/`XhsOps` | 归档 |
| `nurture_blueprint.py ` 的 `BLUEPRINT_NURTURE` | `blueprints/*.json` + `engine.py` | 保留(nurture_loop 仍在用) |
| `yanghao_runner.py` | `mc run` 命令 | 归档 |
| `orchestrator.py` | `mc/engine.py` | 归档 |
| `step_by_step_v2.py` / `step_by_step_v3.py` | `engine.py` | 归档 |
| `archive/` 内全部 | (已在 archive) | 保持不动 |
| `browser_manager.py` | `cdp_connector.py` | 保留(CommandBus 可能引用) |
| `xhs_session_test.py` / `watch_session.py` | 测试文件 | 删除或归档 |
@@ -0,0 +1,430 @@
# AgentOS 任务编排与调度架构 v1.0
> 版本: 1.0 | 日期: 2026-07-04 | 基于全部现有代码审计 + 需求讨论
> 前置阅读: `PLANS/SCHEDULER_ARCHITECTURE_v3.md`(调度引擎原始设计)
> 本文件替代: 旧版调度设计中的 Phase 2/3 部分,整合为新架构
---
## 一、设计目标
| 目标 | 说明 |
|:-----|:------|
| **评论与视频内容关联** | 评论不再随机,根据视频标题/标签匹配行业语料 |
| **账号行业隔离** | 大健康账号发健康评论,通用账号发通用评论,互不串 |
| **三优先级调度** | P0优先/P1日常/P2劣后,插队不中断浏览器 |
| **账号互斥** | 同一账号不能同时出现在两个浏览器 |
| **中央分析+远程执行** | Master统一做视频分析/分类/选评论,Worker只执行 |
---
## 二、最小任务单元
### 2.1 定义
```
最小任务单元 = {account_id, operation_type, params, machine, priority}
```
一个任务单元 = 一个账号 × 一次浏览器操作的组合,不可再拆。
### 2.2 任务类型
| operation_type | 说明 | 默认优先级 | 来源 |
|:---------------|:-----|:-----------|:-----|
| `smart_comment` | 智能评论(带视频分析+行业匹配) | P0 | Dashboard 提交 |
| `comment` | 定向评论(已有模式) | P0 | Dashboard / CLI |
| `nurture` | 日常养号 | P1 | 定时任务 / 手动 |
| `collect` | 信息采集 | P2 | 手动 / 定时 |
| `like` | 点赞互动 | P1 | 蓝图 |
| `login` | 登录(特殊,不走调度器) | - | 单独处理 |
### 2.3 任务状态
```
PENDING → QUEUED → RUNNING → COMPLETED
↓ ↓
FAILED CANCELLED
```
---
## 三、三层编排体系
### 3.1 系统分层
```
用户提交(Dashboard / API)
│
▼
┌── L3: Master 中央编排 ──────────────────────────────┐
│ (chengzigedeAir) │
│ │
│ ① 接收任务(url列表 + 账号列表 + 操作类型) │
│ │
│ ② 视频分析(本机浏览器提取信息) │
│ ├─ 标题 / 描述 / 标签 │
│ ├─ 关键词匹配 → 分类(医疗健康 / 通用) │
│ └─ 从对应语料池选评论 │
│ │
│ ③ 拆解为最小单元 │
│ {douyin_133, comment, url, "医生讲得很清楚"} │
│ │
│ ④ 按机器打包 │
│ 7kecheng → [5个单元] │
│ 5kechengdeAir → [3个单元] │
│ │
│ ⑤ POST /scheduler/submit → 各机 guardd │
└────────────────────────────┬──────────────────────────┘
│ Tailscale
▼
┌── L2: 各机 guardd 调度器 ──────────────────────────┐
│ (7kecheng / 5kechengdeAir) │
│ │
│ 收到大包 → 展开为独立任务 │
│ │
│ 三队列管理: │
│ P0 优先: 智能评论、定向操作(当前任务结束后插队) │
│ P1 日常: 养号、点赞(FIFO 正常排队) │
│ P2 劣后: 采集、同步(slot 空闲才执行) │
│ │
│ 账号互斥守卫 │
│ │
│ 3 Slot 流水线 │
│ slot0: [P1→P1→P1] │
│ slot1: [P1→P0→P1] ← P0插队 │
│ slot2: [P2→空闲→P2] ← P2填空 │
└──────────────────────────────────────────────────────┘
```
### 3.2 各程序职责
| 节点 | 程序 | 职责 |
|:-----|:------|:------|
| **Master** | CommandBus | 接收请求→拆解→按机器分组→分发 |
| **Master** | VideoAnalyzer 🆕 | 视频URL分析、行业分类、选评论 |
| **Master** | Dashboard API | 前端界面、健康监控 |
| **Worker** | guardd HTTP Server | 接收任务、返回状态 |
| **Worker** | Scheduler 🆕改 | 三队列管理、3 slot流水线、P0抢插、账号互斥 |
| **Worker** | Executor | 子进程执行(mc run / mc task comment) |
| **Worker** | SlotManager | 浏览器槽位管理、进程监控 |
| **Worker** | HeartbeatReporter | 每15秒上报slot/队列/账号状态到Dashboard |
---
## 四、三队列调度算法
### 4.1 队列结构
```python
class Scheduler:
# 三个独立优先队列
queue_priority = PriorityQueue() # P0: 智能评论/定向操作
queue_normal = PriorityQueue() # P1: 养号/点赞/日常
queue_filler = PriorityQueue() # P2: 采集/同步/劣后
# 3 条流水线
active_tasks: dict[int, dict] # {slot_id: task}
# 账号互斥表
account_slots: dict[str, int] # {account_id: slot_id}
# 被 P0 打断的 P1 任务暂存
paused_tasks: dict[int, dict] # {slot_id: task}
```
### 4.2 调度循环(每15秒)
```
run_cycle():
step 1: 检查所有 slot
任务完成 → 释放 slot + 从 account_slots 中移除账号
step 2: 检查暂停队列
有被 P0 打断的 P1 任务 → 放回日常队列恢复
step 3: 分配空闲 slot
for slot_id in [0, 1, 2]:
if slot 正在运行: continue
# 取当前活跃账号列表
busy = set(account_slots.values())
# 按优先级取任务(避开 busy 账号)
task = pop_available(P0优先, P1日常, P2劣后)
if task:
account_slots[task.account] = slot_id
start_execution(slot_id, task)
```
### 4.3 P0 抢占逻辑
```
收到 P0 任务 → 检查目标账号:
├─ 空闲 → 直接分配给空闲 slot
└─ 忙碌 → 等到当前任务结束后插入:
slot0: [P1养号_01, ▶️P0评论, P1养号_02, P1养号_03]
↑ P1完成后立即执行P0
P0完成后恢复P1队列
不中断正在执行的浏览器(不强行 kill 进程)
```
### 4.4 P2 劣后逻辑
```
P2 只在 slot 空闲且 P0/P1 都为空时才执行
P2 可被任何 P0/P1 抢占:
slot2: [▶️P2采集] → 收到P1养号 → P2回队列 → [▶️P1养号] → P1完成 → [▶️P2采集]
```
---
## 五、账号互斥守卫(三层检查)
### 5.1 检查层级
| 层级 | 位置 | 检查内容 | 阻止时机 |
|:-----|:------|:---------|:---------|
| 第1层 | `submit_task()` | 该账号在 task_store 中是否有 running/queued 状态 | 入队时拒绝 |
| 第2层 | `_schedule_all_slots()` | 该账号在 `account_slots` 表中是否存在 | 分配时跳过 |
| 第3层 | `slot_manager.find_account()` | 该账号是否已打开浏览器 | 执行前拦截 |
### 5.2 账号状态表
```python
account_slots = {
"douyin_133": 0, # slot 0 正在运行
"douyin_134": 1, # slot 1 正在运行
# "douyin_135" → 不在表中 = 空闲
}
```
任务完成自动移除,异常崩溃时 scheduler 清理。
---
## 六、视频分析引擎(VideoAnalyzer)
### 6.1 模块说明
```
新建文件: agent-sync/05_tools/10_dashboard/services/video_analyzer.py
运行位置: 仅 Master(本机),Worker 不需要
使用技术: Camoufox 浏览器(已有)+ 关键词匹配(已有)
```
### 6.2 核心逻辑
```python
class VideoAnalyzer:
"""视频分析器:提取信息 → 行业分类 → 选评论"""
# 行业关键词映射
INDUSTRY_TAGS = {
"medical": ["医生","医院","药","健康","养生","中医","体检",
"症状","治疗","康复","营养","饮食","锻炼","专家"],
"finance": ["股票","基金","理财","投资","经济","A股","财经"],
"tech": ["手机","数码","电脑","科技","AI","人工智能","评测"],
"food": ["美食","做饭","菜谱","餐厅","好吃","探店"],
}
async def analyze(self, url: str) -> VideoContext:
"""分析单个视频URL
1. Camoufox 浏览器打开 URL
2. 提取: 标题(document.title) / meta描述 / 标签
3. 读取评论区热门评论(可选)
4. 返回 VideoContext
"""
def classify(self, context: VideoContext) -> str:
"""分类行业"""
for ind, tags in INDUSTRY_TAGS.items():
if any(tag in context.title for tag in tags):
return ind
return "general" # 兜底
def pick_comment(self, industry: str, account_industry: str, direction: str) -> str:
"""选评论
账号行业匹配视频行业 → 行业语料
不匹配 → 万能语料
"""
```
### 6.3 与现有能力的关系
| 现有能力 | 是否使用 | 说明 |
|:---------|:---------|:------|
| **Camoufox + Playwright** | ✅ 直接使用 | 已有,打开视频页取信息 |
| **douyin_ops.goto_url()** | ✅ 直接使用 | 已有,导航到指定URL |
| **CorpusManager** | ✅ 改造使用 | 加行业过滤 + 万能池 |
| **Scrapling / Crawl4AI** | ❌ 不使用 | 抓不了抖音动态内容 |
| **ChromaDB (agent-local/vector_db/)** | ⚠️ 可选 | Phase 2 加向量分类时可复用 |
---
## 七、语料库结构
### 7.1 两层语料池
```yaml
# corpus/douyin.yaml
categories:
# ── 万能池(所有账号可用,不匹配行业时兜底)──
万能称赞:
accessible: "*"
comments:
- 博主说得很对
- 讲得不错,学到了
- 分析得很到位
万能提问:
accessible: "*"
comments:
- 请问这个怎么学?
- 大概需要多长时间?
万能共鸣:
accessible: "*"
comments:
- 太真实了
- 说出了我的心声
# ── 行业池(仅对应行业账号可用)──
大健康称赞:
accessible: ["health"]
match_tags: ["医生","医院","药","健康","养生","中医","体检","症状"]
comments:
- 医生讲得很清楚,通俗易懂
- 这个方子很实用,收藏了
- 讲得很专业,学到了
大健康提问:
accessible: ["health"]
comments:
- 这个症状一般怎么处理?
- 平时饮食有什么需要注意的?
```
### 7.2 账号行业标记
```json
// profiles.json
{
"douyin_133": {"nickname":"苏州胃肠体检敏敏", "industry":"health"},
"douyin_test": {"nickname":"小美养生茶", "industry":"health"},
"douyin_134": {"nickname":"在苏州呀", "industry":"general"},
"xhs_01": {"nickname":"...", "industry":"general"}
}
```
两种行业:`health`(大健康)、`general`(通用)。现阶段统一。
---
## 八、完整数据流示例
### 场景:提交 20 个账号评论 1 个视频
```
Step 1: Master 收到请求
POST /api/ops/run {type:"smart_comment", urls:["https://..."], accounts:[...]}
↓
Step 2: VideoAnalyzer 分析视频
本机 Camoufox 打开视频URL
→ 标题: "胃镜检查到底疼不疼?医生告诉你真相"
→ 关键词匹配: "医生"、"胃" → industry: medical
→ 选评论: "医生讲得很清楚,通俗易懂"
↓
Step 3: 拆解最小单元
20个账号 × 1个视频 = 20个任务单元
每个单元 = {account_id, comment:"医生讲得很清楚", url, priority:P0}
↓
Step 4: 按机器打包
查 ORACLE 账号→机器分配表:
7kecheng → 12个账号 → 12个单元
5kechengdeAir → 8个账号 → 8个单元
↓
Step 5: 分发到各机 guardd
POST http://100.65.35.28:9090/scheduler/submit (12个P0任务)
POST http://100.72.182.121:9090/scheduler/submit (8个P0任务)
↓
Step 6: 各机 scheduler 处理
7kecheng:
slot0: [P1养号, P1养号, P1养号] (正在执行)
slot1: [P1养号, P1养号, P1养号]
slot2: [P2采集, P2采集]
插入 P0 评论包:
slot0: [P1养号, ▶️P0评论×4, 恢复P1养号]
slot1: [P1养号, ▶️P0评论×4, 恢复P1养号]
slot2: [▶️P0评论×4, P2采集, P2采集]
↓
Step 7: 各账号打开视频 → 贴预选评论 → 验证
(Worker 只做这一步,不做任何分析)
```
---
## 九、要改的文件清单
### Phase 1:队列改造(核心)
| 文件 | 改动 | 工作量 |
|:-----|:------|:-------|
| `guardd/modules/scheduler.py` | 三队列分立 + P0抢插 + P2填空 + 账号互斥表 | 大(~200行) |
| `guardd/modules/priority_queue.py` | 现有类不需要大改,加`pop_if()`方法 | 小(~20行) |
### Phase 2:语料重组
| 文件 | 改动 | 工作量 |
|:-----|:------|:-------|
| `corpus/douyin.yaml` | 万能池 + 行业池 分层结构 | 中(重组) |
| `scripts/mc/corpus.py` | `get_comment_for_video()` 加行业过滤 + 万能兜底 | 中(~50行) |
| `profiles.json` | 各账号加 `industry` 字段 | 手动 |
### Phase 3:视频分析 + 智能评论
| 文件 | 改动 | 工作量 |
|:-----|:------|:-------|
| **新建** `services/video_analyzer.py` | 视频分析+行业分类+选评论 | 中(~150行) |
| `services/command_bus.py` | CMD_REGISTRY 加 `smart_comment` 类型 | 小(~20行) |
| `routes/ops.py` | 加智能评论端点 | 小(~10行) |
### Phase 4:指挥台展示(可选)
| 文件 | 改动 | 工作量 |
|:-----|:------|:-------|
| `frontend/views/ops-command.js` | 显示三队列 + P0/P1/P2 过滤 | 中(~80行) |
---
## 十、回退方案
| 标签 | commit | 说明 |
|:-----|:--------|:------|
| `pre-task-architecture` | `7d2b5b14d` | **改架构前的完整备份** |
| `stable-ba34e3d56` | `ba34e3d56` | 再往前的稳定版 |
| `pre-fix-backup` | 略 | 更早备份 |
```bash
# 回退命令
git checkout pre-task-architecture
git push origin --force HEAD:main
```
---
## 十一、暂不处理
| 事项 | 原因 |
|:-----|:------|
| 三级接力评论 | 需求暂缓 |
| 向量模型分类 (ChromaDB) | Phase 2 可选,关键词匹配先行 |
| 视频内容深度分析(字幕/画面) | 复杂度高,当前只分析标题+描述 |
| AI 生成评论(大模型) | 需配置 API key,后续可加 |
| 评论风格跟随热门评论 ("跟风") | 后续可加 |
@@ -0,0 +1,74 @@
# 20 秒测试片剧本(音频先行 + 对口型 验证用)
> 目的:验证 P1(音频先行)+ P3(对口型)链路
> 结构:**2 个空镜(不说话)+ 2 个角色说话镜头**(口型同步)
> 成本:画面约 ¥5~10(可灵)· 对口型 ¥0(走 1800 秒免费额度)· TTS 几分钱
---
## 分镜表
| # | 类型 | 时长(音频先行后会调整) | 画面 | 台词 | 出场人物 |
|---|---|---|---|---|---|
| shot_01 | 空镜 | 5s | 病房窗外,晨光透过百叶窗在地面投出条纹,窗帘轻微飘动,**画面里没有人** | — | — |
| shot_02 | 角色说话 | 5s(按音频调) | 病人半躺在病床上,正面近景,对着镜头说话,表情轻松 | 我住院第三天了,前两天刚做完手术。 | 主角 |
| shot_03 | 角色说话 | 5s(按音频调) | 病人微笑看着镜头,稍微侧了一下头 | 说实话,真没想象中那么可怕。 | 主角 |
| shot_04 | 空镜 | 5s | 病房走廊尽头,护士推着车经过,画面虚焦 | — | — |
预计成片:**约 18~20 秒**
---
## 演员表配置
| 代号 | 角色资产 | 音色(voice_id) | 说明 |
|---|---|---|---|
| 主角 | (选你已建的角色,如「害羞美女患者」或新建) | `longanyang`(阳光大男孩)或按角色性别选 | 音色决定口型用的声音 |
> 💡 音色建议:`longanyang`(年轻男主)· `longxing_v3`(温婉邻家女)· `longqiang_v3`(御姐)
> 完整清单见 `09_ave/docs/cosyvoice_voices.md`
---
## 关键要求(对口型的硬条件)
VideoRetalk 对输入有要求,**我们的参数都能满足**:
| 要求 | 我们的情况 |
|---|---|
| 视频:正面近景、人脸清晰 | ✅ 分镜写"正面近景对镜头说话" |
| 视频:2~120 秒 | ✅ 单镜头 5s |
| 视频:15~60fps、边长 640~2048 | ✅ 我们生成 1080×1920@30fps |
| 音频:干净人声(无 BGM/噪音) | ✅ TTS 产物天然纯净 |
⚠️ **注意**:说话镜头必须是**正面/近景**——大角度侧脸或人脸太小会影响对口型效果。
---
## 操作步骤
```
1. 导演台 → 粘贴上面的"分镜表"作为故事/文案(或按它写一段文案)
2. 🎭 AI 分析这场戏需要什么 → 演员表绑定角色 + 指定音色
3. 生成分镜 → 在卡片里逐镜确认:
· shot_02/03 填台词 + 勾「出场人物: 主角」
· shot_01/04 台词留空、出场人物不勾(= 空镜)
4. 勾选 [✓] 🎙 音频先行 [✓] 🎭 对口型 → 点「🎥 生成成片」
5. 完成后 → 「📋 生产记录」→ 🎙 加配音 → 听口型效果
```
## 验证要点(跑完检查这几项)
- [ ] **音频先行生效**:日志里 shot_02/03 的时长被按台词音频调整过(≠ 原 5s)
- [ ] **镜头时长各不相同**:跟台词长短走
- [ ] **对口型只作用在 shot_02/03**:日志显示 2 个镜头做了,shot_01/04 跳过
- [ ] **口型对上**:播放时人在说那句话,嘴型明显匹配
- [ ] **失败兜底**:若对口型失败,日志提示"保留原片段",成片仍完整
## 成本记录(跑完填这里,用于校准后续估算)
| 项 | 预估 | 实际 |
|---|---|---|
| 画面生成(可灵 4 镜头) | ¥5~10 | |
| 对口型(约 10 秒) | ¥0(免费额度) | |
| TTS | 几分钱 | |
@@ -0,0 +1,112 @@
# 视频工厂能力现状审计(2026-10-02)
> 回答「是不是缺东西」—— 逐项列出**能用 / 不能用 / 待接**,以及缺的具体是什么
> 基准:三端 `a2b367973`
---
## 一、能力层(25 个注册能力)
**状态**:✅ 可用 19 · 🟡 部分可用 3 · ⚪ 规划中 3
### 执行器已接入(8 个 —— 流程里能自动跑)
| 能力 | 用途 | 依赖 | 状态 |
|:--|:--|:--|:--|
| `storyboard_plan` 分镜规划 | 故事 → 分镜 | LLM(DeepSeek) | ✅ |
| `prompt_gen` 提示词生成 | 分镜 → 六模块提示词 | 无 | ✅ |
| `text_to_video` 视频生成 | 提示词 → 视频 | **可灵**(已配) | ✅ |
| `video_concat` 视频合成 | 片段 → 去AI化 → 拼接 → 混流 | FFmpeg | ✅ |
| `tts_generate` 语音合成 | 文本 → 音频 | **阿里百炼**(已配) | ✅ |
| `material_search` 素材搜索 | 关键词 → 素材 | **Pexels**(已配) | ✅ |
| `music_select` BGM 选择 | 风格 → BGM | 本地音乐库 | ✅ |
| `subtitle` 字幕生成 | 台词 → ASS 字幕 | FFmpeg | ✅ |
### 注册但执行器未接入(流程中**明确跳过并说明原因**,不会静默失败)
`script_generate`(映射已连但实现待补)· `image_to_video` 图生视频 · `text_to_image` 文生图 ·
`person_swap` 人物置换 · `lipsync` 对口型 · `vfx_apply` 特效 · `comfyui_workflow` · `character_3d`
---
## 二、模型与供应商(配置现状)
| 供应商 | 用途 | 配置 | 状态 |
|:--|:--|:--|:--|
| **可灵 Kling** | 视频生成 / 图片生成 | ✅ 已配 | **视频 ✅ 可用**;**图片 ⚠️ 额度不足**(需单独充值) |
| **阿里百炼** | TTS / 人物置换 | ✅ 已配(已充值) | ✅ 可用 |
| **DeepSeek** | 文本(剧本/分镜/评论) | ✅ 已配 | ✅ 可用 |
| **Pexels** | 素材搜索 | ✅ 已配 | ✅ 可用 |
| 火山方舟(即梦) | 图片/视频备选引擎 | ⚪ 未配 / 模型名待确认 | ⚪ 待接 |
| fal.ai | 对口型(Kling Lipsync) | ❌ 未配 | ⚪ 待接 |
---
## 三、资产库(11 类,全部可用)
角色 · 场景 · 真实场地 · 产品 · 道具 · 服装 · 音色 · BGM · 音效 · 特效预设 · 素材
**每类都具备**:搜索/筛选/排序 · 卡片/表格视图 · 编辑字段(**含下拉建议**)· 上传参考图 · **🎨 AI 生成参考图** · 删除
**角色生成器**(专门页面):**10 层 61 字段**(44 个下拉)+ 5 视角 + 引擎选择
---
## 四、导演系统(已接 2 个)
| 导演 | 类型 | 状态 |
|:--|:--|:--|
| `legacy_scene_planner` | 本地分镜 | ✅ 可用 |
| `storyboard_v52`(AI Storyboard Director v5.2) | 技能型 | ✅ 可用(技能文档已入库) |
| ?用户提到的**另 2 种** | — | ⏳ **需名称 / 来源** |
---
## 五、缺什么(明确清单)
| # | 缺的东西 | 影响 | 补法 |
|:--|:--|:--|:--|
| 1 | **可灵「图片生成」额度** | 定妆照 / 资产参考图生成不可用(视频额度不通用) | 可灵开放平台**单独充值图片生成** |
| 2 | **`fal.api_key`** | 口型同步(`lipsync`)不可用 | 申请 fal.ai key → 🔑 API 配置 |
| 3 | **另 2 个导演系统** | 只能选 2 种分镜风格 | 提供名称/来源(接入约 3 步) |
| 4 | **人脸表情精细控制** | 目前只能靠提示词描述 | 接 **ComfyUI**(表情/风格精细)或等可灵支持 |
| 5 | `script_generate` 实现 | 流程里「剧本改编」节点会跳过 | 补实现(约 20 行,复用 LLM) |
| 6 | 火山方舟(即梦) | 少一个图片/视频备选引擎 | 控制台确认模型名后接入 |
| 7 | `person_swap` 参数接入 | 「人物置换」流程节点会跳过 | 补实现(API 与代码已存在) |
---
## 六、现在就能跑的(已验证)
### ✅ 完整可用 ①:口播视频(素材版,**零生成费用**)
```
脚本 → 素材(Pexels) → TTS(阿里) → 字幕 → 混流成片
```
**实测**:20 秒出片 · 3.21MB / 12.46 秒 / 1080x1920 · **含音轨 + 字幕烧录** ✓
### ✅ 完整可用 ②:分镜驱动视频(可灵版,**按镜头计费**)
```
脚本 → 分镜(v5.2) → 可灵逐镜头生成 → 去AI化 → 拼接 → 混流
```
**实测**:3 镜头 **1.9 分钟**(并发生成)· 成片 3.2MB ✓
### ✅ 可用:流程画布
6 个模板 + 节点状态徽章 + 产物预览(视频可播)+ 🔄 重做 + ▶️ 从此起跑 + ⏹ 停止 + **生成前费用确认**
### ✅ 可用:分镜透明化
「🎬 预览生成方案」→ 逐镜头看 **提示词 / 能力 / 引擎 / 参数**(**零费用**)
### ✅ 可用:通知与产物中心
任务完成右上角通知 + 「📋 生产记录」页可播全部产物
---
## 七、建议优先级(我的判断)
| 优先级 | 事项 | 理由 |
|:--|:--|:--|
| 🔴 高 | **可灵图片充值** | 角色/场景参考图是"资产先行"的前提,没有参考图流程就不完整 |
| 🟡 中 | 另 2 个导演系统接入 | 分镜质量多样性(你明确提过) |
| 🟡 中 | `script_generate` + `person_swap` 实现 | 两个流程节点目前会跳过(代码量小) |
| ⚪ 低 | fal.ai 口型 / ComfyUI 表情 | 精细控制,主流程跑顺后再做 |
| ⚪ 低 | 火山方舟即梦 | 备选引擎,可灵够用时不急 |
@@ -0,0 +1,526 @@
# 视频工厂 · 总体架构 v2.0(唯一权威版)
> 创建:2026-10-01 | 状态:**讨论中,待确认后动手**
> 本文档**替代**此前的 `VIDEO_FACTORY_FRAMEWORK.md` / `VIDEO_FACTORY_ARCHITECTURE.md` / `DCS_VIDEO_FACTORY_PLAN.md`(已归档,见文末)
> 原则:**流程是主角,能力是零件,资产是原料** —— 三者是引用关系,不是平级菜单
---
## 〇、一句话
> 我进「流程」做一件事(口播 / 短剧 / 导演创作…)→ 流程由若干「节点」串成 → 每个节点是一个「能力」(可换、可配、可调模型)→ 执行后**每一步都能看结果、能改、能重做** → 产物出片。
> 「资产底座」(角色 / 场景 / 道具 / 产品 / 音色…)是所有流程共用的原料库。
---
## 一、三层模型(核心,先看这张)
```
┌─────────────────────────────────────────────────────────────┐
│ 【流程】Process / Template —— 我要做的一件事 │
│ 导演创作 · 口播 · 卡点视频 · 角色叙事 · 数字人口播 │
│ 口播+混剪 · 短剧创作 · 人物置换 · …(可扩展、可自建) │
│ │
│ 流程 = 节点串(每个节点 = 一个能力 + 该节点的配置) │
│ 可预制(原来的 6 条)· 可自建(拖节点拼)· 节点可替换 │
└──────────────────────────┬──────────────────────────────────┘
│ 节点引用能力
▼
┌─────────────────────────────────────────────────────────────┐
│ 【能力】Capability —— 解决"一个环节"的最小可执行单元 │
│ 语音合成(文字→音频)· 文生图(文字→图片)· 图生视频 │
│ 音色提炼(音频→音色)· 去AI化 · 拼接/变速/转场 · 字幕 │
│ 分镜规划 · 提示词生成 · 审核门 · 导演编排(元能力)… │
│ │
│ 每个能力都有:默认设置 + 可调整参数 + **可选不同大模型** │
│ 同一个环节可以有多个能力可选(要声音:调库音色 / AI提炼音色 /│
│ 文字直转),节点上可**替换** │
│ │
│ 能力分两类用途: │
│ ① 产出型(生成资产):角色生成 / 背景生成 / 音色提炼 … │
│ ② 处理型(流程节点):TTS / 生图 / 生视频 / 合成 … │
└──────────────────────────┬──────────────────────────────────┘
│ 产物落入 / 被引用
▼
┌─────────────────────────────────────────────────────────────┐
│ 【资产底座】Assets —— 共用原料库(所有流程共享) │
│ 角色 · 场景/背景 · 道具 · 产品 · 服装 · 音色 · BGM · 音效 │
│ 特效预设 · 风格 · … │
│ (字段与分类:**待你给出**,见第九节) │
└─────────────────────────────────────────────────────────────┘
```
**关键结论**:
- **导演创作 = 一条流程**(不是独立板块)
- **人物置换 = 一条流程**(选人→换人),不属于资产
- **工作流 = 流程本身**(画布是流程的编辑/查看形式)
- **资产 ≠ 能力**:资产是"原料"(角色图、音色文件),能力是"做事的手"(生成、合成、转换)
---
## 二、前端信息架构(一二级菜单)
```
🎬 视频工厂 ← 一级:大模块
│
├─ 📦 资源库 ← 二级:基础底座(原料)
│ ├─ 🧑 角色库 角色筛选/生成/引用
│ ├─ 🏞️ 场景库 AI 生成场景
│ ├─ 🏙️ 真实场地库 实拍参考(多角度图 + 视频)
│ ├─ 🧰 道具库
│ ├─ 📦 产品库 含 must_keep 必保特征
│ ├─ 👗 服装库
│ ├─ 🔊 音色库 音色样本 + 音色 ID(可从音频提炼)
│ ├─ 🎵 BGM 库
│ ├─ 💥 音效库
│ └─ ✨ 特效预设库 子弹时间/环绕/慢动作(参数模板)
│
├─ 🎞️ 流程 ← 二级:做事入口(模板)
│ ├─ 🎬 导演创作 ★ 剧本→分镜→逐镜头配置→生成→成片
│ ├─ 🎭 短剧创作 故事→脚本→角色→分镜→场景→配音→字幕→成片(原有,12 节点)
│ ├─ 🎙️ 基础口播 脚本→TTS→素材→BGM→输出(原有)
│ ├─ 🥁 卡点视频 BGM→卡点风格→审核→输出(原有)
│ ├─ 📖 角色叙事 剧本→改编→角色→策略→生成→旁白→审核→输出(原有)
│ ├─ 👤 数字人口播 文案→人声→数字人角色→数字人视频(原有)
│ ├─ 🎞️ 口播+混剪 口播脚本→人声→混合风格→混合视频(原有)
│ ├─ 🔄 人物置换 选源人物→选目标人物→换人→出片
│ └─ ➕ 新建流程 从能力库拖节点自建
│
├─ 🧩 能力中心 ← 二级:能力配置
│ ├─ ⚙️ 能力配置 25 能力 × 供应商 × 模型 × 参数默认值
│ ├─ 🔌 供应商管理 各能力可选哪些供应商 + 密钥状态
│ └─ 🧪 能力试跑 单独测某个能力(不跑整条流程)
│
└─ 📊 运营 ← 二级:辅助
├─ 📋 生产记录 每次跑流程的记录(产物/耗时/状态)
├─ 💰 费用统计 按能力/供应商/项目统计
├─ 🕐 历史操作 谁在什么时候改了什么
└─ ⚙️ 视频工厂设置 全局默认(去AI化参数/输出规格…)
```
**设计原则**:
- **一级只有 4 个**:资源库(原料)· 流程(做事)· 能力中心(零件)· 运营(辅助)
- **二级是具体库/流程**(可继续扩)
- 你**日常只用「流程」**(选一条 → 画布 → 执行);资源库/能力中心是**配置时**才去
### 2.1 🧑 角色库细化(重点,按你的要求)
**列表页**
```
🔍 [搜索名字/标签] 筛选:类型▾ 用途▾ 项目▾ 标签▾ 有音色☐ 有LoRA☐ 排序:最近使用▾
────────────────────────────────────────────────────────────
卡片视图(默认):
┌─────────┐ ┌─────────┐ ┌─────────┐
│ [缩略图] │ │ [缩略图] │ │ [缩略图] │
│ 阿远 │ │ 小漫 │ │ 患者A │
│ 真人·主角│ │ 动漫·配角│ │ 真人·主角│
│ 用过 12 次│ │ 用过 3 次│ │ 用过 8 次│
└─────────┘ └─────────┘ └─────────┘
表格视图:名字 | 类型 | 用途 | 音色 | 参考图数 | 使用次数 | 更新时间
批量操作:☑多选 → 加标签 / 导出 / 删除
```
**角色详情页**
```
[基本信息] 名字 · 类型(真人/动漫/3D) · 用途(主角/配角/群演) · 项目 · 标签 · 一致性种子
[参考图] 正面 / 侧面 / 背面 / 全身 / 多角度缩略图(可上传、可生成、可删)
[服装变体] 服装A(图) · 服装B(图) …(每套可切换)
[音色] voice_sample.mp3 ▶ + 音色 ID(可从「音色库」选,或现场提炼)
[使用记录] 被哪些项目/流程用过(可跳转)
[操作] ✏️ 编辑 · 🎨 重新生成参考图 · 📤 导出 · 🔒 锁定(流程中不被覆盖)
```
**生成入口**("基础能力"的体现)
```
➕ 新建角色 → ① 填描述(性别/年龄/外形/性格)
→ ② 调「文生图」能力(Kling Grid Method 出 6 张候选)
→ ③ 选 1 张 → ④ 生成多角度(图生图变体)
→ ⑤ 补音色(录音上传 / TTS 合成 / 从音色库选)
→ ⑥ 确认入库
📤 上传已有参考图(跳过生成)
```
**在流程里怎么用**(引用机制)
```
流程节点「角色」字段 → 点击 → 弹【角色选择器】(带上面的筛选器)
选中 → 节点保存 character_id
→ 执行器按 ID 从资源库取:参考图路径 + 音色文件 → 注入 API 请求
分镜级:每个镜头可指定不同角色(shot.character_id)
```
### 2.2 其他资源库(同结构,字段按 DCS 文档第五节)
| 库 | 字段要点 |
|:--|:--|
| **场景库** | id / 名字 / 拓扑结构 / 空间锚点 / 光源 / 材质 / 参考图 + 参考视频 |
| **真实场地库** | 多角度图(wide/detail/light)+ 实拍视频 + 备注 |
| **道具库** | id / 结构 / 比例 / 可见面 / 持用状态 / 新旧状态 / 参考图 |
| **产品库** | id / 名字 / **category** / **must_keep[](必保特征)** / 参考图(front/angle/detail/in_hand)/ 一致性种子 |
| **服装库** | 关联角色 / 正面背面图 / 材质 · 可挂到角色的"服装变体" |
| **音色库** | id / 名字 / 样本音频 / 来源(官方库/AI提炼/录制)/ owned_by |
| **BGM 库 / 音效库** | 标签(情绪/节奏)· 时长 · 版权 |
| **特效预设库** | 类型(子弹时间/环绕/慢动作/焦点锁定)· 参数模板 · 适用供应商 |
**统一能力**(每个库都有):
```
🔍 搜索 + 筛选 + 排序 📤 上传 ➕ 生成(调对应产出型能力)
✏️ 编辑 🗑 删除 🔗 查看被哪些流程引用
```
---
## 三、流程清单与现状(诚实标注)
| # | 流程 | 节点链 | 现状 | 待修 |
|:--|:--|:--|:--|:--|
| 1 | **导演创作** | 剧本输入 → 剧本创作(导演系统) → 分镜配置 → 编排执行 → 结果挑选 | 🟡 可跑通(引擎已接),但缺"每步审视/纠正" | 补:分镜后的逐镜头配置面板、执行前预览 |
| 2 | 基础口播 | 脚本 → TTS → 素材搜索 → BGM → 视频输出 | ❌ **模板在,执行器空转** | 通电(接能力)+ 逐节点审视 |
| 3 | 卡点视频 | BGM导入 → 卡点风格 → 质量审核 → 视频输出 | ❌ 同上 | 同上 |
| 4 | 角色叙事 | 剧本→改编→角色→策略→Kling生成→旁白TTS→审核→输出 | ❌ 同上 | 同上 |
| 5 | 数字人口播 | 文案 → 人声合成 → 数字人角色 → 数字人视频 | ❌ 同上(且数字人能力未接) | 同上 + 接数字人供应商 |
| 6 | 口播+混剪 | 口播脚本 → 人声合成 → 混合风格 → 混合视频 | ❌ 同上 | 同上 |
| 7 | 短剧创作 | 12 节点(故事→…→成片) | ❌ 同上(但模板结构完整) | 同上 |
| 8 | 人物置换 | 选源人物 → 选目标人物 → 换人 → 出片 | 🟡 能力已接(百炼 wan2.2),未包成流程 | 包成流程 + 界面 |
> **现状真相**:`workflows.py` 的 6 条模板**结构完整、节点定义齐全**,但 `WorkflowRunner._execute()` **只做拓扑排序然后标记 completed**,**没有任何节点真的执行** —— 这是"点了不跑"的根因。
---
## 四、节点与配置体系(你强调的重点)
### 4.1 节点 = 能力 + 配置 + 上下游
```yaml
node:
id: n3
capability_id: tts_generate # 用哪个能力(可替换!)
provider: volcano # 该能力的供应商(默认可改)
model: CosyVoice-v2 # 大模型(默认可改)
params: # 该节点所有可配置项(默认值预填,全部可改)
text: "{{n1.script}}" # 上游节点输出 → 本节点输入(数据流)
emotion: warm
speed: 1.0
outputs: { audio_path: "var.vo" } # 本节点输出 → 供下游引用
```
### 4.2 配置的三个来源(全部暴露给你)
```
① 能力默认值(出厂设置) ← 打开节点就能看到
② 流程级默认(这条流程整体改) ← 比如"这条流程统一用 9:16 竖屏"
③ 节点级覆盖(本次执行改) ← 只改这一个节点
```
**UI 规则(你要求的"能改的地方都要能选")**:
- 每个节点的**所有可配置项都列出来**(默认值预填)
- 显示**来源标记**(默认 / 流程 / 节点),改了就在当前层生效
- 提供「恢复默认」
- **供应商 + 模型**是独立下拉(每个能力可选多家 → 每个供应商可选自家模型)
### 4.3 节点可替换("同一个需求找不同能力")
以"要一段声音"为例,节点里可以选:
```
▸ 能力 A:TTS 合成 输入文字 → 出音频(默认路径)
▸ 能力 B:音色提炼 + 合成 先给一段参考音频 → 提炼音色 → 再合成
▸ 能力 C:从资产库调音色 选一个已有音色 → 合成
```
→ 节点上有个「🔄 替换能力」,选不同能力,参数面板随之切换。
---
## 五、执行与审查机制 ★ 你最关心的部分
### 5.1 两种模式(可随时切换)
```
▸ 自动模式:点「▶▶ 全部执行(默认配置)」→ 一条龙跑完 → 出成品 → 你在成品上审
(前提:默认配置必须能走通 —— 我会保证并逐条验证)
▸ 逐步模式:点「▶ 执行本节点」→ 出结果 → 你审视 → 改 or 继续
(可设"断点":跑到某节点自动停)
```
### 5.2 每个节点的结果展示 + 纠正(核心)
| 节点类型 | 产物形态 | 你怎么审视/纠正 |
|:--|:--|:--|
| **文本类**(剧本/提示词/台词/字幕) | 原文显示在节点里 | **直接编辑**;不满意可「🔄 重生成」(可加"修改意见"再生成) |
| **音频类**(配音/BGM) | 内嵌播放器 | 听;不满意 → 改参数(音色/语速/情绪)→「🔄 重做」 |
| **图片类**(参考图/分镜图) | 缩略图预览 | 看;不满意 → 改提示词/换模型 →「🔄 重做」;可「选一张」 |
| **视频类**(镜头片段) | 内嵌播放器 | 看;不满意 → 改提示词/换镜头 →「🔄 重做」;可「换一版」多出几条挑 |
| **决策类**(策略/风格/审核门) | 选项列表 | 直接改选项;审核门可"通过/打回" |
**统一交互**:
```
节点卡片
┌───────────────────────────────┐
│ 🔊 TTS 合成 [执行] [重做] │
│ ├ 供应商 [火山▾] 模型 [Cosy▾] │
│ ├ 情绪 [warm▾] 语速 [1.0] │
│ ├ 输入: ← 脚本节点"口播稿" │
│ └ 结果: ▶ [播放音频] 3.2s ✅ │
└───────────────────────────────┘
```
- **未执行的节点**:灰显 + 「▶ 执行」
- **已执行的节点**:绿标 + 产物预览 + 「🔄 重做」(改配置后重跑,下游自动标记"需重跑")
- **全局**:可「从某节点起重跑下游」
### 5.3 导演创作流程的审视点(按你的描述)
```
① 输入剧本/小说/思路 → 你写(或从资产/素材带入)
② 剧本创作(导演系统产出分镜) → **审视**:看分镜表,逐镜头改台词/画面/镜头契约
③ 逐镜头配置(选特效/角度/模型)→ **审视**:每个镜头有默认配置,你只改不满意的
④ 编排执行(生成→去AI化→拼接)→ **审视**:每条片段可看/可重做
⑤ 结果挑选 / 调整 → 选终版 or 重跑某镜头
```
> 你的原话:"每个镜头我不需要手动配,但我要去审视一下现在配的结果;中间要修改就修改,不修改就用默认" ✓ **就是这个设计**。
---
## 六、后端架构
```
┌── L1 能力层(Capability Registry)── ✅ 已有(25 个),需扩展
│ capabilities.yaml + 加载器 + /api/ave/capabilities
│ 每个能力:输入输出契约 / 参数 schema / 供应商[] / 默认值 / 实现位置
│
├── L2 节点层(Node)── 🟡 部分有(workflows.py 的 15 种节点定义)
│ Node = 能力引用 + 参数覆盖 + 上下游映射 + 状态(未跑/跑完/失败)
│
├── L3 流程层(Template/Process)── 🟡 6 条模板已有,需扩展(+导演创作/人物置换)
│ Template = 节点 + 连线 + 流程级默认 + 元信息
│
├── L4 执行器(Runner)── ❌ **空转,必须重做**
│ 拓扑执行 → 逐节点调能力 → 产物落地 → 状态回写 → 断点/续跑 → 重跑上游
│ (这是"工作流能真跑"的核心)
│
├── L5 资产层(Assets)── ❌ **要重建**(旧 character_registry 只覆盖角色且字段旧)
│ 按你的分类建库 + 生成入口 + 引用机制
│
└── L6 接口/UI ── 前端页面 + FastAPI 路由
```
**执行通道**:
- 轻任务(解析/规划/合成)→ 本地线程
- 长任务(可灵生成 / ComfyUI)→ 走 guardd 任务(有任务面板、可停、可重试)
---
## 七、与现有代码的映射(哪些复用、哪些重做)
| 现有资产 | 处置 |
|:--|:--|
| `capabilities.yaml`(25 能力) | **复用**(L1 底座)→ 按需扩充 |
| `workflows.py` 的 6 模板 + 15 节点定义 | **复用结构**(L2/L3)→ 重做执行器 |
| `workflow.js` 画布 UI(485 行) | **复用**(拖拽 + 节点配置面板)→ 补"产物预览 + 重做" |
| `scheduler.py` / `scorer.py`(模板引擎) | 参考(筛选模板用) |
| `composer/*`(去AI化/拼接/变速/转场) | **复用**为能力实现 |
| `capabilities/kling_video.py`(可灵) | **复用**为能力实现 |
| `character_registry/`(旧角色库) | **改造**:字段按你的要求重建;补场景/道具/产品 |
| `character_sheet.py`(定妆照) | **复用**为产出型能力 |
| `person_swap/`(百炼换人) | **复用** → 包成"人物置换"流程 |
| `story_director/` + `directors/` | **复用**(导演流程的②环节) |
| `schemas.py`(统一分镜) | **复用**(导演流程的数据契约) |
| `video_factory.py`(CLI 老流程) | **改造**:拆成能力 + 流程模板 |
| `workflows.py` 的 Runner | **重写**(执行器) |
---
## 八、改造计划与**实际进度**(每阶段以"能点、能看结果、能改"验收)
| 阶段 | 内容 | 状态 |
|:--|:--|:--|
| **P1 架构对齐** | 本文档定稿 + 旧文档归档 + 菜单按新结构重组 | ✅ **已完成**(`4.10.0`:菜单 4 组 + 20 占位页) |
| **P2 执行器** | 重写 `WorkflowRunner`:真执行 + 逐节点产物 + 状态 + 重做 | ⏳ **待决策**(编排层 A/B)· 前置调研已完成(15 节点映射表见附录 D) |
| **P3 节点配置面板** | 每节点全配置暴露(默认值 + 供应商 + 模型 + 参数)+ 替换能力 | ⏳ 属 P2 范围(依赖执行器) |
| **P4 导演创作补全** | 统一分镜 Schema + 导演可切换 + 分镜编辑 + 一键出片 | ✅ **已完成**(`2607a973b`→`304d7e30e`;实测 3 镜头 **1.9 分钟**出片 / **3.2MB**) |
| **P5 资产底座** | 按分类建库(角色/场景/道具/产品/音色…)+ 上传/编辑 | ✅ **主体完成**(`2b866c23a` `eebeabcbc` `1aa4651f6`:**10 类资产** + 通用组件;**生成入口待图片模型名确认**) |
| **P6 流程补齐** | 人物置换 + 6 条老流程逐条通电验证 | ⏳ **待 P2** |
| **P7 辅助** | 生产记录 + 费用 + 设置 | ✅ **已完成**(生产记录含磁盘持久化 · 费用统计含可灵估算+AI token · 设置含去AI化/输出/渲染) |
| — | **S1 能力注册表**(25 能力 + 能力库页 + 供应商管理 + 能力试跑) | ✅ **已完成**(`952b39970` `4c6caf2f3`:39 个供应商,密钥状态 18/27 已配) |
| — | **S2 导演创作**(v5.2 技能入库 + 六模块提示词 + 交付状态三级 + Webhook 验签) | ✅ **已完成**(`82a63f4b3` 起) |
**当前剩余**:**P2(编排通电)** —— 等编排层决策(① 复用 `workflows.py` / ② 装 n8n)后即可开工;「历史操作」页仍为占位(低优先级)。
---
## 九、待你确认(关键,定了才动手)
1. **资产分类的字段**(你说"我给的分类都没有" —— 请再给一次):
- 角色要什么字段?(正面照/多角度/服装变体/表情/音色/年龄/身高…)
- 场景/道具/产品各要什么?**产品 vs 道具**怎么区分?
- 分类方式(按项目?按类型真人/动漫?按用途主角/配角?)
2. **菜单是否按本文第二节重组**?(流程/能力/资产/辅助 四大块)
3. **执行模式默认哪个**?(逐步 or 自动;我建议默认"逐步",你熟了可切自动)
4. **阶段优先级**:P2(执行器通电)和 P5(资产重建)你想先做哪个?
---
## 附录 C|与《导演创作系统说明书 v2.0》的对齐(**重要基准**)
> 用户原始设计文档:`~/Documents/导演创作系统(Director.docx`(829 行,v2.0,2026-10-01 更新)
> 本节把文档的**逻辑架构**映射到**现有看板**,明确哪些复用、哪些要补 —— **以文档为基准,不再自由发挥**
### C.1 文档的五层架构 → 我们的实现
| 文档层 | 文档原方案 | 我们的现状 | 处置 |
|:--|:--|:--|:--|
| **层0 导演控制台** | Appsmith(Docker :80);页面:分镜编辑/资产库/3D角色/特效库/任务状态/成片预览/参数模板/系统设置 | **Dashboard(:9988)** 已有:导演创作 / 能力库 / 工作流 / 生产记录 / 费用 | ✅ **复用现有看板**(功能更全,不必新装 Appsmith) |
| **层1 导演层** | 任一导演系统输出统一 Schema | `directors/`(v5.2 + legacy)+ `schemas.py`(14 模型) | ✅ 已完成 |
| **层2 编排层** | n8n(Docker :5678):Webhook→读Schema→循环shot→Switch按type分发→等完成→下载→FFmpeg→回调 | `workflows.py`(6 模板 + 15 节点 + 画布)**但执行器空转** | ⚠️ **二选一**(见 C.3) |
| **层3 能力层** | 远端 API,8 大类每家多供应商(TTS/口播/动作/背景/ComfyUI/3D/特效) | `capabilities.yaml`(25 能力,含多供应商)+ 可灵/video 引擎 | ✅ 骨架已备,供应商待补 |
| **层4 合成层** | FFmpeg:去AI化 → 帧混合 → 拼接 | `composer/`(de_ai.py + pipeline.py) | ✅ 已完成(**注意**:文档写 `-crf 18`,我们改为 `23` 以控体积) |
### C.2 资产库规范(文档第五节 → 落地基准)
```
assets/
├── characters/ 角色 2D — reference.png / _side.png / _full.png / lora.safetensors / voice_sample.mp3 / meta.json
├── characters_3d/ 角色 3D — model.glb / model.fbx / texture/ / rig_info.json / meta.json
├── locations/ 场景(AI生成)— reference.png / reference_video.mp4 / meta.json
├── real_locations/ 真实场地 — reference_wide.jpg / _detail.jpg / _light.jpg / reference_video.mp4 / meta.json
├── products/ 产品 — reference_front.png / _angle.png / _detail.png / _in_hand.png / meta.json
├── props/ 道具(结构同 products)
├── bgm/ sfx/ 音频资产
└── vfx_presets/ 特效预设 — bullet_time.yaml / orbit.yaml / slow_motion.yaml
```
**元数据规范(文档原文)**:
- **产品**:`id / name / category / must_keep[](必保特征,如"瓶身标签文字""瓶盖金色边框")/ reference_images{front,angle,detail,in_hand} / consistency_seed`
- **3D 角色**:`id / name / source_tool / model_formats[] / rigged / rig_type / reference_2d_id / consistency_seed / created_at`
- **引用方式**:分镜 Schema 通过 `character_id / character_3d_id / location_id / product_id / props[] / bgm_id / sfx.id / vfx.vfx_id` 引用 → 执行器按 ID 从资产库取文件注入 API
**我们现状**:只有 `character_registry/registry.yaml`(14 角色;字段:description/appearance/personality/voice_style/art_style/bgm_style/reference_images/prompt_template)→ **需按上述结构重建**
### C.3 两个关键决策(等你定)
**决策 1:编排层用哪个?**
| 方案 | 说明 | 优劣 |
|:--|:--|:--|
| **A. 复用现有 workflows.py + 重写执行器** | 已有 6 模板 + 15 节点 + 画布 UI + 节点配置面板;只需把"假执行"换成真执行 | ✅ 不用新装服务 · ✅ 与看板一体 · ⚠️ 执行器要自己写 |
| **B. 按文档装 n8n(Docker :5678)** | 照文档原方案,n8n 做编排,看板只当控制台 | ✅ n8n 成熟(可视化/重试/日志) · ⚠️ 要装 Docker 服务 + 学 n8n · ⚠️ 与看板两套系统 |
| **C. 混合** | 看板做控制台 + 流程配置,轻任务本地执行;把"逐镜头生成"这段交给 n8n | 复杂度高 |
**决策 2:控制台用哪个?**
- **A. 现有 Dashboard(:9988)** ← 建议(已能跑、功能多、Tailscale 可访问)
- B. 按文档装 Appsmith(:80)—— 要重搭所有页面
### C.4 文档「导演操作流程 12 步」→ 现状对照
| # | 文档步骤 | 现有看板 | 状态 |
|:--|:--|:--|:--|
| 1 | 打开浏览器 | :9988 | ✅ |
| 2 | 分镜编辑页输入故事大纲 | 视频工厂 → 🎬 导演创作 | ✅ |
| 3 | **选内容类型**(产品广告/个人日记/场景短剧) | — | ❌ **缺** |
| 4 | **选角色**(2D 参考图 / 3D 绑定模型) | — (Schema 有字段,UI 未暴露) | ❌ **缺** |
| 5 | **选场景/场地/产品** | — | ❌ **缺** |
| 6 | 点击生成分镜 | 🚀 生成分镜 | ✅ |
| 7 | 逐条检查/修改 + **添加特效**(子弹时间/环绕运镜) | 能改文字;**特效面板无** | 🟡 部分 |
| 8 | 提交任务 | 🎥 生成成片 | ✅ |
| 9 | 编排层调各 API 生成片段 | 我们的流水线(逐镜头→可灵) | ✅ |
| 10 | FFmpeg 去AI化 + 拼接 | composer(已修 + 体积优化) | ✅ |
| 11 | 刷新预览成片 | 进度条 + 成片路径 | ✅ |
| 12 | 不满意 → **改对应镜头参数** → 重试单条 | 有单镜头重生成,但**不是"改参数重试"** | 🟡 部分 |
**缺的 4 项**:③内容类型 ④选角色 ⑤选场景/产品 ⑦特效面板 ⑫改参数重试
### C.5 文档里的能力清单(供应商维度,能力注册表要照此扩充)
| 模块 | 文档列出的可选供应商 |
|:--|:--|
| TTS | Fish Audio / ElevenLabs / Qwen3-TTS |
| 口播视频 | D-ID / HeyGen / 本地 LongCat |
| 动作视频 | 可灵 / Wan-Animate-2 / Runway |
| 背景空镜 | 通义万相 / Sora 2 / 可灵 |
| ComfyUI | RunningHub / ComfyDeploy / 自建 |
| 3D 角色 | 混元3D / Autodesk Flow Studio |
| 特效·子弹时间 | 万兴天幕 / 海螺AI / 可灵 |
| 特效·运镜 | 可灵(camera_control 六参数 ∈[-10,10])/ 海螺AI(T2V-01-Director) |
---
## 附录 D|节点 → 能力映射表(P2 执行器的实施依据)
> 调研结论:`workflows.py` 的 15 种节点定义**只有 UI 元数据**(label/icon/description/default_config/options_map),
> **没有绑定到真实能力**;`WorkflowRunner` 是空壳。下表把 15 种节点映射到能力注册表里的实现。
| # | 节点类型 | 名称 | 对应能力 | 状态 |
|:--|:--|:--|:--|:--|
| 1 | `story_prototype` | 剧本原型 | `script_generate`(LLM 生成) | ✅ ready |
| 2 | `script` | 脚本输入 | **无执行**(用户输入 / 读文件) | — 透传 |
| 3 | `script_adaptor` | 剧本改编 | `script_parse` + `script_generate` | ✅ ready |
| 4 | `strategy` | 策略选择 | LLM 决策 或 参数选择 | 🟡 待明确 |
| 5 | `tts` | TTS 合成 | `tts_generate`(火山/阿里) | ✅ ready |
| 6 | `model` | AI 模型 | LLM(DeepSeek)通用调用 | ✅ ready |
| 7 | `material` | 素材源 | `material_search`(Pexels/万相/兜底) | ✅ ready |
| 8 | `style` | 风格预设 | **无执行**(参数注入) | — 透传 |
| 9 | `bgm` | BGM 选择 | `bgm_generate` / `music_select` | ✅ ready |
| 10 | `character` | 角色 | **资产引用**(无执行,取资产注入) | — 引用 |
| 11 | `audit_gate` | 审核门 | **人工暂停/继续**(需实现断点机制) | 🟡 待实现 |
| 12 | `output` | 输出 | `video_concat` + `de_ai` | ✅ ready |
| 13 | `storyboard` | 分镜规划 | `storyboard_plan`(v5.2/clip/legacy) | ✅ ready |
| 14 | `prompt_gen` | 分镜提示词 | `prompt_gen`(六模块编译器) | ✅ ready |
| 15 | `subtitle` | 字幕生成 | `subtitle` | 🟡 partial |
**结论**:
- **12/15 节点已有现成能力**(ready 或 partial)
- 4 个是"无执行"节点(`script` 输入 / `style` 参数 / `character` 引用 / `strategy` 决策)→ 执行器**透传**即可
- 1 个需新机制:`audit_gate`(人工审核门 → 暂停/继续)
**P2 执行器工作量**(已明确):
1. 建 `NODE_TYPE → capability_id` 映射(上表)
2. 执行器:拓扑排序 → 逐节点调能力 → 产物存 run context → 下游按 `{{node.xxx}}` 引用 → 状态回写
3. 特殊处理:无执行节点透传 · `audit_gate` 暂停 · 失败重试 · 「从某节点起重跑下游」
4. 前端:节点卡片显示产物预览(文本可编辑 / 音视频可播放)+ 🔄 重做
---
## 附录 E|P2 实施要点(执行器改动清单 —— 决策后即可开工)
**目标文件**:`05_tools/10_dashboard/workflows.py`(599 行)
**现状(3 处关键代码)**:
| 位置 | 现状 |
|:--|:--|
| `WorkflowRunner._execute()`(519 行) | 只做拓扑排序 → 把节点标记 `completed`,**无任何真实执行** |
| `NODE_DEFINITIONS`(35 行) | 15 种节点**只有 UI 元数据**(label/icon/description/options_map),**未绑定能力** |
| `start_run()`(510 行) | 起后台线程调 `_execute` ✓ 骨架可用(可直接复用) |
**改动清单(3 步)**:
1. **建映射**:`NODE_TO_CAPABILITY = {node_type: capability_id}` —— 附录 D 已给出 15 项对应(12 项有现成能力)
2. **写节点执行** `_run_node(node, ctx) -> dict`:
- 查映射 → 取能力 → 合并参数(**能力默认 ← 流程覆盖 ← 节点覆盖**)→ 调实现 → 返回产物
- **4 个无执行节点**(`script` / `style` / `character` / `strategy`)→ **透传**(直接传上游值)
- `audit_gate` → 置 run 状态为 `paused`,等外部 `resume`
3. **改 `_execute()`**:逐节点调 `_run_node` → 产物存 `run["context"][node_id]` → 下游按 `{{node.xxx}}` 解析 → 状态回写(success/failed/skipped)→ 失败按节点重试配置重试
**后端新接口(3 个)**:
| 接口 | 用途 |
|:--|:--|
| `POST /api/workflow/runs/{run_id}/redo/{node_id}` | 单节点重做(改配置后重跑) |
| `POST /api/workflow/runs/{run_id}/resume` | `audit_gate` 审核通过 → 继续 |
| `GET /api/workflow/runs/{run_id}/artifacts` | 各节点产物列表(供前端预览) |
**前端配合**(`views/workflow.js` 画布已就绪):
- 节点卡片加**状态徽章** + **产物预览**(文本可编辑 / 视频可播放)
- 「🔄 重做此节点」·「▶️ 从此刻起跑下游」按钮
**可复用**(无需重写):
- 能力注册表(`capabilities/`)· 可灵引擎(`kling_video.py`)· 流水线(`composer/pipeline.py`)· 资产库(`assets_manager/`)· 成本统计(`api_costs`)
---
## 附:归档说明
以下文档**已归档**(内容被本文档取代,避免误导后续开发):
- `VIDEO_FACTORY_FRAMEWORK.md`(v1 框架:菜单分类有误,见第二节)
- `VIDEO_FACTORY_ARCHITECTURE.md`(技术细节,已并入本文第六节)
- `DCS_VIDEO_FACTORY_PLAN.md`(调研 + M1 计划,M1 已完成)
归档位置:`90_archive/video_factory_docs_20261001/`
@@ -0,0 +1,99 @@
# 视频工厂 · 使用指南
> 更新: 2026-10-02 · 对应版本 4.11.x
> 架构文档: `PLANS/VIDEO_FACTORY_MASTER.md` · 原始设计: `PLANS/reference/DCS_说明书_v2.0_原文.md`
---
## 一、快速开始(3 步出片)
1. 打开看板 **http://localhost:9988**(如果是旧界面,`Cmd+Shift+R` 硬刷新)
2. 侧边栏 → **🎞️ 视频工厂 · 流程** → 任选一条流程(如「🎙️ 基础口播」)
3. 看到流程步骤链 + 预估成本 → 点 **▶️ 开始** → 画布自动加载模板
4. 把「**镜头数**」设为 **1**(首次试跑,控成本)→ 点 **▶ 运行**
5. 观察节点状态(🟢完成 / 🔵执行中 / 🔴失败 / ⚪跳过)→ 点节点看**产物预览**(视频/音频可直接播放)
---
## 二、流程清单
| 流程 | 模板 | 节点数 | 说明 |
|:--|:--|:--|:--|
| 🎬 导演创作 | (单页) | — | 故事 → 分镜(可编辑)→ 一键出片 |
| 🎭 短剧创作 | `short_drama` | 12 | 完整短剧流程 |
| 🎙️ 基础口播 | `basic_dub` | 5 | 脚本 → TTS → 素材 → BGM → 输出 |
| 🥁 卡点视频 | `beat_sync` | 4 | BGM 卡点 |
| 📖 角色叙事 | `character_narrative` | 8 | 角色 + 旁白 |
| 👤 数字人口播 | `digital_human` | 4 | 需数字人能力(待接入) |
| 🎞️ 口播+混剪 | `hybrid_dub` | 4 | — |
| ➕ 新建流程 | (空白画布) | — | 自己拖节点 |
---
## 三、能力与依赖(配 key 就能用)
| 能力 | 状态 | 依赖 | 备注 |
|:--|:--|:--|:--|
| 🎬 分镜规划 | ✅ | `llm.api_key`(DeepSeek) | 已配 |
| 📝 提示词生成 | ✅ | 同上 | 已配 |
| 🎥 视频生成 | ✅ | `kling.api_key` | 已配(`kling-v3`) |
| 📦 视频合成 | ✅ | 本地 FFmpeg | 含去AI化 |
| **🔊 混流** | ✅ | 本地 FFmpeg | 视频+人声+BGM+字幕 |
| **🎤 TTS 语音** | ⚠️ | `aliyun.api_key` **(欠费)** / `volcano.voice_app_key`(缺 token) | **充值阿里即用** |
| 🔌 素材搜索 | ⚠️ | `pexels.api_key` | 免费申请 pexels.com/api |
| 🎵 BGM 选择 | ✅ | 本地音乐库 | — |
| 💬 字幕生成 | ✅ | 本地 | ASS 格式 |
| 🔄 人物置换 | ⚠️ | `aliyun.api_key`(同 TTS) | 充值即用 |
| 💋 对口型 | ⚠️ | `fal.api_key` | 未配 |
**配置入口**:Dashboard → **⚙️ 服务 → 🔑 API 配置**(每项可「🧪 测试」验证连通性)
---
## 四、常见问题
**Q: 报「阿里百炼账号欠费(Arrearage)」**
→ 阿里云控制台充值(同时解锁 TTS + 人物置换)
**Q: 报「Pexels API Key 未配置」**
→ https://www.pexels.com/api/ 免费申请 → 「🔑 API 配置」填入
**Q: 出片很慢(10+ 分钟)**
→ 可灵服务端排队(高峰期常见),非代码问题。可在「能力试跑」页用预检查看任务状态
**Q: 成片没有声音**
→ 检查流程里是否有 TTS 节点 + TTS 是否成功(阿里欠费会失败)
**Q: 节点显示「跳过」**
→ 该能力尚未接入执行器(如 ComfyUI/特效/3D 角色),或缺少必要上游产物
**Q: 分镜不满意**
→ 「🎬 导演创作」页可逐镜头编辑 + 🔄 单镜头重生成;或换导演(v5.2 / 本地)
---
## 五、省钱的调试技巧
1. **镜头数先设 1**(默认 3)—— 每镜头约 ¥1-3
2. **优先只读**:查任务列表/状态用 GET(不扣费),别反复跑生成
3. **用「🧪 能力试跑」的预检**(dry_run,零费用):确认供应商/模型/参数/密钥状态后再真跑
4. **复用已有产物**:TTS 音频、字幕文件可跨 run 复用(修改配置只重做必要节点 → 「🔄 重做此节点」)
---
## 六、关键命令(运维)
```bash
# 重启看板(必须用 launchctl,禁止 pkill+nohup)
launchctl kickstart -k gui/$(id -u)/com.agentos.dashboard
curl -s http://localhost:9988/api/health
# 查看运行
curl -s http://localhost:9988/api/workflow/runs | python3 -m json.tool | head -30
# 产物位置
ls ~/workbuddy-agent-os/agent-local/runtime/ave/workflow/<run_id>/
# 出片记录(导演创作页产物)
ls ~/workbuddy-agent-os/agent-local/runtime/ave/renders/
```
@@ -0,0 +1,837 @@
# 导演创作系统(Director Creative System, DCS)· 项目开发说明书 v2.0
> **来源**:用户原始设计文档 `~/Documents/导演创作系统(Director.docx`(829 行,2026-10-01 09:48 更新)
> **入库原因**:作为视频工厂的**设计基准**(`PLANS/VIDEO_FACTORY_MASTER.md` 附录 C 即对照本文档)
> **入库时间**:2026-10-01 | 原文由 textutil 从 docx 提取(仅格式变换,内容未改)
---
导演创作系统(Director Creative System, DCS)
项目开发说明书 v2.0
一、项目定位
DCS是一套面向广告导演/制片人的AI视频生产系统。导演用自然语言描述故事,系统自动完成分镜拆解、资产调度、视频生成、特效叠加和后期合成,输出接近真人实拍质感的20-30秒短片。
核心设计原则:
1. 解耦:导演系统、编排系统、能力API、合成后期互相独立,可单独替换。
2. 标准化:所有模块通过统一分镜Schema交互,换模块不改流程。
3. 导演优先:3D角色、特效运镜、产品资产均可由导演在控制台按需调用,不盲目抽卡。
4. 真实感优先:分镜遵循伪纪录片/手机随手拍美学,后期强制走去AI化处理链。
5. 低成本起步:本地零GPU,所有算力走远端API。
二、系统架构
```
┌───────────────────────────────────────────────────────────────────────┐
│ 层0:导演控制台(Appsmith,本地Docker,端口80) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │分镜编辑 │ │资产库 │ │3D角色 │ │特效库 │ │任务状态 │ │
│ │ │ │ │ │生产 │ │ │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │成片预览 │ │参数模板 │ │系统设置 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────┬─────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────────────────┐
│ 层1:导演层(可替换) │
│ │
│ 导演系统(当前选型:AI Storyboard Director v5.2) │
│ 职责:自然语言故事 → 统一分镜Schema (JSON) │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 统一分镜Schema(标准接口) │ │
│ │ 所有模块的“普通话” │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────┬─────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────────────────┐
│ 层2:编排层(n8n,本地Docker,端口5678) │
│ │
│ 读取分镜Schema → 按type分发 → 调用各API → 收集输出 → 交给合成层 │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │TTS节点 │ │口播节点│ │动作节点│ │背景节点│ │特效节点│ │3D节点 │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────┬─────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────────────────┐
│ 层3:能力层(全部远端API,可替换) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐│
│ │Fish Audio│ │D-ID/ │ │可灵/ │ │通义万相 │ │RunningHub ││
│ │TTS │ │HeyGen │ │Wan-Anim │ │背景/空镜 │ │(ComfyUI) ││
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────────┘│
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │混元3D │ │万兴天幕 │ │海螺AI │ │其他特效 │ │
│ │角色生成 │ │子弹时间 │ │运镜 │ │ │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────┬─────────────────────────────────────────┘
↓
┌───────────────────────────────────────────────────────────────────────┐
│ 层4:合成层(FFmpeg,本地) │
│ │
│ 去AI化处理链:轻微模糊 → 胶片颗粒 → 调色 → 帧混合 → 拼接 │
│ 输出:成片mp4 │
└───────────────────────────────────────────────────────────────────────┘
```
三、分层职责与模块规范
3.1 层0:导演控制台
部署:Appsmith,本地Docker,端口80。跨平台(macOS/Linux),迁移时导出数据库+环境变量即可。
页面清单:
页面 功能 数据源
分镜编辑 输入故事大纲 → 调用导演系统 → 展示分镜表 → 逐条修改 FastAPI /api/director/generate
资产库 角色/场景/道具/产品/BGM/音效管理 FastAPI /api/assets/*
3D角色生产 上传概念图 → 生成多视图+骨骼绑定 → 存入资产库 混元3D API
特效库 浏览可用特效,查看参数说明,预览示例 FastAPI /api/vfx/list
任务状态 查看n8n任务队列,每条分镜状态 FastAPI /api/task/*
成片预览 按项目分组播放成片 本地文件系统
参数模板 管理各内容类型的模板(广告/日记/短剧) config/templates/
系统设置 API Key管理、提供商切换、去AI化参数 config/providers.yaml
控制台可设置参数:
A. 导演系统配置
· 当前导演系统:下拉选择
· 导演系统API地址
· 默认输出Schema版本
B. 能力提供商配置
模块 可选提供商 切换方式
TTS Fish Audio / ElevenLabs / Qwen3-TTS 下拉 + Key
口播视频 D-ID / HeyGen / 本地LongCat 下拉 + Key
动作视频 可灵 / Wan-Animate-2 / Runway 下拉 + Key
背景/空镜 通义万相 / Sora 2 / 可灵 下拉 + Key
ComfyUI RunningHub / ComfyDeploy / 自建 下拉 + API地址
3D角色 混元3D / Autodesk Flow Studio 下拉 + Key
特效-子弹时间 万兴天幕 / 海螺AI / 可灵 下拉 + Key
特效-运镜 可灵 / 海螺AI 下拉 + Key
C. 去AI化参数(全局默认,可被分镜覆盖)
· 模糊 sigma:默认 0.4
· 胶片颗粒强度:默认 12
· 饱和度偏移:默认 -0.12
· 色温偏移:默认 +0.03
· 帧混合帧数:默认 2
3.2 层1:导演层
职责:接收自然语言故事,输出统一分镜Schema。
可替换性:任何导演系统,只要输出符合统一分镜Schema的JSON,即可接入。若输出格式不同,需写薄适配器转换。
导演系统输入:
```json
{
"story": "我住院第三天,躺在病床上录了一段……",
"content_type": "personal_vlog",
"template_id": "vlog_hospital_001",
"global_anchors": {
"character_id": "char_001",
"location_id": "loc_hospital_302",
"shooting_style": "documentary_realism"
}
}
```
当前推荐:AI Storyboard Director v5.2(支持“假设标记”,可强制保留不完美细节)。备选:clip-storyboard-director(4D持久化缓冲区,跨场景一致性最强)。
3.3 层2:编排层(n8n)
部署:本地 Docker,端口 5678。
工作流设计:
```
[Webhook触发]
→ [读取分镜Schema JSON]
→ [循环每条shot]
→ [Switch节点:按type分发]
├─ type == "talking_head" → [HTTP Request: 口播API]
├─ type == "action" → [HTTP Request: 动作API]
├─ type == "background" → [HTTP Request: 背景API]
├─ type == "comfyui" → [HTTP Request: RunningHub API]
├─ type == "vfx" → [HTTP Request: 特效API]
└─ type == "3d_character" → [HTTP Request: 混元3D API]
→ [等待任务完成(轮询)]
→ [下载输出片段到本地临时目录]
→ [FFmpeg节点:去AI化处理链]
→ [FFmpeg节点:拼接所有片段]
→ [输出成片mp4到指定目录]
→ [回调控制台更新任务状态]
```
3.4 层3:能力层
统一接口约定:所有能力API返回格式统一为:
```json
{
"status": "success",
"video_url": "https://.../output.mp4",
"duration": 8.0,
"format": "mp4",
"error": null
}
```
各模块调用方式:
模块 API 调用方式 关键参数
TTS Fish Audio POST /v1/tts text, voice_id, emotion_tags
口播 D-ID POST /talks source_url, script.audio_url, config.sentiment
动作 可灵 POST /v1/videos image_url, prompt, camera_control
背景 通义万相 POST /api/v1/video prompt, size, seconds
ComfyUI RunningHub POST /api/v1/workflow workflow_id, node_overrides
3D角色 混元3D SubmitHunyuanTo3DProJob Prompt/ImageUrl, ViewImage
子弹时间 万兴天幕 POST /api/v1/vfx image_url, effect_type
运镜 可灵 camera_control参数 pan/tilt/roll/zoom ∈ [-10,10]
运镜 海螺AI 嵌套指令 环绕+降速+焦点锁定
四、统一分镜 Schema(标准接口)
src/schemas.py:
```python
from pydantic import BaseModel, Field
from typing import List, Optional, Literal
class GlobalAnchors(BaseModel):
character_id: str
character_3d_id: Optional[str] = None
location_id: str
product_id: Optional[str] = None
wardrobe: str
lighting_state: str
camera_lens: str
shooting_style: str = "documentary_realism"
consistency_seed: int = 42
class ShotContract(BaseModel):
shot_size: str
angle: str
camera_move: str
lens_feel: str
depth_of_field: str
frame_rate_feel: str
class VFXConfig(BaseModel):
vfx_id: Optional[str] = None
vfx_type: Optional[Literal["bullet_time", "orbit", "slow_motion",
"focus_lock", "custom"]] = None
provider: Optional[str] = None
params: Optional[dict] = None
class ExpressionDetail(BaseModel):
eyes: Optional[str] = None
mouth: Optional[str] = None
brow: Optional[str] = None
class SFX(BaseModel):
id: str
at_second: float
volume: float = 0.4
class AudioConfig(BaseModel):
voice_volume: float = 1.0
bgm_id: Optional[str] = None
bgm_volume: float = 0.15
bgm_fade_in: float = 1.0
bgm_fade_out: float = 1.0
sfx: List[SFX] = []
audio_cue: Optional[str] = None
denoise: bool = False
class Subtitle(BaseModel):
enabled: bool = True
text: str
style: str = "手机系统默认"
position: str = "bottom_center"
class Transition(BaseModel):
type: Literal["cut", "dissolve", "fade", "wipe"] = "cut"
duration: float = 0
class Speed(BaseModel):
factor: float = 1.0
ramp: Optional[str] = None
class ColorConfig(BaseModel):
lut: Optional[str] = None
saturation_offset: float = -0.12
temperature_shift: float = 0.03
class PostProcess(BaseModel):
grain_intensity: int = 12
blur_sigma: float = 0.4
frame_interpolation: bool = False
class OutputConfig(BaseModel):
resolution: str = "1080x1920"
fps: int = 30
bitrate: str = "8M"
class Shot(BaseModel):
shot_id: str
scene_id: str
duration: float
type: Literal["talking_head", "action", "background",
"comfyui", "vfx", "3d_character"]
character_id: str
character_3d_id: Optional[str] = None
location_id: str
product_id: Optional[str] = None
product_focus: bool = False
product_placement: Optional[str] = None
props: List[str] = []
continuity_mode: Literal[
"fresh_location",
"previous_frame_continuation",
"location_reappearance"
]
shot_contract: ShotContract
vfx: Optional[VFXConfig] = None
visual_description: str
text: Optional[str] = None
sentiment: Optional[str] = None
expression_detail: Optional[ExpressionDetail] = None
action: Optional[str] = None
audio: Optional[AudioConfig] = None
subtitle: Optional[Subtitle] = None
transition_in: Transition = Transition()
transition_out: Transition = Transition()
speed: Speed = Speed()
color: ColorConfig = ColorConfig()
post_process: PostProcess = PostProcess()
output: OutputConfig = OutputConfig()
class Storyboard(BaseModel):
project_id: str
schema_version: str = "2.0"
global_anchors: GlobalAnchors
shots: List[Shot]
```
特效参数示例(vfx字段):
```json
{
"vfx": {
"vfx_id": "vfx_bullet_time_01",
"vfx_type": "bullet_time",
"provider": "wondershare_tianmu",
"params": {
"source_image": "keyframe_01.png",
"duration": 3.0,
"freeze_radius": 0.5
}
}
}
```
可灵环绕运镜参数(写入shot_contract.camera_move或vfx.params):
可灵的camera_control支持六种运镜参数,取值范围均为[-10, 10]:horizontal(水平平移)、vertical(垂直平移)、pan(水平摇镜,绕y轴旋转)、tilt(垂直摇镜,绕x轴)、roll(旋转运镜,绕z轴)、zoom(变焦)。同时支持预定义运镜类型:simple、down_back(下移拉远)、forward_up(推进上移)、right_turn_forward(右旋推进)、left_turn_forward(左旋推进)。导演可在控制台选择预定义类型或手动指定六参数组合。
五、资产库规范
目录结构:
```
assets/
├── characters/
│ └── char_001/
│ ├── reference.png
│ ├── reference_side.png
│ ├── reference_full.png
│ ├── lora.safetensors
│ ├── voice_sample.mp3
│ └── meta.json
├── characters_3d/
│ └── char_001_3d/
│ ├── model.glb
│ ├── model.fbx
│ ├── texture/
│ ├── rig_info.json
│ └── meta.json
├── locations/
│ └── loc_hospital_302/
│ ├── reference.png
│ ├── reference_video.mp4
│ └── meta.json
├── real_locations/
│ └── loc_cafe_01/
│ ├── reference_wide.jpg
│ ├── reference_detail.jpg
│ ├── reference_light.jpg
│ ├── reference_video.mp4
│ └── meta.json
├── products/
│ └── prod_skin_cream/
│ ├── reference_front.png
│ ├── reference_angle.png
│ ├── reference_detail.png
│ ├── reference_in_hand.png
│ └── meta.json
├── props/
├── bgm/
├── sfx/
└── vfx_presets/
├── bullet_time.yaml
├── orbit.yaml
└── slow_motion.yaml
```
角色3D元数据(meta.json) :
```json
{
"id": "char_001_3d",
"name": "患者A-3D",
"source_tool": "hunyuan_3d",
"model_formats": ["glb", "fbx"],
"rigged": true,
"rig_type": "humanoid",
"reference_2d_id": "char_001",
"consistency_seed": 42,
"created_at": "2026-10-01"
}
```
产品元数据:
```json
{
"id": "prod_skin_cream",
"name": "XX精华面霜",
"category": "护肤品",
"must_keep": ["瓶身标签文字", "瓶盖金色边框", "整体配色"],
"reference_images": {
"front": "reference_front.png",
"angle": "reference_angle.png",
"detail": "reference_detail.png",
"in_hand": "reference_in_hand.png"
},
"consistency_seed": 88
}
```
调用方式:分镜Schema中通过 character_id、character_3d_id、location_id、product_id、props、bgm_id、sfx.id、vfx.vfx_id 引用。n8n根据ID从资产库读取文件路径,注入API请求。
六、3D角色生产模块
功能:导演上传角色概念图,系统自动生成多视图+骨骼绑定3D模型,存入资产库,后续分镜通过 character_3d_id 引用。
调用流程:
```
导演上传正面概念图
↓ 控制台 → FastAPI → 混元3D API
混元3D SubmitHunyuanTo3DProJob
↓ 传入 Prompt/ImageUrl + ViewImage(多视角图片)
返回 JobId → 轮询 DescribeProfileTo3DJob
↓ Status == DONE
获得 File3D(OBJ/GLB格式,含Url和PreviewImageUrl)
↓ 下载到 assets/characters_3d/
自动绑定骨骼(混元3D内置AutoRigging)
↓ 存入资产库
后续分镜通过 character_3d_id 引用
```
混元3D API关键参数:
· 输入:Prompt(文本)或 ImageUrl(图片URL,有效期24小时)或 ViewImage(多视角图片,支持back/left/right)
· 输出:File3D 数组,包含 Type(文件格式)、Url(文件URL)、PreviewImageUrl(预览图)
· 任务查询:DescribeProfileTo3DJob 返回 Status(WAIT/RUN/FAIL/DONE)和 ResultFile3Ds
· 支持接口:SubmitHunyuanTo3DProJob(专业版)、SubmitHunyuanTo3DRapidJob(极速版)、SubmitAutoRiggingJob(自动骨骼绑定)
七、特效运镜库
7.1 子弹时间
提供商 调用方式 关键参数
万兴天幕 POST /api/v1/vfx image_url, effect_type="bullet_time", duration
可灵 camera_control参数组合 pan ∈ [-10,10], roll ∈ [-10,10], zoom
海螺AI T2V-01-Director模型 内置Bullet Time模板,自动应用时间凝滞+环绕视角
ComfyUI RunningHub工作流 VFX-Bullet Time Effect工作流,两阶段渲染
万兴天幕的“子弹时间”特效支持单张静态图片一键生成影视级动态视频,无需复杂拍摄,且已开放API接口支持MCP协议。海螺AI的T2V-01-Director模型预置了标准化运镜模组,调用内置Bullet Time模板即可触发基础子弹时间逻辑,系统自动应用时间凝滞+环绕视角参数。
7.2 环绕运镜
可灵支持精细的环绕运镜控制。预定义类型中,right_turn_forward 实现“先右旋转后前进”,left_turn_forward 实现“先左旋并前进”。手动模式下可通过 pan 参数实现水平面上的旋转,pan 负值表示绕y轴向左旋转,正值表示向右旋转,取值范围[-10, 10]。
7.3 慢动作/升格
可灵的 frame_rate_feel 参数控制帧率感觉。海螺AI支持嵌套运镜指令,将“环绕+降速+焦点锁定”三重动作按时间顺序嵌套至提示词中。
7.4 特效库的导演操作方式
导演在控制台分镜编辑页面中,每条镜头可展开“特效”面板:
1. 从下拉菜单选择特效类型(子弹时间/环绕/慢动作/焦点锁定/自定义)
2. 选择提供商(万兴天幕/可灵/海螺AI/ComfyUI)
3. 填写参数表单(根据特效类型动态显示)
4. 点击“预览”可调用测试API生成样片
5. 确认后,参数写入分镜Schema的 vfx 字段
八、去AI化处理链
de_ai.py:
```python
class DeAIProcessor:
def process(self, input_path: str, output_path: str,
params: PostProcess, color: ColorConfig):
"""
按顺序执行:
1. gblur sigma={blur_sigma} # 消除AI边缘锐利感
2. noise alls={grain_intensity}:allf=t+u # 添加真实传感器噪点
3. eq saturation={1+saturation_offset} # 饱和度降低
4. curves=all='0/0 0.5/0.55 1/1' # S曲线拉反差
5. colortemperature=temperature=5300 # 色温偏移
"""
```
FFmpeg命令模板:
```bash
ffmpeg -i input.mp4 \
-vf "gblur=sigma=0.4,noise=alls=12:allf=t+u,\
eq=saturation=0.88,curves=all='0/0 0.5/0.55 1/1',\
colortemperature=temperature=5300" \
-c:v libx264 -preset medium -crf 18 \
output.mp4
```
拼接:所有处理后的片段用 concat 滤镜拼接,输出最终mp4。
九、FastAPI入口
端点列表:
方法 路径 功能
POST /api/director/generate 输入故事,返回分镜Schema
POST /api/task/submit 提交分镜,返回task_id
GET /api/task/{task_id} 查询任务状态
POST /api/task/{task_id}/retry 重试某镜头
GET /api/assets/characters 列出所有角色
POST /api/assets/characters 上传角色
GET /api/assets/characters_3d 列出3D角色
POST /api/assets/characters_3d/generate 调用混元3D生成角色
GET /api/assets/products 列出产品资产
POST /api/assets/products 上传产品
GET /api/vfx/list 列出可用特效
POST /api/vfx/preview 生成特效样片
GET /api/output/{project_id} 列出成片
GET /api/config/providers 获取当前提供商配置
PUT /api/config/providers 切换提供商
十、部署说明
10.1 本地环境
组件 部署方式 端口 备注
n8n Docker 5678 挂载 ~/dcs/n8n
Appsmith Docker 80 挂载 ~/dcs/appsmith
FastAPI Docker 8000 挂载 assets/output/temp/config
FFmpeg 本地安装 — brew install ffmpeg / apt install ffmpeg
资产库 本地文件夹 — ~/dcs/assets
导演系统 本地脚本或远端API — 包装为FastAPI端点
10.2 Docker Compose
```yaml
version: '3.8'
services:
n8n:
image: n8nio/n8n
ports:
- "5678:5678"
volumes:
- ./n8n:/home/node/.n8n
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=admin
appsmith:
image: appsmith/appsmith-ce
ports:
- "80:80"
volumes:
- ./appsmith:/appsmith-stacks
api:
build: .
ports:
- "8000:8000"
volumes:
- ./assets:/app/assets
- ./output:/app/output
- ./temp:/app/temp
- ./config:/app/config
env_file:
- .env
depends_on:
- n8n
```
10.3 远程访问
Tailscale:本地机器和其他设备安装Tailscale,登录同一账号。访问 http://<Tailscale IP>:80(Appsmith)和 http://<Tailscale IP>:5678(n8n)。
十一、环境变量清单
```bash
# ========== 导演系统 ==========
DIRECTOR_TYPE=storyboard_director_v52
# ========== TTS ==========
TTS_PROVIDER=fish_audio
FISH_AUDIO_API_KEY=
FISH_AUDIO_VOICE_ID=
ELEVENLABS_API_KEY=
# ========== 口播视频 ==========
TALKING_HEAD_PROVIDER=d_id
D_ID_API_KEY=
D_ID_AVATAR_ID=
HEYGEN_API_KEY=
# ========== 动作视频 ==========
ACTION_PROVIDER=kling
KLING_API_KEY=
KLING_API_SECRET=
WAN_ANIMATE_API_KEY=
# ========== 背景视频 ==========
BACKGROUND_PROVIDER=tongyi_wanxiang
TONGYI_API_KEY=
SORA_API_KEY=
# ========== ComfyUI ==========
COMFYUI_PROVIDER=runninghub
RUNNINGHUB_API_KEY=
RUNNINGHUB_WORKFLOW_ID=
# ========== 3D角色 ==========
CHARACTER_3D_PROVIDER=hunyuan_3d
HUNYUAN_3D_SECRET_ID=
HUNYUAN_3D_SECRET_KEY=
HUNYUAN_3D_REGION=ap-guangzhou
# ========== 特效 ==========
VFX_BULLET_TIME_PROVIDER=wondershare_tianmu
WONDERSHARE_TIANMU_API_KEY=
VFX_CAMERA_PROVIDER=kling
# 可灵camera_control参数在分镜Schema中动态传入
# ========== 本地路径 ==========
ASSETS_DIR=./assets
OUTPUT_DIR=./output
TEMP_DIR=./temp
# ========== 去AI化默认参数 ==========
DEAI_BLUR_SIGMA=0.4
DEAI_GRAIN_INTENSITY=12
DEAI_SATURATION_OFFSET=-0.12
DEAI_TEMPERATURE_SHIFT=0.03
DEAI_FRAME_BLEND=2
# ========== 服务端口 ==========
API_PORT=8000
N8N_PORT=5678
APPSMITH_PORT=80
```
十二、项目目录结构
```
dcs/
├── README.md
├── docker-compose.yml
├── .env.example
├── requirements.txt
├── start.sh
├── stop.sh
│
├── config/
│ ├── providers.yaml
│ ├── templates/
│ │ ├── vlog_hospital.yaml
│ │ ├── product_ad.yaml
│ │ └── daily_diary.yaml
│ └── post_process.yaml
│
├── assets/
│ ├── characters/
│ ├── characters_3d/
│ ├── locations/
│ ├── real_locations/
│ ├── products/
│ ├── props/
│ ├── bgm/
│ ├── sfx/
│ └── vfx_presets/
│
├── src/
│ ├── main.py
│ ├── schemas.py
│ │
│ ├── director/
│ │ ├── base.py
│ │ ├── storyboard_director.py
│ │ └── adapter.py
│ │
│ ├── orchestrator/
│ │ ├── dispatcher.py
│ │ └── task_manager.py
│ │
│ ├── providers/
│ │ ├── base.py
│ │ ├── tts/
│ │ │ ├── fish_audio.py
│ │ │ └── elevenlabs.py
│ │ ├── talking_head/
│ │ │ ├── d_id.py
│ │ │ └── heygen.py
│ │ ├── action/
│ │ │ ├── kling.py
│ │ │ └── wan_animate.py
│ │ ├── background/
│ │ │ ├── tongyi_wanxiang.py
│ │ │ └── sora.py
│ │ ├── comfyui/
│ │ │ └── runninghub.py
│ │ ├── character_3d/
│ │ │ ├── hunyuan_3d.py
│ │ │ └── flow_studio.py
│ │ └── vfx/
│ │ ├── wondershare_tianmu.py
│ │ ├── hailuo.py
│ │ └── kling_vfx.py
│ │
│ ├── compositor/
│ │ ├── de_ai.py
│ │ ├── concat.py
│ │ └── ffmpeg_utils.py
│ │
│ ├── assets_manager/
│ │ ├── loader.py
│ │ └── validator.py
│ │
│ └── utils/
│ ├── logger.py
│ ├── retry.py
│ └── file_utils.py
│
├── n8n/
│ └── workflow.json
│
├── appsmith/
│ └── application.json
│
├── output/
├── temp/
│
└── tests/
├── test_schemas.py
├── test_director.py
├── test_providers.py
├── test_compositor.py
└── fixtures/
└── sample_storyboard.json
```
十三、开发路线图
阶段 目标 交付物
阶段1:手动验证 用现有API跑通一条20秒测试片 分镜JSON、测试视频、去AI化参数
阶段2:本地环境 部署n8n + Appsmith + FFmpeg 可访问的控制台
阶段3:导演系统接入 导演系统输出统一Schema 分镜编辑页面可用
阶段4:n8n工作流 串联TTS+口播+背景+FFmpeg 自动生成第一条成片
阶段5:3D角色+特效 接入混元3D + 万兴天幕/可灵运镜 3D角色和特效可用
阶段6:ComfyUI接入 RunningHub API调用 精细控制镜头
阶段7:批量生产 循环分镜表,批量输出 批量任务队列
阶段8:优化迭代 调参、换API、迁移服务器 稳定生产系统
十四、AI编程工具执行清单
```
请按以下顺序生成项目代码:
1. 创建项目根目录结构(mkdir -p dcs/src/...)
2. requirements.txt(fastapi, uvicorn, pydantic, requests, pyyaml, ffmpeg-python)
3. .env.example(按第十一节)
4. src/schemas.py(按第四节)
5. src/director/base.py + storyboard_director.py + adapter.py
6. src/providers/base.py
7. src/providers/tts/fish_audio.py
8. src/providers/talking_head/d_id.py
9. src/providers/action/kling.py(含camera_control参数支持)
10. src/providers/background/tongyi_wanxiang.py
11. src/providers/comfyui/runninghub.py
12. src/providers/character_3d/hunyuan_3d.py
13. src/providers/vfx/wondershare_tianmu.py
14. src/providers/vfx/hailuo.py
15. src/providers/vfx/kling_vfx.py
16. src/compositor/de_ai.py + concat.py + ffmpeg_utils.py
17. src/assets_manager/loader.py + validator.py
18. src/orchestrator/dispatcher.py + task_manager.py
19. src/main.py
20. src/utils/logger.py + retry.py
21. docker-compose.yml
22. start.sh
23. config/providers.yaml + templates/vlog_hospital.yaml
24. tests/test_schemas.py + fixtures/sample_storyboard.json
25. n8n/workflow.json
26. appsmith/application.json(可先留框架)
生成后运行 pytest 确保测试通过。
所有API Key从环境变量读取,不硬编码。
所有异步API调用使用统一的 poll_until_complete 轮询逻辑。
所有Provider继承 BaseProvider,实现 generate(shot, assets) -> dict 方法。
```
十五、需团队手动完成的事项
事项 操作
注册API Fish Audio、D-ID、可灵、通义万相、RunningHub、混元3D、万兴天幕
填写.env 把Key填入.env文件
导入n8n工作流 n8n界面 → Import from File
导入Appsmith应用 Appsmith界面 → Import Application
准备角色参考图 放入assets/characters/char_001/
准备产品参考图 放入assets/products/
在RunningHub搭建工作流 导入社区工作流或手动搭建,发布为API工作流
跑第一条测试 在控制台输入故事,点击生成
十六、导演操作流程(日常使用)
```
1. 打开浏览器 → http://localhost
2. 在分镜编辑页输入故事大纲
3. 选择内容类型(产品广告/个人日记/场景短剧)
4. 选择角色(2D参考图 或 3D绑定模型)
5. 选择场景/场地/产品
6. 点击“生成分镜” → 导演系统返回分镜表
7. 逐条检查/修改 → 可添加特效(子弹时间/环绕运镜等)
8. 点击“提交任务”
9. n8n自动调用各API生成片段
10. FFmpeg自动去AI化+拼接
11. 刷新页面 → 预览成片
12. 不满意 → 修改对应镜头参数 → 重试单条
```