拆解MoneyPrinter四段流水线:Ollama写稿、TikTok TTS配音、Pexels素材、MoviePy合成如何协作 拆解MoneyPrinter四段流水线Ollama写稿、TikTok TTS配音、Pexels素材、MoviePy合成如何协作【免费下载链接】MoneyPrinterTurbo利用 AI 大模型和自动化工作流根据主题或关键词一键生成高清短视频。Generate HD short videos from a topic or keyword with an automated AI workflow.项目地址: https://gitcode.com/GitHub_Trending/mo/MoneyPrinterTurbo从 2024 年初开始在中文开发者社区持续刷屏的 MoneyPrinterTurbo只凭一个主题词就能在几分钟内产出一条 1080x1920 的高清竖屏短视频。社区里流传最多的描述是Ollama 写稿、TikTok TTS 配音、Pexels 抓素材、MoviePy 合成。但四段流水线究竟是四条独立脚本的简单串联还是一套有明确职责边界、有数据契约、有容错机制的工程架构带着这个问题去读一遍仓库源码会发现答案比营销话术扎实得多——真正的枢纽不是大模型而是一段音频的时长。一条以音频时长为纽带的流水线整条流水线的编排逻辑集中在 app/services/task.py 的start()方法中。它按注释明确拆成了六步生成脚本、生成搜索词、生成音频、生成字幕、获取素材、合成成片。每完成一步就调用sm.state.update_task()推进一次进度百分比把状态从 5 推到 100。阶段服务模块产物下游消费者1. 脚本app/services/llm.py纯文本旁白配音、字幕、搜索词2. 搜索词app/services/llm.py5 个英文关键词素材检索3. 音频app/services/voice.pyaudio.mp3 词边界时间戳字幕、时长基准4. 字幕app/services/subtitle.py / voice.pysubtitle.srt画面叠加5. 素材app/services/material.py本地缓存视频列表画面拼接6. 合成app/services/video.pycombined-.mp4 → final-.mp4成品关键的设计点在第 3 步之后generate_audio()用math.ceil(voice.get_audio_duration(sub_maker))算出音频秒数这个值随后决定了素材下载的目标时长audio_duration * params.video_count和画面拼接的填充目标。也就是说旁白文本是唯一的内容源头音频时长是唯一的时间基准素材与画面全部向它对齐——这避免了画面比配音长或配音放不完这两类新手工具最常见的翻车。Web 界面只暴露了最小操作面输入主题、选语言和画幅剩下的交给流水线Ollama 写稿两段 Prompt 输出两种契约脚本生成在 app/services/llm.py 中实现它不是一个调一次模型就完事的步骤而是两次独立调用、两份不同的输出契约。第一次调用generate_script()Prompt 以系统化的 Role/Goals/Constrains 结构约束模型不得输出任何 Markdown 和标题、禁止欢迎来到本期视频式开场白、禁止出现旁白解说等提示词、响应语言必须与视频主题一致。拿到响应后format_response()还会兜底清洗一遍去掉*、#用正则剥离方括号和圆括号注释再按\n\n切段。这些清洗规则并非洁癖而是因为脚本要直接进 TTS 朗读和字幕匹配任何 Markdown 残留都会变成旁白里的杂音。第二次调用generate_terms()面向素材检索要求模型只返回一个 JSON 数组、每个词 1-3 个词、必须包含视频主主题、强制英文you must use English for generating video search terms然后用json.loads解析失败时用正则r\[.*]兜底提取。两个模型调用之间还有 5 次重试循环_max_retries 5单次失败不会中断任务。模型接入层_generate_response()是一张巨大的 provider 路由表openai、ollama、moonshot、oneapi、azure、gemini、qwen、deepseek、ernie、cloudflare、g4f 都可通过 config.example.toml 一键切换。其中 Ollama 的配置非常轻llm_providerollama ollama_base_url # 默认为 http://localhost:11434/v1 ollama_model_name # 例如 llama3代码里对应分支只有三行api_key ollama注释写明any string works but you are required to have one、base_url缺省时落到http://localhost:11434/v1然后走标准 OpenAI SDK。这解释了为什么社区教程都说本地部署零 API 成本——Ollama 提供的 OpenAI 兼容端点让整个 provider 体系可以复用同一套客户端代码。Pexels 素材分辨率精确匹配 内容寻址缓存素材检索在 app/services/material.py。search_videos_pexels()做了一件很多AI 视频工具不做的事按目标分辨率精确过滤而不是能看就行。w int(video[width]); h int(video[height]) if w video_width and h video_height: item.provider pexels item.url video[link]VideoAspect枚举把 9:16 映射为1080x1920请求参数里的orientation也按画幅传入保证竖屏任务不会搜出横屏素材。API Key 支持多把配置get_api_key()用requested_count % len(api_keys)轮询分发规避单 Key 限流——config.example.toml里明确注释了可以使用多个 Key 避免限流。download_videos()的策略也很有工程味道逐词搜索→按 URL 去重→random模式下random.shuffle打乱→顺序下载一旦累计时长超过音频时长立即停止。下载层面save_video()用md5(url_without_query)作为缓存文件名已存在且非空就直接复用video_id fvid-{url_hash} if os.path.exists(video_path) and os.path.getsize(video_path) 0: logger.info(fvideo already exists: {video_path}) return video_path这是一套典型的内容寻址缓存同一批搜索词反复使用比如做系列化内容时网络流量和 API 配额只会产生一次。文件下载后还会用 MoviePy 的VideoFileClip校验时长和 fps无效文件会被丢弃避免脏数据进入合成阶段。配音edge-tts 与词级时间戳而非TikTok TTS这是全仓库最值得澄清的一个事实社区文章普遍把配音称为TikTok TTS但 MoneyPrinterTurbo 重构后的 app/services/voice.py 实际使用的是微软 Edge 的edge-tts协议实现azure_tts_v1并可选升级到 Azure Speech SDK 的azure_tts_v2。原版 MoneyPrinter 的 tiktokvoice.py 在这一版中并未保留——TikTok TTS的称呼更多是沿袭旧版叙事。azure_tts_v1()的写法值得留意它把音频流与词边界时间戳同步收集communicate edge_tts.Communicate(text, voice_name, raterate_str) sub_maker edge_tts.SubMaker() async for chunk in communicate.stream(): if chunk[type] audio: file.write(chunk[data]) elif chunk[type] WordBoundary: sub_maker.create_sub((chunk[offset], chunk[duration]), chunk[text])这一步同时解决了两件事音频落盘 每个词的时间偏移被记录进SubMaker。后者被两个下游依赖——get_audio_duration()取sub_maker.offset[-1][1] / 10000000作为音频时长基准create_subtitle()则用这些词边界逐词拼装、按脚本的标点分词逐行匹配产出对齐到毫秒的 SRT。TTS 本身带 3 次重试失败时task.py会给出检查语音语言与脚本语言是否匹配 / 检查网络的排障提示。声音清单在 docs/voice-list.txt 中完整列出内置 100 个 Azure 神经语音界面传入的形如zh-CN-XiaoyiNeural-Female的名字经parse_voice_name()去掉性别后缀后即得到真实 voice name。MoviePy 合成时长驱动的裁剪、缩放与字幕叠加渲染是 app/services/video.py 的主场分两段完成。combine_videos()先把每条素材按max_clip_duration默认 5 秒切段random模式下全部打乱然后进入一个以音频时长为终止条件的循环不断把片段填进去直到video_duration audio_duration不足的部分用subclipped精确补齐。画幅不一致的素材不会被暴力拉伸而是先等比缩放再用黑色ColorClip垫底、素材居中合成——这是竖屏工具处理横屏素材的标准信箱/留黑方案。转场效果FadeIn/FadeOut/SlideIn/SlideOutshuffle 模式随机选择在 app/services/utils/video_effects.py 里用 MoviePy 的vfx封装一行一个函数。generate_video()做最后润色读取 SRT 用SubtitlesClip解析每个字幕条目经wrap_text()按video_width * 0.9换行后生成TextClip位置支持 bottom/top/center/custom 四档BGM 从resource/songs随机取AudioFadeOut(3)淡出 AudioLoop循环到视频长度再与旁白CompositeAudioClip混音语音与 BGM 音量分别由voice_volume、bgm_volume控制。所有中间文件都写在任务目录下最终输出final-*.mp4。字幕路径值得一提默认subtitle_provider edge走上述词边界方案快、无配置要求切到whisper则用 faster-whisper 的 large-v3 模型转写app/services/subtitle.py并配了一个correct()校正器——用 Levenshtein 相似度把识别文本与原始脚本逐行对齐、合并误切分相似度低于 0.8 的行也强行以脚本为准。edge 生成失败还会自动降级到 whispersubtitle_fallback容错链是显式写出来的。这套架构解决了批量生产的哪些工程问题把四段流水线串起来的编排层才是这个项目真正工程化的部分集中在三个文件里任务可分段、可中断。start()的stop_at参数允许任务停在 script / terms / audio / subtitle / materials / video 任意一步并返回中间产物。对应地app/controllers/v1/video.py 对外暴露了/videos、/subtitle、/audio三个独立端点——用户可以先只生成文案并反复修改满意后再继续配音和成片而不是每次改动都重跑全流程。这对脚本是唯一内容源头的架构是自然的收尾。并发有界、队列可插拔。app/controllers/manager/base_manager.py 的TaskManager用线程池 队列实现max_concurrent_tasks默认 5的有界并发任务超过上限时入队等待。内存队列InMemoryTaskManager适合单机Redis 队列app/controllers/manager/redis_manager.py把函数名序列化进队列、出队时经FUNC_MAP还原可以跨进程调度。任务状态则经 app/services/state.py 抽象成 MemoryState / RedisState 两个实现开启enable_redis即可把进度与产物路径共享给多个查询端。API 文档页把这些端点完整暴露出来一个任务可以产出一组视频。video_count 1时generate_final_videos()会循环生成多个成片且强制把拼接模式切到random——同一段脚本、同一批素材靠随机打乱和转场随机产生多个版本让创作者挑最满意的一条。这正是社区案例里一次批量生成多个备选的产能来源。不确定交给模型确定性交给代码。LLM 输出有 5 次重试 正则兜底TTS 有 3 次重试字幕 edge→whisper 有降级链素材下载有分辨率过滤 内容寻址缓存 时长校验多 Key 轮询对抗限流。整条链路的失败处理都不是报错退出而是能救则救、能缓存则缓存、能降级则降级。回看这四段流水线脚本与搜索词是文本契约音频时长是时间契约素材缓存是内容契约MoviePy 是渲染终结者。对想自建内容流水线的团队而言可复制的不是某个 Prompt 或某段代码而是这套模型产出不确定内容、管道只消费结构化产物的架构思想——它让从主题到成片从一段魔法变成了可调试、可中断、可并发的工程流程。【免费下载链接】MoneyPrinterTurbo利用 AI 大模型和自动化工作流根据主题或关键词一键生成高清短视频。Generate HD short videos from a topic or keyword with an automated AI workflow.项目地址: https://gitcode.com/GitHub_Trending/mo/MoneyPrinterTurbo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考