按官方文档搭 VibeVoice 的 Gradio demo:依赖、启动参数与页面怎么暴露
想给团队里不写代码的同事一个网页:丢一段会议录音进去,出带说话人和时间戳的转写。VibeVoice 仓库里确实带了这么个 Gradio 页面,但你照着 README 点进去会发现有两个脚本、两套参数、两种依赖,选错一个就会卡在第一步——比如你按 docs/setup_gradio_demo.md 拉起了容器,却拿另一个脚本的 --model_path 去传参,argparse 会直接报未知参数。
这篇把这条路顺一遍:依赖到底要装什么、启动参数各自是哪些、页面起来之后从哪儿访问。事实全部来自仓库里的 docs/setup_gradio_demo.md、docs/vibevoice-asr.md、vllm_plugin/scripts/gradio_asr_demo_api_video.py、demo/vibevoice_asr_gradio_demo.py、vllm_plugin/scripts/start_server.py 与 pyproject.toml。
先分清两个 Gradio 脚本
仓库里叫 Gradio demo 的有两个,落在不同目录:
| 脚本路径 | 模型从哪来 | 对应文档 |
|---|---|---|
vllm_plugin/scripts/gradio_asr_demo_api_video.py | 通过 HTTP 调外部 vLLM 服务 | docs/setup_gradio_demo.md |
demo/vibevoice_asr_gradio_demo.py | 进程内直接加载模型权重 | docs/vibevoice-asr.md 的 Usage 1 |
前者的模块 docstring 写得很直白:这个 demo 使用 vLLM API 服务而不是直接加载模型,支持并发请求与流式输出。后者的文件头则直接 from vibevoice.modular.modeling_vibevoice_asr import VibeVoiceASRForConditionalGeneration,模型是在建界面之前就加载好的。
两者的参数集合不通用。API 版的 argparse 定义了 --api_url、--model_name、--max_new_tokens、--host、--port、--share、--cloudflared、--max_video_size 这八项;本机版定义的是 --model_path、--device、--attn_implementation、--max_new_tokens、--host、--port、--share 这七项。只有 --max_new_tokens、--host、--port、--share 四个是重名的。
前置条件:两条路线各自要什么
**路线 A(API 版)**的前置条件在 docs/setup_gradio_demo.md 的 Prerequisites 一节写明,是三条:CUDA-capable GPU、带 GPU 支持的 Docker(nvidia-docker)、本地已克隆仓库。也就是说这条路线默认你用容器,宿主机上不需要单独准备 Python 环境。
容器里的依赖由 vllm_plugin/scripts/start_server.py 自己装。它的 docstring 列了五步职责:装系统依赖(FFmpeg 等)、装 VibeVoice Python 包、从 Hugging Face 下模型、生成 tokenizer 文件、启动 vLLM 服务。对应到函数上,install_system_deps() 执行的是 apt-get update 与 apt-get install -y ffmpeg libsndfile1;install_vibevoice() 执行的是 pip install -e /app[vllm]。这两条都是 Debian 系镜像的写法,换基础镜像要自己改。
这里有一处文档与配置对不上,值得先说:start_server.py 装的是 /app[vllm] 这个 extra,但 pyproject.toml 的 [project.optional-dependencies] 里我们只找到 streamingtts 一项,没有 vllm。两处白纸黑字放在一起就是这个状态,具体后果以你实际执行 pip 时的输出为准。
**路线 B(本机版)**的前置条件在 docs/vibevoice-asr.md 的 Installation 一节:文档建议用 NVIDIA Deep Learning Container 管理 CUDA 环境,注释里写明若镜像内没有 flash attention 需要按 Dao-AILab/flash-attention 的说明自行安装;然后 git clone 加 pip install -e .。跑 demo 前另有一句 apt update && apt install ffmpeg -y # for demo。
FFmpeg 不是可选项。两个脚本里音频解码都走 ffmpeg 这个可执行名的 subprocess 调用(API 版的 load_audio_ffmpeg() 在 soundfile 失败时回退到 ffmpeg,视频转音频也走它),所以 ffmpeg 必须在 PATH 上。
pyproject.toml 里 requires-python 写的是 >=3.10,依赖清单里 gradio 是主依赖不是 extra,装了包就有。
路线 A 的三步:文档写了什么
第一步是起 ASR 服务。单卡的命令原样是这样:
docker run -d --gpus '"device=0"' --name vibevoice-asr-demo \
--ipc=host \
-p 6001:6001 \
-e VIBEVOICE_FFMPEG_MAX_CONCURRENCY=64 \
-e PYTORCH_ALLOC_CONF=expandable_segments:True \
-v $(pwd):/app \
-w /app \
--entrypoint bash \
vllm/vllm-openai:v0.14.1 \
-c "python3 /app/vllm_plugin/scripts/start_server.py --port 6001"
这一步在改的是:把仓库挂进容器的 /app,用 --entrypoint bash 顶掉镜像原本的入口,改成跑启动脚本。文档给的判定信号不是等固定时间,而是 docker logs -f vibevoice-asr-demo 里出现 Application startup complete.。多卡场景文档另给了一条命令,与单卡那条的差别只有两处:--gpus 换成 '"device=0,1,2,3"',末尾的启动脚本多带一个 --dp 4,其余参数一字不改。文档在 Tip 里区分:--dp N 是数据并行、--tp N 是张量并行,细节指向 docs/vibevoice-vllm-asr.md。
第二步是验服务,curl http://localhost:6001/v1/models,文档给的期望输出里 data 数组的第一项 id 是 vibevoice。
第三步才是 Gradio。文档先让你在容器里装 tmux,再把脚本丢进 tmux 会话:
docker exec vibevoice-asr-demo apt-get install -y tmux
docker exec vibevoice-asr-demo bash -c \
"PYTHONUNBUFFERED=1 tmux new-session -d -s gradio \
'PYTHONUNBUFFERED=1 python3 /app/vllm_plugin/scripts/gradio_asr_demo_api_video.py \
--api_url http://localhost:6001 --share \
2>&1 | tee /tmp/gradio.log'"
这一段里每个部分都有明确职责:tmux new-session -d 让进程在 docker exec 退出后仍留在容器里;两处 PYTHONUNBUFFERED=1 是为了让日志立刻落到文件,文档的排错表里专门有一行说 Gradio 日志为空多半是缓冲导致;tee /tmp/gradio.log 决定了下一步你从哪儿捞链接。--api_url http://localhost:6001 必须显式给,因为脚本里这个参数的默认值是 http://localhost:8000——这是仓库当前代码里的默认值,随版本可能变动。
页面暴露与访问方式
这是最容易踩的一处,值得把几个事实摆在一起看。
两个脚本的 --host 默认值都是 0.0.0.0,--port 默认值都是 7860,demo.launch() 传入的 server_name / server_port 就是这两个值——这是仓库当前代码里的默认值,随版本可能变动。也就是说页面默认绑定容器内的所有网卡。
而第一步那条 docker run 只发布了 -p 6001:6001,没有发布 7860。这两处放在一起,就能解释为什么文档第三步默认带了 --share:加了 --share 之后,Gradio 会生成一个 gradio.live 的公开链接,文档写明这个链接是公网可访问的、有效期一周(这是文档当前的写法,Gradio 服务方的策略以实际为准)。捞链接的动作是 docker exec vibevoice-asr-demo cat /tmp/gradio.log,文档给的样例输出里同时有 Running on local URL: http://0.0.0.0:7860 和 Running on public URL: https://xxxxxx.gradio.live 两行。
不想走 gradio.live 的话,API 版脚本还有 --cloudflared,help 文本写的是用 cloudflared 隧道创建公开链接。看实现:CLOUDFLARED_PATH 写死在 ~/.local/bin/cloudflared,download_cloudflared() 下载的地址后缀是 cloudflared-linux-amd64。这是个 Linux 二进制,Windows 侧不要指望这个开关直接可用。
再看数据落点。API 版脚本里 DEFAULT_UPLOAD_SAVE_DIR = "local/from_custom",async_copy_uploaded_file() 会在后台线程里把上传的文件按 时间戳_uuid前八位_原文件名 复制到脚本所在目录下的这个子目录;另有 CUSTOM_TEMP_DIR = os.environ.get("VIBEVOICE_TEMP_DIR", "/tmp/vibevoice_demo"),模块导入时就会 os.makedirs。把公开链接发出去之前,先想清楚谁上传的东西会留在你的磁盘上。
还有一点必须直说:两个脚本的 demo.launch() 参数里,我们没有找到任何鉴权相关的设置(例如 Gradio 的 auth)。所以 --share 生成的链接在有效期内谁拿到谁能用。
以上命令均原样取自仓库文档;组合使用时以仓库最新内容与 --help 的实际输出为准,我们没有实测。
Windows 侧的几处差异
路线 A 整条链路是 Docker 加 Linux shell 写法:$(pwd)、--gpus '"device=0"'、apt-get,在 PowerShell 里这些都需要自己改写,$(pwd) 尤其要注意路径分隔与引号。
路线 B 的脚本对 Windows 有专门处理:demo/vibevoice_asr_gradio_demo.py 文件头有一段 if sys.platform == 'win32' 分支,把 USER 从 USERNAME 补上,并把 TORCHINDUCTOR_CACHE_DIR 指到 TEMP 下的 torch_cache。注释写的是给 Windows 做 pwd 的纠错。
同一个脚本里 _detect_device_and_attn() 决定了 --device auto 的落点:先看 torch.cuda.is_available(),再看 torch.backends.mps.is_available(),都不满足落到 cpu;注意力实现方面,只有设备是 cuda 时才会尝试 import flash_attn,导入失败打印一行提示并退回 sdpa,非 CUDA 设备则代码注释直接写明 MPS / XPU / CPU 不支持 flash_attention_2,一律用 sdpa。这段逻辑对 Windows 用户的实际意义是:装没装 flash-attn 不会让脚本起不来,但它会走哪条分支是由这几个判断决定的,不是由你的期望决定的。
API 版脚本里那个 /tmp/vibevoice_demo 默认值是 POSIX 风格路径,好在它可以用环境变量 VIBEVOICE_TEMP_DIR 覆盖。
边界:哪些地方文档没兜住
docs/setup_gradio_demo.md的 Gradio Options 表只列了五个 flag(--api_url、--share、--port、--cloudflared、--max_video_size),而脚本 argparse 里实际有八个,--model_name、--max_new_tokens、--host三个没进表。要写脚本自动化就别只看表。- 文档第二步的快速测试命令引用了
/app/en-Alice_woman.wav。按-v $(pwd):/app的挂载关系,这对应仓库根目录下的同名文件,而我们在当前仓库根目录没有找到它。要自备音频,或改用demo/asr_demo/下已有的样例文件。 - 文档的排错表里有
CUDA out of memory一行,给的处置是换一块 GPU(device=X)或在start_server.py里调低--gpu-memory-utilization。该参数在start_server.py的 argparse 里存在,默认值0.8——这是仓库当前代码里的默认值,随版本可能变动。 start_server.py的 docstring 写明:当--dp > 1时,它会拉起 N 个独立 vLLM 进程并放在 nginx 反向代理后面,理由是避免 vLLM 内建 DP 协调器的单进程 HTTP 瓶颈(仓库文档自述)。这意味着 DP 模式下容器内多了一个 nginx,排查问题时别忘了这一层。- 这两个 Gradio 页面都是 ASR 的。关于仓库里 TTS 代码的状态,见文末声明,不要指望在这个页面上做语音合成。
怎么验证配对了
按文档给的信号逐级确认,不要跳级:
- 服务层:
docker logs -f vibevoice-asr-demo里出现Application startup complete.。 - 接口层:
curl http://localhost:6001/v1/models返回的data里能看到id为vibevoice的条目。 - 端到端:文档给的是
docker exec -it vibevoice-asr-demo python3 /app/vllm_plugin/tests/test_api.py <你的音频文件> --url http://localhost:6001(音频路径按上一节说明自备)。 - 页面层:
docker exec vibevoice-asr-demo cat /tmp/gradio.log,看有没有那两行 URL;文档还给了一行确认 API 已连上的输出Connected to API: http://localhost:6001 | Model: vibevoice。 - 收工:
docker exec vibevoice-asr-demo tmux kill-session -t gradio只停 Gradio、保留 ASR 服务;docker stop加docker rm才是全停。
如果第 2 步不通就别去看 Gradio 日志了,--api_url 指向的是同一个端口,服务没起来页面也接不上——文档排错表里「Share link shows “No interface”」那一行给的处置也是回去看服务端日志。
本文依据 github.com/microsoft/VibeVoice 仓库与 Hugging Face 模型卡于 2026-08-18 的公开内容整理,
事实来自仓库内的文档与源码。我们没有下载权重、没有跑过推理、也没有做过训练,
因此不涉及显存占用、推理速度、识别准确率与音质的任何描述,也不与其它模型做比较或排名。
该项目持续更新,文中涉及的模块路径、配置字段与接口写法随版本变动,请以仓库最新内容为准。
需要说明的是:仓库 README 记载,2025-09-05 微软因发现有与既定意图不符的使用方式,
基于负责任 AI 原则从该仓库移除了 VibeVoice-TTS 代码;
当前 vibevoice/modular/modeling_vibevoice.py 首行注释标明其来自社区 fork,
且该模块未被 vibevoice/modular/__init__.py 的 __all__ 导出。
本文只讲代码与架构,不构成 TTS 推理的可用性保证。
仓库 README 的风险与限制一节写明:该模型仅供研究与开发用途, 未经进一步测试与开发不建议用于商业或真实场景,并特别提示了合成语音被用于伪造与虚假信息的风险。 使用合成语音时应遵守所在司法辖区的法律法规,并在分享 AI 生成内容时主动披露。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。