Files
xiaoxia-saas/deploy/gpu_worker/README.md
T
xiaoxia 08de0d9946
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 2s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 1s
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Failing after 2m40s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 3m10s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m16s
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
Preview Deploy / Deploy Preview Environment (pull_request) Has been cancelled
perf: async GPU lipsync inference + fix 16x performance regression
- Move GPU wait_for_result to Celery background task (lipsync_gpu_process_async)
  POST /lipsync/jobs now returns <1s instead of blocking 200s+
- Rewrite musetalk_server.py: MuseTalk receives full audio directly
  (v2 architecture) — no pre-looping video before inference
  Output video length = audio length, mux is fast stream copy
- Frontend polls GET /lipsync/jobs/{id} for status updates
- refresh_job_status: GPU async path (processing + no mediakit_task_id)
  skips MediaKit polling; stale jobs (>30min) auto-marked failed
- 21 unit tests pass (11 GPU integration + 10 musetalk audio mux)

Co-Authored-By: Coze <coze-opensource@bytedance.com>
2026-09-20 09:43:47 +08:00

9.1 KiB
Raw Blame History

MuseTalk GPU Worker 部署指南

本目录包含两个组件:

  1. gpu_worker.py:反向轮询客户端,部署在 RTX2060 本地,轮询 SaaS API 拉取口型任务,调用本地 MuseTalk 服务推理,上传结果回 SaaS。
  2. musetalk_server.py:MuseTalk Flask HTTP 服务端,接收 gpu_worker.py 的推理请求,调用 MuseTalk 模型生成口型同步视频。

一、环境准备

1.1 硬件要求

  • GPU: NVIDIA RTX 2060 或更高(显存 ≥ 6GB)
  • CUDA: 11.8+
  • Python: 3.10+
  • ffmpeg: 需安装并加入 PATH

1.2 安装依赖

cd deploy/gpu_worker
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

二、MuseTalk 服务端部署(musetalk_server.py)

2.1 配置环境变量

复制 .env.example 为 .env,修改配置:

cp .env.example .env
vim .env

关键配置:

变量 说明 默认值
MUSE_PORT 监听端口 7861
MUSE_INFERENCE_TIMEOUT 推理超时秒数 600
MUSE_VIDEO_MAX_MB 视频上传大小限制 MB 100
MUSE_AUDIO_MAX_MB 音频上传大小限制 MB 20
MUSE_DEFAULT_FPS 视频 fps 兜底值 25.0
MUSE_TEMP_DIR 临时文件目录 /tmp/musetalk_$$
MUSE_VIDEO_ENCODER 兜底循环视频时的编码器:auto(优先 h264_nvenc,失败回退 libx264)/h264_nvenc/libx264 auto

2.2 更新部署(v2 性能修复,必做)

⚠️ 2026-09-20 v2 架构:修复 16 倍性能回归。旧版在推理前 loop 视频导致 MuseTalk 处理帧数翻倍、RTX2060 推理 >200s、nginx 504。必须重新拉取并重启:

# 在 RTX2060 上备份旧文件并拉取新版本
cp ~/projects/MuseTalk/musetalk_server.py ~/projects/MuseTalk/musetalk_server.py.bak
wget -O ~/projects/MuseTalk/musetalk_server.py \
  "https://git.xiaoxiajianji.com/xiaoxia/xiaoxia-saas/raw/branch/develop/deploy/gpu_worker/musetalk_server.py"

# 重启服务
sudo systemctl restart musetalk-server
sudo systemctl status musetalk-server
curl http://127.0.0.1:7861/health

v2 架构核心变化:

  • MuseTalk 直传全量音频:不再在推理前用 ffmpeg 循环视频。MuseTalk 原生支持长音频输入,内部自动循环视频帧。推理时间不变(~14s/5s 视频)
  • ffmpeg 只做快速封装:-c:v copy -c:a aac -shortest,秒级完成,不重编码
  • 循环仅兜底:仅当 MuseTalk 输出画面短于音频时(极端情况),才 -stream_loop + NVENC 兜底
  • 删除 MUSE_ENABLE_VIDEO_LOOP:不再需要此开关,MuseTalk 原生处理

2.3 启动服务

# 前台运行(调试用)
python musetalk_server.py

# 后台运行(生产用 systemd)
sudo systemctl start musetalk-server
sudo systemctl enable musetalk-server

2.4 验证健康检查

curl http://127.0.0.1:7861/health

应返回:

{
  "status": "healthy",
  "gpu": {
    "gpu_name": "NVIDIA GeForce RTX 2060",
    "memory_total_mb": 6144,
    "memory_used_mb": 1024,
    "memory_free_mb": 5120
  },
  "current_task": {
    "task_id": null,
    "running": false,
    "elapsed_seconds": 0.0
  },
  "timestamp": 1700000000.0
}

三、GPU Worker 客户端部署(gpu_worker.py)

3.1 配置环境变量

复制 .env.example 为 .env,修改配置:

cp .env.example .env
vim .env

关键配置:

变量 说明 默认值
API_BASE_URL SaaS API 基础 URL https://staging-api.xiaoxiajianji.com
GPU_WORKER_TOKEN 长期 API Token(与服务端一致) -
MUSE_TALK_URL 本地 MuseTalk 服务地址 http://127.0.0.1:7861
POLL_INTERVAL 轮询间隔秒 5
HEARTBEAT_INTERVAL 空闲心跳间隔秒 15
REQUEST_TIMEOUT HTTP 请求超时秒 900
TASK_MAX_RETRY 本地最大重试次数 1
TASK_HEARTBEAT_INTERVAL 推理期间任务心跳间隔秒 30
MIN_VIDEO_DURATION_SECONDS 最短输入视频时长秒 3

