songhuiming2007-coder/anime-video-agent

把选题变成动漫二创成片的 agent 流水线:字幕语义索引 → 排片 → 本地 TTS → 渲染 → 11 项自动质检

1

stars

100

commits

Python

primary language

Sep 8, 2026

updated

README

anime-video-agent

一条把选题变成动漫二创成片的命令行流水线(默认目标 2–4 分钟,可按选题体裁覆盖)。输入是一句选题,输出是可以直接上传的 mp4、封面图和标题候选。中间的写稿、配音、找素材、剪辑、质检由脚本和 coding agent 完成, 人类在 02.5(人审改稿)、03.5(配音顺听)、05(审时间码)与 09(发布)四处介入。

目录


一、项目介绍

1.1 它做什么

选题 → 写稿 + 稿件机检 → 本地 TTS 配音 → 语义检索排画面 → [人审时间码]
     → 渲染(切片 + 烧字幕 + 混 BGM)→ 11 项自动质检 → 封面候选 + 标题 → [人选并发布]

每一步都是一条独立命令,产物带编号落盘在 data/episodes/<本期>/01-topic.md07-cover/)。看目录里有哪些文件,就知道进行到哪一步。 没有数据库、没有状态文件、没有任务队列,任何一步失败,修好之后从那一步接着跑。

1.2 人在哪里出现

步骤谁做时长
周批量选题(摊到每期)1.5 分钟
写稿、配音、排片Agent约 6 分钟机器时间
02.5 人审改稿约 3–5 分钟
05 审时间码5 分钟
渲染、质检、封面Agent + 机器约 2.5 分钟机器时间
09 选封面、选标题、上传3 分钟

设计目标是人类每期投入 ≤ 10 分钟(尚未端到端验证)。超预算不当作「这期多花点时间」, 而是当作流水线有 bug——改流水线或砍掉那个环节。

1.3 核心设计取向:让失败显式发生

几乎所有难修的 bug 都有同一个特征:它不报错。ffmpeg 截取超出片尾时静默截断; 检索找不到画面照样返回 Top-K;索引只建了 6 集而片源有 41 集时成片照常渲染。所以项目的 重点不在功能,而在判据:每加一道检查,先问它测的是不是真实产物;每引入一个分数, 先问它能不能用来排序。完整证据见 docs/STANDARD.md

1.4 明确不做的事

  • 不做纯搬运。 混剪加原创口播属于灰区,口播是加分项;没有口播的内容不做。
  • 不自动上传。 省下的几分钟不值得拿账号冒险,第 09 步永远手动。
  • 不做画质、转场、文案的无限打磨。 边际收益极低,时间只花在让流水线更自动、更可靠上。
  • 政治议题不进自动管道。 agent 不掌握中文平台的审核边界,风险显著高于人工。
  • 不引入 NLE 和视频框架。 MoviePy 比直接调 ffmpeg 慢一个量级且不增加能力。

二、前置要求

2.1 运行环境

项目要求不满足会怎样
coding agent能跑 shell、能读图第 02 步写稿没有对应脚本,缺了它这一步就是空的。详见 2.2
操作系统macOS只在 macOS 上跑过
处理器Apple Silicon(配音与 ASR 需要)装不上 mlx,配音与 ASR 兜底不可用;其余步骤能跑
Python3.12 / 3.13 / 3.143.15 还在 beta,没验过。numpy<2.5 上界不能删,理由见 2.6
ffmpeg必须带 libass烧不了字幕,渲染会在最后一步失败。brew install ffmpeg 的默认版本带
包管理uv也可以用别的,但依赖版本是按 uv 那一组钉住的

语音部分只跑 Apple Silicon 是硬限制。config/voice.json 留了 engine 字段作为接缝, 目前有两种 mlx 实现:IndexTTS-1.5(纯中文)与 Qwen3-TTS 1.7B(多语种,2026-08-15 起为默认)。

2.2 Coding Agent 是前置要求(默认推荐 Pi)

这个仓库的预期用法是 clone 下来交给成熟的 Coding Agent 驱动,不是一个人对着终端逐条手敲命令。 实战中默认推荐 Pi(配合 Gemini 3.8 / Kimi K3,已稳定生产并发布 15 期全网视频),亦完全兼容 Claude Code 等通用 Agent。

仓库里有两份东西专门写给 Agent 看:

文件给 Agent 的内容
AGENTS.md / CLAUDE.md工程约定:六条红线、四阶段人工停机点、台词因果哈希、哪些判据不许绕过
skills/write-script/写稿技能:五种题材骨架与判据、8–12 秒微单元标准、气口起伏量化

各步骤对 Agent 的依赖程度不同:02 写稿没有 Agent 不行(没有任何脚本会生成稿子); 08 挑封面候选和写标题可以没有 Agent,但会退化成机械铺开取样、不一定切题;其余各步都是 纯脚本。对 Agent 的能力要求有两条是实的:能跑 shell能读图(第 08 步要看 6×5 的联系表认人)。不能读图的 Agent 仍能跑完整条流水线,只是封面挑选退化成机械取样。

2.3 需要的模型(合计约 4G)

模型全部落在 data/models/ 下,不落系统盘——由 pipeline/paths.py 在 import 时把 HF_HOME 钉过去。

模型用途大小怎么来
BAAI/bge-base-zh-v1.5字幕语义索引与检索约 400M首次运行自动下载
mlx-community/whisper-large-v3-turbo回读质检、字幕对轴校验、无字幕时兜底转录约 1.5G首次运行自动下载
mlx-community/Qwen3-TTS-12Hz-1.7B-Base-bf16配音(多语种,中文旁白 + 英日歌名混读)约 4.3Gconfig/voice.json 自动下载
deepghs/anime_face_detection视觉索引:人脸检测约 42M首次运行自动下载
deepghs/ccip_onnx视觉索引:角色身份嵌入约 143M首次运行自动下载

注意 import 顺序:任何会下载模型的模块,第一个 import 必须是 pipeline.paths,否则 模型会静默写进系统盘。paths.py 会检测并当场报错。

2.4 需要自备的素材

仓库不包含也不分发任何素材。

素材要求
片源一部番的完整正片,几十 G 量级
字幕时间轴必须照你手上那个视频文件打的。 只允许三种来源:ffmpeg 提取的内封字幕;对该文件跑 ASR 转录的结果;与该文件同属一个发布、文件名逐一对应且通过对轴校验的外挂字幕。日语无字幕片源不支持(ASR 兜底仅中文,见 ADR-0007)
参考干声5–8 条,每条 8–10 秒,连续说话不要留大段静音。用来克隆口播音色
BGM该番自己的 OST / OP / ED。整轨镜像加 cue 的碟需要先分轨

