前面几篇,我们已经分析了 Pixelle-Video 的整体架构、目录结构、启动流程和配置系统。
从这一篇开始,我们进入真正的 AI 内容生成部分。
Pixelle-Video 的核心卖点是"一句话生成短视频"。但从源码角度看,它并不是直接把一句话丢给视频模型,然后等模型吐出一个 MP4。
它的真实流程是:
text
主题
↓
AI 生成多段解说词
↓
每段解说词对应一个分镜
↓
每个分镜再生成图片/视频提示词
↓
TTS 生成语音
↓
模板渲染画面
↓
合成短视频
所以,AI 文案生成是整个视频生成流程的第一块骨牌。
如果解说词写得不好,后面的图片提示词、配音、画面节奏都会受影响。
这一篇我们重点看 Pixelle-Video 是如何根据一个主题自动生成多段短视频解说词的。
一、文案生成在完整流程中的位置
在 Pixelle-Video 的标准生成流程里,文案生成发生在 StandardPipeline.generate_content() 阶段。
源码中 StandardPipeline 的注释已经说明,它是默认的通用短视频生成 pipeline,支持两种模式:generate 和 fixed。其中 generate 模式表示根据主题由 LLM 自动生成 narration,fixed 模式表示用户提供现成脚本,系统只负责拆分。
也就是说,Pixelle-Video 的文案入口并不是单一的。
它有两条路线:
text
generate 模式:
用户输入主题 → LLM 自动扩写成多段解说词
fixed 模式:
用户输入完整文案 → 系统按段落/行/句子拆成多段解说词
本文主要分析第一条路线,也就是:
text
主题 → AI 解说词
不过 fixed 模式也很重要,因为它适合用户自己写好文案,只让 Pixelle-Video 负责后续配图、配音和合成。
二、generate_content:文案生成的 pipeline 入口
先看 StandardPipeline.generate_content()。
这一方法会从上下文参数里读取:
text
mode
text
n_scenes
min_narration_words
max_narration_words
其中:
text 是用户输入的主题。
n_scenes 是要生成多少个分镜。
min_narration_words 是每段解说词的最少词数。
max_narration_words 是每段解说词的最多词数。
在 generate 模式下,代码会调用 generate_narrations_from_topic(),把主题、分镜数量、最小词数、最大词数传进去;在 fixed 模式下,则调用 split_narration_script(),按指定拆分方式处理已有文案。
伪代码可以简化成这样:
python
async def generate_content(ctx):
mode = ctx.params.get("mode", "generate")
text = ctx.input_text
n_scenes = ctx.params.get("n_scenes", 5)
min_words = ctx.params.get("min_narration_words", 5)
max_words = ctx.params.get("max_narration_words", 20)
if mode == "generate":
ctx.narrations = await generate_narrations_from_topic(
self.llm,
topic=text,
n_scenes=n_scenes,
min_words=min_words,
max_words=max_words
)
else:
ctx.narrations = await split_narration_script(
text,
split_mode=split_mode
)
这一步的结果是:
text
ctx.narrations = [
"第一段解说词",
"第二段解说词",
"第三段解说词",
...
]
后面所有分镜、配图、配音,都会围绕这个 ctx.narrations 继续执行。
三、为什么叫 narration,而不是 script?
Pixelle-Video 源码里大量使用的是 narration,而不是简单叫 script。
这个命名很准确。
script 更像完整脚本,可能包括标题、人物、场景、台词、动作、镜头说明。
narration 则更像旁白,是可以直接交给 TTS 生成语音的一段文本。
Pixelle-Video 的短视频生成流程,本质上是"旁白驱动"的。
每一段 narration 会对应:
text
一段 TTS 语音
一个分镜 frame
一个图片/视频 prompt
一个最终视频片段 segment
因此,文案生成的目标不是写一篇完整文章,而是生成一组适合配音、适合分镜、适合短视频节奏的旁白句子。
这也是它和普通 AI 写作工具的区别。
普通 AI 写作工具可能输出一篇文章。
Pixelle-Video 需要输出一个可被程序继续处理的 narration 数组。
四、generate_narrations_from_topic:真正调用 LLM 的地方
文案生成的核心函数在 pixelle_video/utils/content_generators.py 中。
generate_narrations_from_topic() 的职责很明确:根据主题调用 LLM,生成指定数量的 narration。它会先调用 build_topic_narration_prompt() 构造 prompt,然后调用 llm_service,最后解析 JSON,并校验返回结果中是否包含 narrations 字段。
它的逻辑可以拆成四步:
text
1. 构造 prompt
2. 调用 LLM
3. 解析 JSON
4. 校验 narration 数量
简化后的伪代码如下:
python
async def generate_narrations_from_topic(
llm_service,
topic,
n_scenes=5,
min_words=5,
max_words=20
):
prompt = build_topic_narration_prompt(
topic=topic,
n_storyboard=n_scenes,
min_words=min_words,
max_words=max_words
)
response = await llm_service(
prompt=prompt,
temperature=0.8,
max_tokens=2000
)
result = _parse_json(response)
if "narrations" not in result:
raise ValueError("missing narrations")
narrations = result["narrations"]
if len(narrations) > n_scenes:
narrations = narrations[:n_scenes]
elif len(narrations) < n_scenes:
raise ValueError("narration count not enough")
return narrations
这里有几个细节值得注意。
第一,文案生成使用 temperature=0.8。
这说明 Pixelle-Video 希望文案有一定创造性,而不是完全保守。
第二,返回结果必须是 JSON。
因为后续程序要继续处理,不可能让模型随便输出一大段自然语言。
第三,必须包含 narrations 字段。
这是 LLM 输出和程序之间的接口约定。
第四,数量必须满足 n_scenes。
多了可以截断,少了直接报错。
这说明 Pixelle-Video 对 LLM 输出并不是完全信任,而是做了格式校验。
五、Prompt:真正控制文案质量的地方
AI 文案生成效果好不好,关键不只在模型,还在 prompt。
Pixelle-Video 把 topic narration 的 prompt 放在 pixelle_video/prompts/topic_narration.py 中,并通过 build_topic_narration_prompt() 注入主题、分镜数量、最小词数、最大词数。
这个 prompt 不是简单一句:
text
请根据主题写 5 段短视频文案
它对模型提出了非常具体的要求,包括:
text
角色:专业内容创作专家
任务:把用户主题扩展成多个短视频分镜旁白
语言:必须和用户输入语言保持一致
用途:用于 TTS 生成视频解说音频
长度:每段控制在指定词数范围内
风格:像朋友聊天,自然、真诚、有启发
结构:形成完整观点表达
输出:严格 JSON 格式,只输出 narrations 数组
这说明 Pixelle-Video 对文案生成的要求不是"写得漂亮"这么简单,而是要同时满足:
text
适合短视频
适合 TTS
适合拆分镜
适合程序解析
适合后续生成画面
这就是 AI 应用里 prompt 工程的价值。
很多人写 AI 项目,只是在代码里硬塞一句提示词。
但 Pixelle-Video 把 prompt 单独放到 prompts/ 目录,作为可维护模块,这是比较正确的工程做法。
六、为什么 prompt 要强制 JSON 输出?
Pixelle-Video 的 topic narration prompt 明确要求模型只输出 JSON,并且格式是:
json
{
"narrations": [
"First narration content",
"Second narration content",
"Third narration content"
]
}
源码中的 generate_narrations_from_topic() 随后会调用 _parse_json() 解析 LLM 返回值,如果没有 narrations 字段,就抛出错误。
为什么要这么严格?
因为 Pixelle-Video 后面不是给人读,而是给程序继续跑。
如果 LLM 输出的是:
text
好的,下面是为你生成的五段文案:
1. ...
2. ...
人看起来没问题,但程序解析就麻烦。
如果输出的是 JSON:
json
{
"narrations": [
"很多人学习效率低,并不是因为不努力,而是方法错了",
"真正高效的学习,第一步是先明确目标",
"把大目标拆成每天能执行的小动作,才不会越学越焦虑"
]
}
程序就可以直接拿到数组,然后生成分镜。
所以,在 Pixelle-Video 里,JSON 不是形式主义,而是 LLM 和 pipeline 之间的数据协议。
七、_parse_json:给 LLM 输出做兜底解析
LLM 虽然被要求只输出 JSON,但实际使用中,模型仍然可能输出 markdown 代码块,或者在 JSON 前后加解释文字。
Pixelle-Video 的 _parse_json() 做了几个兜底:
text
1. 先尝试直接 json.loads
2. 如果失败,尝试从 ```json 代码块中提取 JSON
3. 如果还失败,尝试用正则寻找包含 narrations 或 image_prompts 的 JSON 对象
4. 最后仍失败,抛出 JSONDecodeError
这些逻辑定义在 content_generators.py 中,用来提升 LLM 输出解析的容错能力。
这点非常实际。
因为不同模型的"听话程度"不一样。
有些模型会严格输出 JSON。
有些模型会输出:
text
当然可以,以下是 JSON:
```json
{
"narrations": [...]
}
有些模型甚至会在 JSON 前后加说明。
如果程序只做 `json.loads(response)`,就很容易失败。
Pixelle-Video 这里做了多层解析,能提高不同模型下的可用性。
不过,这个兜底也不是万能的。
如果模型返回的 JSON 本身不合法,或者数组数量不对,程序仍然会报错。
这也是 AI 应用开发中很常见的问题:
**Prompt 负责约束,Parser 负责兜底,Validator 负责兜底失败后的报错。**
## 八、LLMService:统一调用 OpenAI-compatible 模型
再往下看,`generate_narrations_from_topic()` 并不直接调用 OpenAI、通义千问或 DeepSeek,而是调用传入的 `llm_service`。
这个服务就是 `pixelle_video/services/llm_service.py` 中的 `LLMService`。
源码注释中说明,`LLMService` 使用 OpenAI SDK 的异步客户端 `AsyncOpenAI`,并支持 OpenAI SDK 兼容的 provider,例如 OpenAI、通义千问、DeepSeek、Ollama,以及自定义 OpenAI-compatible API。
它的调用入口是 `__call__()`:
```python
async def __call__(
self,
prompt: str,
api_key: Optional[str] = None,
base_url: Optional[str] = None,
model: Optional[str] = None,
temperature: float = 0.7,
max_tokens: int = 2000,
response_type: Optional[Type[T]] = None,
**kwargs
) -> Union[str, T]:
...
这里有几个关键点。
第一,api_key、base_url、model 都可以通过参数传入,也可以从配置系统读取。
第二,默认使用 chat.completions.create() 发送用户 prompt。
第三,如果传入 response_type,它还支持结构化输出解析。
第四,它每次调用都会创建 client,以支持参数覆盖和配置热更新。源码中也说明,它不再缓存配置,而是通过 config_manager 动态读取 LLM 配置。
所以,Pixelle-Video 的文案生成并不关心底层到底是哪家模型。
文案生成函数只知道:
text
我有一个 llm_service
我给它 prompt
它返回 response
我解析 JSON
具体模型来自配置系统。
这就是服务层封装的价值。
九、为什么支持 OpenAI-compatible 很重要?
短视频文案生成是一个高频操作。
如果每次都绑定某一个模型供应商,成本和可用性都会受限制。
Pixelle-Video 的 LLMService 通过 OpenAI SDK 兼容接口来调用模型,这意味着只要服务商提供类似接口,就可以通过 api_key、base_url、model 切换。源码注释中列出了 OpenAI、Qwen、DeepSeek、Ollama 和自定义 provider 等类型。
这带来几个好处:
text
想省钱:可以接本地 Ollama
想稳定:可以接商业 API
想中文效果好:可以接中文模型
想测试不同模型:只改配置即可
想私有化部署:可以接 OpenAI-compatible 内部服务
从二次开发角度看,这比写死一个模型要灵活很多。
例如,你可以让用户在 WebUI 中选择:
text
DeepSeek:便宜,适合大量生成文案
通义千问:中文表达稳定
OpenAI:综合能力强
Ollama:本地免费,但效果依赖模型
底层调用逻辑不用大改,只需要配置不同的 base_url 和 model。
十、文案生成不是孤立的,它会影响后续所有模块
ctx.narrations 生成出来后,并不是结束。
后面的 plan_visuals() 会根据这些 narrations 生成图片或视频提示词。StandardPipeline 中可以看到,如果模板类型是 image 或 video,它会调用 generate_image_prompts();如果是静态模板,则跳过媒体生成。
也就是说,narration 同时承担两个作用:
text
对用户来说:
它是视频旁白
对程序来说:
它是后续生成图片/视频 prompt 的输入
例如 narration 是:
text
很多人学习效率低,并不是因为不努力,而是方法错了
后续图像提示词可能会变成:
text
一个深夜坐在书桌前学习的年轻人,桌上堆满书和笔记,表情疲惫,暖色灯光,电影感构图
如果 narration 太抽象,比如:
text
人生就是一场修行
后续生成画面就会困难。
如果 narration 太长,TTS 时间会变长,画面节奏也会拖。
如果 narration 太短,视频会碎片化,信息量不足。
如果 narration 之间逻辑不连续,最终视频就会像几句随机语录拼在一起。
所以 Pixelle-Video 在 prompt 中强调:
text
每段 narration 要有价值
整体要形成完整观点表达
语气要统一
要像同一个人在连续分享
这些要求不是为了文案好看,而是为了让后续视频生成更稳定。
十一、从 narration 到 StoryboardFrame
文案生成结束后,后续会进入 storyboard 初始化阶段。
StoryboardFrame 的数据结构中包含 index、narration、image_prompt、audio_path、media_type、image_path、video_path、composed_image_path、video_segment_path、duration 等字段。
这说明每一段 narration 后面都会变成一个 frame。
可以理解成:
text
narrations[0] → StoryboardFrame(index=0)
narrations[1] → StoryboardFrame(index=1)
narrations[2] → StoryboardFrame(index=2)
每个 frame 初始时只有:
text
index
narration
image_prompt
后续经过 TTS、媒体生成、模板合成、视频片段生成,才逐渐补齐:
text
audio_path
image_path / video_path
composed_image_path
video_segment_path
duration
所以,AI 文案生成不是最终内容,而是 storyboard 的起点。
这一点很重要:
Pixelle-Video 的视频结构,是由 narration 数组驱动出来的。
narration 的数量决定分镜数量。
narration 的长度影响每段视频时长。
narration 的内容影响画面提示词。
narration 的语言影响 TTS 语言和标题语言。
十二、标题生成:和 narration 并列的文案能力
除了生成 narration,Pixelle-Video 还会生成标题。
在 StandardPipeline.determine_title() 中,如果用户传入了标题,就直接使用;如果没有传入标题,generate 模式下会调用 generate_title(self.llm, text, strategy="auto"),fixed 模式下则调用 generate_title(self.llm, text, strategy="llm")。
generate_title() 的逻辑在 content_generators.py 中:
text
direct 策略:直接使用输入内容,必要时截断
auto 策略:如果内容很短,直接当标题;否则调用 LLM
llm 策略:强制调用 LLM 生成标题
标题生成使用的是 build_title_generation_prompt(),该 prompt 要求标题必须和输入内容语言一致、不能超过指定字符数、准确概括核心内容、结尾不能带标点,并且只输出标题文本。
这说明 Pixelle-Video 把"标题"和"旁白"分开处理。
旁白需要 JSON 数组。
标题只需要一行短文本。
两者使用不同 prompt,符合不同输出目标。
十三、fixed 模式:不是 AI 写稿,而是脚本拆分
虽然本文重点是 AI 自动写解说词,但 fixed 模式也值得看一下。
split_narration_script() 支持三种拆分方式:
text
paragraph:按段落拆分
line:按单行拆分
sentence:按句号、问号、感叹号等句末标点拆分
源码里 paragraph 模式按双换行拆分,line 模式按单换行拆分,sentence 模式支持中文和英文句末标点。
这对实际使用很有价值。
因为很多时候用户并不想让 AI 改文案,只想让 Pixelle-Video 根据已有文案生成视频。
例如你已经写好:
text
很多人学习效率低,并不是因为不努力,而是方法错了。
真正高效的学习,第一步是明确目标。
把大目标拆成每天能执行的小动作,才不会越学越焦虑。
这时就不需要 LLM 重新创作,而是直接按段落拆成三段 narration。
这也说明 Pixelle-Video 的内容层设计比较灵活:
text
想省事:generate 模式自动写
想可控:fixed 模式自己写
十四、文案生成流程图
把前面的内容串起来,Pixelle-Video 的 AI 文案生成流程可以画成这样:
text
用户输入主题
↓
StandardPipeline.generate_content()
↓
读取参数:
mode
n_scenes
min_narration_words
max_narration_words
↓
判断 mode
↓
generate 模式
↓
generate_narrations_from_topic()
↓
build_topic_narration_prompt()
↓
LLMService.__call__()
↓
OpenAI-compatible chat.completions.create()
↓
返回文本 response
↓
_parse_json(response)
↓
校验 narrations 字段
↓
校验数量是否等于 n_scenes
↓
ctx.narrations
↓
后续生成 image_prompts
↓
初始化 StoryboardFrame
如果是 fixed 模式,则变成:
text
用户输入完整文案
↓
StandardPipeline.generate_content()
↓
split_narration_script()
↓
按 paragraph / line / sentence 拆分
↓
ctx.narrations
↓
后续生成 image_prompts
↓
初始化 StoryboardFrame
这两条路线最后都会汇合到 ctx.narrations。
这就是 Pixelle-Video 内容生成层的设计重点:
不管文案来自 AI 生成,还是用户手写,最终都统一成 narration 列表。
十五、这个设计有什么优点?
Pixelle-Video 的文案生成设计,有几个明显优点。
1. 输出结构清晰
LLM 不直接输出整篇文章,而是输出:
json
{
"narrations": [...]
}
这让后续程序可以稳定处理。
2. 和分镜天然对应
n_scenes 决定 narration 数量。
每一段 narration 对应一个分镜。
这让短视频生成流程更容易控制。
3. 适合 TTS
prompt 明确要求 narration 适合 TTS,语言自然、有停顿感、像朋友聊天。
这比普通文章更适合直接转语音。
4. 支持多语言
topic narration prompt 要求输出语言和用户输入语言保持一致。
这对中英文短视频都很有用。
5. 支持模型替换
文案生成只依赖 LLMService,而 LLMService 支持 OpenAI-compatible provider。
换模型不需要重写文案生成逻辑。
6. 支持手写文案
fixed 模式可以跳过 AI 写稿,直接拆分用户脚本。
这对追求内容可控的用户很重要。
十六、可能存在的问题
当然,这套设计也有一些需要注意的地方。
1. LLM 输出不稳定
虽然 prompt 要求输出 JSON,但模型仍可能输出非法 JSON。
Pixelle-Video 用 _parse_json() 做了兜底,但如果模型返回结构严重错误,仍然会失败。
2. 字数控制未必绝对准确
prompt 要求每段控制在 min_words 到 max_words 之间,但 LLM 对"词数"的执行并不总是精准。
尤其是中文场景下,"word count"和"字符数"并不是一回事。
这可能导致每段旁白长短不稳定。
3. 内容真实性需要人工审核
prompt 中允许在某些主题下自然引用权威内容,但也要求不要编造来源。
不过 LLM 仍可能产生事实错误。
如果用于健康、财经、法律、科技科普等内容,最好增加人工审核或事实校验环节。
4. 每段 narration 的镜头可视化程度不同
有些旁白天然适合画面生成。
例如:
text
一个年轻人深夜坐在书桌前,反复翻看同一本书
这种很容易生成画面。
但有些旁白很抽象:
text
真正的成长,是重新理解自己的内在秩序
这种就不容易生成明确画面。
所以,如果想提升最终视频效果,后续可以在文案生成阶段增加"画面可视化约束"。
十七、二次开发可以怎么优化?
如果你想基于 Pixelle-Video 做自己的短视频工具,文案生成模块有很多优化空间。
1. 增加账号风格参数
可以在 prompt 中加入账号定位:
text
账号类型:健康科普
目标用户:50 岁以上中老年人
表达风格:通俗、稳重、不夸张
禁用风格:焦虑营销、虚假医学结论
这样生成的 narration 会更符合账号长期风格。
2. 增加平台参数
不同平台文案节奏不一样。
抖音、快手更需要强开头。
B 站可以稍微解释完整。
小红书更适合生活化表达。
YouTube Shorts 更适合英文短句和强节奏。
可以增加:
text
platform = douyin / kuaishou / xiaohongshu / youtube_shorts
然后让 prompt 根据平台调整开头、语气和节奏。
3. 增加内容安全检查
如果用于健康、财经、法律等内容,可以在 narration 生成后增加二次检查:
text
是否存在绝对化承诺
是否存在医疗建议
是否存在夸大收益
是否存在虚假引用
是否存在敏感词
这对真实运营账号很重要。
4. 增加镜头可视化评分
可以让 LLM 在生成 narration 时同时输出可视化建议:
json
{
"narrations": [...],
"visual_notes": [...]
}
或者在生成后检查每段 narration 是否容易生成画面。
这能提高后续图片/视频生成质量。
5. 增加爆款标题和开头模板
Pixelle-Video 当前更偏通用文案生成。
如果要做短视频运营工具,可以增加更强的标题和开头策略,比如:
text
反常识开头
问题式开头
场景式开头
数字式开头
痛点式开头
结果前置式开头
但要注意避免低质标题党,尤其是健康类、财经类内容。
十八、源码阅读建议
如果你想跟着源码读这部分,我建议按这个顺序:
text
1. pixelle_video/pipelines/standard.py
看 generate_content() 如何进入文案生成
2. pixelle_video/utils/content_generators.py
看 generate_narrations_from_topic() 如何构造 prompt、调用 LLM、解析 JSON
3. pixelle_video/prompts/topic_narration.py
看 prompt 如何约束语言、风格、长度、JSON 输出
4. pixelle_video/services/llm_service.py
看 LLMService 如何统一调用 OpenAI-compatible 模型
5. pixelle_video/models/storyboard.py
看 narration 如何变成 StoryboardFrame 的核心字段
这条阅读路线从 pipeline 入口一路追到 LLM 调用,再回到数据结构,不容易迷路。
十九、总结
这一篇我们分析了 Pixelle-Video 的 AI 文案生成流程。
它的核心链路是:
text
StandardPipeline.generate_content()
↓
generate_narrations_from_topic()
↓
build_topic_narration_prompt()
↓
LLMService.__call__()
↓
_parse_json()
↓
ctx.narrations
↓
StoryboardFrame
从设计上看,Pixelle-Video 并不是让 AI 随便写一篇文章,而是让 LLM 输出一组结构化 narration。
这些 narration 有几个特点:
text
数量受 n_scenes 控制
长度受 min/max words 控制
语言跟随用户输入
语气适合 TTS
内容适合短视频
格式必须是 JSON
后续直接驱动分镜、配图和配音
所以,AI 文案生成在 Pixelle-Video 中不是一个可有可无的小功能,而是整个短视频生成流程的起点。
一句话总结:
Pixelle-Video 的 AI 文案生成,本质是把用户主题转换成一组可配音、可分镜、可继续生成画面的结构化旁白。