1. 从图文到视频的自动化链路拆解
公众号文章和视频号短视频之间,隔着的不是简单的“复制粘贴”,而是一整套内容形态的转换工程。我做了大半年的智能体基建,踩过的坑比写过的代码还多,今天就把这套“公众号文章自动生成视频号短视频”的完整方案摊开来讲。核心思路很直接:用智能体串联起文案提取、语音合成、画面生成、视频合成四个环节,让一篇三千字的公众号长文,在十分钟内变成一条带字幕、有配音、画面不违和的短视频。这套方案适合谁?适合那些手里有大量图文内容、想低成本试水短视频的内容创作者,也适合想了解智能体落地场景的技术爱好者。你不需要会剪辑,但需要有一点折腾环境的耐心。
先说说为什么选智能体这条路。传统做法是人工把文章改成脚本,再录音、找素材、剪辑,一条视频至少两小时。而智能体的价值在于,它能把“理解文章结构”这件事自动化。我试过用纯脚本硬编码,结果文章一换风格就崩;也试过用现成的SaaS工具,但模板感太重,发出去像批量生产的垃圾内容。最后定下来的方案是:用大语言模型做内容理解和脚本改写,用Whisper做语音转写校对,用FFmpeg做视频合成,中间用Python脚本做调度。这套组合的灵活性最高,每个环节都能单独替换或调参。
整个链路我拆成四步。第一步,从公众号文章链接或正文里提取纯文本,去掉广告和无关推荐位。第二步,把长文喂给大语言模型,让它输出适合口播的短文案,同时生成分镜描述。第三步,用TTS把文案转成语音,再用Whisper做一遍回译校对,确保没有多音字错误。第四步,根据分镜描述匹配素材或生成纯色背景加文字动画,最后用FFmpeg把语音、画面、字幕合成到一起。这四步里,第三步的校对环节最容易被忽略,但恰恰是决定视频“能不能听”的关键。
注意:公众号文章里经常有图片、表格、代码块,提取文本时要做好过滤,否则大语言模型会被无关符号干扰,输出的脚本质量断崖式下跌。
1.1 为什么不用现成的视频生成大模型
市面上确实有文生视频的大模型,但我实测下来,直接拿公众号文章生成视频,效果并不好。原因有两个:一是文生视频模型对长文本的理解能力有限,三千字的文章它抓不住重点;二是生成视频的时长和分辨率不可控,一条三分钟的视频可能要渲染半小时,成本扛不住。所以我选择“拆解再组装”的思路,把视频生成拆成语音、画面、字幕三个独立模块,每个模块用最成熟的工具解决。语音用Edge TTS,免费且音色自然;画面用FFmpeg合成,稳定且速度快;字幕用Whisper对齐时间轴,准确率够用。这套方案的单条视频生成时间可以压到三分钟以内,硬件成本几乎为零。
1.2 智能体在链路中的角色定位
这里的“智能体”不是那种能自主决策的复杂系统,而是一个有状态的工作流调度器。它负责接收文章输入,判断文章类型(干货、故事、资讯),然后选择不同的脚本改写策略。比如干货类文章,智能体会保留核心论点,删掉冗余案例;故事类文章,智能体会保留情节线,压缩环境描写。这个判断逻辑我用的是提示词工程加少量规则匹配,没有上复杂的多智能体框架。原因很简单:内容创作这件事,过度自动化反而会丢失“人味”。智能体做80%的脏活累活,剩下20%的润色和把关,还是得人来。
2. 核心工具链的选型与配置细节
工具选型这件事,我走过不少弯路。最开始用某款在线TTS,结果免费额度用完后按字符收费,一条视频成本三块钱,一个月下来比买会员还贵。后来换成Edge TTS,虽然音色选择少一些,但胜在免费、稳定、支持SSML标记。FFmpeg的安装是个门槛,Windows用户建议直接下载官网的静态编译包,解压后把bin目录加到环境变量里,别去折腾什么包管理器,容易出玄学问题。Whisper本地部署对硬件有要求,如果机器没有独立显卡,建议用whisper.cpp的量化版本,速度慢一点但能跑。
2.1 Edge TTS的安装与音色选择
Edge TTS的安装很简单,一行命令搞定:
pip install edge-tts但音色选择有讲究。中文口播我推荐这几个音色:zh-CN-XiaoxiaoNeural适合情感类内容,语调起伏自然;zh-CN-YunxiNeural适合干货类内容,语速平稳;zh-CN-YunjianNeural适合资讯类内容,节奏偏快。你可以在命令行里用edge-tts --list-voices查看所有可用音色。实测下来,Xiaoxiao的断句最准,遇到长句不会一口气读完,而是会在逗号处自然停顿。如果你要做多角色对话的视频,可以给不同角色分配不同音色,但注意别超过三种,否则观众会听觉疲劳。
提示:Edge TTS生成的音频默认是24kHz采样率,如果后续要用FFmpeg做变调或变速处理,建议先用
ffmpeg -i input.mp3 -ar 44100 output.wav转成44.1kHz,避免重采样带来的音质损失。
2.2 FFmpeg的安装与常用命令速查
Windows用户去FFmpeg官网下载ffmpeg-release-essentials.zip,解压到C:\ffmpeg,然后把C:\ffmpeg\bin加到系统Path里。验证安装是否成功:
ffmpeg -versionLinux用户直接用包管理器:
sudo apt install ffmpegmacOS用户用Homebrew:
brew install ffmpeg安装完成后,这几个命令你一定会用到。把音频和图片合成视频:
ffmpeg -loop 1 -i background.jpg -i audio.mp3 -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest output.mp4给视频加字幕:
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='FontSize=24,PrimaryColour=&HFFFFFF&'" output.mp4调整视频速度:
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" -filter:a "atempo=2.0" output.mp4这几个命令覆盖了80%的合成需求。注意-pix_fmt yuv420p这个参数,不加的话在某些播放器上会显示花屏,这是编码格式兼容性问题,踩过一次坑就记住了。
2.3 Whisper本地部署的硬件门槛与优化
Whisper的官方实现基于PyTorch,安装命令是:
pip install openai-whisper但如果你没有NVIDIA显卡,推理速度会慢到怀疑人生。我的测试数据是:用CPU跑medium模型,一分钟的音频要转写三分钟;用GPU跑同样的模型,一分钟音频只要十秒。所以没有显卡的话,建议用whisper.cpp,它支持量化模型,CPU推理速度能提升三到五倍。安装whisper.cpp的步骤稍微麻烦一点,需要先克隆仓库再编译:
git clone https://github.com/ggerganov/whisper.cpp cd whisper.cpp make然后下载量化模型:
bash ./models/download-ggml-model.sh base用的时候:
./main -m models/ggml-base.bin -f audio.wav -l zhbase模型在中文上的准确率已经够用,如果对时间轴精度要求高,可以换small模型,但速度会慢一倍。
3. 完整实操流程与关键环节实现
这一节我把整个流程拆成可复现的步骤,你跟着做就能跑通。先说明一下我的运行环境:Windows 11,Python 3.10,没有独立显卡,所以Whisper用的是whisper.cpp的base模型。如果你有显卡,可以把Whisper换成官方版本,速度更快。整个项目我放在一个叫wechat-video-creator的目录里,结构如下:
wechat-video-creator/ ├── input/ │ └── article.txt ├── output/ │ ├── audio.mp3 │ ├── subtitle.srt │ └── video.mp4 ├── assets/ │ └── background.jpg ├── scripts/ │ ├── extract_text.py │ ├── rewrite_script.py │ ├── tts_generate.py │ ├── whisper_align.py │ └── compose_video.py └── config.yaml3.1 文章提取与脚本改写
第一步是把公众号文章转成纯文本。如果你有文章链接,可以用requests加BeautifulSoup抓取,但公众号的页面结构经常变,更稳妥的做法是手动复制正文到article.txt。提取文本的脚本很简单:
import re def clean_text(raw_text): # 去掉多余空行 text = re.sub(r'\n{3,}', '\n\n', raw_text) # 去掉图片标记 text = re.sub(r'!\[.*?\]\(.*?\)', '', text) # 去掉链接 text = re.sub(r'\[.*?\]\(.*?\)', '', text) return text.strip() with open('input/article.txt', 'r', encoding='utf-8') as f: raw = f.read() cleaned = clean_text(raw) with open('input/article_cleaned.txt', 'w', encoding='utf-8') as f: f.write(cleaned)接下来是脚本改写。我用的是大语言模型的API,提示词是这样设计的:
你是一个短视频脚本改写助手。请把下面的公众号文章改写成适合口播的短视频脚本,要求: 1. 保留核心观点,删掉冗余案例和重复论述 2. 每句话不超过30个字,适合口语表达 3. 开头3秒内抛出钩子,吸引观众停留 4. 结尾引导点赞关注 5. 输出格式为纯文本,不要加任何标记 文章内容: {article_text}实测下来,这个提示词对干货类文章效果最好,改写后的脚本长度大约是原文的20%到30%。如果文章是故事类,我会把提示词里的“保留核心观点”改成“保留情节转折”,其他不变。
3.2 语音合成与字幕对齐
拿到改写后的脚本,用Edge TTS生成语音:
import edge_tts import asyncio async def generate_audio(text, output_path): communicate = edge_tts.Communicate(text, 'zh-CN-XiaoxiaoNeural') await communicate.save(output_path) asyncio.run(generate_audio(script_text, 'output/audio.mp3'))生成完语音后,用Whisper做回译校对。这一步的目的是生成带时间轴的字幕文件,同时检查TTS有没有读错多音字。命令如下:
./whisper.cpp/main -m models/ggml-base.bin -f output/audio.wav -l zh -osrt这个命令会生成audio.wav.srt文件,里面是带时间轴的字幕。我一般会打开这个文件快速扫一遍,看看有没有明显的错字。比如“重”字在“重要”和“重复”里读音不同,TTS有时候会读错,Whisper的回译能帮我发现这类问题。如果发现错误,就回到脚本里把那个词换成同义词,重新生成语音。
注意:Whisper生成的字幕时间轴有时候会偏移,尤其是语速较快的时候。如果偏移超过0.5秒,建议手动调整SRT文件里的时间码,或者用FFmpeg的
-itsoffset参数做整体偏移。
3.3 画面合成与最终输出
画面部分我走的是极简路线:一张纯色背景图加文字动画。背景图用PIL生成,尺寸1920x1080,颜色选深灰或深蓝,文字用白色,字号72。生成背景图的代码:
from PIL import Image, ImageDraw, ImageFont def create_background(text, output_path): img = Image.new('RGB', (1920, 1080), color=(30, 30, 40)) draw = ImageDraw.Draw(img) font = ImageFont.truetype('C:/Windows/Fonts/msyh.ttc', 72) # 文字居中 bbox = draw.textbbox((0, 0), text, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] x = (1920 - text_width) / 2 y = (1080 - text_height) / 2 draw.text((x, y), text, font=font, fill=(255, 255, 255)) img.save(output_path) create_background('公众号文章自动生成视频', 'assets/background.jpg')最后用FFmpeg合成:
ffmpeg -loop 1 -i assets/background.jpg -i output/audio.mp3 -vf "subtitles=output/audio.wav.srt:force_style='FontSize=28,PrimaryColour=&HFFFFFF&,OutlineColour=&H000000&,Outline=2'" -c:v libx264 -tune stillimage -c:a aac -b:a 192k -pix_fmt yuv420p -shortest output/video.mp4这条命令做了三件事:把背景图循环成视频流,把字幕烧录到画面上,把音频和视频合并。-shortest参数确保视频长度和音频一致,不会出现黑屏尾巴。整个流程跑下来,一条三分钟的视频大概占用50MB空间,生成时间在两到三分钟之间。
4. 常见问题与排查技巧实录
这套方案我跑了上百条视频,遇到的问题五花八门,这里挑几个高频的说说。
4.1 TTS语音断句不自然的解决思路
Edge TTS的断句逻辑是基于标点符号的,如果脚本里全是逗号,它会读得很平。我的做法是在改写脚本时,故意在长句中间插入句号,把一句话拆成两到三个短句。比如“我们今天要讲的是如何用智能体把公众号文章自动生成视频号短视频”这句话,改成“今天讲一个实用技巧。用智能体把公众号文章,自动生成视频号短视频。”这样TTS读起来就有节奏感了。另外,可以在文本里加<break time="500ms"/>这样的SSML标记,强制停顿,但Edge TTS对SSML的支持不完整,实测只有break标签生效。
4.2 FFmpeg合成报错的排查清单
FFmpeg的报错信息有时候很模糊,我整理了一个速查表:
| 报错信息 | 可能原因 | 解决方法 |
|---|---|---|
No such filter: 'subtitles' | 编译时未启用libass | 换用官网静态编译包 |
Invalid argument | 参数顺序错误 | 检查-i是否在输出文件之前 |
Codec not found | 缺少编码器 | 安装libx264和aac |
Permission denied | 输出文件被占用 | 关闭播放器或编辑器 |
Moov atom not found | 输入文件损坏 | 用ffmpeg -i input.mp4 -c copy output.mp4修复 |
最常见的是subtitles滤镜报错,这是因为有些FFmpeg版本没有编译libass。解决办法很简单:去官网下载ffmpeg-release-full.7z,解压后用里面的ffmpeg.exe,别用essentials版本。
4.3 Whisper识别多音字错误的修正方法
Whisper在中文多音字上的表现时好时坏。我遇到过的典型错误包括:“银行”读成“xing”,“音乐”读成“le”,“长大”读成“chang”。修正方法有两个:一是把脚本里的多音字换成同义词,比如“银行”改成“金融机构”;二是在Whisper的提示词里加一个热词表,但whisper.cpp对提示词的支持有限,所以我一般用第一种方法。另外,如果视频里出现了人名或专业术语,建议在脚本里用拼音标注,TTS读拼音的准确率比读汉字高。
4.4 视频号上传的格式要求与转码建议
视频号对上传视频的格式有要求:MP4容器,H.264编码,分辨率建议1080x1920(竖屏)或1920x1080(横屏),码率不低于2Mbps,音频AAC编码,采样率44.1kHz。我生成的视频默认是横屏1920x1080,如果要做竖屏,把背景图尺寸改成1080x1920,FFmpeg命令里的分辨率参数同步改一下就行。转码命令:
ffmpeg -i output/video.mp4 -c:v libx264 -preset medium -crf 23 -c:a aac -b:a 128k -ar 44100 -vf "scale=1080:1920:force_original_aspect_ratio=decrease,pad=1080:1920:(ow-iw)/2:(oh-ih)/2" output/video_vertical.mp4这条命令会把横屏视频居中放到竖屏画布上,上下留黑边。如果你想要全屏竖屏,那就得重新生成竖版背景图。
5. 智能体调度的工程化实践
前面讲的都是单条视频的生成流程,但如果你要批量处理几十篇文章,手动跑脚本就不现实了。这时候需要一个调度层,也就是我所说的“智能体”。这个调度层不复杂,核心是一个状态机:接收文章链接,判断文章类型,调用对应的改写策略,然后依次执行TTS、Whisper、FFmpeg,最后把成品视频放到输出目录。我用的是Python的asyncio加queue,并发数控制在3,避免同时跑太多任务把CPU吃满。
5.1 任务队列与并发控制
调度器的核心逻辑:
import asyncio from queue import Queue task_queue = Queue() async def worker(worker_id): while not task_queue.empty(): article = task_queue.get() print(f'Worker {worker_id} processing {article["title"]}') await process_article(article) task_queue.task_done() async def main(): articles = load_articles('input/articles.json') for article in articles: task_queue.put(article) workers = [asyncio.create_task(worker(i)) for i in range(3)] await asyncio.gather(*workers) asyncio.run(main())这个调度器的好处是,如果某条视频生成失败,不会影响其他任务。我一般会在process_article里加try-except,把失败的任务记录到日志里,方便后续重试。
5.2 失败重试与日志记录
失败重试的策略是:第一次失败后等30秒重试,第二次失败后等60秒,第三次失败就跳过并记录。日志用Python的logging模块,输出到文件和控制台。关键日志包括:任务开始时间、文章标题、当前步骤、耗时、是否成功。这些日志在排查问题时非常有用,比如我发现某篇文章的TTS总是失败,查日志才发现是文章里有个特殊符号导致Edge TTS报错,把符号删掉就好了。
5.3 批量处理的性能优化
批量处理时,瓶颈通常在Whisper的转写速度上。我的优化方法是:先用Edge TTS生成所有音频,然后集中跑Whisper,这样能减少模型加载的次数。另外,FFmpeg合成也可以并行,但要注意磁盘IO,如果同时写太多大文件,硬盘会成为瓶颈。实测下来,一台普通笔记本(16GB内存,无独显)跑十条三分钟的视频,总耗时大约25分钟,平均每条2.5分钟。如果换成有独显的机器,Whisper用GPU加速,总耗时能压到10分钟以内。
6. 内容质量把控与人工干预点
自动化生成的内容,最大的风险是“看起来像垃圾”。我见过太多用模板批量生成的视频,画面是几张图来回切,配音是机械的AI音,字幕还有错别字,发出去不仅没流量,还会伤账号权重。所以我在流程里设了三个必须人工干预的点。
6.1 脚本改写后的人工审核
大语言模型改写的脚本,我每次都会通读一遍。重点看三件事:开头有没有钩子,逻辑有没有断层,结尾有没有引导。钩子这件事,模型经常写得太泛,比如“今天分享一个技巧”,这种开头没人会停留。我会手动改成“我花了三个月,终于把这件事自动化了”,制造悬念。逻辑断层通常出现在模型删减内容的时候,前后句接不上,读起来很突兀。结尾的引导语,模型喜欢写“点赞关注”,太生硬,我会改成“如果这个方案对你有用,点个赞让我知道”。
6.2 字幕时间轴的微调技巧
Whisper生成的字幕,时间轴有时候会偏。我的经验是:如果偏移在0.3秒以内,不用管,观众感知不到;如果超过0.5秒,就要手动调。调的方法很简单,用文本编辑器打开SRT文件,把时间码整体加或减一个固定值。比如所有时间码都慢了0.5秒,就把00:00:01,000改成00:00:00,500。如果偏移不均匀,那就得逐条调,比较费时间,但这种情况很少见。
6.3 背景音乐与音效的添加建议
纯口播的视频,加一点背景音乐能提升完播率。我一般用FFmpeg的amix滤镜把背景音乐和口播音频混合:
ffmpeg -i audio.mp3 -i bgm.mp3 -filter_complex "[1:a]volume=0.1[bgm];[0:a][bgm]amix=inputs=2:duration=first" output/mixed.mp3volume=0.1是把背景音乐音量降到10%,避免盖住人声。背景音乐的选择上,我推荐用无版权音乐库里的轻音乐,节奏舒缓,不要有歌词。音效方面,转场的时候可以加一个“嗖”的声音,但别加太多,否则显得廉价。
7. 扩展方向与个人经验分享
这套方案目前能稳定处理干货类和资讯类文章,但故事类文章的效果还不太理想。原因是故事需要情绪起伏,而TTS的语调变化有限。我试过用SSML的prosody标签调整语速和音调,但Edge TTS对prosody的支持不稳定,有时候生效有时候不生效。下一步我打算试试用大语言模型给脚本标注情绪标签,然后根据标签切换不同的TTS音色,比如平静的段落用Xiaoxiao,激动的段落用Yunjian。这个思路还在实验阶段,等跑通了再分享。
另外,画面部分目前是纯色背景加文字,比较单调。我试过用FFmpeg的zoompan滤镜给背景图加缓慢缩放效果,看起来会生动一些:
ffmpeg -loop 1 -i background.jpg -filter_complex "zoompan=z='min(zoom+0.001,1.5)':d=125:s=1920x1080" -t 5 output/zoom.mp4这个命令会让背景图在5秒内缓慢放大到1.5倍,适合做视频的开场。但注意d参数是帧数,如果视频是25帧每秒,5秒就是125帧。这个效果对静态图片有效,如果背景是纯色,缩放看不出来,所以建议用有纹理的图片。
最后说一个我踩过的坑:Edge TTS生成的音频,在某些播放器上会有“爆音”,尤其是音量突然升高的地方。解决办法是在FFmpeg合成时加一个loudnorm滤镜做响度归一化:
ffmpeg -i audio.mp3 -af loudnorm=I=-16:TP=-1.5:LRA=11 output/audio_normalized.mp3I=-16是目标响度,TP=-1.5是最大峰值,LRA=11是响度范围。这三个参数是视频号平台的推荐值,加了这个滤镜之后,音频听起来会平稳很多,不会忽大忽小。这个细节在官方文档里不会写,但实际发布时能明显感觉到差别。