
简介一份以AiPy工具为核心的AI短剧创作教程源码包面向希望借助人工智能快速产出短剧的创作者、自媒体运营者及对AI内容生成感兴趣的开发者。资源聚焦从剧本构思到成片输出的完整流程通过提示词设计解决故事主题、镜头调度与风格统一等关键问题无需专业编剧背景也能上手覆盖剧本生成、旁白撰写、分镜头合成与音视频封装等环节。压缩包共3个文件主要包括HTML格式的教程页面、inscode项目配置以及gitignore文件其中HTML页面承载操作指引与提示词示例inscode配置便于云端运行整体仅7KB轻量易读。已有1247人学习下载。借助源码与操作示例读者可掌握利用AI生成剧本大纲、细化分镜头、确保人物一致性并合成音视频的整套方法同时理解AiPy在短剧创作场景中的调用逻辑与实现细节为进一步开发自己的AI内容工具提供参考。1. AI短剧创作教程[源码]先别急着写代码想清楚它到底帮你省了哪笔钱如果你所在团队正被“一周要出 7 集、每集 90 秒”的短剧排期压得喘不过气那这个标题大概率能对上你的痛点。AI短剧创作教程[源码]本质是一套把“剧本、分镜、画面、配音、合成”串成自动化流水线的工程模板而不是某个一键出片的黑盒工具。它解决的是短剧供给量跟不上排期的问题过去一天只能拍一条现在可以把编剧、画分镜、配旁白的活拆给大模型、Stable Diffusion 和 TTS人只做审核与微调。适合短视频机构的产线负责人、独立创作者以及想基于 Python 源码做二次开发的技术同学——这篇文章就是按这个路径讲的。2. 拆解AI短剧创作源码先把产线切成五个能独立跑通的模块2.1 为什么先拆模块再写代码短剧生产是流水线不是单点功能短剧的工业属性和传统短视频不太一样。传统口播视频只需要一个文案模型加一个剪辑脚本而短剧有完整的故事线、人物关系和镜头语言单点 AI 功能解决不了。常见做法是把整条产线切成五个模块剧本生成、分镜提示词、画面生成、配音生成、视频合成。每个模块独立成文件、独立接参数一个环节挂了不影响另外四个。这样拆还有一个现实原因失败成本。如果四个环节揉在一个长脚本里中途任何一个 API 超时、图片生成崩坏整个流程都要重跑token 和 GPU 时间都烧掉了。拆开之后画面崩了只需要重跑画面剧本 JSON 格式不对只需要重跑剧本。我们团队最初把模块揉在一起结果一次跑批要盯着终端盯两个小时后来全部改成模块化才把夜间无人值守的跑批稳定下来。拆完后要定义模块间的数据契约也就是上游输出和下游输入必须对齐的数据结构。最省事的数据契约是剧本模块输出 JSON分镜模块读取 JSON 生成提示词出图模块读提示词存 PNG配音模块读台词存 MP3最后合成模块按文件命名排序做混流。数据契约一旦确定每个模块都能单独调试这也是源码工程最值得先写的部分。2.2 本地Stable Diffusion与LLM API的选型边界选型不能只看名气要看模块对成本和质量的要求。剧本生成适合走大模型 API因为一次生成 60-90 秒的短剧剧本通常几千 token成本低、质量高而且大模型对情绪和钩子的理解明显强于小模型。画面生成则推荐本地跑 Stable Diffusion原因是短剧对人物一致性要求极高你需要给主角训练 LoRA反复抽卡调权重这个互动过程放 API 上跑不仅贵而且延迟不可控。配音模块存在两条路云端 TTS 的效果稳定适合对音色有要求的商业团队开源 TTS 嵌入源码工程更自由可以控制停顿和情绪标签适合批量跑、集中调。我们一般先把配音做成可切换的接口同一份代码先跑开源方案不满意再切云端不把底座焊死。视频合成用 FFmpeg 是最稳的选择因为短剧合成其实就是“图片流音轨字幕背景音乐”的拼接FFmpeg 批处理完全不占用 GPU而且失败重试的成本几乎为零。选型结论可以汇总成一张表模块常见方案成本量级主要风险剧本大模型 APIJSON 输出低单集几分钱格式不稳定需要强约束提示词出图本地 Stable Diffusion LoRA中取决于 GPU 时间人物一致性难控配音开源 TTS / 云端 TTS 切换极低情感表达容易平合成FFmpeg Python 封装几乎为零时间轴对不齐2.3 源码工程的目录设计模块边界决定你失败时先救谁一个能跑起来的 AI 短剧产线源码目录不需要花哨但模块边界要清楚。我一般会这样建ai-short-drama/ ├── pipeline/ │ ├── run_today.py # 日更调度入口串起全部模块 │ ├── gen_script.py # 剧本生成模块 │ ├── gen_scene_prompt.py # 分镜提示词模块 │ ├── gen_frames.py # 画面生成模块 │ ├── gen_tts.py # 配音模块 │ └── ffmpeg_ops.py # 视频合成模块 ├── prompts/ │ ├── script_template.md # 剧本提示词模板 │ └── scene_template.md # 分镜提示词模板 ├── assets/ │ ├── character_lora/ # 人物 LoRA 权重 │ └── voices/ # 配音缓存避免重复调 TTS ├── config.yaml # 模型路径、API Key、分辨率等全局参数 └── output/ ├── scripts/ # 剧本 JSON ├── frames/ # 分镜 PNG ├── audio/ # 配音 MP3 └── videos/ # 成片 MP4这个结构的设计逻辑很直白pipeline/下每个文件对应一个模块文件之间直接通过import调用但数据都落在output/里不传内存对象。好处是任何一个模块跑挂了你只需要删掉对应输出目录重跑其他产物原封不动。assets/voices是容易被忽略的省钱点同一个角色的台词缓存起来第二次跑同一集就不需要再调一次 TTS批量跑 100 集能省下不少时间。config.yaml 是整个工程的地基。模型路径、LoRA 路径、API Key、图片分辨率、TTS 音色、配音语速都要放进去写死在代码里后期就是灾难。代码里只允许读环境变量和这个配置文件保证换机器和换模型时不用改逻辑。3. 剧本生成源码用提示词模板把故事梗概变成可生产的分集JSON3.1 第一段源码LLM调用与JSON输出控制剧本是整个产线的起点如果剧本输出是散文而不是结构化数据后面分镜、配音都接不上。所以第一步就是强制模型输出 JSON。下面是一段可以直接改来用的 Python 代码按 OpenAI 兼容协议调用大模型import os, json from openai import OpenAI client OpenAI( api_keyos.environ[LLM_API_KEY], base_urlos.environ.get(LLM_BASE_URL, https://api.example.com/v1) ) def gen_script(synopsis: str, episode: int 1) - dict: sys_prompt ( 你是一个擅长竖屏短剧的编剧。短剧规则单集60-90秒 包含3-5场戏每场戏必有推进剧情的台词结尾必须留反转或悬念。 只输出JSON不要输出任何解释。 ) user_prompt f请基于以下故事梗概生成第{episode}集剧本输出JSON格式 {{ episode: {episode}, title: 一集标题, scenes: [ {{ scene_id: 1, location: 地点, action: 动作描述, dialog: [{{char: 角色名, line: 台词}}], emotion: 全场景情绪基调如愤怒、压抑、慌张, camera: 景别/运镜如近景/手持 }} ], hook: 结尾钩子台词 }} 故事梗概{synopsis} resp client.chat.completions.create( modelos.environ.get(LLM_MODEL, gpt-4o-mini), messages[ {role: system, content: sys_prompt}, {role: user, content: user_prompt} ], temperature0.7, response_format{type: json_object} ) return json.loads(resp.choices[0].message.content) if __name__ __main__: with open(synopsis.txt, encodingutf-8) as f: synopsis f.read() script gen_script(synopsis, episode1) with open(output/scripts/script_ep01.json, w, encodingutf-8) as f: json.dump(script, f, ensure_asciiFalse, indent2)这段代码里有三个关键点。第一response_format{type: json_object}是硬约束没有它模型会在 JSON 前后追加“好的这是你要的剧本”这类废话破坏解析。第二temperature0.7是试出来的经验值太低会让反转套路高度雷同太高会跑题0.7 在可控与惊喜之间比较平衡。第三emotion和camera字段不是给读者看的是给后面配音和出图模块用的一定不要省。代码跑通以后我建议你顺手把每次生成的 JSON 都存在output/scripts/目录里文件名带集数。这样做有两个好处一是素材可追溯调试出图时能快速定位是哪一集的哪一场戏二是后面跑批量时不会因为内存态丢失导致重复生成白白烧 token。3.2 第二段源码把剧本JSON转成分镜提示词剧本 JSON 不是给人念的是给模型看的。出图模块需要的是 Stable Diffusion 能理解的自然语言提示词这一步需要把场景字段翻译成画面语言import json def scene_to_prompt(scene: dict, char_style: str) - str: return ( f{char_style}, {scene[location]}, {scene[action]}, f{scene[emotion]} mood, {scene[camera]}, fvertical composition 9:16, cinematic lighting, fhigh detail, best quality ) def build_prompts(script_path: str, char_style: str) - list: with open(script_path, encodingutf-8) as f: script json.load(f) prompts [] for scene in script[scenes]: prompts.append({ scene_id: scene[scene_id], prompt: scene_to_prompt(scene, char_style), }) return prompts if __name__ __main__: scenes build_prompts(output/scripts/script_ep01.json, main_char: female, age 25, black hair, red coat) print(json.dumps(scenes[:2], ensure_asciiFalse, indent2))这段代码的逻辑是把剧本里抽象的“地点/动作/情绪”翻译成 Stable Diffusion 能直接消费的视觉描述。其中char_style是人物基础描述在实际项目中会被替换成 LoRA 的触发词比如liya character。这里有个容易踩的坑不要把人物描述写得太固定比如“黑色头发、红色外套”否则换场景换衣服时 LoRA 会强行把外套画出来。更好的做法是只写固定的面部特征服饰交给action和location字段去决定。3.3 参数与边界token、temperature、重启会话序号错乱是常见情况特别是超过 5 场戏之后。解决方式是不要把整个分集一次性生成而是先生成场景列表再逐场生成细节或者像本节代码一样在 user prompt 里把场景数量写死并注明“scene_id 必须连续”。关于 token一次生成 3-5 场戏大约消耗 2000-4000 token成本上完全可控。但要注意大模型的输出长度不是无限的如果你在提示词里给了它非常长的故事梗概它很可能只写到一半就截断。常见做法是把梗概压缩成 200-300 字以内的摘要再交给剧本模型。另一个坑是会话污染如果你的脚本在测试阶段反复往同一个对话里追加消息模型会越聊越偏最后生成的台词风格会和第一集差很远。每集生成都开新会话别复用上下文。这一点在你接源码工程的时候特别容易忽略因为开发调试会反复跑同一段代码我建议在代码里显式每次创建新 client 调用而不是把client对象保存在一个长驻进程里反复用。4. 画面与配音源码人物一致性LoRA与TTS情绪标注的调参要点4.1 批量出图Stable Diffusion的diffusers调用与关键参数画面模块是 AI 短剧产线里最重的一环核心矛盾是质量与一致性。单张图好看不难难的是女主角每一帧都像同一个人。解决这个问题的主流做法是训练一个专属 LoRA然后在出图代码里加载它。下面是一段基于 diffusers 的批量出图代码from diffusers import StableDiffusionXLPipeline import torch, json, os def load_pipe(lora_path: str): pipe StableDiffusionXLPipeline.from_pretrained( os.environ.get(SD_BASE_MODEL, models/sdxl_base), torch_dtypetorch.float16, ).to(cuda) if lora_path: pipe.load_lora_weights(lora_path) return pipe def generate_frames(prompts: list, lora_path: str): pipe load_pipe(lora_path) os.makedirs(output/frames, exist_okTrue) for item in prompts: img pipe( promptitem[prompt], negative_promptblurry, deformed face, low quality, watermark, text, width540, height960, num_inference_steps25, guidance_scale7.0, seed42, ).images[0] img.save(foutput/frames/ep01_sc{item[scene_id]:02d}.png) if __name__ __main__: with open(prompts.json, encodingutf-8) as f: prompts json.load(f) generate_frames(prompts, assets/character_lora/liya_v3.safetensors)这里几个参数值得展开。width540, height960是竖屏短剧的标准尺寸如果你盲目用 512x512 再裁剪构图会崩。num_inference_steps25是质量和速度的折中点SDXL 在 25 步时细节已经足够再高收益不明显。guidance_scale7.0不能乱动太低画面游离于提示词之外太高会让边缘锐化得很难看。seed42固定种子保证可复现这是源码工程调试的基础不固定种子的话你根本没法判断改动提示词的效果。实际跑的时候你会发现一个现实问题按场景逐张生成图相邻两张图的脸可能还是对不上因为扩散模型每次生成都是一次独立采样。我们后来改用“关键帧生成 视频运镜”的方式解决只生成每个镜头的首帧和尾帧中间的运动交给 FFmpeg 的缩放和位移动画这样既省钱又回避了逐帧生成带来的脸崩问题。4.2 配音源码用情绪标签解决“AI朗读腔”配音是最容易被新手高估的模块。很多人以为直接把台词丢给 TTS 就能用结果整集听起来像新闻联播情绪完全不在线。短剧配音需要的是“白噪音化”的压抑感或爆发感所以台词必须带情绪标注。Edge TTS 是入门最快实现方案但它的情绪控制能力取决于文本里的语气词和停顿标记做法如下import edge_tts import asyncio import json VOICE_MAP { 男主: zh-CN-YunjianNeural, 女主: zh-CN-XiaoxiaoNeural, 反派: zh-CN-YunxiNeural } async def generate_line_audio(scene_id: int, line: dict, output_dir: str): text f{line[line]} communicate edge_tts.Communicate( text, VOICE_MAP.get(line[char], zh-CN-XiaoxiaoNeural), rate-10%, pitch2Hz ) path f{output_dir}/ep01_sc{scene_id:02d}_{line[char]}.mp3 await communicate.save(path) return path def generate_all_audio(script_path: str, output_dir: str): with open(script_path, encodingutf-8) as f: script json.load(f) for scene in script[scenes]: for line in scene[dialog]: asyncio.run(generate_line_audio(scene[scene_id], line, output_dir)) if __name__ __main__: generate_all_audio(output/scripts/script_ep01.json, output/audio)这里真正起作用的是rate-10%和pitch2Hz这两个参数。短剧对白的语速不能太快太快会显得轻浮音调也不能太尖否则情绪紧张时听感会刺耳。情绪爆发戏的处理方式是让台词文本里自带逗号和感叹号但更可控的做法是先用 LLM 给每句台词做一次情绪改写比如把“你敢动他试试”改成“你敢动他、试、试低声、停顿”再喂给 TTS。4.3 混剪前的时间轴约定画面和音频都齐了之后最难的不是调用 FFmpeg而是对齐时间轴。常见做法是先算音频总时长再按场景拆分视频片段并保持每段视频时长略长于对应配音长度。这里有一个约定每个场景的图像文件名按ep01_sc01.png命名音频按ep01_sc01_女主.mp3命名合成脚本就按场景 ID 对齐不会错位。如果你在命名上偷懒到了批量跑 30 集的时候一定会翻车。5. AI短剧创作常见问题与避坑最典型的5个翻车点5.1 脸上每个镜头都换人——LoRA权重与种子管理不到位现象同一集里女主角的脸每换一个镜头就像换了一个演员。原因只靠文字描述人物外貌没有训练独立 LoRA也没有固定 seedStable Diffusion 每次采样都有随机性。解决训练一个只含该角色的 LoRA权重建议控制在 0.7-0.9并在同一集的生成中固定 seed如果经济允许对关键画面做人脸重绘用图生图的方式把崩坏的脸拉回来。5.2 配音朗读腔浓——emotion字段没进TTS现象台词内容没问题但所有情绪爆发戏听上去都很平。原因剧本模块生成的emotion字段只被写进了 JSON台词模块根本没读取它直接拿原始台词裸合成。解决在 TTS 代码里把emotion转成语气修饰词比如angry变成“压低声音、语速加快”再拼进台词文本或者改用带情感控制的 TTS 模型。我们最后是让 LLM 把每句台词先做情绪改写再走 TTS整条链路才稳定下来。5.3 单集时长失控——台词字数与镜头数没在剧本阶段掐死现象剧本生成的时长是 90 秒实际合成出来 2 分半运营根本排不进去。原因大模型对“时长”没有物理感知它写的台词数量往往超标3 场戏可能拉了 5 分钟的细节。解决在剧本提示词里硬性规定“每场戏台词总字数不超过 120 字”“每场戏动作描述不超过 40 字”合成前加一道自动校验脚本统计 JSON 里的总台词字数超过阈值直接重生成。别指望模型自己守规矩靠校验脚本兜底。5.4 音画错位——时间轴基准不统一现象画面切到下一个镜头了上一句台词还在响或者反过来。原因配音模块生成的音频时长不一致而画面模块按固定秒数切片段两边没有对齐。解决合成前统一计算每个场景的音频时长再按“音频时长 0.5 秒余量”生成对应视频片段。这里有个小技巧用 FFmpeg 给视频片段补帧或尾部静帧而不是压缩音频去迁就画面压缩音频会直接破坏语气节奏。5.5 成片过不了审——重复画面指纹与缺少生成日志现象连更 10 集后被平台提示“重复内容”或“疑似搬运”。原因同一 LoRA、同一 seed、同一提示词模板生成的画面高度相似加上逐帧静态画面本身存在固定的指纹特征容易被识别为批量产出的同质内容。解决不要让连续几集共用同一固定 seed对运镜参数做随机化处理例如缩放起点、平移方向同一套 LoRA 在连续集数之间不要复用太频繁。另外强烈建议从第一集开始就把生成参数写进日志文件包括 seed、提示词、LoRA 权重。这样万一被误判你还有完整的参数链能做解释而不是空口无凭。6. 进阶把多AI协作调度器跑成无人值守并用三集样片验证6.1 调度器如何串联剧本、出图、配音、合成当五个模块都单独跑通后下一步是把它们包进一个调度入口。这个阶段的核心诉求是“失败重试、断点续跑”而不是简单的按顺序执行。每个子模块都可以包成一个 AI Agent封装成统一的接口输入目录 → 输出目录 → 成功/失败标志。调度器只认输出目录里有没有产物文件不依赖代码里的返回值。set -e python pipeline/gen_script.py --episode 1 python pipeline/gen_scene_prompt.py --script output/scripts/script_ep01.json python pipeline/gen_frames.py --prompts output/prompts_ep01.json python pipeline/gen_tts.py --script output/scripts/script_ep01.json python pipeline/ffmpeg_ops.py --sync --pad 0.5这行命令串起了整条产线但它的缺点是任何一个环节挂了后续都不会执行。实际源码里我建议给每个gen_*.py加上--resume参数启动时先检查输出目录如果目标文件已存在且参数没变就跳过这一环。这样夜间跑批时某个 API 超时只影响当下这一步重启后能接着跑完而不是从头再来。各模块之间的职责可以用一张表理清也方便你检查 Agent 的输入输出是不是闭环Agent输入输出失败重试策略script_agent故事梗概分集 JSON温度调低重试上限 2 次scene_agent分集 JSON分镜提示词 JSON不重试直接人工改frame_agent提示词 JSONPNG 序列换 seed 重试上限 3 次tts_agent台词 JSONMP3 序列换语音重试 1 次compose_agentPNGMP3成片 MP4检查时长差异后重试6.2 三集样片的验收清单把调度器跑起来以后不要急着连更 50 集先做三集样片的人工验收。验收项不需要复杂就够第一随机抽三帧画面对比女主角的脸确认 LoRA 在同一集内是稳定的第二选一段情绪爆发戏闭眼听台词确认没有播音腔第三打开成片的时间轴确认音画不同步的时间点不超过 0.3 秒。如果三集样片这三项都过就可以上量如果某一项翻车优先在那个模块调参数不要动整条流水线。我自己的习惯是每次批量跑完后把 seed、LoRA 权重和台词字数做成一张小表核对一遍再上线。这套流程里真正贵的不是 GPU 也不是 API而是出图参数与 LoRA 权重之间那点“说不清的手感”。把参数存成日志是给自己留后悔药毕竟黑匣子越少产线才越可控。希望帮到你。本文还有配套的精品资源点击获取