3.2 启动 Worker

# 前台运行(调试用)
python gpu_worker.py

# 后台运行(生产用 systemd)
sudo systemctl start xiaoxia-gpu-worker
sudo systemctl enable xiaoxia-gpu-worker

3.3 验证启动日志

应看到:

============================================================
MuseTalk GPU Worker 启动
  worker_id   = rtx2060-xxxx
  api_base    = https://staging-api.xiaoxiajianji.com
  muse_talk   = http://127.0.0.1:7861
  poll        = 5.0s / heartbeat = 15.0s
============================================================
MuseTalk 健康检查通过: {...}
注册/心跳成功

四、常见问题排查

现象 可能原因 / 排查
日志 401 Invalid GPU worker token .env 的 GPU_WORKER_TOKEN 与服务端不一致
日志 MuseTalk 健康检查未通过 本地 MuseTalk 没启动,或端口不是 7861;curl http://127.0.0.1:7861/health 验证
任务长时间不被拉取 Worker 和服务端连不上;检查 API_BASE_URL 是否可达、Token 是否正确
推理后上传 OSS 失败 本地出口网络被防火墙拦截 OSS 域名(oss-cn-hangzhou.aliyuncs.com)
服务端看到任务回退到 pending 重试 任务心跳真正超时(默认 900s):Worker 进程崩溃/断网,或推理彻底卡死;正常长推理期间心跳线程每 30s 续期,不会回退
日志 MuseTalk 推理超时或连接失败 视频太长或显存不足;可临时调大 REQUEST_TIMEOUT(服务端 GPU_TASK_TIMEOUT_SECONDS 需同步调大),或限制输入视频时长
日志 视频过短(x.xxs < 3s) 输入视频不足 3s,MuseTalk 对短视频会 division by zero,已在本地直接上报失败;可用 MIN_VIDEO_DURATION_SECONDS 调整阈值
MuseTalk 服务端 503 GPU 正在处理其他任务 并发请求被锁拒绝,等当前推理完成即可
MuseTalk 服务端 504 推理超时 推理超过 MUSE_INFERENCE_TIMEOUT,客户端会调 /cancel 终止服务端任务

五、安全注意事项

  • .env 包含长期 Token,文件权限设为 600(chmod 600 .env)
  • Token 泄露要立即在服务端更换 GPU_WORKER_TOKEN 并重启 Worker
  • Worker 只需要出站访问 SaaS API 和 OSS,不需要开放任何入站端口
  • MuseTalk 服务端只监听本地 127.0.0.1(或 0.0.0.0 但通过防火墙限制),不暴露到公网
  • 临时文件自动清理(推理完成/失败后),无需手动维护

六、工程改进记录(musetalk_server.py)

相比原 worker.py,修复了以下 8 个 bug:

  1. Flask 单线程阻塞:app.run(threaded=True),推理时 /health 仍可响应
  2. fps=0 除零崩溃:_get_video_fps() 兜底 MUSE_DEFAULT_FPS
  3. ffmpeg 不检查返回码:subprocess.run(check=True) + 超时检查,失败立即报错
  4. 无并发锁:threading.Lock 控制并发,第二请求立即 503
  5. 无推理超时:线程 join timeout,超时返回 504 并调 /cancel
  6. 结果文件不清理:推理完成/失败后自动删除临时目录
  7. 无人脸检测兜底:MuseTalk 推理内部处理(TODO: 可在 _run_inference 前置检查)
  8. 上传无大小限制:_check_file_size() 校验,超限返回 413

新增:

  • /cancel 端点:终止当前推理任务,清理临时文件
  • /health 端点:返回 GPU 显存信息和当前任务状态

2026-09-20 追加修复(音轨正确性,上线阻断级):

  1. 音轨未替换(严重):旧最终封装让 ffmpeg 默认选流,结果保留了源视频自带音轨(与画面相关系数 0.9998,与 TTS 无关)。改为 _mux_video_with_audio() 统一封装,强制 -map 0:v:0 -map 1:a:0,画面取 MuseTalk 无声产物、音轨只取驱动音频
  2. 音视频时长不对齐:TTS 长于原视频时 -shortest 会截短语音。改为探测双方时长,音频更长时 -stream_loop -1 循环画面 + h264_nvenc 硬件重编码(MUSE_VIDEO_ENCODER=auto,失败回退 libx264)+ -t <音频时长>;不循环时 -c:v copy 秒封装
    • 开关 MUSE_ENABLE_VIDEO_LOOP=0 可关闭循环;请求也支持 form 参数 enable_video_loop 单任务覆盖

2026-09-20 v2 架构重构(性能回归修复,上线阻断级):

  1. 16 倍性能回归:#9/#10 的实现虽然音轨正确,但在某些集成场景下(推理前 loop 视频再喂 MuseTalk)导致推理帧数 ×2.2 + 叠加 ffmpeg 软编码预处理,5s 视频 +11s 音频推理 >200s,nginx 60s 超时 504
    • 正确架构:MuseTalk 原生支持长音频输入,内部自动循环视频帧。把【原视频】+【全量音频】直传 MuseTalk,输出时长=音频时长
    • ffmpeg 后置快速封装:-c:v copy -c:a aac -shortest 秒级完成,不重编码
    • 循环仅兜底:仅当 MuseTalk 输出画面短于音频时(极端情况),才 -stream_loop + NVENC 兜底补齐
    • 业务侧异步化:POST /lipsync/jobs 创建 GPU 任务后立即返回 job.status="processing",Celery 异步等待结果回写。前端 GET /jobs/{id} 轮询。避免同步阻塞 HTTP 请求 >200s
    • 删除 MUSE_ENABLE_VIDEO_LOOP:不再需要此开关