前言这是本人完成的第一个项目项目是当下比较火热的AI漫剧制作因为这个项目是借助Codex完成所以可能有一些讲解失误的地方1. 先定边界MVP 要打通流程不要先造一艘航母项目当前的主流程是创建项目 - 记录创意 / 生成小说 - 生成并编辑分镜 - 为分镜生成插画和视频片段 - 生成台词配音 - 在时间轴中排列素材 - FFmpeg 合成并下载 MP4一开始我也想过加消息队列、Redis、对象存储、异步 Worker、Kubernetes 等组件。冷静下来后发现当前阶段最大的风险不是并发不够而是创作链条没有闭环。因此 MVP 做了几个取舍后端先用 FastAPI 同步提供 API生成任务失败后把原因返回到页面。数据先落 MySQL本地生成的媒体文件挂在/media下。视频合成直接调用 FFmpeg优先保证导出的文件可以播放。外部 AI 服务通过配置替换业务代码不把某一家模型供应商写死。这让系统还不算「大」但已经能用。对于个人项目或课程项目来说这种顺序比一开始堆中间件更合适。2. 技术架构前端负责工作台后端负责把事情落地在这里我展示一些前端部分页面因为是使用网站进行UI设计的所以展示起来有点差强人意前端使用 Vue 3、TypeScript、Vite、Vue Router、Pinia 和 Tailwind CSS后端使用 FastAPI、SQLAlchemy 和 MySQL。部署时用 Docker Compose 将前端、后端和数据库分开运行。前端路由按创作顺序拆分为工作区、小说、角色、分镜、漫画、视频、配音、剪辑和设置等页面。这样做的好处是用户不用在一个超长页面里找入口下一步该做什么比较直观。后端统一返回下面的结构前端只需要在一处处理业务错误和网络错误{ code: 0, message: success, data: {} }这个约定看起来很小但后面接模型接口时很省心。外部接口可能超时、返回格式不对、任务排队页面不应该把这些异常直接展示成一串难懂的报错。3. 小说和分镜重点不是「生成一次」而是能继续改AI 创作的一个现实问题是第一次生成通常只是可编辑的初稿。于是项目没有只存一段最终文本而是把创意、小说和章节做成版本化数据。Project保存项目基本信息。IdeaVersion保存题材、标签、梗概和生成参数。NovelVersion与Chapter保存小说版本及可单独修改的章节。分镜从小说或当前上下文生成生成后仍可在页面内调整镜头内容。这样做的目的不是为了把表设计得复杂而是防止点击一次「重新生成」就把上一个版本覆盖掉。对创作类产品来说可回看、可修改往往比一次性生成更重要。文本模型接入采用 OpenAI 兼容的 Chat Completions 形式。为了处理模型偶尔把 JSON 放进 Markdown 代码块、或者在 JSON 前后加说明文字的情况后端会先清理常见包装再解析内容。核心思路类似下面这样try: result json.loads(cleaned_text) except json.JSONDecodeError: start cleaned_text.find({) end cleaned_text.rfind(}) result json.loads(cleaned_text[start:end 1])当然这不能替代数据校验。模型输出最终仍应经过 Schema 校验不能直接原样写数据库。这个项目目前已经对异常、空结果和解析失败进行提示后续还会补充更严格的 Pydantic 结构校验。4. 模型接口配置把「换模型」从改代码变成填表单项目开发中最常遇到的需求之一就是「我想把图片模型换成另一个」。如果每换一次模型都要改 Python 文件、重启服务、再重新打包对非后端用户并不友好。因此在剪辑页面附近增加了独立的“API 接口设置”入口目前可管理四类模块模块可配置内容用途小说 / 分镜Base URL、模型名、API Key创意扩写、小说和分镜生成插画生成Base URL、模型名、API Key角色设定、分镜画面与画面变体视频生成Base URL、模型名、API Key图生视频与任务查询配音 / TTS模型名、API Key、默认音色台词语音合成设置页读取时不会返回完整密钥只会返回是否已配置和掩码预览。保存时会写入后端.env同时更新当前 FastAPI 进程内的配置因此本地开发时不需要每次保存后再重启服务。这里有一个很容易踩的坑Base URL 输入框只能填地址本身。正确示例https://api.example.com/v1错误示例IMAGE_BASE_URLhttps://api.example.com/v1后者会被当成 URL 使用Python 发请求时可能出现unknown url type: image_base_urlhttps。项目里对这种「把环境变量整行粘进去」的情况做了清洗不过从使用习惯上说填纯地址永远最稳。图片生成层也针对不同兼容程度做了适配通用 OpenAI 兼容格式、Agnes 接口和 SiliconFlow 图片接口使用的字段并不完全一样。代码会根据接口地址决定请求体例如 SiliconFlow 使用image_size、batch_size等字段并根据横竖屏给出候选尺寸当远端连接失败时页面会显示本地占位预览和实际失败原因避免用户误以为真的生成成功。要注意当前的.env写入方式适合单机或开发环境。正式多用户环境不应把用户密钥直接写在应用目录里应该改为加密存储、密钥托管服务或由服务端统一管理平台账号。5. 剪辑和导出不能只显示预览必须拿到 MP4 文件剪辑器是这次最想做完整的部分。用户在时间轴里排好视频片段和配音后点击“导出成片”后端会执行以下过程按时间轴起始时间排序视频片段。下载或读取本地媒体并限制远程单文件最大 260 MB。对每个片段裁剪、缩放、补边统一分辨率、帧率和像素格式。生成黑色视频填补片段之间的空档再拼接视频轨。将音频按时间轴延迟、截断和混音。用 H.264 编码视频、AAC 编码音频输出.mp4。合成接口返回的是媒体地址例如{ status: composed, provider: ffmpeg, output_video_url: /media/editor/GleamDream-1785468063.mp4 }前端拿到地址后提供“下载 MP4”和“新窗口预览”两个操作。这样用户点击导出后得到的是可以保存、可以发给别人、可以上传到平台的视频文件而不只是浏览器临时播放。FFmpeg 部分还有两个细节值得记录对所有片段统一输出yuv420p兼容性比直接拼接原始格式好很多。文件输出时加faststart把 MP4 的索引移动到文件前部网页和手机端打开时不必等整个文件下载完才开始播放。6. 本地启动做了一个不改项目代码的 Windows 启动器对于不熟悉命令行的同学每次手动打开两个终端、启动 Python 和 Vite确实有点折磨。项目额外提供了一个 C# 编写的GleamDreamLauncher.exe它不替代 Docker也不修改前后端逻辑只解决本地开发启动这一件事。启动器会自动寻找包含backend和front-end的项目根目录。检查 8000 和 5173 端口已有服务时直接复用。启动 FastAPI 与 Vite并将日志写入.launcher-logs。等待两个端口可访问后自动打开http://127.0.0.1:5173。关闭启动器时只结束它自己拉起的进程不会误杀原本就在运行的服务。这个工具本身很小但对演示和日常测试很有用。需要注意首次使用前仍要安装 Python 依赖、创建backend/.venv并在front-end目录执行过npm install。启动器不是魔法它只是把重复动作收起来了。7. 部署给小服务器留一点呼吸空间生产部署使用 Docker Compose分为frontend、backend和mysql三个服务。前端 Nginx 对外暴露 80 端口后端和数据库只在容器网络内通信前端把/api和/media反向代理到 FastAPI。这样做的直接好处是生产环境不会出现“前端还在请求localhost:8000”的问题。浏览器里的localhost永远指向访问者自己的电脑而/api由同域 Nginx 转发才是适合部署的路径。考虑到目标机器是 2 核 2 GB 左右的配置Compose 文件还对 MySQL、后端和前端设置了内存、CPU、PID 和日志滚动上限。它不是高并发方案但可以避免一次视频合成把整台小服务器拖得太难受。至于可以供大家阅读的公网网址我思来想去还是不展示了因为我购买的手机短信验证包已经失效了导致无法注册所以进入不了网站里面虽然可以通过开发者模式直接进入里面。8. 目前还没有做完的部分一篇开发记录只写“我实现了什么”是不够的也要把边界写清楚。GleamDream 当前仍有这些待完善项长耗时的图片、视频、合成任务目前还没有队列、进度推送和自动重试。媒体文件目前主要存本地卷后续应迁移到对象存储并接 CDN。AI 输出的结构化校验、内容安全和额度控制还需要继续补齐。认证已经有密码散列、Token 和短信登录流程但生产环境仍应加强权限校验、Token 轮换和安全审计。这些没有被包装成“已实现功能”因为它们确实还在路上。MVP 的价值不是假装完善而是先证明创作流程可以跑通。结语做这个项目后我最大的感受是AI 应用最难的部分往往不是调一个模型接口而是把模型输出变成一个用户可以编辑、保存、导出和复用的流程。从版本管理、模型配置、失败提示到音视频合成和部署这些看起来不那么“AI”的细节反而决定了工具有没有实际使用价值。GleamDream 现在还只是一个持续迭代的 MVP但它已经从“几个生成按钮”走到了“可以导出成片”的工作台。