永远不要用第三方字幕文件配第三方视频文件。 跨版本差异是中间的插入与删除,不是恒定 偏移,加 offset 修不好。而帧级精确截取是渲染链路的前提,前提一塌视频照样渲染, 只是全程画面对不上话,没有任何报错。

2.5 data/ 放在哪

仓库本身只有纯文本(代码、配置、文档、skills),全部进 git。片源、字幕、索引、模型、 每期产物都在 data/ 下,不进 git。两种放法都支持:

./pipeline/preflight.sh --init                            # 系统盘装得下,建实体目录
./pipeline/preflight.sh --init /Volumes/<你的盘>/anime-video-data   # 外置盘 + 符号链接

脚本绝不自动创建 data/,不可达就立刻报错退出。 符号链接指向未挂载的卷时,mkdir -p 会把几十 G 静默写进系统盘且盘插上后看不见——建骨架必须是显式动作,preflight.sh --init 会打印结果落在哪块盘上。代码里一律用 ./data/... 相对路径,不硬编码卷路径。

2.6 安装

brew install ffmpeg
uv venv --python 3.14                         # 3.12 / 3.13 / 3.14 都可以
uv pip install -e ".[apple,dev]"              # 非 Apple Silicon 去掉 apple
pytest                                        # 纯函数测试,不碰片源/模型/外置盘
./pipeline/preflight.sh                       # 自检
cp CLAUDE.local.md.example CLAUDE.local.md    # 填本机情况,不进 git

pytest 首次跑要一分钟左右,之后约 3 秒。preflight.sh 检查 data/ 可达、ffmpeg 在、 ffmpeg 真的带 ass 滤镜——有 ffmpeg 不等于能烧字幕,缺 libass 渲染会在最后一步才失败。 CLAUDE.md 是给 coding agent 读的工程约定,跑这个项目的人也建议读一遍。CLAUDE.local.md 放只对你这台机器成立的事实,不进 git。

关于 Python 版本和那条 numpy<2.5

2026-07-30 实测,3.12、3.13、3.14 三个版本都跑通,3.15 还在 beta,没验。

pyproject.toml 里那条 numpy>=2.0,<2.5 的上界不能删。依赖链 mlx-whisper → numba → llvmlite 里 numba 0.66 要求 numpy<2.5;numpy 2.5 一发布, 解析器就优先选它,把 numba 0.66 排除,回退到只支持 Python <3.10 的版本,转去源码构建 并失败。这个坑只咬新环境——已有 venv 一切正常不构成证据。判据得是真装一遍: uv pip install --dry-run 只解析不构建,会「成功」地解出装不上的组合。


三、技术栈及全流程工作介绍

3.1 技术栈一览

