# txt-2-video_opencode_20261026 **Repository Path**: burns/txt-2-video_opencode_20261026 ## Basic Information - **Project Name**: txt-2-video_opencode_20261026 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-27 - **Last Updated**: 2026-10-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一句成片 · 多智能体 AI 视频生成工坊 > 输入一句中文描述 → 编剧智能体拆解分镜 → 画师智能体生成画面 → 配音智能体合成旁白 → 剪辑智能体输出 MP4。 > 全流程使用**免费、免 API Key** 的工具,前端 Vue 3,后端 Spring Boot (JDK 17) + MySQL。 ![技术栈](https://img.shields.io/badge/Vue-3-42b883) ![技术栈](https://img.shields.io/badge/Spring%20Boot-3.3-6db33f) ![技术栈](https://img.shields.io/badge/MySQL-8-4479a1) ![AI](https://img.shields.io/badge/AI-Pollinations%20%7C%20edge--tts%20%7C%20FFmpeg-8b5cf6) --- ## 1. 它能做什么 在浏览器里输入一句中文,例如: > 雨夜的东京街头,一只橘猫跳过积水,霓虹倒影在它的眼睛里闪烁。用电影感的镜头,讲一个关于孤独与重逢的故事。 点击「开始生成视频」后,系统会: 1. **编剧智能体**调用免费 LLM,把一句话扩写成 3~6 个镜头的分镜脚本(片名、风格、每镜旁白、画面提示词); 2. **画师智能体**调用免费文生图(Pollinations / Flux),为每个镜头生成电影感画面; 3. **配音智能体**用 edge-tts 的微软神经网络语音合成中文旁白; 4. **剪辑智能体**用 FFmpeg 做缓慢推拉运镜、淡入淡出、烧录字幕、混入音轨、拼接成片; 5. **发布**把 MP4 写入静态目录,前端实时显示进度,并提供**在线播放 + 下载链接**。 生成的视频示例参数:1280×720 / 720×1280 / 1024×1024,H.264 + AAC,约 15~50 秒。 --- ## 2. 核心特性 - **多智能体流水线**:编剧 → 画师 → 配音 → 剪辑 → 发布,每一步的状态、耗时、日志都持久化到 MySQL,前端时间线实时可见。 - **全免费**:Pollinations 生图/文本、edge-tts 语音、FFmpeg 合成,均无需注册或 API Key。 - **强容错**: - LLM 失败 → 自动重试 + 备用 GET 接口 → 仍失败则本地规则分镜; - 免费生图限流(约 45 秒/张)→ 自动解析 `Retry after` 并等待重试 → 仍失败则程序化电影感底图; - 本地规则分镜产生中文画面描述 → 内置中英视觉词表转成英文关键词,避免上游对中文提示词报错; - TTS 不可用 → Google TTS 备用 → 仍失败则静音音轨,视频照样能出。 - **智能体可替换**:任何 OpenAI 兼容接口(Ollama、LM Studio、硅基流动等)都能替换 LLM;生图服务地址也可配置成自建 ComfyUI/SD 网关。 - **任务异步化**:提交立即返回任务 ID,独立线程池执行,前端轮询进度,不会阻塞 HTTP 请求。 - **中文优先**:中文提示词、中文旁白、中文字幕、中文界面。 - **开箱即用**:提供 MySQL Docker Compose、FFmpeg 一键下载脚本、edge-tts 一键安装脚本,以及无 MySQL 的 H2 快速体验模式。 --- ## 3. 技术架构 ```mermaid flowchart LR U["Vue 3 前端
:5173"] -->|"POST /api/videos"| C["Spring Boot
:8080"] C --> DB[("MySQL 8
video_task")] C -.->|"异步线程池"| P["智能体编排器
VideoPipeline"] P --> A1["编剧智能体
Pollinations LLM"] A1 --> A2["画师智能体
Pollinations Flux"] A2 --> A3["配音智能体
edge-tts"] A3 --> A4["剪辑智能体
FFmpeg"] A4 --> F["data/output/*.mp4"] F -->|"GET /files/**"| U C -->|"轮询 GET /api/videos/{id}"| U ``` ### 为什么用「图片 + 运镜」而不是文生视频模型? 免费、可匿名调用的文生视频 API 极少且额度紧张。本项目采用短视频行业常见的低成本方案: **AI 分镜 + AI 生图 + Ken Burns 运镜 + TTS + 字幕**,视觉上接近「动态分镜短片」,且完全可离线合成、时长可控、失败可降级。 如果后续接入可用的免费文生视频接口,只需替换 `ImageGenerator` / `VideoComposer` 两步。 --- ## 4. 使用的免费工具 | 环节 | 工具 | 是否免费 | 是否需要 Key | 说明 | |---|---|---|---|---| | 分镜脚本 | [Pollinations Text](https://text.pollinations.ai)(gpt-oss-20b / openai) | ✅ | ❌ | 匿名共享额度,高峰期可能 503,代码已做重试与降级 | | 文生图 | [Pollinations Image](https://image.pollinations.ai)(Flux) | ✅ | ❌ | 免费额度约 **1 IP / 45 秒 1 张**,代码自动排队等待 | | 中文配音 | [edge-tts](https://github.com/rany2/edge-tts) | ✅ | ❌ | 微软 Edge 神经网络语音,需要本机 Python | | 视频合成 | [FFmpeg](https://ffmpeg.org) | ✅ | ❌ | 推拉运镜、字幕、混音、拼接 | | 数据库 | MySQL Community 8 | ✅ | — | 也可以通过 H2 demo profile 零安装体验 | | 后端 | Spring Boot 3.3.5 / JDK 17 | ✅ | — | Web + JPA + 异步线程池 | | 前端 | Vue 3 + Vite | ✅ | — | 单页应用,无 UI 框架依赖 | > 免费公共服务有公共限额与稳定性波动,适合学习、演示与个人创作,请勿滥用。生产环境建议替换为自建模型或商业 API。 --- ## 5. 目录结构 ``` . ├─ backend/ # Spring Boot 后端 │ ├─ src/main/java/com/example/text2video/ │ │ ├─ agent/StoryboardAgent.java # 编剧智能体(LLM + 本地降级) │ │ ├─ media/ImageGenerator.java # 画师智能体(Pollinations + 限流等待) │ │ ├─ media/VisualPrompt.java # 中文画面描述 → 英文视觉关键词(离线词表) │ │ ├─ media/SpeechSynthesizer.java# 配音智能体(edge-tts → Google → 静音) │ │ ├─ media/VideoComposer.java # 剪辑智能体(FFmpeg 运镜/字幕/混音/拼接) │ │ ├─ service/VideoPipeline.java # 多智能体编排 │ │ ├─ service/TaskService.java # 任务状态机 + 进度持久化 │ │ ├─ web/VideoTaskController.java# REST API │ │ ├─ domain/VideoTask.java # MySQL 实体 │ │ └─ support/FfmpegSupport.java # FFmpeg/ffprobe/字体探测 │ ├─ src/main/resources/application.yml │ └─ src/main/resources/application-demo.yml # 无 MySQL 的 H2 模式 ├─ frontend/ # Vue 3 前端 │ ├─ src/App.vue │ ├─ src/components/PromptForm.vue # 输入描述与参数 │ ├─ src/components/TaskStage.vue # 进度、视频播放、下载、分镜 │ ├─ src/components/HistoryList.vue # 最近生成 │ └─ vite.config.js # /api、/files 代理 ├─ sql/init.sql # 建库建表(JPA 也会自动建表) ├─ docker-compose.yml # MySQL 8 一键启动 ├─ scripts/install-ffmpeg.ps1 # 下载 FFmpeg 到 tools/ffmpeg ├─ scripts/install-voice.ps1 # 安装 edge-tts └─ backend/data/output/ # 生成的 MP4 与封面(运行时创建) ``` --- ## 6. 快速开始 ### 6.1 环境要求 | 依赖 | 版本 | 检查命令 | |---|---|---| | JDK | 17+ | `java -version` | | Maven | 3.8+ | `mvn -v` | | Node.js | 18+ | `node -v` | | MySQL | 8.x | `mysql --version`(也可用 demo 模式跳过) | | Python | 3.8+ | `python --version` | | FFmpeg | 6+(建议 7/8/9) | `ffmpeg -version` | ### 6.2 第 1 步:准备免费工具 ```powershell # Windows:下载 FFmpeg 到 tools/ffmpeg/bin(约 100MB) powershell -ExecutionPolicy Bypass -File scripts/install-ffmpeg.ps1 # 安装免费中文语音 powershell -ExecutionPolicy Bypass -File scripts/install-voice.ps1 ``` - 如果系统已经装好 FFmpeg 并加入 PATH,可跳过第一步;后端会自动探测 `tools/ffmpeg/bin` 和 PATH。 - Linux/macOS:`sudo apt install ffmpeg` / `brew install ffmpeg`,并 `pip install edge-tts`。 ### 6.3 第 2 步:启动 MySQL 任选一种: ```powershell # 方式 A:Docker(推荐,自动建库) docker compose up -d # 方式 B:本机 MySQL,默认连接 root/root,可自动建库 # 如有账号密码不同,用环境变量覆盖: $env:DB_USERNAME="root"; $env:DB_PASSWORD="你的密码" ``` 也可以手动执行 `sql/init.sql`。 ### 6.4 第 3 步:启动后端 ```powershell cd backend mvn spring-boot:run ``` 访问 ,应返回: ```json { "ffmpegAvailable": true, "fontPath": "C:\\Windows\\Fonts\\msyh.ttc", "edgeTtsAvailable": true, "llmEnabled": true, "imageEnabled": true } ``` > 没有 MySQL?用零安装体验模式: > `mvn spring-boot:run -Dspring-boot.run.profiles=demo` > 数据会写入 `backend/data/db`,其余功能完全一致。 ### 6.5 第 4 步:启动前端 ```powershell cd frontend npm install npm run dev ``` 打开 ,输入描述、选择镜头数/画幅/音色,点击生成。 > 前端通过 Vite 代理访问 `/api` 与 `/files`。如果后端换端口,设置: > `$env:VITE_PROXY_TARGET="http://localhost:8081"; npm run dev` --- ## 7. 使用与观察 - **进度时间线**:编剧 / 画师 / 配音 / 剪辑 / 发布 五个步骤,实时显示状态与消息。 - **免费生图排队**:当 Pollinations 返回 402 时,界面会显示「免费生图额度冷却中,等待 N 秒后继续绘制」,这是正常现象。 - **任务串行**:免费额度按 IP 计算,后端默认一次只跑一个任务,后续任务显示「排队中」,避免互相抢额度。 - **完成**:右侧出现播放器、下载按钮、复制链接、分镜脚本。 - **历史记录**:页面底部展示最近 8 条,点击可回看;URL 中带 `?task=` 可直接分享。 - **失败重试**:失败卡片一键用同样的描述重试。 一次 3 镜头生成的大致耗时(网络正常): | 阶段 | 耗时 | |---|---| | 分镜(LLM) | 5~20 秒 | | 生图(3 张,含限流等待) | 60~120 秒 | | 配音(3 段) | 3~8 秒 | | 合成(3 镜头) | 10~25 秒 | | **合计** | **约 1.5~3 分钟** | --- ## 8. 配置说明 配置文件:`backend/src/main/resources/application.yml`,全部支持环境变量覆盖。 | 环境变量 | 默认值 | 说明 | |---|---|---| | `SERVER_PORT` | `8080` | 后端端口 | | `PUBLIC_BASE_URL` | `http://localhost:8080` | 视频绝对下载链接前缀 | | `DB_URL` | `jdbc:mysql://localhost:3306/text2video?...` | MySQL 连接串(自动建库) | | `DB_USERNAME` / `DB_PASSWORD` | `root` / `root` | 数据库账号 | | `OUTPUT_DIR` | `./data/output` | MP4 输出目录,映射为 `/files/**` | | `WORK_DIR` | `./data/work` | 中间文件目录 | | `KEEP_WORK_DIR` | `false` | 是否保留中间文件便于调试 | | `LLM_ENABLED` | `true` | 关闭后使用本地规则分镜 | | `LLM_BASE_URL` | `https://text.pollinations.ai/openai` | OpenAI 兼容接口 | | `LLM_MODEL` | `openai` | 模型名 | | `LLM_API_KEY` | 空 | 使用需要 Key 的服务时填写 | | `IMAGE_ENABLED` | `true` | 关闭后直接使用兜底底图 | | `IMAGE_BASE_URL` | `https://image.pollinations.ai/prompt` | 文生图地址 | | `IMAGE_MODEL` | `flux` | 生图模型 | | `TTS_ENABLED` | `true` | 语音总开关 | | `TTS_PROVIDER` | `auto` | `auto` / `edge` / `google` / `silent` | | `TTS_VOICE` | `zh-CN-XiaoxiaoNeural` | 默认音色 | | `PYTHON_COMMAND` | `python` | Python 命令(可填绝对路径) | | `FFMPEG_PATH` | `ffmpeg` | FFmpeg 可执行文件路径 | | `FONT_PATH` | 自动探测 | 字幕字体,如 `C:/Windows/Fonts/msyh.ttc` | | `BURN_SUBTITLES` | `true` | 是否烧录字幕 | | `PIPELINE_CORE_POOL_SIZE` / `PIPELINE_MAX_POOL_SIZE` | `1` / `1` | 同时执行的任务数。免费生图按 IP 限流,建议保持 1,其余任务自动排队 | ### 换成完全本地的 Ollama(免费、无限额) ```yaml app: llm: base-url: http://localhost:11434/v1/chat/completions model: qwen2.5:7b api-key: ollama ``` ### 关闭字幕 ```powershell $env:BURN_SUBTITLES="false" ``` --- ## 9. REST API ### 提交任务 ```bash curl -X POST http://localhost:8080/api/videos \ -H "Content-Type: application/json" \ -d '{ "prompt": "清晨的高山草甸,薄雾升起,一头小鹿低头饮水,第一缕阳光越过雪线。", "sceneCount": 3, "aspect": "16:9", "voice": "zh-CN-XiaoxiaoNeural", "subtitles": true }' ``` 返回 `202 Accepted`: ```json { "id": "0f0ae919-81f6-4e78-8401-dba72d18f4ba", "status": "QUEUED", "progress": 0, "stage": "任务排队中,等待智能体调度...", "steps": [ { "key": "script", "status": "PENDING", "...": "..." } ] } ``` ### 查询任务 / 历史 / 系统状态 ```bash curl http://localhost:8080/api/videos/{id} curl "http://localhost:8080/api/videos?limit=8" curl http://localhost:8080/api/system ``` 任务成功后的关键字段: ```json { "status": "SUCCEEDED", "progress": 100, "videoPath": "/files/0f0ae919-....mp4", "videoUrl": "http://localhost:8080/files/0f0ae919-....mp4", "coverPath": "/files/0f0ae919-...-cover.jpg", "durationMs": 25500, "storyboard": { "title": "...", "scenes": [ ... ] } } ``` ### 参数约束 | 字段 | 类型 | 约束 | |---|---|---| | `prompt` | string | 6~800 字 | | `sceneCount` | int | 2~8,默认 3 | | `aspect` | string | `16:9` / `9:16` / `1:1` | | `voice` | string | edge-tts 音色名 | | `subtitles` | boolean | 默认 true | --- ## 10. 智能体实现细节 ### 10.1 编剧智能体(`StoryboardAgent`) - System Prompt 限定「只输出 JSON」; - User Prompt 约束旁白长度、画面描述、统一风格、禁止文字水印; - 输出解析支持 Markdown 代码块、前后废话、缺字段; - 失败策略:2 次 POST 重试(间隔 6s)→ Pollinations GET 备用接口 → 本地规则分镜。 ### 10.2 画师智能体(`ImageGenerator`) - 请求串行化,避免并发任务争抢同一 IP 的免费额度; - 解析 402 响应中的 `Retry after Ns` 并等待; - 最多等待 100 秒/张,失败则用 Java2D 生成渐变光斑 + 镜头标题的兜底画面; - 本地规则分镜产生的中文画面描述会通过内置中英视觉词表转成英文关键词,提升 Flux 的稳定性; - 画面统一追加「电影感、写实摄影、柔和光、无文字/水印」等风格后缀。 ### 10.3 配音智能体(`SpeechSynthesizer`) - 首选 `python -m edge_tts`,支持 6 种中文音色; - 备用 Google Translate TTS(分块 + FFmpeg 拼接); - 最终兜底:按字数估算时长生成静音轨,视频仍可完整产出。 ### 10.4 剪辑智能体(`VideoComposer`) 每个镜头: 1. 2 倍超采样后 `zoompan` 缓慢推近/拉远(Ken Burns); 2. 底部半透明字幕框 + 自动折行(中文按字宽计算); 3. 0.45 秒淡入/淡出; 4. `apad + atrim` 对齐旁白与画面时长; 5. 统一 H.264/AAC 参数后用 concat demuxer 无损拼接,失败自动改为重编码; 6. `-movflags +faststart` 支持网页秒开。 --- ## 11. 生产部署 ### 11.1 构建 ```bash cd backend && mvn clean package -DskipTests cd ../frontend && npm ci && npm run build ``` ### 11.2 Nginx 示例 ```nginx server { listen 80; server_name video.example.com; root /var/www/text2video; index index.html; location / { try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_read_timeout 300s; } location /files/ { proxy_pass http://127.0.0.1:8080; proxy_read_timeout 300s; } } ``` 启动后端时设置: ```bash PUBLIC_BASE_URL=https://video.example.com \ DB_PASSWORD=*** \ java -jar backend/target/text2video-1.0.0.jar ``` > 前端构建产物是静态文件,与后端完全解耦;也可以把 `dist/` 放到任意 CDN,只要保证 `/api`、`/files` 反向代理到后端即可。 --- ## 12. 常见问题 | 现象 | 原因与解决 | |---|---| | `/api/system` 显示 `ffmpegAvailable: false` | 未安装 FFmpeg 或路径不对。执行 `scripts/install-ffmpeg.ps1`,或设置 `FFMPEG_PATH` 为绝对路径后重启 | | 视频没声音 | `/api/system` 看 `edgeTtsAvailable`。执行 `python -m pip install edge-tts`;若使用虚拟环境,设置 `PYTHON_COMMAND` 为对应解释器 | | 字幕是方框 | 找不到中文字体。设置 `FONT_PATH=C:/Windows/Fonts/msyh.ttc`(Linux 用 Noto Sans CJK) | | 一直显示「免费生图额度冷却中」 | Pollinations 免费额度约 45 秒/张,等待即可;若持续 503,稍后再试或减少镜头数 | | 分镜步骤显示「LLM 暂不可用」 | Pollinations 高峰期限流。可配置 Ollama 本地模型,或稍后重试;即使失败也会用本地规则分镜出片 | | 下载链接是 `localhost:8080` | 修改 `PUBLIC_BASE_URL` 为真实域名;前端播放使用相对路径,不受影响 | | 8080 端口被占用 | `$env:SERVER_PORT="8081"` 启动后端,前端设置 `VITE_PROXY_TARGET` | | MySQL `Access denied` | 设置 `DB_USERNAME` / `DB_PASSWORD`,或给账号建库权限 | | 想清空生成记录 | 清空 `video_task` 表并删除 `data/output/*.mp4` | | 生成很慢 | 免费生图限流是主要瓶颈。减少镜头数(3 个最快)、关闭字幕可略快 | --- ## 13. 已知限制与可扩展方向 **限制** - 视频长度约 15~50 秒,画面为「静态图 + 运镜」而非真实视频扩散; - 免费服务有公共限额,生成耗时受网络与限流影响; - 不包含背景音乐、转场特效、数字人口型同步; - 生成文件保存在本机磁盘,多实例部署需换成对象存储。 **可扩展** - 把 `ImageGenerator` 换成自建 ComfyUI / Stable Diffusion / 可用的文生视频 API; - 增加 BGM、多种转场、片头片尾模板(FFmpeg 或 Remotion); - 接入对象存储(MinIO/OSS)并返回 CDN 链接; - 引入 WebSocket / SSE 替代轮询; - 增加任务取消、失败重试、配额与鉴权; - 用 Spring AI / LangChain4j 做更复杂的智能体工具调用。 --- ## 14. 验证环境 本项目已在以下环境完成端到端生成验证: - Windows 11 / JDK 17.0.11 / Maven 3.9.9 - MySQL 8.0.39(root/root) - Node.js 20.19 / Vue 3.5 / Vite 6 - Python 3.8.6 + edge-tts 7.3.1 - FFmpeg 9.0.2 essentials build 实际产物:1280×720、H.264 + AAC、约 12~30 秒的 MP4,字幕与中文旁白正常。 --- ## License MIT,仅用于学习与演示。使用第三方免费服务时请遵守其服务条款。