Text Polish Video(文本润色 → 短视频生成)
Overview
Receive raw text from the user, intelligently optimize and polish it (restructure, extract
key points, adjust tone), then turn the optimized script into a short video: a structured
storyboard, per-scene keyframe visuals, and rendered video clips ready for short-video
platforms (抖音 / 快手 / 视频号 / B站 / 小红书 / YouTube Shorts). Output is the optimized
script, a storyboard (HTML + JSON), and publishable video clips (MP4). When ffmpeg is installed
(see Dependencies below), the clips are stitched into a single final.mp4 with
burned-in captions. If ffmpeg is missing, assemble.py automatically falls back to
moviepy (which bundles its own ffmpeg) so a single final.mp4 can still be produced
without a system ffmpeg install.
> 角色·场景预生产(Phase 2.5,小说/剧情类强烈推荐):在正式生成视频前,先把整本/整章
> 文本扫描,确定人物(穿搭 / 性格 / 外表 / 神态)与场景,预生成一套「视觉身份库」
> (风格母版 + 角色卡 + 场景卡)。后续所有镜头都锚定到这套预设,既能保证角色/场景高度一致
> (不串脸、不跳场景),又能省去每镜反复试生成的额度与时间,配合 剧情模式
> (--density dramatic) 还能把戏拆细、拉长,表现更贴近真人。
Dependencies(拼合后端)
> 拼合 final.mp4 需要 ffmpeg 或 moviepy 其中之一。 各场景视频片段由 VideoGen 直接产出
> MP4,无需额外依赖;但凡涉及 拼接多镜片段、转码、烧录字幕(assemble.py 产出 final.mp4),
> 需要以下两个后端之一:
>
> - ffmpeg(推荐,必装优先项):功能最完整、烧字最稳。
> - moviepy(可选备援):pip install moviepy 即可,它自带 ffmpeg(imageio-ffmpeg),
> 因此无需系统安装 ffmpeg 也能拼合并烧字。适合 ffmpeg 装不上的环境。
>
> 两者都缺失时,流水线仍交付分段 scene_XX.mp4 + concat_list.txt,但无法生成单条成片。
一键安装(按系统选一条执行)
| 系统 | 一键命令 |
|---|---|
| Windows(推荐 winget) | winget install ffmpeg |
| Windows(Scoop) | scoop install ffmpeg |
| macOS(Homebrew) | brew install ffmpeg |
| Linux Debian/Ubuntu | sudo apt update && sudo apt install -y ffmpeg |
| Linux RHEL/Fedora | sudo dnf install -y ffmpeg |
安装后重开终端 / 重启 WorkBuddy 会话,让 ffmpeg 进入 PATH。验证:
ffmpeg -version # 应输出版本号,如 ffmpeg version 6.x
当前状态
- 本技能无需系统级 ffmpeg 即可产出成片:
assemble.py默认后端为 ffmpeg(推荐,质量与速度更优);
若系统未安装 ffmpeg,则自动回退到 moviepy(pip install moviepy—— 其内置 imageio-ffmpeg,
无需系统 ffmpeg)。两种后端均支持字幕烧入与封面抽取,且字幕定位(alignment/margin_v)
与样式保持完全一致。换言之,成片拼合只需「ffmpeg 或 moviepy 二者之一」,无需两者皆装。 - 建议交付成片前先校验
ffmpeg -version;无 ffmpeg 环境直接走 moviepy 备援即可,无需额外配置。
Subtitle Font(字幕字体 / 防中文乱码)
字幕烧录使用 ffmpeg subtitles 滤镜 + ASS 字幕文件,按字体文件「路径」直接加载
(经 fontsdir 指定字体目录),不依赖系统是否装有某个字体名,从根本上避免中文乱码 /
系统字体回退。moviepy 备援后端则用 Pillow 渲染字幕位图后叠加,同样走字体文件路径:
- 内置开源中文字体:
assets/fonts/SmileySans-Oblique.ttf(得意黑 / Smiley Sans,
SIL OFL 1.1,可商用、可再分发)。它已是各平台预设的默认font_file,开箱即用、零配置。 - 自定义字体:把你的
.ttf/.otf(建议 OFL / GPL 等可再分发协议)放进assets/fonts/,
在caption_presets.json里把default_font_file或对应平台的font_file指向它
(填相对技能根目录的路径,或绝对路径)。重跑assemble.py即生效。 - 兜底:若
font_file缺失 / 无法解析,退化为font系统字体名(Microsoft YaHei /
PingFang SC / Arial 等);此时若系统无对应中文字体仍可能回退——因此优先用font_file。 - 字体授权与替换说明见
assets/FONT_LICENSE.md。注意:微软「微软雅黑 / 黑体」等
商用字体不可随技能打包分发,仅适合本机自用(用font名引用,不要内置)。 - SkillHub 发布包不含字体文件:第三方平台(如 SkillHub)限制 .ttf/.otf 等字体随
包发布,故上传打包时会自动跳过assets/fonts/目录。本地运行如需得意黑字体,
按FONT_LICENSE.md指引手动落位即可;不落位时 libass 会回退到系统字体,绝大多数
Windows / macOS 系统均能正常渲染中文,不会出现乱码。
When To Use
Activate this skill when the user:
- Says "把这段'文本'做成视频" / "把这段文本做成视频" (the primary trigger; '文本' is the pasted content).
- Uses colloquial / spoken triggers, e.g. "帮我把这段话拍成视频" / "把这段话拍成视频" /
"给我剪个视频" / "把这段文案做成视频" / "把这段文字做成短视频" / "这段话做成视频发抖音"。
- Provides text and asks to turn it into a short video / reel / 口播视频 / 短视频 / 竖屏视频.
- Asks to polish/润色 a 文案 and also produce a video from it.
- Hands over an article, note, or draft and wants a video version.
- Uses any phrase in the description's trigger list (Chinese or English).
Input Interface(文本输入接口)
Accept text from any of these sources, in priority order:
1. Direct message text — the user pasted the content in the message.
2. Quoted block — content inside > or fenced `` blocks in the message.
3. **Local file** — a path to.txt/.md/.docx/.pdf`. Read it with the Read tool
(for docx/pdf prefer the tencent-local-office-edit or tencent-docs-routing skill if connected).
4. Parameters — collect the following (ask only if missing and they materially change output):
| Parameter | Default | Notes |
|---|---|---|
platform |
douyin |
One of douyin / kuaishou / shipinhao / bilibili / xiaohongshu / ytshorts. Drives aspect, duration, style. See references/platforms.md. |
tone |
enthusiastic |
One of the presets in references/tone-presets.md. |
duration |
60 |
Total target seconds (e.g. 15 / 30 / 60 / 120). |
aspect |
9:16 |
9:16 (vertical) or 16:9 (horizontal). Most platforms default to 9:16. |
language |
zh |
Narration language. |
style |
realistic |
视觉总风格:realistic = 短剧/真人实拍感(默认);anime = 动漫/2D赛璐珞动画感。决定角色卡/场景卡/关键帧的画风,并通过 gen_cast_sheets.py --style 与 build_storyboard.py --style 贯穿全流程。 |
If the user gives no parameters, pick sensible defaults from platform=douyin,
tone=enthusiastic, duration=60, aspect=9:16 and state the assumption.
Workflow
Execute the six phases in order. Use the bundled scripts for deterministic steps.
Phase 1 — Receive & parse input
- Extract the raw text via the Input Interface above.
- Strip obvious boilerplate (ads, signatures, repeated headers). Keep the substance.
- Confirm
platform/tone/duration/aspectare set; if not, apply defaults and note them. - Estimate a target word count for the narration:
words ≈ duration × wps, where
wps(words per second) ≈ 3.0 for Chinese narration, ≈ 2.5 for English. Forduration=60
that is ~180 Chinese characters. If the raw text is far longer, plan to compress in Phase 2.
Phase 2.5 — 角色·场景扫描预生产(小说/剧情类强烈推荐)
在正式生成视频前,先把整本/整章文本扫描一遍,确定人物(穿搭 / 性格 / 外表 / 神态)与
场景,预生成一套视觉身份库(风格母版 + 角色卡 + 场景卡)。后续所有镜头都锚定到这套预设,
既能保证角色/场景高度一致(不串脸、不跳场景),又能省去每镜反复试生成的额度与时间,
配合 Phase 3 的 --density dramatic 还能把戏拆细、拉长,让剧情表现更充分。
> 两种画风(style):
> - realistic(默认)= 短剧 / 真人实拍感:角色卡走写实肖像、场景卡走实景概念图。
> - anime = 动漫 / 2D 赛璐珞动画感:角色卡走动漫设定稿(干净线稿 + 平涂 + 大眼睛 +
> 表情化),场景卡走动漫背景画(手绘赛璐珞背景 + 柔和空气透视)。style.look 与
> gen_cast_sheets.py --style 必须配套选 anime,否则画风会串。
> 两者与 Phase 6.7 角色对戏配音完全独立——动漫版同样可以是「角色对话 + 逐句字幕」形式。
步骤 A — 扫描文本,提取角色与场景(LLM 语义 + 可选辅助脚本)
- 若原文很长(如整本小说 txt),先跑辅助脚本压缩成线索,避免通读全书:
bash
python scripts/scan_script.py --text 原文.txt --out scan_report.json --top-terms 60
它按「第X章」切片并统计高频中文词(疑似人名/地名)。LLM 据 scan_report.json 的章节与
高频词,挑关键章用 Read 精读,语义提取:
- 人物:姓名、性别、年龄感、外表(脸型/发型/五官/身材)、穿搭(常服/标志服饰)、
性格、神态特征(常有的表情/气质)、建议音色 voice。
- 场景:名称、时间(昼/夜/黄昏)、视觉描述(地点/陈设/光线)、氛围。
- 统一风格 style.look:一段英文视觉风格描述(给 ImageGen 用),例如
cinematic realistic, teal-and-orange neon contrast, cinematic lighting, ...。
- 把结果写成 cast.json(结构见 references/cast_template.json,可直接复制填):
json
{
"style": {"name":"realistic","look":"<英文视觉风格>","ref_image":""},
"characters":[{"id":"suwuji","name":"苏无际","gender":"male","age":"二十多岁",
"appearance":"...","outfit":"...","personality":"...","manner":"...",
"voice":"zh-CN-YunxiNeural","shot":"three-quarter bust portrait","ref_image":""}],
"sets":[{"id":"empress_bar","name":"女皇酒吧","time":"夜晚",
"description":"...","mood":"...","ref_image":""}]
}
# 动漫风格示例:name 改为 anime,look 用 STYLE_PRESETS["anime"] 的 ANIME_LOOK
# "style": {"name":"anime",
# "look":"anime style, 2D cel-shaded animation, clean line art, vibrant flat colors,
# Japanese/Chinese animation aesthetic, soft gradient shading,
# expressive character design, vertical 9:16 composition, high detail"}
步骤 B — 生成视觉锚(角色卡 / 场景卡 / 风格母版)
# 1) 规划:输出待生成清单(含每图的 ImageGen prompt + 锚定关系)
# --style 与 cast.json 的 style.look 必须配套:realistic(短剧) 或 anime(动漫)。
# 若 cast.json 的 style.look 为空,plan 会按 --style 自动插入对应默认风格
# (realistic→DEFAULT_LOOK / anime→ANIME_LOOK),不会串味;若已手动填写 look,
# 请确保它与 --style 一致(脚本会在不一致时打印 [warn] 提醒)。
python scripts/gen_cast_sheets.py plan --cast cast.json --out cast_plan.json --style anime
# 2) LLM 据 plan 调 ImageGen:style_ref 先生成(无 ref),其余项 image=style_ref、
# input_fidelity=0.9 锁定统一风格;把生成路径整理成 refs.json:
# {"style_ref":"assets/cast/style_ref.png","character_suwuji":"assets/cast/character_suwuji.png",...}
# 路径可以是绝对路径,也可以是相对于 cast.json 所在目录的相对路径;apply 会自动转成绝对路径保存。
python scripts/gen_cast_sheets.py apply --cast cast.json --refs refs.json
# 3) 校验
python scripts/gen_cast_sheets.py verify --cast cast.json
产物:assets/cast/style_ref.png + character_XX.png + set_XX.png,存盘复用——
这是「减少制作时间」的关键:角色/场景长相一次定型,后续所有镜头直接锚定,不再每镜试错。
步骤 C — 分镜引用(在 Phase 3/4 落实)
- Phase 3 的每镜 scene 已预留 cast:["苏无际"] 与 set:"empress_bar" 字段(dramatic 模式
下更常用);LLM 在 Phase 4 调 ImageGen 时,以对应 character_XX.png / set_XX.png 为
image 参考图(input_fidelity≈0.9),保证全片人物/场景一致。
> 真人感要点:① 角色卡锚定确保同一人物每镜长相一致;② image_prompt 强调写实 +
> 微表情/肢体(不是定格摆拍);③ VideoGen 的 motion_prompt 给人物自然动作(挑眉、抬手、
> 走动、眼神变化)而非静止;④ 关键台词用 Phase 6.7 分角色对话 + 可选情感注入。多管齐下,
> 观感接近真人短剧。
Phase 2 — Polish & optimize text
Rewrite the raw text into a tight short-video script. Apply all of the following:
- Hook first (0–3s): open with a question, conflict, surprising fact, or bold claim that
makes the viewer stop scrolling. Never open with "大家好" or vague pleasantries.
- Clear structure: 钩子(Hook) → 展开(Body, 2–4 points) → 价值点/转折 → 金句/行动号召(CTA).
One idea per scene.
- Key-point extraction: identify the 1–3 core messages; make them explicit and memorable
(numbers, contrasts, rules-of-thumb). Drop low-value filler.
- Tone adjustment: apply the chosen preset from references/tone-presets.md — rewrite
vocabulary, sentence rhythm, and emotional temperature to match.
- Length control: compress/expand toward the Phase-1 word target. Favor short sentences,
active voice, conversational phrasing.
- CTA: end with a clear, low-friction action (关注 / 收藏 / 评论关键词 / 点击链接).
Deliver the polished script as a compact block (it becomes the narration + caption source).
Phase 3 — Build script & storyboard
平台时长上限映射(每镜时长 ↔ 单视频上限) — 切分前先按目标平台约束总时长与单镜时长。
build_storyboard.py 已内置下表硬上限:传入的 --duration 超过上限时会自动截断并打印警告。
--duration默认auto(按文本长度自动估算时长):估算公式 = 字数 ÷ 4.5(中文口播语速)- 句数 × 1.0s(停顿/转场缓冲),结果夹在
[10s, 平台硬上限]。文本越长 → 估算时长越长,
直到顶到平台上限(抖音/快手/视频号/B站/Shorts = 180s,小红书 = 60s)。也可显式传数字秒数
(如--duration 90)覆盖自动估算。当文本句子数少于期望镜数时,实际时长会短于估算值(单镜
最长 12s),storyboard.json的meta.duration记录的是真实各镜时长之和,绝不虚高。
| 平台 | key | 单视频时长硬上限 | 推荐总时长 | 推荐每镜时长 | 脚本最大镜数(硬上限) |
|---|---|---|---|---|---|
| 抖音 | douyin |
≤ 180s(普通号默认 60s,长视频权限可达更久;本 Skill 成片封顶 180s) | 30–60s | 5–8s | 15 |
| 快手 | kuaishou |
≤ 180s(常规 60s 内;长视频权限可达更久) | 30–90s | 5–8s | 15 |
| 视频号 | shipinhao |
≤ 180s(常规 30–60s,权限内可达更久) | 30–60s | 5–8s | 15 |
| B站 | bilibili |
≤ 180s(B站无硬上限,本 Skill 以 180s 为短视频封顶) | 60–180s | 6–10s | 15 |
| 小红书 | xiaohongshu |
≤ 60s(视频笔记常规 60s,部分账号可达更久) | 15–45s | 4–7s | 15 |
| YouTube Shorts | ytshorts |
≤ 180s(2024 起由 60s 扩至 3 分钟;本 Skill 成片封顶 180s) | 15–60s | 5–8s | 15 |
> 数据基于 2026-08 各平台公开规则整理,平台策略会调整,以官方为准;普通号默认上限通常
> 低于封顶值,因此「推荐总时长」远小于硬上限。详细规格仍见 references/platforms.md。
> 「脚本最大镜数」由 build_storyboard.py 按 min(15, cap ÷ min_scene, 句子数) 计算,
> 所有平台硬上限均为 15 镜。实际镜数 = 推荐总时长 ÷ 单镜时长,并夹在 3–15 之间。
切分规则(遵循上表):
- 每镜时长默认 = 总时长 / 镜数,并夹在 [min_scene, max_scene](默认 3–12s)。总时长偏长时
优先增加镜数而非拉长单镜——单镜 > 12s 易拖节奏。
- 第 1 镜固定为 Hook(0–3s 抛钩子);末镜为 CTA(4–6s)。
- --scenes 镜数同时受「上限对应最大镜数」约束,不会超出平台能力。
- 若 --duration 超过上表「单视频时长硬上限」,build_storyboard.py 自动截断到上限并提示,
无需手动换算。
-
剧情模式
--density dramatic(小说/剧情类推荐):在普通切分基础上,把镜数上限从 15 提到
30、单镜上限放宽到 15s、时长估算更宽松(≈3.2 字/秒 + 句×1.2s 缓冲),让每场戏拆得更细、
表演更充分、总时长可顶到平台上限(180s)。每个 scene 还会预留cast/set字段,供在 Phase 4
以 Phase 2.5 预生成的角色卡/场景卡为锚,保证全片人物与场景一致。用法:
bash python scripts/build_storyboard.py --text "..." --platform douyin \ --duration auto --density dramatic --aspect 9:16 --style anime --out storyboard.json
普通口播/推书仍用默认--density normal。 -
Run
scripts/build_storyboard.pyto segment the polished script into balanced scenes with
timing, and emitstoryboard.json+storyboard.html:
bash python scripts/build_storyboard.py \ --text "<polished script>" \ --platform douyin --tone enthusiastic --duration auto --aspect 9:16 \ --style anime --out storyboard.json --html storyboard.html
>--duration默认即auto(按文本长度自动估算,越长越长,封顶平台上限);也可传数字秒数(如--duration 90)固定时长。
> 若已做 Phase 2.5 预生产,建议加--cast cast.json:脚本会交叉校验 cast.json 推断风格与
>--style是否一致,不一致则打印[warn],避免「写实角色卡 + 动漫分镜」画风打架。
The script splits the text into scenes (~6s each, 3–15 scenes) and computesstart/end/
durationper scene. It leavesimage_prompt,motion_prompt, andvisual_styleempty. - Fill the creative fields for every scene using judgment +
references/video-tech.md: visual_style: 全片统一的基础风格 token(字符级一致,供validate与 Phase 4 锚定),
必须匹配--style:realistic→cinematic realistic;anime→anime style, 2D cel-shaded。
每镜的细化(如动漫风加clean line art, vibrant flat colors, large expressive eyes)
写在image_prompt里,不要改visual_style,否则各镜视觉风格会漂移、validate也会判不一致。- 风格一致性由
validate兜底:build_storyboard.py --from storyboard.json --validate
现在会检查每镜image_prompt是否包含visual_style头 token、且不含与--style相反的
风格词(如 anime 镜里出现cinematic realistic/film still会报警)。填完 prompt 务必跑一次
--validate再进 Phase 4。 image_prompt: a detailed ImageGen prompt describing the keyframe for that scene
(subject, composition, lighting, color, mood). Keep it concrete and on-topic.motion_prompt: a short VideoGen motion description (camera move + action), e.g.
"slow push-in, subject explains, subtle background motion".- Write the filled storyboard back to
storyboard.jsonand re-render the HTML:
bash python scripts/build_storyboard.py --from storyboard.json --html storyboard.html - Present the storyboard HTML to the user for a quick sanity check before rendering (optional
but recommended for long videos).
Phase 4 — Generate scene visuals (ImageGen)
目标:为每镜生成一张关键帧 scene_XX.png,并让整套镜头在色调、风格、环境、质感上保持
连贯(多镜一致性)。
若已做 Phase 2.5 预生产(推荐):每镜在 storyboard 里已标注 cast(角色列表)与 set(场景)。
生成该镜关键帧时,直接以对应 character_XX.png(角色卡)和/或 set_XX.png(场景卡)作为 ImageGen 的
image 参考图,并设 input_fidelity≈0.9 锁定外貌/场景——比「首镜锚定法」更稳:角色/场景的视觉身份
已经在预生产阶段定型,后续所有镜头复用同一套参考,几乎不会串脸或跳场景,也省去每镜重新设计长相的试错成本。
角色卡/场景卡路径取自 cast.json 的 ref_image,由 gen_cast_sheets.py apply 回填。
推荐流程(首镜锚定法 / 未做预生产时的备选):
1. 首镜 scene_01.png 先生成(Hook 场景)。
- 用纯文本 image_prompt,不加 image 参考图。
- 在 prompt 末尾固定写入全局 visual_style token(如 cinematic realistic)和
vertical 9:16 composition,作为整套序列的风格母版。
2. 后续镜 scene_02.png 及以后用首镜锁定风格。
- 调用 ImageGen 时传入 image: [scene_01.png],并在 input_fidelity 中填一个较高值。
- input_fidelity 取值建议为 "0.85" 至 "0.95" 之间的字符串(越高越忠实于首镜风格)。
实测 "0.9" 能在锁定风格的同时允许画面内容随 prompt 变化。
- prompt 中仍需保留全局 visual_style token,并追加
"same visual style, color palette and lighting as the reference image" 等锚定词,
进一步强化一致性。
3. 生成长度与命名。
- 竖屏 9:16 建议请求 size="1024x1536";横屏 16:9 建议 size="1536x1024"。
- 输出文件统一命名为 scene_01.png, scene_02.png, …,与 storyboard.json 索引一致。
示例调用(后续镜):
ImageGen(
prompt="cinematic realistic, a stylized glowing brain made of neon wires with floating notification icons, ...",
image=["scene_01.png"],
input_fidelity="0.9",
size="1024x1536",
quality="high",
output_dir="./demo_video"
)
动漫模式(--style anime)关键帧示例:在母版 anime style 基础上细化,并以
动漫角色卡/场景卡为 image 参考图锁定画风与长相:
> 动漫专属 VideoGen 运动提示词(2D idle / 微表情 / 多参考图 ≤3 张上限)见
> references/video-tech.md §二「动漫模式运动提示词」;每镜 motion_prompt 应体现
> 手绘动画感而非实拍运镜。
ImageGen(
prompt="anime style, 2D cel-shaded, clean line art, vibrant flat colors, "
"a young man in a red plaid shirt sitting on airport steps looking at passing "
"travelers with a roguish smile, large expressive eyes, soft cel shading, "
"same visual style and character design as the reference image, vertical 9:16, high detail",
image=["character_surui.png", "set_ninghai_airport.png"],
input_fidelity="0.9",
size="1024x1536",
quality="high",
output_dir="./demo_video"
)
降级方案:若当前 ImageGen 不支持 image 参考图或 input_fidelity(旧版本),则退化为
「全局 visual_style token 复用」——所有 prompt 的第一段保持一致(风格、光线、画幅),并人工
检查相邻两镜的色调是否接近,必要时在 prompt 中补充 "same as previous scene"。
- 记录关键帧路径:每镜 ImageGen 生成后,把返回的图片
localPath写回storyboard.json
的scenes[i].keyframe(首镜尤其重要)。assemble.py --cover-out优先用首镜视频抽帧,
视频缺失时回退到scenes[0].keyframe作为封面源。
Phase 5 — Generate video clips (VideoGen)
For each scene, use the VideoGen tool in image-to-video mode with the scene image
(scene_XX.png) plus its motion_prompt, producing scene_01.mp4, scene_02.mp4, … .
- Match clip duration to the scene duration when the tool allows; otherwise use the tool
default and record the actual length in storyboard.json.
- Keep motion subtle and on-brand; avoid jitter that fights the narration.
- If image-to-video is unavailable, fall back to text-to-video using image_prompt +
motion_prompt together. See references/video-tech.md for prompt tips and limits.
- Generate caption/subtitle text per scene (already in caption field) — keep them short
(≤ 2 lines, ≤ 14 Chinese chars/line) for mobile readability.
Phase 5.5 — Generate cover image(封面图)
封面是短视频的门面,直接决定点击率。两套来源任选,默认用首镜高光帧(零额外额度)。
来源 A — 首镜高光帧(默认推荐)
- 已生成 scene_01.mp4:用 assemble.py 抽取首镜视频首帧并缩放为封面尺寸:
bash
python scripts/assemble.py --manifest storyboard.json --cover-out cover.png
- 仅想要封面、不出成片时加 --cover-only。
- 抽取的是观众实际看到的首帧,与成片视觉连贯。
- 尚未生成视频时:直接以 scene_01.png 作为 cover.png(assemble.py 会自动回退复制首镜
关键帧;记得在 Phase 4 把首镜 png 路径写入 storyboard.json 的 scenes[0].keyframe)。
来源 B — 单独生成封面(进阶,额外 1 张 ImageGen 额度)
- 用首镜锚定让 ImageGen 生成一张「封面专版」:构图居中、主体突出、四周留白给标题文字,
比随手抽帧更可控、更具封面感:
python
ImageGen(
prompt="cinematic realistic, a young person on a sofa holding a glowing smartphone, "
"centered composition, generous negative space at top for title text, "
"same visual style and lighting as the reference image, vertical 9:16, high detail",
image=["scene_01.png"],
input_fidelity="0.7", # 略低,留出重新构图的空间
size="1024x1536",
quality="high",
output_dir="./demo_video"
)
- 导出为 cover_custom.png,需要时覆盖 cover.png。
- 封面叠加标题/钩子文字:平台端上传时叠加最稳;若想本地烧字,可把标题写进 ASS 用
assemble.py 的 subtitles 滤镜叠加到封面图上(需 ffmpeg)。
封面尺寸:竖屏 1080×1920;横屏 1920×1080(与合成画幅一致)。
平台要点:小红书「封面党」,首帧即封面需精美、信息前置;抖音/视频号/快手 前3秒抛钩子即可;
B站封面横屏比例(约 1146×717)可单独导出。详见 references/platforms.md。
Phase 6 — Assemble & deliver
- Stitch backend (二选一,auto 默认):
assemble.py拼合后端优先级是
ffmpeg → moviepy → 仅交付分段素材。可用--stitch-backend显式指定: auto(默认):有 ffmpeg 走 ffmpeg;否则自动尝试 moviepy;都没有则只产出分段素材并打印安装指引。ffmpeg:强制用 ffmpeg(缺失则报错退出)。moviepy:强制用 moviepy(无需系统 ffmpeg,它自带 ffmpeg;缺失则报错退出)。- Pre-check (建议): 跑
ffmpeg -version确认首选后端可用。缺失也不影响——auto会自动
回退到 moviepy(需先pip install moviepy)。 - With a backend available, run
scripts/assemble.pyto stitch the scene clips in order,
burn the captions, and output a singlefinal.mp4:
bash python scripts/assemble.py --manifest storyboard.json --out final.mp4 # 显式指定后端: python scripts/assemble.py --manifest storyboard.json --out final.mp4 --stitch-backend moviepy - If neither ffmpeg nor moviepy is available,
assemble.pystill writes
concat_list.txt+ 各场景scene_XX.mp4;明确告诉用户这是阶段性交付,final.mp4
需要安装二者之一(ffmpeg 一键命令见 Dependencies;moviepy 用pip install moviepy)。 - Always present: (1) the optimized script, (2) the storyboard HTML, (3) the video clip(s)/final.
Phase 6.5 — 合成并叠加 BGM(可选)
成片默认无声。若环境无现成音乐素材、也无 TTS/音频库,可用 scripts/synth_bgm.py 程序化合成一段
贴合风格的 BGM(低音 drone + 节拍 + 小调 pad 和弦进行),再用 scripts/mix_bgm.py 经 moviepy
(自带 ffmpeg)以 AAC 编码烧入成片。依赖:numpy(合成)、moviepy(叠加,已随备援后端安装)。
# 1) 合成 BGM(时长与视频对齐,单位秒;也可先读 final.mp4 时长再传入)
python scripts/synth_bgm.py 40 bgm.wav
# 2) 叠加进成片 -> final_music.mp4(原无声 final.mp4 自动备份为 final_nomusic.mp4)
python scripts/mix_bgm.py --video final.mp4 --bgm bgm.wav --out final_music.mp4
- 风格可调:
synth_bgm.py内BPM、_PROGRESSION(和弦进行)、gain(整体电平,默认 0.7)
常量可按平台/情绪修改(推书常用 118 BPM、A 小调悬疑进行 Am–F–C–G–E)。 - 若已有自有 BGM 文件,跳过第 1 步,直接
mix_bgm.py --bgm 你的音乐.mp3。 - 人声配音(TTS)本管线仍不含,建议叠加 BGM 后在剪映/CapCut 再加 AI 旁白。
Phase 6.6 — 合成并叠加人声配音(可选,需联网)
成片默认无声;Phase 6.5 加了 BGM,但没有人声。若需要人物旁白 / 解说(推书、口播类必需),
用 scripts/gen_voice.py 调 edge-tts(微软神经网络中文语音,免费)生成 TTS 旁白,再用
scripts/add_voice.py(混音器)把人声(主)+ BGM(底)烧入成片。依赖:pip install edge-tts(联网)。
# 1) 生成旁白:可用纯文本稿,或从 storyboard.json 自动拼接各镜 narration
python scripts/gen_voice.py --text-file narration_voice.txt --voice zh-CN-YunxiNeural --out voice.mp3
# 或:python scripts/gen_voice.py --from storyboard.json --out voice.mp3
# 2) 混音:人声为主、BGM 压底,画面自动慢放匹配旁白时长 -> final_voice.mp4
python scripts/add_voice.py
# (读 final_nomusic.mp4 + voice.mp3 + bgm.wav,输出 final_voice.mp4)
- 音色:
zh-CN-YunxiNeural(故事感男声)/zh-CN-XiaoxiaoNeural(甜美女声)等;
edge-tts --list-voices查全部。 - 电平:edge-tts 输出偏轻(RMS 仅 0.03–0.06),混音器自动按峰值增益提升人声清晰度,
BGM 压到 0.15 防抢戏;峰值控制在 < 0.9 避免叠加爆音。 - 时长对齐:旁白时长通常长于原无声成片,混音器用
with_speed_scaled把画面慢放匹配旁白,
避免音画不同步。若想固定时长,先精简旁白稿字数(约 4–5 字/秒)。 - 注意:
edge-tts需联网访问微软语音服务;CLI 的--file在本机可能报错,脚本已改用 Python API。 - 进阶:分角色对白 —— 若需要不同角色用不同音色「演」出来(而非单声线旁白),见 Phase 6.7 角色对话模式(短剧/动漫通用):分角色、带感情的对话配音 + 逐句对话字幕,更适合小说推书 / 剧情号。
Phase 6.7 — 角色对话模式(分角色 + 带感情,可选,需联网,短剧/动漫通用)
把旁白解说升级为像短剧一样的角色对戏:每个角色用独立音色(苏无际/Yunxi、
慕千羽/Xiaoxiao、小庞/Yunjian 等),可按需在台词上通过 SSML <mstts:express-as>
注入情感(认真 / 温柔 / 愤怒 / 欢快 / 难过 / 冷静 …);逐句生成 TTS 并按时间轴
拼成「对话音轨」;字幕也改为逐句对话字幕(随角色切换)。
适用:小说推书、剧情解说、口播短剧——要让「人物活起来」而非一人读稿。
画风无关:无论 Phase 2.5/3 选 realistic(短剧)还是 anime(动漫),本阶段
都按 storyboard.json 的 dialogue 剧本逐句配音 + 逐句字幕,成片只是画风不同,
对话/字幕逻辑完全通用。
1) 在 storyboard.json 里写角色对话剧本。每个镜的 scenes[i] 增加一个
dialogue 数组(与 caption 并存;此模式以 dialogue 为准)。每句:
{
"speaker": "苏无际",
"line": "钱我收了,人,我可没答应。",
"voice": "zh-CN-YunxiNeural", // 可选,覆盖默认音色
"emotion": "serious" // 可选,覆盖默认情感
}
整部剧本按 scenes 顺序、镜内顺序展开为逐句时间轴。
默认角色音色 / 情感(剧本缺省时回退,可在 gen_dialogue.py 顶部按需增改):
| 角色(示例) | 默认音色 voice | 默认情感 emotion |
|---|---|---|
| 苏无际(痞气男主) | zh-CN-YunxiNeural |
无(自然语速) |
| 慕千羽(甜美女主) | zh-CN-XiaoxiaoNeural |
无 |
| 小庞(憨直男配) | zh-CN-YunjianNeural |
无 |
关于情感与语速:实测 edge-tts 的 SSML <mstts:express-as> 路径会显著放慢语速
(可能让 20 字短句念到 30 秒以上),因此技能默认不注入情感,靠不同音色区分角色。
如需感情渲染,在剧本里显式写 "emotion": "serious" 等,并接受语速变慢;推荐只在关键句上点缀使用。
可选情感 emotion(edge-tts 中文 Neural voice 支持的 style 子集):
angry / cheerful / sad / fearful / gentle / affectionate /
disgusted / terrified / disgruntled / embarrassed / serious /
depressed / envious / worried / apologetic / tranquil /
thoughtful / shy / calm。引擎不支持的 style 会被忽略(不报错)。
套用「人设说话风格」(如抖音/网络爆款男声 陆飞):技能内置 references/personas.json
人设库,可让某个角色一键套用「音色 + 说话腔调」,无需逐句改 voice。
- 在
personas.json定义人设:voice(音色)、default_emotion(默认留空,避免拖慢语速)、
tone/signature(口头禅)/style_prompt(写对白时参考的口吻)。 - 生成时传入映射,把角色名指向人设 key:
python scripts/gen_dialogue.py --manifest storyboard.json \
--personas references/personas.json \
--persona-map '{"苏锐":"lufei"}'
- 优先级:台词逐句
voice/emotion显式覆盖 > 人设默认 > 全局默认角色映射。 - 关键认知:edge-tts 只有预设音色,无法克隆某个真人的声纹。所以「套用陆飞」实际是:
① 用云扬(Yunyang) 等近似音色;② 把台词按style_prompt改写成该人设的痞帅/格局大/金句腔
(在 Phase 6.7 第 1 步写dialogue时落实);③ 可选点缀情绪 SSML。真实声纹克隆需外部
语音克隆工具/服务,不在本技能能力内。
2) 生成分角色带情感 TTS + 写出时间轴:
python scripts/gen_dialogue.py --manifest storyboard.json
脚本逐句调用 edge-tts(SSML 注入情感),生成 line_NN.mp3,并把
dialogue_timeline(start/end/text/audio/speaker/emotion)写回 storyboard.json,
同时产出 dialogue_meta.json(总时长秒)。句间留 0.28s 静音让对话有呼吸感。
- 健壮性:单句 TTS 失败后自动指数退避重试 5 次(最多等 30s),仍失败则以纯文本(无 SSML)
兜底一次;最终失败会跳过该句并继续生成后续对白,不会中断整条管线。
3) 烧入逐句对话字幕:
python scripts/assemble.py --manifest storyboard.json --out final_nomusic.mp4 --stitch-backend moviepy
assemble.py 检测到 dialogue_timeline 后,自动按时间轴逐句烧字幕(而非整镜一句),
画面与对话严格同步。ffmpeg 与 moviepy 两个后端都支持逐句字幕;推荐
--stitch-backend ffmpeg(更省内存、更稳;系统无 ffmpeg 时会自动回退到 moviepy 自带的
ffmpeg)。若用 moviepy 后端拼接长片出现内存爆掉/被杀,请改用 ffmpeg 后端。
4) 混音成片(对话人声为主 + BGM 垫底):
python scripts/add_dialogue.py --manifest storyboard.json \
--video final_nomusic.mp4 --bgm bgm.wav --out final_dialogue.mp4
- 人声按峰值归一化(edge-tts 偏轻,自动增益到 0.9)提升清晰度;
- BGM 循环到对话总时长并压到 0.15 做背景;
- 画面整体
speedx匹配对话总时长,音画同步。 - 未提供
--bgm时只烧入对话人声。
注意:edge-tts 需联网;音色/情感实际效果取决于微软服务端可用 voice 与 style。
Outputs
| File | Purpose |
|---|---|
polished_script.md |
The optimized, tone-adjusted narration text. |
storyboard.json |
Machine-readable storyboard: scenes, timing, prompts, clip paths. |
storyboard.html |
Human-readable storyboard preview (scenes, timing, captions, prompts). |
cast.json |
角色·场景档案(Phase 2.5 预生产):人物穿搭/性格/外表/神态/音色 + 场景 + 统一风格,含各 ref_image。 |
scan_report.json |
长文本扫描报告(章节 + 高频词),辅助预生产定位角色/场景。 |
cast_plan.json |
角色卡/场景卡生成清单(gen_cast_sheets.py plan 产出)。 |
assets/cast/style_ref.png |
风格母版(统一色调/质感的锚点)。 |
assets/cast/character_XX.png |
各角色视觉参考卡(锚定角色外貌,防止串脸)。 |
assets/cast/set_XX.png |
各场景概念图(锚定场景,防止跳场景)。 |
scene_XX.png |
Per-scene keyframe image. |
scene_XX.mp4 |
Per-scene rendered video clip. |
final.mp4 |
Stitched finished video (when a stitch backend is available: ffmpeg or moviepy). |
final_music.mp4 |
Final video with BGM only (optional, Phase 6.5; superseded by final_voice.mp4). |
final_nomusic.mp4 |
Backup of the silent stitched video before any audio mix. |
bgm.wav |
Synthesized BGM track (optional, Phase 6.5). |
final_voice.mp4 |
Final video with TTS narration + BGM burned in (optional, Phase 6.6). |
voice.mp3 |
TTS narration track (optional, Phase 6.6). |
final_dialogue.mp4 |
Final video with role-based, emotional dialogue dubbing + per-line captions + BGM (optional, Phase 6.7). |
dialogue_meta.json |
Dialogue timeline metadata (total duration, line count) from gen_dialogue.py. |
line_NN.mp3 |
Per-line character dialogue audio (optional, Phase 6.7). |
cover.png |
Cover image (first-scene highlight frame, or a separately generated cover). |
concat_list.txt |
ffmpeg concat manifest for later stitching. |
Quality Checklist (before delivering)
- [ ] Hook grabs attention in the first 3 seconds.
- [ ] Each scene carries exactly one idea; total within ±15% of
duration. - [ ] Tone matches the chosen preset consistently.
- [ ] Visual consistency is achieved: scenes 2..N use
image: [scene_01.png]with
input_fidelity≥ 0.85; if unavailable, at leastvisual_styletoken is identical
across all scenes. - [ ] 画风与
--style一致:build_storyboard.py --from storyboard.json --validate
无image_prompt风格漂移/冲突词告警;cast.json与storyboard.json的 style 一致
(如已做 Phase 2.5,构造时带--cast cast.json交叉校验)。 - [ ] Every scene has a non-empty
image_promptandmotion_prompt. - [ ] Captions are short, readable on mobile, and match the narration.
- [ ] Video clips use the correct
aspectforplatform. - [ ] A
cover.pngexists: it is the first-scene highlight frame (or a separately
generated cover); size matches9:16 → 1080×1920/16:9 → 1920×1080.
Resources
scripts/
build_storyboard.py— Segment polished text into timed scenes; render storyboard JSON/HTML;
validate a filled storyboard. Pure stdlib, deterministic. New:--density {normal,dramatic}
(dramatic = 剧情模式,≤30 镜 / 单镜≤15s / 时长更宽松),scene 预留cast/set引用字段;
新增--style {realistic,anime}(写入meta.style与默认visual_style,供 Phase 4 锁定画风)。scan_script.py— (可选) 长文本扫描辅助:按「第X章」切片 + 统计高频中文词,输出
scan_report.json,辅助 LLM 在预生产阶段快速定位人物与场景。纯 stdlib。gen_cast_sheets.py— (可选, 角色·场景预生产) 读cast.json:plan输出风格母版+角色卡+场景卡
的生成清单(含 ImageGen prompt 与锚定关系,支持--style {realistic,anime}切换卡片措辞);
apply把生成路径回填cast.json;verify校验齐全。assemble.py— Stitch scene clips and burn captions intofinal.mp4. Backend is
ffmpeg (recommended) or moviepy (optional fallback, no system ffmpeg needed),
selectable via--stitch-backend {auto,ffmpeg,moviepy}(defaultauto). Also exports
a cover image with--cover-out cover.png(add--cover-onlyto skip final assembly).synth_bgm.py— (可选) 纯 numpy 合成 BGM:低音 drone + 节拍(kick/hihat) + 小调 pad 和弦进行。
用法python scripts/synth_bgm.py <时长秒> <输出wav>;可调BPM/_PROGRESSION/gain。mix_bgm.py— (可选) 把 BGM(wav/mp3)经 moviepy 以 AAC 烧入成片:
python scripts/mix_bgm.py --video final.mp4 --bgm bgm.wav --out final_music.mp4
(原无声版自动备份为final_nomusic.mp4)。gen_voice.py— (可选) 用 edge-tts 生成中文旁白 TTS:python scripts/gen_voice.py --text-file narration.txt --voice zh-CN-YunxiNeural --out voice.mp3(或从--from storyboard.json
自动拼接各镜 narration)。需联网、pip install edge-tts。add_voice.py— (可选) 混音器:读final_nomusic.mp4+voice.mp3+bgm.wav,把人声(主)
与 BGM(底)烧入final_voice.mp4,并自动慢放画面匹配旁白时长。gen_dialogue.py— (可选) 角色对话模式(短剧/动漫通用):读storyboard.json的scenes[].dialogue
剧本,逐句用edge-tts生成分角色 TTS(SSML 注入情感),写出逐句dialogue_timeline
(start/end/text/audio/speaker/emotion)回storyboard.json,并产出dialogue_meta.json。
默认角色音色/情感见 Phase 6.7;剧本可逐句覆盖voice/emotion。需联网、pip install edge-tts。add_dialogue.py— (可选) 角色对话模式混音器(短剧/动漫通用):读dialogue_timeline拼接逐句对话音轨
(主,人声峰值增益) + BGM(循环压低垫底),画面speedx匹配对话总时长,输出final_dialogue.mp4。
references/
platforms.md— Per-platform specs (aspect, duration, style, caption, cover tips).tone-presets.md— Tone presets with vocabulary/rhythm guidance.video-tech.md— ImageGen / VideoGen prompt structure, duration limits, consistency tips.
assets/
caption_presets.json— Subtitle/caption style presets per platform for burn-in.
```