环节用什么为什么这么选
语义检索sentence-transformers + bge-base-zh-v1.5bge-small 实测命中率只有 75%,base 是 100%
索引单元ASS 字幕滑窗 2 行,一集一个 .npy单行太碎,一句话常跨两行轴
配音mlx-community/Qwen3-TTS-12Hz-1.7B-Base-bf16 跑在 mlx-audio 上(多语种,中文旁白夹英日歌名混读)云 API 把联网+账号+配额塞进主循环,还要外传参考干声
ASRmlx-whisper large-v3-turbo回读质检、对轴校验、兜底转录三处都用
视频与音频全程 ffmpeg,无 NLE见 1.4
字幕烧录ass 滤镜(libass),折行自己算libass 靠空格找断点,中文整句没有空格就不折
BGM侧链闪避,按实测响度归一到 -26 LUFS固定音量系数是错的控制量
镜头切分ffmpeg scdet,低阈值扫一遍再过滤检索单元必须是镜头不是帧;改阈值不用重解码
角色在场动漫人脸检测 → CCIP 嵌入 → 聚类 → 人工贴名booru tagger 词表大的认不准、认得准的词表小
封面筛选Pillow:清晰度/亮度/去重,可选角色在场过滤只做剔除,不做排序
状态管理文件系统产物即状态。人机交接一律走文件
测试pytest,纯函数测试(条数见 CI / pytest --collect-only不 mock ffmpeg 和模型,mock 检查的是 mock

没有的东西也是选择:没有云 API、没有数据库、没有编排框架、没有 web 界面、没有一键脚本。

3.2 Phase 0:一部番做一次

成本固定,摊到多期上才划算。一部番榨干再换番。 完整判据见 docs/WORKFLOW.md

第一步:验片源完整性

python -m pipeline.ingest intact data/library/raw/<番>/*/*.mkv

下载器显示 100% 不等于文件完整。 BT 没下完的文件是稀疏文件,ffprobe 照样读得出时长。 判据是 ffmpeg 全片解复用无报错(-c copy -f null -),约 0.9 秒一个文件。「实占块 ÷ 逻辑大小」只当前置快筛:说「没下完」可信,说「下完了」不可信。

第二步:整季入库

python -m pipeline.ingest phase0 data/library/raw/<番>/<该季目录>/*.mkv \
    --anime <番> --season 1

一条命令做三件事:逐集对轴校验 → 过了才建索引 → 登记片源进 sources.json,三步不许拆开, 任何一集对轴不过就跳过并说明原因,不静默降级。对轴判据是 ASR 回读比对字符错误率——文件 名对应只能证明「打包时放在一起」,真正能证伪的只有拿视频自己的声音去对。需要字幕带日文轨, 只有纯中文字幕的集走 ASR 兜底或者放弃。

第三步:建视觉索引

字幕索引答的是「谁说了什么」,画面里有谁它答不了。这一步补上(设计见 ADR-0003),机器时间约 2.4 小时:

python -m pipeline.shots calibrate <一集视频>               # 定切分阈值,看抽检图再拍板
# 选定的数写进 config/project.json 的 visual.scene_threshold
python -m pipeline.shots build <视频> --anime <番> --season N --episode M   # 逐集切分
python -m pipeline.shots frames <番> <集号>                                  # 抽代表帧
python -m pipeline.faces detect <番> <集号>...                               # 人脸检测
python -m pipeline.faces cluster <番> && python -m pipeline.faces sheet <番> # 聚类出联系表
python -m pipeline.faces name <番> 0 八幡      # ← 人在这里:看图给每簇贴名(约 2 分钟)
python -m pipeline.faces presence <番>                                        # 落索引

第 5 步的人工介入是设计的一部分,不是妥协:一部番只做一次,姐妹脸这类只有人能一眼 分开。不用现成 booru tagger 的原因:词表大的置信度太低,认得准的词表里连主角都没有。

第四步:确认六条数字相等

python -m pipeline.vindex status --anime <番>
#   片源 / 字幕索引 / 笔记 / 镜头表 / 角色在场 / 画面语义

六条数字不相等就不许进每期循环。 索引或笔记悄悄缩水时,检索照常返回 Top-K、分数照常 在阈值以上、成片照常渲染,全程没有任何报错——判据不能是「检索得到东西吗」, 必须是「集数对得上吗」,前者永远为真。

第五步:选音色

for f in data/voice/reference/*.wav; do
  python -m pipeline.tts probe "随便一句带长句和短判断的话" \
      --ref "$f" --out "data/voice/probe/$(basename "$f")"
done

按重要性听三样:语速(不同参考音实测差 65%,直接决定成片长度)、稳不稳(电音、 忽快忽慢、句尾发飘)、音色(排最后,听的是「能不能撑 2–4 分钟口播」)。单句试音 不能预测整篇语速,估成片长度必须看 manifest.json 的总时长。选定后改 config/voice.jsonref_audioscript.cpm 要重测(同一音色不同文风下差过 24%)。

第六步:定 BGM 曲目表

python -m pipeline.bgm scan    <CD 目录>                    # 解 cue,列出 instrumental 轨
python -m pipeline.bgm extract <CD 目录> --anime <番>        # 切成独立 flac
python -m pipeline.bgm measure data/library/bgm/<番>/*.flac  # 量时长、响度、入声点

Phase 0 只攒候选池不 定死选曲(2026-08-08 起):具体每期用哪首,等这期配音(03)出来、 人耳听过之后填进当期 01-topic.md——BGM: 列表每行一首,@N秒 定起点(不写自动接上一首 结尾),支持任意首数拼接;老写法 BGM正文 / BGM中段(配 BGM中段切入点: N秒)/ BGM结尾 仍可用。扫曲库必须解 cue,不能只数文件(OP/ED 单曲碟是整轨镜像)。曲目表里没有实测 lufs 的曲子不许用(劇伴与 OP/ED 伴奏实测极差 11 dB)。乐评类期数还有试听型渲染 (pipeline/music):音乐段当前景、段落间降 BGM、结尾自然收尾。

3.3 每期九步

01 选题 —— 人,周批量

01-topic.md 必须带齐四项:类型(人物志 / 剧情回顾 / 杂谈 / 盘点 / 共鸣)、锚点 (季集号),可选 封面集。杂谈还要带 模式(驳论 / 立论 / 吐槽)与 张力(驳论/立论)。 张力是整条流水线里唯一的编辑判断——必须在这一步定死并经人批准,不能留到写稿阶段由 agent 自行发明(那等于绕过唯一的人工关卡)。人物志/剧情回顾/共鸣不设张力:观点就是人物/故事本身。 写稿只校验、不更换。

02 写稿 —— Agent 约 3 分钟

skills/write-script:读上一期的稿子(为了不重样)→ 查证剧情 → 按 类型 读第 4 节对应骨架 (杂谈先校验 模式/张力)→ 按题材骨架写正文 → 切成 8–20 段,每段配一条 查询 和一条 备选

五种题材五种骨架,全部从真实优秀内容里拆的(人物志=罗十五;剧情回顾/杂谈/盘点/共鸣=bangumi 长评与知乎长文)。骨架是「这类内容怎么走通」的范本,不是分步模板——写的时候像人说话, 写完再拿判据筛。

python -m pipeline.check_script data/episodes/<本期>/02-script.md

机检覆盖:字数、时长、单句上限、句长起伏、论文连接词、跨期套话、论据是否报菜名、剧情 锚点数、查询是否重复、查询是否误写成画面构图等。主观项机器判不了,脚本按 01-topic.md类型 给出对应提示(杂谈看张力/公道话,人物志看有没有给角色安论点……)。机检全过不代表能交,自检两遍顺序不能反:先保真(台词 原文、说话人、集号、数字),再去味查询 是机器接口,不是备注——它被原样送进 字幕索引检索,要写成台词语义:「角色承认自己一直在逃避」有效,「中景,逆光」必然落空, 字幕里没有构图信息。

03 配音 —— Agent 约 5–10 分钟机器时间

python -m pipeline.tts data/episodes/<本期>

逐段合成,保留段落边界。每段时长用 ffprobe 复核后写进 03-audio/manifest.json—— 这是下一步排画面的唯一依据,不采信模型自报。中断可直接重跑,已过的段落跳过; 改稿、换音色(engine/model/ref_audio/读音表)后再跑都只重做受影响的段。 按句合成不按段(语速与文本长度正相关)。

每段生成后用 Whisper 回读比对,抓漏读、重复、跑飞;不过就换种子重生成,三次仍不过 就整体退出——自回归 TTS 的典型失败不是报错,是静默地念错。回读比对前会归一化,而归一化 可能把缺陷一起抹掉,所以合成前用 tts.speakable 剥掉纯书面符号。成片交人前至少听一遍 开头和最长的那段。

04 素材检索排片 —— Agent 约 1 分钟

python -m pipeline.clips data/episodes/<本期>

每段 查询 送进索引取 Top-24,然后全局贪心分派:所有 (段, 画面, 分数) 摊平按分数 降序占坑,同一处画面整期只用一次——不按段落顺序分,那是先到先得。每段按音频真实时长 填满,片段不短于 2.5 秒。顺序不可交换:字数估算与实际语速的偏差攒出几秒的渐进错位, 越到后面画面与口播差得越远,全程不报错。

检索落空走查询阶梯查询备选 → 该段 配音 原文,逐级重试,门槛 0.45 不动。 阶梯只救不比——上一级够格就到此为止,绝不因为下一级分数更高而换掉。三级都不及格就 写 "status": "no_match",渲染硬失败交人处理,不自动降级——自动塞空镜是把「画文不符」 藏起来。

视觉索引接进来的两个通道

分镜可以声明走哪条通道(ADR-0003),二选一,都不写就走台词检索:人物: 雪乃 = 台词检索

  • 角色在场过滤(修「命中了谁说的、镜头却在说话人身上」这类错配;过滤是软的,为空就 退回不过滤的结果——「没检测到 X」不代表 X 不在场);场景: 描述 = 画面语义检索, 当前不可用——门槛立不住,CLIP 余弦能排高低、答不了「这算不算命中」(ADR-0003 待实测 #4),写了会当场报错。

两条铁律: 一段只走一个通道,两个字段都写会当场报错;分数只在自己的通道内排序,绝不 跨通道比较。分派画面时台词段先挑——它们要的是「那句话发生的那一刻」,具体且不可替换。

05 审时间码 —— 人 5 分钟

python -m pipeline.review data/episodes/<本期>              # 出 04-review.html
open data/episodes/<本期>/04-review.html
python -m pipeline.review data/episodes/<本期> --approve

这是整条流水线唯一的人工关卡。 一页 HTML,每段并排口播、画面、字幕原文三样,每个片段 抽三帧(进点、中间、出点)。要抓的是台词对了但画面不对:那句话可能是画外音,机器判 不了,只有眼睛能抓。--approve 必须是显式动作——自动写 approved 是最省事的做法, 也正是这一关曾经形同虚设的原因。

06 渲染 —— Agent 约 1.5 分钟

python -m pipeline.render data/episodes/<本期>

切片 → 统一中间格式 → 拼接 → 混 BGM → 烧字幕 → 响度归一,一趟出片。40 个片段、3 分钟 成片实测 77 秒。

两道截取守卫强制执行,缺一不可: 切前校验 seek + duration <= 源时长,不足立即失败; 切后复核实际时长与请求值之差不超过 1 帧(按源片实际帧率现算,不许写死——番剧常见 23.976 / 24 / 29.97 三种帧率)。

字幕折行自己算,不指望 libass(它靠空格找断点,中文没有空格就不折):断点取标点, 贪心取放得下的最远那个;中文破折号是两个字符,必须等一对补全再断。

BGM 支持任意首数拼接01-topic.mdBGM: 列表每行一首、@N秒 定起点,后一首 起点早于前一首自然结尾就等功率交叉(qsin,3 秒),晚了留停顿;老写法(正文/中段/结尾 槽位)仍可用,换曲点卡段落边界。每首按实测响度归一到 -26 LUFS,再以人声为触发做侧链 闪避。固定音量系数是错的控制量——换一首响度不同的曲子会凭空大 9.8 dB 压过口播, 且不报错。

07 质检 —— 机器约 40 秒

python -m pipeline.qc data/episodes/<本期>

11 项,不达标非零退出,不进人工环节:时长落在目标带(默认 2–4 分钟,01-topic.md 写了 时长目标 就按那个带判,见 CLAUDE.md「内容参数」);音画误差 < 0.5s;响度 -16 LUFS、 true peak ≤ -1 dBTP;无 >0.5s 黑帧、>2s 静音;字幕无空段、不超宽、每卡一行、不超高。 查的是实际折行结果,不是「原文长度 ÷ 每行容量」——检查项一旦测的不是真实产物, 通过就毫无意义。主观项(节奏、观感)不进门禁,根在稿子和排片,回 02/05 改。

08 封面与标题 —— Agent 约 1 分钟

python -m pipeline.cover data/episodes/<本期>                     # 出池子 + 联系表
python -m pipeline.cover data/episodes/<本期> --pick 107,110,20    # 定 9 张

这一步不新增人工环节,选封面和选标题并进第 09 步。

候选帧从三处取: 实际用上的片段(每 0.5 秒一帧)、名场面时间码、01-topic.md封面集 通篇(每 12 秒一帧,跳过 OP/ED)。第 3 路是被打脸打出来的:只用前两路时九张里 没有一张主角占主位——前两路的帧都来自字幕检索命中的时刻,而台词大多是别人说给主角听的, 镜头自然在说话人身上。

机器只做剔除,逐条有明确判据: 拉普拉斯方差 < 60 剔运动模糊;平均亮度落 40–215 之外 剔黑场过曝;同集相隔 < 6 秒或 dHash 相近算同一镜头只留一张;可选按 封面人物: 一色彩羽 (或 --character)硬过滤掉没有本期主角的帧(硬过滤为空则失败,与排片的软过滤相反); 2 个坑留给名场面,其余按段落号均分取样。候选之间没有排名,这是刻意的——拉普拉斯方差 测的是「画面里有多少细节」,不是「画面有多好」,两版打分都压掉了正确答案;清晰度是准入门槛, 不是排序依据。

分工是三层,不是两层: 机器剔黑场/过曝/糊帧、去重、编号 → agent 看联系表(6×5 一张、 带编号)挑出符合本期主题的(认人、占不占主位)→ 人从 9 张里定一张(审美)。agent 看完 报编号给 --pick;不加 --pick 时退到机械铺开取样,仍然出得了 9 张。

标题给 5 条候选,每条注明路子(下判断 / 反问 / 复述再打 / 剧情钩子 / 金句),原料取 稿件的第 2 节(亮判断)和第 8 节(结论)。判据是金句式而非论文式——这句话能不能脱离 视频单独发出去07-titles.md 已填表就不再覆盖(标题和封面同一条命令出,重跑会冲掉)。

09 发布 —— 人 3 分钟

点一张封面、点一条标题,然后上传。上传手动做,不自动化。(2026-08-09 起本期耗时 由 agent 在会话内记录,不再落盘 meta.md。)

3.4 测试与守卫

pytest        # 纯函数测试,约 3 秒,不碰片源、模型、外置盘

测试只覆盖纯函数,测的是踩过的坑,不是 API 形状——每条断言对应一个具体错误。不为了 提覆盖率去 mock 掉 ffmpeg 或模型,涉及媒体的正确性交给截取守卫和质检门禁在真跑时兜。

写测试两条纪律:期望值先在实现上跑一遍、看懂为什么是这个值,再写进断言;写完做变异检验 ——把被测行为故意改坏,看测试红不红(一条永远绿的断言和没有断言效果一样)。

3.5 换一部番

  1. config/project.jsonanime.default
  2. config/bgm.json 加一组曲目,每首必须带实测 lufs
  3. config/characters.json 加这部番的角色名表(中文名 ↔ 聚类贴的名字)
  4. 重新标定镜头切分阈值——画风、剪辑节奏逐番不同,沿用上一部的数不算实测
  5. 重跑整个 Phase 0。索引按番隔离,clipssubindex search 都按番过滤

换成真人影视素材时,视觉索引第 1 层要整块换掉(动漫人脸检测器和 CCIP 都是动漫专用的), 这是有意做成可插拔通道的原因。

skills/write-script/VOICE.md空模板,教你怎么从自己的既有文稿里提炼一份,填好放 VOICE.local.md(不进 git)。不填也能出稿,但会是通用 AI 腔。


License

MIT,见 LICENSE

素材本身(片源、字幕、音乐)不属于本仓库,也不随仓库分发。 二创的版权风险由使用者 自负。config/bgm.json 里的曲目表只有路径和实测响度,不含任何音频。

Contributors

songhuiming2007-coder/anime-video-agent

把选题变成动漫二创成片的 agent 流水线:字幕语义索引 → 排片 → 本地 TTS → 渲染 → 11 项自动质检

1

stars

100

commits

Python

primary language

Sep 8, 2026

updated

README

anime-video-agent

一条把选题变成动漫二创成片的命令行流水线(默认目标 2–4 分钟,可按选题体裁覆盖)。输入是一句选题,输出是可以直接上传的 mp4、封面图和标题候选。中间的写稿、配音、找素材、剪辑、质检由脚本和 coding agent 完成, 人类在 02.5(人审改稿)、03.5(配音顺听)、05(审时间码)与 09(发布)四处介入。

目录


一、项目介绍

1.1 它做什么

选题 → 写稿 + 稿件机检 → 本地 TTS 配音 → 语义检索排画面 → [人审时间码]
     → 渲染(切片 + 烧字幕 + 混 BGM)→ 11 项自动质检 → 封面候选 + 标题 → [人选并发布]

每一步都是一条独立命令,产物带编号落盘在 data/episodes/<本期>/01-topic.md07-cover/)。看目录里有哪些文件,就知道进行到哪一步。 没有数据库、没有状态文件、没有任务队列,任何一步失败,修好之后从那一步接着跑。

1.2 人在哪里出现

步骤谁做时长
周批量选题(摊到每期)1.5 分钟
写稿、配音、排片Agent约 6 分钟机器时间
02.5 人审改稿约 3–5 分钟
05 审时间码5 分钟
渲染、质检、封面Agent + 机器约 2.5 分钟机器时间
09 选封面、选标题、上传3 分钟

设计目标是人类每期投入 ≤ 10 分钟(尚未端到端验证)。超预算不当作「这期多花点时间」, 而是当作流水线有 bug——改流水线或砍掉那个环节。

1.3 核心设计取向:让失败显式发生

几乎所有难修的 bug 都有同一个特征:它不报错。ffmpeg 截取超出片尾时静默截断; 检索找不到画面照样返回 Top-K;索引只建了 6 集而片源有 41 集时成片照常渲染。所以项目的 重点不在功能,而在判据:每加一道检查,先问它测的是不是真实产物;每引入一个分数, 先问它能不能用来排序。完整证据见 docs/STANDARD.md

1.4 明确不做的事

  • 不做纯搬运。 混剪加原创口播属于灰区,口播是加分项;没有口播的内容不做。
  • 不自动上传。 省下的几分钟不值得拿账号冒险,第 09 步永远手动。
  • 不做画质、转场、文案的无限打磨。 边际收益极低,时间只花在让流水线更自动、更可靠上。
  • 政治议题不进自动管道。 agent 不掌握中文平台的审核边界,风险显著高于人工。
  • 不引入 NLE 和视频框架。 MoviePy 比直接调 ffmpeg 慢一个量级且不增加能力。

二、前置要求

2.1 运行环境

项目要求不满足会怎样
coding agent能跑 shell、能读图第 02 步写稿没有对应脚本,缺了它这一步就是空的。详见 2.2
操作系统macOS只在 macOS 上跑过
处理器Apple Silicon(配音与 ASR 需要)装不上 mlx,配音与 ASR 兜底不可用;其余步骤能跑
Python3.12 / 3.13 / 3.143.15 还在 beta,没验过。numpy<2.5 上界不能删,理由见 2.6
ffmpeg必须带 libass烧不了字幕,渲染会在最后一步失败。brew install ffmpeg 的默认版本带
包管理uv也可以用别的,但依赖版本是按 uv 那一组钉住的

语音部分只跑 Apple Silicon 是硬限制。config/voice.json 留了 engine 字段作为接缝, 目前有两种 mlx 实现:IndexTTS-1.5(纯中文)与 Qwen3-TTS 1.7B(多语种,2026-08-15 起为默认)。

2.2 Coding Agent 是前置要求(默认推荐 Pi)

这个仓库的预期用法是 clone 下来交给成熟的 Coding Agent 驱动,不是一个人对着终端逐条手敲命令。 实战中默认推荐 Pi(配合 Gemini 3.8 / Kimi K3,已稳定生产并发布 15 期全网视频),亦完全兼容 Claude Code 等通用 Agent。

仓库里有两份东西专门写给 Agent 看:

文件给 Agent 的内容
AGENTS.md / CLAUDE.md工程约定:六条红线、四阶段人工停机点、台词因果哈希、哪些判据不许绕过
skills/write-script/写稿技能:五种题材骨架与判据、8–12 秒微单元标准、气口起伏量化

各步骤对 Agent 的依赖程度不同:02 写稿没有 Agent 不行(没有任何脚本会生成稿子); 08 挑封面候选和写标题可以没有 Agent,但会退化成机械铺开取样、不一定切题;其余各步都是 纯脚本。对 Agent 的能力要求有两条是实的:能跑 shell能读图(第 08 步要看 6×5 的联系表认人)。不能读图的 Agent 仍能跑完整条流水线,只是封面挑选退化成机械取样。

2.3 需要的模型(合计约 4G)

模型全部落在 data/models/ 下,不落系统盘——由 pipeline/paths.py 在 import 时把 HF_HOME 钉过去。

模型用途大小怎么来
BAAI/bge-base-zh-v1.5字幕语义索引与检索约 400M首次运行自动下载
mlx-community/whisper-large-v3-turbo回读质检、字幕对轴校验、无字幕时兜底转录约 1.5G首次运行自动下载
mlx-community/Qwen3-TTS-12Hz-1.7B-Base-bf16配音(多语种,中文旁白 + 英日歌名混读)约 4.3Gconfig/voice.json 自动下载
deepghs/anime_face_detection视觉索引:人脸检测约 42M首次运行自动下载
deepghs/ccip_onnx视觉索引:角色身份嵌入约 143M首次运行自动下载

注意 import 顺序:任何会下载模型的模块,第一个 import 必须是 pipeline.paths,否则 模型会静默写进系统盘。paths.py 会检测并当场报错。

2.4 需要自备的素材

仓库不包含也不分发任何素材。

素材要求
片源一部番的完整正片,几十 G 量级
字幕时间轴必须照你手上那个视频文件打的。 只允许三种来源:ffmpeg 提取的内封字幕;对该文件跑 ASR 转录的结果;与该文件同属一个发布、文件名逐一对应且通过对轴校验的外挂字幕。日语无字幕片源不支持(ASR 兜底仅中文,见 ADR-0007)
参考干声5–8 条,每条 8–10 秒,连续说话不要留大段静音。用来克隆口播音色
BGM该番自己的 OST / OP / ED。整轨镜像加 cue 的碟需要先分轨

永远不要用第三方字幕文件配第三方视频文件。 跨版本差异是中间的插入与删除,不是恒定 偏移,加 offset 修不好。而帧级精确截取是渲染链路的前提,前提一塌视频照样渲染, 只是全程画面对不上话,没有任何报错。

2.5 data/ 放在哪

仓库本身只有纯文本(代码、配置、文档、skills),全部进 git。片源、字幕、索引、模型、 每期产物都在 data/ 下,不进 git。两种放法都支持:

./pipeline/preflight.sh --init                            # 系统盘装得下,建实体目录
./pipeline/preflight.sh --init /Volumes/<你的盘>/anime-video-data   # 外置盘 + 符号链接

脚本绝不自动创建 data/,不可达就立刻报错退出。 符号链接指向未挂载的卷时,mkdir -p 会把几十 G 静默写进系统盘且盘插上后看不见——建骨架必须是显式动作,preflight.sh --init 会打印结果落在哪块盘上。代码里一律用 ./data/... 相对路径,不硬编码卷路径。

2.6 安装

brew install ffmpeg
uv venv --python 3.14                         # 3.12 / 3.13 / 3.14 都可以
uv pip install -e ".[apple,dev]"              # 非 Apple Silicon 去掉 apple
pytest                                        # 纯函数测试,不碰片源/模型/外置盘
./pipeline/preflight.sh                       # 自检
cp CLAUDE.local.md.example CLAUDE.local.md    # 填本机情况,不进 git

pytest 首次跑要一分钟左右,之后约 3 秒。preflight.sh 检查 data/ 可达、ffmpeg 在、 ffmpeg 真的带 ass 滤镜——有 ffmpeg 不等于能烧字幕,缺 libass 渲染会在最后一步才失败。 CLAUDE.md 是给 coding agent 读的工程约定,跑这个项目的人也建议读一遍。CLAUDE.local.md 放只对你这台机器成立的事实,不进 git。

关于 Python 版本和那条 numpy<2.5

2026-07-30 实测,3.12、3.13、3.14 三个版本都跑通,3.15 还在 beta,没验。

pyproject.toml 里那条 numpy>=2.0,<2.5 的上界不能删。依赖链 mlx-whisper → numba → llvmlite 里 numba 0.66 要求 numpy<2.5;numpy 2.5 一发布, 解析器就优先选它,把 numba 0.66 排除,回退到只支持 Python <3.10 的版本,转去源码构建 并失败。这个坑只咬新环境——已有 venv 一切正常不构成证据。判据得是真装一遍: uv pip install --dry-run 只解析不构建,会「成功」地解出装不上的组合。


三、技术栈及全流程工作介绍

3.1 技术栈一览

环节用什么为什么这么选
语义检索sentence-transformers + bge-base-zh-v1.5bge-small 实测命中率只有 75%,base 是 100%
索引单元ASS 字幕滑窗 2 行,一集一个 .npy单行太碎,一句话常跨两行轴
配音mlx-community/Qwen3-TTS-12Hz-1.7B-Base-bf16 跑在 mlx-audio 上(多语种,中文旁白夹英日歌名混读)云 API 把联网+账号+配额塞进主循环,还要外传参考干声
ASRmlx-whisper large-v3-turbo回读质检、对轴校验、兜底转录三处都用
视频与音频全程 ffmpeg,无 NLE见 1.4
字幕烧录ass 滤镜(libass),折行自己算libass 靠空格找断点,中文整句没有空格就不折
BGM侧链闪避,按实测响度归一到 -26 LUFS固定音量系数是错的控制量
镜头切分ffmpeg scdet,低阈值扫一遍再过滤检索单元必须是镜头不是帧;改阈值不用重解码
角色在场动漫人脸检测 → CCIP 嵌入 → 聚类 → 人工贴名booru tagger 词表大的认不准、认得准的词表小
封面筛选Pillow:清晰度/亮度/去重,可选角色在场过滤只做剔除,不做排序
状态管理文件系统产物即状态。人机交接一律走文件
测试pytest,纯函数测试(条数见 CI / pytest --collect-only不 mock ffmpeg 和模型,mock 检查的是 mock

没有的东西也是选择:没有云 API、没有数据库、没有编排框架、没有 web 界面、没有一键脚本。

3.2 Phase 0:一部番做一次

成本固定,摊到多期上才划算。一部番榨干再换番。 完整判据见 docs/WORKFLOW.md

第一步:验片源完整性

python -m pipeline.ingest intact data/library/raw/<番>/*/*.mkv

下载器显示 100% 不等于文件完整。 BT 没下完的文件是稀疏文件,ffprobe 照样读得出时长。 判据是 ffmpeg 全片解复用无报错(-c copy -f null -),约 0.9 秒一个文件。「实占块 ÷ 逻辑大小」只当前置快筛:说「没下完」可信,说「下完了」不可信。

第二步:整季入库

python -m pipeline.ingest phase0 data/library/raw/<番>/<该季目录>/*.mkv \
    --anime <番> --season 1

一条命令做三件事:逐集对轴校验 → 过了才建索引 → 登记片源进 sources.json,三步不许拆开, 任何一集对轴不过就跳过并说明原因,不静默降级。对轴判据是 ASR 回读比对字符错误率——文件 名对应只能证明「打包时放在一起」,真正能证伪的只有拿视频自己的声音去对。需要字幕带日文轨, 只有纯中文字幕的集走 ASR 兜底或者放弃。

第三步:建视觉索引

字幕索引答的是「谁说了什么」,画面里有谁它答不了。这一步补上(设计见 ADR-0003),机器时间约 2.4 小时:

python -m pipeline.shots calibrate <一集视频>               # 定切分阈值,看抽检图再拍板
# 选定的数写进 config/project.json 的 visual.scene_threshold
python -m pipeline.shots build <视频> --anime <番> --season N --episode M   # 逐集切分
python -m pipeline.shots frames <番> <集号>                                  # 抽代表帧
python -m pipeline.faces detect <番> <集号>...                               # 人脸检测
python -m pipeline.faces cluster <番> && python -m pipeline.faces sheet <番> # 聚类出联系表
python -m pipeline.faces name <番> 0 八幡      # ← 人在这里:看图给每簇贴名(约 2 分钟)
python -m pipeline.faces presence <番>                                        # 落索引

第 5 步的人工介入是设计的一部分,不是妥协:一部番只做一次,姐妹脸这类只有人能一眼 分开。不用现成 booru tagger 的原因:词表大的置信度太低,认得准的词表里连主角都没有。

第四步:确认六条数字相等

python -m pipeline.vindex status --anime <番>
#   片源 / 字幕索引 / 笔记 / 镜头表 / 角色在场 / 画面语义

六条数字不相等就不许进每期循环。 索引或笔记悄悄缩水时,检索照常返回 Top-K、分数照常 在阈值以上、成片照常渲染,全程没有任何报错——判据不能是「检索得到东西吗」, 必须是「集数对得上吗」,前者永远为真。

第五步:选音色

for f in data/voice/reference/*.wav; do
  python -m pipeline.tts probe "随便一句带长句和短判断的话" \
      --ref "$f" --out "data/voice/probe/$(basename "$f")"
done

按重要性听三样:语速(不同参考音实测差 65%,直接决定成片长度)、稳不稳(电音、 忽快忽慢、句尾发飘)、音色(排最后,听的是「能不能撑 2–4 分钟口播」)。单句试音 不能预测整篇语速,估成片长度必须看 manifest.json 的总时长。选定后改 config/voice.jsonref_audioscript.cpm 要重测(同一音色不同文风下差过 24%)。

第六步:定 BGM 曲目表

python -m pipeline.bgm scan    <CD 目录>                    # 解 cue,列出 instrumental 轨
python -m pipeline.bgm extract <CD 目录> --anime <番>        # 切成独立 flac
python -m pipeline.bgm measure data/library/bgm/<番>/*.flac  # 量时长、响度、入声点

Phase 0 只攒候选池不 定死选曲(2026-08-08 起):具体每期用哪首,等这期配音(03)出来、 人耳听过之后填进当期 01-topic.md——BGM: 列表每行一首,@N秒 定起点(不写自动接上一首 结尾),支持任意首数拼接;老写法 BGM正文 / BGM中段(配 BGM中段切入点: N秒)/ BGM结尾 仍可用。扫曲库必须解 cue,不能只数文件(OP/ED 单曲碟是整轨镜像)。曲目表里没有实测 lufs 的曲子不许用(劇伴与 OP/ED 伴奏实测极差 11 dB)。乐评类期数还有试听型渲染 (pipeline/music):音乐段当前景、段落间降 BGM、结尾自然收尾。

3.3 每期九步

01 选题 —— 人,周批量

01-topic.md 必须带齐四项:类型(人物志 / 剧情回顾 / 杂谈 / 盘点 / 共鸣)、锚点 (季集号),可选 封面集。杂谈还要带 模式(驳论 / 立论 / 吐槽)与 张力(驳论/立论)。 张力是整条流水线里唯一的编辑判断——必须在这一步定死并经人批准,不能留到写稿阶段由 agent 自行发明(那等于绕过唯一的人工关卡)。人物志/剧情回顾/共鸣不设张力:观点就是人物/故事本身。 写稿只校验、不更换。

02 写稿 —— Agent 约 3 分钟

skills/write-script:读上一期的稿子(为了不重样)→ 查证剧情 → 按 类型 读第 4 节对应骨架 (杂谈先校验 模式/张力)→ 按题材骨架写正文 → 切成 8–20 段,每段配一条 查询 和一条 备选

五种题材五种骨架,全部从真实优秀内容里拆的(人物志=罗十五;剧情回顾/杂谈/盘点/共鸣=bangumi 长评与知乎长文)。骨架是「这类内容怎么走通」的范本,不是分步模板——写的时候像人说话, 写完再拿判据筛。

python -m pipeline.check_script data/episodes/<本期>/02-script.md

机检覆盖:字数、时长、单句上限、句长起伏、论文连接词、跨期套话、论据是否报菜名、剧情 锚点数、查询是否重复、查询是否误写成画面构图等。主观项机器判不了,脚本按 01-topic.md类型 给出对应提示(杂谈看张力/公道话,人物志看有没有给角色安论点……)。机检全过不代表能交,自检两遍顺序不能反:先保真(台词 原文、说话人、集号、数字),再去味查询 是机器接口,不是备注——它被原样送进 字幕索引检索,要写成台词语义:「角色承认自己一直在逃避」有效,「中景,逆光」必然落空, 字幕里没有构图信息。

03 配音 —— Agent 约 5–10 分钟机器时间

python -m pipeline.tts data/episodes/<本期>

逐段合成,保留段落边界。每段时长用 ffprobe 复核后写进 03-audio/manifest.json—— 这是下一步排画面的唯一依据,不采信模型自报。中断可直接重跑,已过的段落跳过; 改稿、换音色(engine/model/ref_audio/读音表)后再跑都只重做受影响的段。 按句合成不按段(语速与文本长度正相关)。

每段生成后用 Whisper 回读比对,抓漏读、重复、跑飞;不过就换种子重生成,三次仍不过 就整体退出——自回归 TTS 的典型失败不是报错,是静默地念错。回读比对前会归一化,而归一化 可能把缺陷一起抹掉,所以合成前用 tts.speakable 剥掉纯书面符号。成片交人前至少听一遍 开头和最长的那段。

04 素材检索排片 —— Agent 约 1 分钟

python -m pipeline.clips data/episodes/<本期>

每段 查询 送进索引取 Top-24,然后全局贪心分派:所有 (段, 画面, 分数) 摊平按分数 降序占坑,同一处画面整期只用一次——不按段落顺序分,那是先到先得。每段按音频真实时长 填满,片段不短于 2.5 秒。顺序不可交换:字数估算与实际语速的偏差攒出几秒的渐进错位, 越到后面画面与口播差得越远,全程不报错。

检索落空走查询阶梯查询备选 → 该段 配音 原文,逐级重试,门槛 0.45 不动。 阶梯只救不比——上一级够格就到此为止,绝不因为下一级分数更高而换掉。三级都不及格就 写 "status": "no_match",渲染硬失败交人处理,不自动降级——自动塞空镜是把「画文不符」 藏起来。

视觉索引接进来的两个通道

分镜可以声明走哪条通道(ADR-0003),二选一,都不写就走台词检索:人物: 雪乃 = 台词检索

  • 角色在场过滤(修「命中了谁说的、镜头却在说话人身上」这类错配;过滤是软的,为空就 退回不过滤的结果——「没检测到 X」不代表 X 不在场);场景: 描述 = 画面语义检索, 当前不可用——门槛立不住,CLIP 余弦能排高低、答不了「这算不算命中」(ADR-0003 待实测 #4),写了会当场报错。

两条铁律: 一段只走一个通道,两个字段都写会当场报错;分数只在自己的通道内排序,绝不 跨通道比较。分派画面时台词段先挑——它们要的是「那句话发生的那一刻」,具体且不可替换。

05 审时间码 —— 人 5 分钟

python -m pipeline.review data/episodes/<本期>              # 出 04-review.html
open data/episodes/<本期>/04-review.html
python -m pipeline.review data/episodes/<本期> --approve

这是整条流水线唯一的人工关卡。 一页 HTML,每段并排口播、画面、字幕原文三样,每个片段 抽三帧(进点、中间、出点)。要抓的是台词对了但画面不对:那句话可能是画外音,机器判 不了,只有眼睛能抓。--approve 必须是显式动作——自动写 approved 是最省事的做法, 也正是这一关曾经形同虚设的原因。

06 渲染 —— Agent 约 1.5 分钟

python -m pipeline.render data/episodes/<本期>

切片 → 统一中间格式 → 拼接 → 混 BGM → 烧字幕 → 响度归一,一趟出片。40 个片段、3 分钟 成片实测 77 秒。

两道截取守卫强制执行,缺一不可: 切前校验 seek + duration <= 源时长,不足立即失败; 切后复核实际时长与请求值之差不超过 1 帧(按源片实际帧率现算,不许写死——番剧常见 23.976 / 24 / 29.97 三种帧率)。

字幕折行自己算,不指望 libass(它靠空格找断点,中文没有空格就不折):断点取标点, 贪心取放得下的最远那个;中文破折号是两个字符,必须等一对补全再断。

BGM 支持任意首数拼接01-topic.mdBGM: 列表每行一首、@N秒 定起点,后一首 起点早于前一首自然结尾就等功率交叉(qsin,3 秒),晚了留停顿;老写法(正文/中段/结尾 槽位)仍可用,换曲点卡段落边界。每首按实测响度归一到 -26 LUFS,再以人声为触发做侧链 闪避。固定音量系数是错的控制量——换一首响度不同的曲子会凭空大 9.8 dB 压过口播, 且不报错。

07 质检 —— 机器约 40 秒

python -m pipeline.qc data/episodes/<本期>

11 项,不达标非零退出,不进人工环节:时长落在目标带(默认 2–4 分钟,01-topic.md 写了 时长目标 就按那个带判,见 CLAUDE.md「内容参数」);音画误差 < 0.5s;响度 -16 LUFS、 true peak ≤ -1 dBTP;无 >0.5s 黑帧、>2s 静音;字幕无空段、不超宽、每卡一行、不超高。 查的是实际折行结果,不是「原文长度 ÷ 每行容量」——检查项一旦测的不是真实产物, 通过就毫无意义。主观项(节奏、观感)不进门禁,根在稿子和排片,回 02/05 改。

08 封面与标题 —— Agent 约 1 分钟

python -m pipeline.cover data/episodes/<本期>                     # 出池子 + 联系表
python -m pipeline.cover data/episodes/<本期> --pick 107,110,20    # 定 9 张

这一步不新增人工环节,选封面和选标题并进第 09 步。

候选帧从三处取: 实际用上的片段(每 0.5 秒一帧)、名场面时间码、01-topic.md封面集 通篇(每 12 秒一帧,跳过 OP/ED)。第 3 路是被打脸打出来的:只用前两路时九张里 没有一张主角占主位——前两路的帧都来自字幕检索命中的时刻,而台词大多是别人说给主角听的, 镜头自然在说话人身上。

机器只做剔除,逐条有明确判据: 拉普拉斯方差 < 60 剔运动模糊;平均亮度落 40–215 之外 剔黑场过曝;同集相隔 < 6 秒或 dHash 相近算同一镜头只留一张;可选按 封面人物: 一色彩羽 (或 --character)硬过滤掉没有本期主角的帧(硬过滤为空则失败,与排片的软过滤相反); 2 个坑留给名场面,其余按段落号均分取样。候选之间没有排名,这是刻意的——拉普拉斯方差 测的是「画面里有多少细节」,不是「画面有多好」,两版打分都压掉了正确答案;清晰度是准入门槛, 不是排序依据。

分工是三层,不是两层: 机器剔黑场/过曝/糊帧、去重、编号 → agent 看联系表(6×5 一张、 带编号)挑出符合本期主题的(认人、占不占主位)→ 人从 9 张里定一张(审美)。agent 看完 报编号给 --pick;不加 --pick 时退到机械铺开取样,仍然出得了 9 张。

标题给 5 条候选,每条注明路子(下判断 / 反问 / 复述再打 / 剧情钩子 / 金句),原料取 稿件的第 2 节(亮判断)和第 8 节(结论)。判据是金句式而非论文式——这句话能不能脱离 视频单独发出去07-titles.md 已填表就不再覆盖(标题和封面同一条命令出,重跑会冲掉)。

09 发布 —— 人 3 分钟

点一张封面、点一条标题,然后上传。上传手动做,不自动化。(2026-08-09 起本期耗时 由 agent 在会话内记录,不再落盘 meta.md。)

3.4 测试与守卫

pytest        # 纯函数测试,约 3 秒,不碰片源、模型、外置盘

测试只覆盖纯函数,测的是踩过的坑,不是 API 形状——每条断言对应一个具体错误。不为了 提覆盖率去 mock 掉 ffmpeg 或模型,涉及媒体的正确性交给截取守卫和质检门禁在真跑时兜。

写测试两条纪律:期望值先在实现上跑一遍、看懂为什么是这个值,再写进断言;写完做变异检验 ——把被测行为故意改坏,看测试红不红(一条永远绿的断言和没有断言效果一样)。

3.5 换一部番

  1. config/project.jsonanime.default
  2. config/bgm.json 加一组曲目,每首必须带实测 lufs
  3. config/characters.json 加这部番的角色名表(中文名 ↔ 聚类贴的名字)
  4. 重新标定镜头切分阈值——画风、剪辑节奏逐番不同,沿用上一部的数不算实测
  5. 重跑整个 Phase 0。索引按番隔离,clipssubindex search 都按番过滤

换成真人影视素材时,视觉索引第 1 层要整块换掉(动漫人脸检测器和 CCIP 都是动漫专用的), 这是有意做成可插拔通道的原因。

skills/write-script/VOICE.md空模板,教你怎么从自己的既有文稿里提炼一份,填好放 VOICE.local.md(不进 git)。不填也能出稿,但会是通用 AI 腔。


License

MIT,见 LICENSE

素材本身(片源、字幕、音乐)不属于本仓库,也不随仓库分发。 二创的版权风险由使用者 自负。config/bgm.json 里的曲目表只有路径和实测响度,不含任何音频。

Contributors

Languages

Python

99.3%