591 lines
9.4 KiB
Markdown
591 lines
9.4 KiB
Markdown
你是一个资深 Python / AI Infra / 推理服务工程师。你的任务不是讨论方案,而是**直接在本地完成一个可运行的项目**。
|
||
|
||
# 任务目标
|
||
|
||
在 **WSL2 + Ubuntu + NVIDIA RTX A4000 16GB** 环境下,开发一个 **本地单机视频生成 Worker 服务**,只做一件事:
|
||
|
||
> 接收一次视频生成请求 → 根据模式选择模型 → 在 A4000 上执行推理 → 输出视频文件 → 返回任务状态与结果路径。
|
||
|
||
这个 Worker 是一个**边缘执行节点**,不是完整平台。
|
||
|
||
---
|
||
|
||
# 必须遵守的边界
|
||
|
||
## 只做这些
|
||
|
||
* 提供本地 HTTP API
|
||
* 接收 text-to-video 请求
|
||
* 使用本地模型推理
|
||
* 单任务串行执行
|
||
* 输出固定目录结构
|
||
* 支持两种模式:
|
||
|
||
* `preview` → `LTX-Video`
|
||
* `refine` → `HunyuanVideo-1.5`
|
||
|
||
## 不要做这些
|
||
|
||
* 不做脚本生成
|
||
* 不做分镜拆解
|
||
* 不做 prompt 自动生成
|
||
* 不做剪辑
|
||
* 不做 ComfyUI 集成
|
||
* 不做多机调度
|
||
* 不做前端页面
|
||
* 不做复杂鉴权
|
||
* 不做 image-to-video
|
||
* 不做 video extend
|
||
* 不做数据库集群
|
||
* 不做消息队列中间件
|
||
|
||
---
|
||
|
||
# 最终交付物
|
||
|
||
你必须直接生成一个完整可运行项目,至少包含:
|
||
|
||
1. 项目源码目录
|
||
2. `requirements.txt`
|
||
3. `.env.example`
|
||
4. `README.md`
|
||
5. `scripts/install_wsl_env.sh`
|
||
6. `scripts/run_server.sh`
|
||
7. `scripts/smoke_test.py`
|
||
8. FastAPI 服务源码
|
||
9. SQLite 任务存储
|
||
10. 单 worker 串行队列
|
||
11. 模型路由器
|
||
12. `LTX` backend
|
||
13. `Hunyuan` backend
|
||
14. 统一输出目录
|
||
15. 基础日志
|
||
16. 错误处理
|
||
17. 健康检查接口
|
||
|
||
---
|
||
|
||
# 技术要求
|
||
|
||
## 基础技术栈
|
||
|
||
* Python 3.10+
|
||
* FastAPI
|
||
* Uvicorn
|
||
* Pydantic
|
||
* SQLite
|
||
* asyncio
|
||
* ffmpeg
|
||
* torch
|
||
* diffusers / transformers / accelerate / safetensors(按需要引入)
|
||
* WSL2 下通过 CUDA 调用 A4000
|
||
|
||
## 代码要求
|
||
|
||
* 代码必须结构清晰
|
||
* 所有核心模块必须可直接运行
|
||
* 不要只写伪代码
|
||
* 必须包含真实可执行代码骨架
|
||
* 重要处要有注释
|
||
* 要考虑异常处理
|
||
* 要考虑模型懒加载
|
||
* 要考虑单卡显存限制
|
||
* 所有路径都要可配置
|
||
* 配置统一放到 `settings.py` 和 `.env`
|
||
|
||
---
|
||
|
||
# 系统架构
|
||
|
||
实现下面这个最小架构:
|
||
|
||
```text
|
||
Client
|
||
-> FastAPI
|
||
-> TaskManager
|
||
-> ModelRouter
|
||
-> GPUWorker
|
||
-> Backend(LTX/Hunyuan)
|
||
-> OutputWriter
|
||
-> outputs/{task_id}/video.mp4
|
||
```
|
||
|
||
---
|
||
|
||
# 模型路由规则
|
||
|
||
固定规则:
|
||
|
||
* `quality_mode = "preview"` → `LTX-Video`
|
||
* `quality_mode = "refine"` → `HunyuanVideo-1.5`
|
||
|
||
请把模型路由实现成独立模块,后续方便替换。
|
||
|
||
---
|
||
|
||
# 任务状态
|
||
|
||
只保留这些状态:
|
||
|
||
* `PENDING`
|
||
* `RUNNING`
|
||
* `SUCCEEDED`
|
||
* `FAILED`
|
||
|
||
不要额外扩展复杂状态机。
|
||
|
||
---
|
||
|
||
# API 设计
|
||
|
||
你必须实现以下接口。
|
||
|
||
## 1)创建任务
|
||
|
||
### `POST /generate`
|
||
|
||
请求体:
|
||
|
||
```json
|
||
{
|
||
"prompt": "a lonely man walking in a rainy neon street, cinematic, handheld camera",
|
||
"negative_prompt": "blurry, deformed face, extra limbs, flicker",
|
||
"quality_mode": "preview",
|
||
"duration_sec": 5,
|
||
"width": 832,
|
||
"height": 480,
|
||
"fps": 16,
|
||
"steps": 8,
|
||
"seed": 123456
|
||
}
|
||
```
|
||
|
||
要求:
|
||
|
||
* 自动生成 `task_id`
|
||
* 写入 SQLite
|
||
* 入队
|
||
* 返回 `task_id` 和状态
|
||
|
||
---
|
||
|
||
## 2)查询任务状态
|
||
|
||
### `GET /tasks/{task_id}`
|
||
|
||
返回:
|
||
|
||
* `task_id`
|
||
* `status`
|
||
* `backend`
|
||
* `model_name`
|
||
* `progress`
|
||
* `created_at`
|
||
* `updated_at`
|
||
|
||
---
|
||
|
||
## 3)查询任务结果
|
||
|
||
### `GET /tasks/{task_id}/result`
|
||
|
||
成功时返回:
|
||
|
||
* `task_id`
|
||
* `status`
|
||
* `video_path`
|
||
* `first_frame_path`
|
||
* `metadata_path`
|
||
* `log_path`
|
||
|
||
失败时返回:
|
||
|
||
* `task_id`
|
||
* `status`
|
||
* `error`
|
||
|
||
---
|
||
|
||
## 4)健康检查
|
||
|
||
### `GET /health`
|
||
|
||
返回:
|
||
|
||
* 服务状态
|
||
* CUDA 是否可用
|
||
* GPU 名称
|
||
* 两个模型是否已加载
|
||
|
||
---
|
||
|
||
# 输入参数约束
|
||
|
||
第一版严格限制:
|
||
|
||
* 只支持 text-to-video
|
||
* `duration_sec` 允许 1~5
|
||
* `width` 最大 832
|
||
* `height` 最大 480
|
||
* `fps` 最大 24
|
||
* `quality_mode` 只允许 `preview` 或 `refine`
|
||
|
||
你需要在 Pydantic schema 中严格校验。
|
||
|
||
---
|
||
|
||
# 输出目录规范
|
||
|
||
每个任务固定输出到:
|
||
|
||
```text
|
||
outputs/{task_id}/
|
||
├─ video.mp4
|
||
├─ first_frame.jpg
|
||
├─ metadata.json
|
||
└─ run.log
|
||
```
|
||
|
||
其中:
|
||
|
||
## `metadata.json`
|
||
|
||
至少包含:
|
||
|
||
* task_id
|
||
* backend
|
||
* model_name
|
||
* prompt
|
||
* negative_prompt
|
||
* seed
|
||
* width
|
||
* height
|
||
* fps
|
||
* steps
|
||
* duration_sec
|
||
* status
|
||
* created_at
|
||
* started_at
|
||
* finished_at
|
||
* video_path
|
||
|
||
---
|
||
|
||
# 目录结构要求
|
||
|
||
按下面结构生成项目:
|
||
|
||
```text
|
||
video_worker/
|
||
├─ app/
|
||
│ ├─ main.py
|
||
│ ├─ api.py
|
||
│ ├─ schemas.py
|
||
│ ├─ settings.py
|
||
│ ├─ task_manager.py
|
||
│ ├─ model_router.py
|
||
│ ├─ gpu_worker.py
|
||
│ ├─ task_store.py
|
||
│ ├─ backends/
|
||
│ │ ├─ base.py
|
||
│ │ ├─ ltx_backend.py
|
||
│ │ └─ hunyuan_backend.py
|
||
│ └─ utils/
|
||
│ ├─ files.py
|
||
│ ├─ ffmpeg_utils.py
|
||
│ ├─ image_utils.py
|
||
│ └─ logger.py
|
||
├─ models/
|
||
│ ├─ ltx/
|
||
│ └─ hunyuan/
|
||
├─ outputs/
|
||
├─ runtime/
|
||
│ ├─ tasks.db
|
||
│ └─ logs/
|
||
├─ scripts/
|
||
│ ├─ install_wsl_env.sh
|
||
│ ├─ run_server.sh
|
||
│ └─ smoke_test.py
|
||
├─ requirements.txt
|
||
├─ .env.example
|
||
└─ README.md
|
||
```
|
||
|
||
---
|
||
|
||
# 模块职责
|
||
|
||
## `schemas.py`
|
||
|
||
定义:
|
||
|
||
* `GenerateRequest`
|
||
* `TaskStatusResponse`
|
||
* `TaskResultResponse`
|
||
* `HealthResponse`
|
||
|
||
---
|
||
|
||
## `task_store.py`
|
||
|
||
使用 SQLite 存储任务信息,至少包含:
|
||
|
||
* `task_id`
|
||
* `status`
|
||
* `backend`
|
||
* `model_name`
|
||
* `request_json`
|
||
* `output_dir`
|
||
* `error_message`
|
||
* `created_at`
|
||
* `updated_at`
|
||
|
||
---
|
||
|
||
## `task_manager.py`
|
||
|
||
负责:
|
||
|
||
* 创建任务
|
||
* 写入数据库
|
||
* 入队
|
||
* 更新状态
|
||
* 查询状态与结果
|
||
|
||
---
|
||
|
||
## `gpu_worker.py`
|
||
|
||
负责:
|
||
|
||
* 后台单线程取任务
|
||
* 标记任务为 RUNNING
|
||
* 调用路由器选择 backend
|
||
* 执行生成
|
||
* 写入结果
|
||
* 成功标记 SUCCEEDED
|
||
* 失败标记 FAILED
|
||
|
||
要求:
|
||
|
||
* 必须是**单任务串行**
|
||
* 不允许多任务并发占用 GPU
|
||
|
||
---
|
||
|
||
## `model_router.py`
|
||
|
||
根据 `quality_mode` 返回 `ltx_backend` 或 `hunyuan_backend`
|
||
|
||
---
|
||
|
||
## `backends/base.py`
|
||
|
||
定义统一接口:
|
||
|
||
* `load()`
|
||
* `is_loaded()`
|
||
* `generate(task)`
|
||
|
||
---
|
||
|
||
## `backends/ltx_backend.py`
|
||
|
||
要求:
|
||
|
||
* 实现懒加载
|
||
* 作为默认 preview 模型
|
||
* 重点保证代码结构正确
|
||
* 若本地真实模型推理接入较复杂,可先封装清晰的推理入口与参数映射,但不要省略真实调用预留位
|
||
* 输出必须符合统一目录规范
|
||
|
||
---
|
||
|
||
## `backends/hunyuan_backend.py`
|
||
|
||
要求:
|
||
|
||
* 实现懒加载
|
||
* 作为 refine 模型
|
||
* 保留 `cpu offload`、`vae tiling` 等内存优化入口
|
||
* 输出必须符合统一目录规范
|
||
|
||
---
|
||
|
||
## `utils/ffmpeg_utils.py`
|
||
|
||
必须实现:
|
||
|
||
* 如果 backend 输出帧序列,则合成为 `video.mp4`
|
||
* 从 `video.mp4` 抽取 `first_frame.jpg`
|
||
|
||
---
|
||
|
||
# 运行原则
|
||
|
||
## 1)模型懒加载
|
||
|
||
* 服务启动时不要强制加载所有模型
|
||
* 第一次调用对应 backend 时再加载
|
||
* 加载后常驻
|
||
|
||
## 2)单任务串行
|
||
|
||
* A4000 16GB 只允许一个视频任务同时运行
|
||
* 必须实现内存队列 + 单 worker
|
||
|
||
## 3)先支持 preview,再支持 refine
|
||
|
||
* 但代码结构里两个 backend 都要存在
|
||
* 如果某个 backend 先以占位实现,也必须说明后续替换点
|
||
|
||
---
|
||
|
||
# 配置要求
|
||
|
||
在 `.env.example` 中提供以下配置项:
|
||
|
||
```env
|
||
APP_HOST=0.0.0.0
|
||
APP_PORT=8000
|
||
OUTPUT_DIR=./outputs
|
||
RUNTIME_DIR=./runtime
|
||
SQLITE_PATH=./runtime/tasks.db
|
||
|
||
LTX_MODEL_DIR=./models/ltx
|
||
HUNYUAN_MODEL_DIR=./models/hunyuan
|
||
|
||
DEFAULT_WIDTH=832
|
||
DEFAULT_HEIGHT=480
|
||
DEFAULT_FPS=16
|
||
DEFAULT_DURATION=5
|
||
DEFAULT_STEPS_PREVIEW=8
|
||
DEFAULT_STEPS_REFINE=12
|
||
```
|
||
|
||
---
|
||
|
||
# README 必须包含
|
||
|
||
1. 项目说明
|
||
2. 环境准备
|
||
3. WSL + CUDA 检查方法
|
||
4. 安装命令
|
||
5. 启动命令
|
||
6. 调用示例
|
||
7. 目录说明
|
||
8. API 说明
|
||
9. 常见问题
|
||
10. 已知限制
|
||
|
||
---
|
||
|
||
# 安装脚本要求
|
||
|
||
## `scripts/install_wsl_env.sh`
|
||
|
||
需要完成:
|
||
|
||
* 创建 Python venv
|
||
* 升级 pip
|
||
* 安装 requirements
|
||
* 安装 ffmpeg
|
||
* 创建输出目录
|
||
* 创建 runtime 目录
|
||
* 给出后续启动提示
|
||
|
||
---
|
||
|
||
# 启动脚本要求
|
||
|
||
## `scripts/run_server.sh`
|
||
|
||
需要完成:
|
||
|
||
* 激活 venv
|
||
* 检查 `.env`
|
||
* 启动 uvicorn
|
||
|
||
---
|
||
|
||
# 烟雾测试要求
|
||
|
||
## `scripts/smoke_test.py`
|
||
|
||
需要完成:
|
||
|
||
* 调用 `/health`
|
||
* 创建一个 `preview` 任务
|
||
* 轮询任务状态
|
||
* 打印结果路径
|
||
|
||
---
|
||
|
||
# 开发顺序
|
||
|
||
严格按这个顺序实现:
|
||
|
||
## Phase 1
|
||
|
||
* 建目录
|
||
* 写 `settings.py`
|
||
* 写 `schemas.py`
|
||
* 写 `task_store.py`
|
||
* 写 `task_manager.py`
|
||
* 写基础 API
|
||
* 写 SQLite 初始化
|
||
* 写单 worker 队列
|
||
|
||
## Phase 2
|
||
|
||
* 写 `model_router.py`
|
||
* 写 `backends/base.py`
|
||
* 写 `ltx_backend.py`
|
||
* 打通 preview 路由
|
||
* 输出 `video.mp4 / metadata.json / run.log`
|
||
|
||
## Phase 3
|
||
|
||
* 写 `hunyuan_backend.py`
|
||
* 打通 refine 路由
|
||
* 增加 `/health`
|
||
* 增加 ffmpeg 抽帧
|
||
|
||
## Phase 4
|
||
|
||
* 完善 README
|
||
* 完善脚本
|
||
* 完善错误处理
|
||
* 完善 smoke test
|
||
|
||
---
|
||
|
||
# 验收标准
|
||
|
||
你完成后,必须满足以下条件:
|
||
|
||
1. 项目可直接启动
|
||
2. `GET /health` 可用
|
||
3. `POST /generate` 可创建任务
|
||
4. 任务会进入 `PENDING -> RUNNING -> SUCCEEDED/FAILED`
|
||
5. preview 模式能真正走 `LTX backend`
|
||
6. refine 模式能真正走 `Hunyuan backend`
|
||
7. 输出目录结构正确
|
||
8. `metadata.json` 完整
|
||
9. 失败时有明确错误信息
|
||
10. 代码结构足够清晰,后续方便替换真实模型实现
|
||
|
||
---
|
||
|
||
# 输出要求
|
||
|
||
你现在直接开始产出代码与文件内容,不要继续解释方案,不要重复需求,不要空谈架构。
|
||
|
||
请按下面顺序输出:
|
||
|
||
1. 项目目录树
|
||
2. 每个文件的完整内容
|
||
3. 最后给出运行步骤
|
||
|
||
要求所有内容都尽可能完整,可复制使用。
|