用 NVIDIA API Key 同时做画图和语音:一套从实测到落地的技术方案

8 阅读6分钟

用 NVIDIA API Key 同时做画图和语音:一套从实测到落地的技术方案

最近我在本地把一条很实用的链路跑通了:

  • 用 NVIDIA API Key 生成图片
  • 用 NVIDIA 官方 TTS 模型生成语音
  • 把语音转换成 Feishu 可以直接播放的语音气泡

这篇文章不讲空泛概念,直接总结成一套可复用的技术方案。

先说结论:

同一个 NVIDIA API Key,确实可以同时用于画图和语音,但这两条链路的调用方式并不一样。

很多人第一次试的时候会踩一个坑:

  • 画图用的是一套比较直接的 HTTP API
  • 语音不是简单地去撞几个 /v1/audio/* endpoint 就能成功
  • 真正跑通 TTS,要按 NVIDIA 官方示例走 Riva / Speech NIM client 的方式

如果这一点没搞清楚,很容易得出错误结论:

“图像接口能用,语音接口是不是根本不存在?”

其实不是。是入口不一样


一、先搞清楚:NVIDIA 现在到底提供了什么能力

1. 图像生成:Stable Diffusion 3 Medium

在这套环境里,图像生成走的是 NVIDIA 提供的 SD3 Medium 接口。

本地脚本调用的是:

https://ai.api.nvidia.com/v1/genai/stabilityai/stable-diffusion-3-medium

请求方式很直接:

  • Authorization: Bearer $NVIDIA_API_KEY
  • JSON body 里放 promptnegative_promptsteps

从工程实现上看,它更接近一个常规 REST 图像生成接口。

2. 语音生成:Magpie TTS / Riva TTS

语音这边不一样。

NVIDIA 官方现在有明确的 TTS 模型和文档体系,包括:

  • Magpie TTS Multilingual
  • Magpie TTS Zeroshot
  • Magpie TTS Flow

其中最适合直接拿来做文本转语音的是:

Magpie TTS Multilingual

它支持多语言,官方文档里明确包含:

  • English
  • Spanish
  • French
  • German
  • Mandarin
  • Vietnamese
  • Italian

而且支持多 voice、部分 voice 的情绪变体。

重点是:

它的官方调用示例,不是你以为的简单 REST /audio/speech,而是基于 Riva Python Client / gRPC 的方式。

这也是很多人第一次测不通的根源。


二、为什么很多人会误判“这把 key 不能做 TTS”

我一开始也先走了一个很自然的验证路径:

尝试访问类似下面这些 endpoint:

  • /v1/audio/generation
  • /v1/audio/speech
  • /v1/tts
  • /v1/speech/synthesis
  • /v1/riva/tts

结果几乎都是 404

如果到这里就停下,很容易得出一个错误结论:

“这把 NVIDIA API Key 只能画图,不能生成语音。”

但后来查了 NVIDIA 官方文档和 build 页面后就会发现:

不是没有 TTS,而是你走错了入口。

真正该走的是:

  • grpc.nvcf.nvidia.com:443
  • function-id
  • Bearer $NVIDIA_API_KEY
  • 用 Riva Python Client 去调用 talk.py

也就是说:

同样是 NVIDIA API Key,图像和 TTS 的接入方式属于两条不同的产品路径。


三、图像生成怎么接:最简单的可落地方案

我这边图像生成用的是一个本地脚本:

python3 skills/nvidia-nim/scripts/generate_image.py \
  --prompt "A scenic view of Shenzhen, China, modern skyline..." \
  --negative-prompt "blurry, low quality, distorted" \
  --steps 30 \
  --output ./out.jpg

它底层做的事其实不复杂:

  1. 从参数或环境变量读取 NVIDIA_API_KEY
  2. 向 SD3 Medium 接口发 POST 请求
  3. 读取返回的 base64 图片
  4. 落盘到本地文件

核心实现可以概括成:

payload = {
  'prompt': prompt,
  'negative_prompt': negative_prompt,
  'steps': steps,
}

curl -X POST \
  https://ai.api.nvidia.com/v1/genai/stabilityai/stable-diffusion-3-medium \
  -H "Authorization: Bearer $NVIDIA_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '<payload>'

一个容易踩的坑

虽然脚本暴露了这些参数:

  • cfg_scale
  • width
  • height

但这个模型实际支持的关键字段主要是:

  • prompt
  • negative_prompt
  • seed
  • steps

也就是说,Stable Diffusion 3 Medium 在这条 NVIDIA 接口上,并不是你传什么尺寸都能生效。

这个点如果不写清楚,后面排查“为什么尺寸没变”会很浪费时间。


四、TTS 怎么接:一定要按官方示例来

1. 安装官方 Python client

官方示例依赖:

pip install -U nvidia-riva-client

以及官方仓库里的 python-clients

git clone https://github.com/nvidia-riva/python-clients.git

2. 官方关键调用方式

这次实测真正跑通的命令,本质上是:

python python-clients/scripts/tts/talk.py \
  --server grpc.nvcf.nvidia.com:443 --use-ssl \
  --metadata function-id "877104f7-e885-42b9-8de8-f6e4c6303969" \
  --metadata authorization "Bearer $NVIDIA_API_KEY" \
  --language-code zh-CN \
  --text "你好,这是一条测试语音。" \
  --voice "Magpie-Multilingual.ZH-CN.Siwei" \
  --output audio.wav

这里最重要的是三个点:

A. server 不是普通 REST endpoint

而是:

grpc.nvcf.nvidia.com:443
B. 必须带 function-id

这条 Magpie multilingual TTS 的 function-id,在我这次实测里用的是:

877104f7-e885-42b9-8de8-f6e4c6303969
C. 需要按 Riva client 的参数格式传 metadata

也就是:

--metadata function-id "..."
--metadata authorization "Bearer $NVIDIA_API_KEY"

3. 先 list voices,再决定用哪个 voice

这是一个很好的习惯。

先跑:

python python-clients/scripts/tts/talk.py \
  --server grpc.nvcf.nvidia.com:443 --use-ssl \
  --metadata function-id "877104f7-e885-42b9-8de8-f6e4c6303969" \
  --metadata authorization "Bearer $NVIDIA_API_KEY" \
  --list-voices

我本地实际列出了很多 voice,其中中文可直接用的就包括:

  • Magpie-Multilingual.ZH-CN.Siwei
  • Magpie-Multilingual.ZH-CN.HouZhen
  • 以及一些跨语言 voice 在 zh-CN 下的映射项

这一步的意义很大:

不要先拍脑袋猜 voice name。先 list,再写死。


五、如果你要接 Feishu 语音气泡,还差一步格式转换

到这里,NVIDIA 已经能生成语音了,但它输出的是 .wav

问题是:

Feishu 想要“直接在聊天里点开播放”的效果,不是随便发个文件就行。

你要的是:

  • 音频先转成合适格式(我这里用 .opus
  • 再走 Feishu 的 audio message 接口
  • msg_type 必须是 audio

1. 先转 Opus

我这边用的是:

ffmpeg -i input.wav -c:a libopus -b:a 32k -ar 24000 -ac 1 output.opus

为什么这么做? 因为这条链路对 Feishu 语音气泡比较稳,体积也小。

2. 再调用 Feishu audio API

这一步我本地封装成了一个 Python 脚本。它做的事情包括:

  1. 从 OpenClaw config 读取 Feishu app 凭据
  2. 获取 tenant access token
  3. 上传 opus 文件
  4. file_key 作为 msg_type=audio 发给目标用户

这一步和 OpenClaw 自带 tts 的差别是:

OpenClaw 内置 tts 发出去更像普通音频文件;而这条链路能发成真正的 Feishu 语音气泡。


六、把它封装成一条可复用的命令,才是真正落地

如果只是“偶尔试一下”,你可能手动敲命令也无所谓。

但如果你想把它变成一个 daily-use capability,就不能停在 demo 阶段。

我最后做的,是把它封装成一个 shell shortcut:

bash skills/nvidia-feishu-voice-shortcut/scripts/send-nvidia-feishu-voice.sh \
  --text "这是一条测试语音" \
  --to <feishu_open_id>

它内部串了 3 个步骤:

  1. skills/nvidia-nim/.env 读取 NVIDIA_API_KEY
  2. 用 NVIDIA 官方 talk.py 生成 .wav
  3. ffmpeg.opus
  4. 用 Feishu API 发送成语音气泡

这样以后你就不需要每次都记住:

  • gRPC server 地址
  • function-id
  • 输出格式
  • Feishu 上传流程

工程上真正省时间的,不是“知道原理”,而是:

把正确路径封装成一个稳定入口。


七、这套方案里最容易踩的坑

1. 把 TTS 当 REST API 去撞

这是最大坑。

NVIDIA 有 TTS,但不代表你随手猜一个 /v1/audio/speech 就能通。

2. 到处散落 API key

这一点我非常建议做清理。

最稳的做法是:

  • 只保留一个 canonical secret store
  • 例如:skills/nvidia-nim/.env
  • 其他脚本统一从环境变量或这个 .env
  • 不要把真实 key 硬编码进脚本和 README

否则以后维护时会非常混乱,也有安全风险。

3. 图像和语音混用同一套调用思维

虽然它们都叫 NVIDIA API,但:

  • 图像 = 直接 HTTP 图像生成
  • 语音 = Speech NIM / Riva client / gRPC metadata

不要把一条链路的经验直接套到另一条链路上。

4. 忽略目标平台的媒体格式要求

即使语音已经生成成功,发到目标平台时也可能仍然不对。

例如 Feishu 这边,你需要关注:

  • 编码格式
  • duration
  • 上传类型
  • 消息类型是不是 audio

否则用户看到的可能只是一个附件,而不是可直接播放的语音气泡。


八、我对这套方案的判断

如果你问我,这套方案值不值得做,我的答案是:

值得,但前提是你把它做成 workflow,而不是停留在单次试验。

为什么? 因为单次 demo 的价值很有限,真正有价值的是下面这些能力:

  • 一句话生成一张图
  • 一句话生成一条语音
  • 语音能直接投递到 Feishu / IM / workflow
  • image 和 TTS 共用同一套 secret management
  • 出错时你知道该查哪一层

这时候它才从“玩具”变成“能力”。


九、结语

这次实测之后,我对 NVIDIA 这套能力的感受是:

图像生成这条线,接入门槛很低;语音生成这条线,能力是有的,但必须尊重官方的调用范式。

所以最值得记住的不是某条命令,而是下面这句话:

同一个 NVIDIA API Key 可以同时做图像和语音,但图像走 REST,TTS 走 Riva / Speech NIM 官方路径,不能混着猜。

如果你把这条认知建立起来,再把它封装成自己的脚本和 shortcut,后面无论是画图、做语音,还是接到企业消息系统里,都会顺很多。

真正难的从来不是“API 能不能调通”,而是:

你能不能把一次成功,整理成一条可长期复用的工程路径。