关于 listenhub-voice
此 skill 使用 ListenHub-Voice-1.0 将文本或图片生成完整音频。它支持文本描述的音效、单人或多人对白及参考音频克隆,并通过异步任务生成。
主要功能
- 01从文本或图片生成音频
- 02合成文本描述的音效
- 03生成单人或多人对白
- 04克隆参考音频中的音色
- 05设置音频格式和时长提示
适用场景
- 01将脚本转换为含音效的音频
- 02用不同参考音色制作对白
- 03根据图片生成音频
- 04使用参考音频生成语音
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ marswaveai/ skills --skill listenhub-voice安装后在 Claude Code 中输入/listenhub-voice确认已加载。
详细介绍
适用场景
- 用户想根据文本生成端到端音频(模型会将音效融入音频)
- 用户想生成多音色对白,让不同的声音朗读每句台词
- 用户想根据参考音频克隆声音
- 用户想将参考图片转换为音频(图片 → 音频)
- 用户想根据文本描述生成纯音效
- 用户提到“生成音频”、“端到端音频”、“图片转音频”、“多音色对白”、“参考音频克隆”或“音效”
不适用场景
- 用户只想让单个已注册的 ListenHub 音色朗读文本(使用
/tts)—— 对于使用已注册 ListenHub 音色进行纯旁白,/tts延迟更低 - 用户想要围绕主题展开讨论的播客风格内容(使用
/podcast) - 用户想要音乐或翻唱歌曲(使用
/music) - 用户想要视频(使用
/video-gen) - 用户想将音频/视频转录为文本(使用
/asr)
/tts 与 /listenhub-voice 的区别:/listenhub-voice 使用 ListenHub-Voice-1.0 端到端模型,可将文本或图片转换为完整音轨,其中可包含音效、多音色对白和参考音频声音克隆,还可通过可选的 durationHint 指定目标时长。使用已注册 ListenHub 音色进行单人旁白时,仍可使用 /tts。
用途
使用 ListenHub-Voice-1.0 模型生成端到端音频。一个异步任务会接收文本脚本(以及可选的音色、参考图片、音频参数和时长提示),并返回完整的音频文件。支持以下模式:
- 纯文本/音效 — 不传入
voices和image。模型会合成文本及其中描述的任何音效。 - 单人声 —
voices包含 1 项,可以是已注册的 ListenHub 说话人/官方voice_type(type: speaker),也可以是参考音频克隆(type: reference)。 - 多音色对白 —
voices包含 2–3 项;脚本需按voices数组中的顺序,为每句台词添加@音频1/@音频2前缀。多音色请求中的每一项都必须支持参考音频;官方voice_type仅支持单人声。 - 参考音频克隆 —
voices中包含type: reference项,并指向用于克隆声音的公开音频 URL。 - 图片 → 音频 — 传入
image(url 或 data)。不能与voices同时使用。
硬性约束
- 始终按照
shared/cli-authentication.md检查 CLI 身份验证 - 按照
shared/cli-patterns.md处理 CLI 执行、错误和交互模式 - 进行任何交互前,始终按照
shared/config-pattern.md读取配置 - 按照
shared/output-mode.md呈现结果——download模式会将{slug}.{ext}(ext =audioConfig.format:默认为mp3,也可以是wav/pcm/ogg_opus)保存到当前工作目录,并按照shared/config-pattern.md§ Artifact Naming 避免文件名重复 - 始终使用异步模式:提交请求后会返回
taskId,然后轮询任务端点,直到状态为success/failed——绝不能阻塞等待单次调用完成 image和voices不能同时使用——绝不能在同一个请求中同时发送- 多音色请求(
voices长度 > 1)中的每一项都必须支持参考音频;官方voice_type(type: speaker)仅支持单人声,在多音色请求中会被拒绝 - 绝不公开提供方路由信息、凭据、内部状态名称、DAO、MongoDB 或回调内部信息;仅使用下方公开的 3 个端点契约
⚠️ CLI 状态:
listenhub-cli尚未提供listenhub-voice子命令。 因此,以下示例均直接使用curl调用 OpenAPI HTTP 契约,并通过 Bearer API Key(lh_sk_...)进行身份验证。当listenhub-voiceCLI 子命令推出后,应更新此技能,优先使用该命令(仿照/video-gen的$CMD_PREFIX模式)。
检测未来的 CLI 子命令是否存在;如果不存在,则回退到 HTTP:
if listenhub listenhub-voice --help &>/dev/null; then
LISTENHUB_VOICE_MODE="cli"
else
echo "LISTENHUB_VOICE_COMMAND_UNAVAILABLE — falling back to OpenAPI HTTP (curl)"
LISTENHUB_VOICE_MODE="http"
fi
对于 http 模式,需要 OpenAPI API Key。从配置或环境变量中读取:
API_BASE="https://api.marswave.ai/openapi" # OpenAPI base; see shared/cli-authentication.md
API_KEY="${LISTENHUB_API_KEY:-$(listenhub openapi config show --json 2>/dev/null | jq -r '.apiKey // empty')}"
if [ -z "$API_KEY" ]; then
echo "需要 OpenAPI API Key(lh_sk_...)。请先用 listenhub openapi config set-key 配置,或设置 LISTENHUB_API_KEY 环境变量。"
fi
所有请求均通过 Authorization: Bearer $API_KEY 进行身份验证。
步骤 0:配置设置
遵循 shared/config-pattern.md 步骤 0(零问题启动)。
如果文件不存在——静默使用默认值创建文件并继续:
mkdir -p ".listenhub/listenhub-voice"
echo '{"outputMode":"inline"}' > ".listenhub/listenhub-voice/config.json"
CONFIG_PATH=".listenhub/listenhub-voice/config.json"
CONFIG=$(cat "$CONFIG_PATH")
会话默认值(除非用户重新配置,否则不会持久化):
- model:
listenhub-voice-1.0(唯一有效值) - audioConfig.format:
mp3
不要询问任何设置问题。 直接进入交互流程。
如果文件存在——静默读取配置并继续:
CONFIG_PATH=".listenhub/listenhub-voice/config.json"
[ ! -f "$CONFIG_PATH" ] && CONFIG_PATH="$HOME/.listenhub/listenhub-voice/config.json"
CONFIG=$(cat "$CONFIG_PATH")
OUTPUT_MODE=$(echo "$CONFIG" | jq -r '.outputMode // "inline"')
设置流程(仅由用户发起的重新配置)
仅当用户明确要求重新配置时才运行。询问:
- outputMode:遵循
shared/output-mode.md§ 设置流程问题。
立即保存:
NEW_CONFIG=$(echo "$CONFIG" | jq --arg m "$OUTPUT_MODE" '. + {"outputMode": $m}')
echo "$NEW_CONFIG" > "$CONFIG_PATH"
CONFIG=$(cat "$CONFIG_PATH")
交互流程
步骤 1:收集文本
询问用户要合成的脚本/文本(必填,≤ 1400 个字符,去除首尾空白):
输入要合成的文本(≤1400 字)。需要音效就直接在文本里描述;多音色对白用
@音频1/@音频2前缀指派每行台词。
自由文本。按原样使用——除非用户要求协助,否则不要修改。
步骤 2:音色/输入模式
Question: "音频用什么音色 / 输入方式?"
Options:
- "无音色(纯文本 / 音效)" — No voices, no image → Step 3 (audio params)
- "单个 ListenHub 音色" — voices=[{type:speaker, id:<ListenHub 代号>}] → Step 2a
- "单个官方 voice_type" — voices=[{type:speaker, id:<voice_type>}] → Step 2a
- "多音色对白(参考音频)" — voices=2–3 项,每项 type:reference → Step 2b
- "参考音频克隆(单条)" — voices=[{type:reference, url:...}] → Step 2b
- "图片 → 音频" — image (与 voices 互斥) → Step 2c
步骤 2a:单个已注册音色(type: speaker)
收集一个发言人 id:
- ListenHub 音色代码——通过
GET /v1/speakers/list获取(已注册的 ListenHub 发言人)。遵循shared/speaker-selection.md,让用户选择。 - 官方
voice_type——例如zh_female_vv_uranus_bigtts。如果用户已知道voice_type,则直接使用;服务器会自动识别 ListenHub 代码或官方代码。
构建:voices = [{ "type": "speaker", "id": "<id>" }]。继续步骤 3。
注意:官方
voice_type仅支持单音色——不能用于多音色(>1 项)请求。
步骤 2b:参考音频(type: reference)
每个参考项都需要一个公开音频 URL(http/https):
- 时长 ≤ 30 秒,大小 ≤ 10MB,格式为
wav/mp3/pcm/ogg_opus
对于单片段克隆:收集一个 URL → voices = [{ "type": "reference", "url": "..." }]。
对于多音色对话:收集 2–3 个参考 URL(音色总数最多为 3)。每一项
都必须是参考音频(也可以混用 ListenHub 发言人和参考音频——但不能使用
官方 voice_type)。然后指示用户在 text 中每行脚本前加上
@音频1 / @音频2 / @音频3,与 voices 数组的顺序对应(@音频1 = voices[0])。
例如,构建:
"voices": [
{ "type": "reference", "url": "https://example.com/host.mp3" },
{ "type": "reference", "url": "https://example.com/guest.mp3" }
]
继续步骤 3。
步骤 2c:图片 → 音频(image,与 voices 互斥)
收集一张图片,可以是公开 URL 或 Base64(任选一种,不能同时使用):
- 最多 1 张图片,大小 ≤ 10MB,格式为
jpeg/png/webp
构建:image = { "url": "https://..." } 或 image = { "data": "<base64>" }。
此模式下不要发送 voices。继续步骤 3。
步骤 3:可选音频参数
Question: "要调整音频参数吗?(默认:格式 mp3,语速/音量/音调不变)"
Options:
- "用默认,跳过" — Skip, audioConfig omitted (server uses format mp3)
- "我要调整" — Ask each below
如果需要调整,逐项询问(均为可选项,用户未设置的参数应省略):
- format:
mp3(默认) /wav/pcm/ogg_opus - speechRate(语速):-50 .. 100 之间的整数
- loudnessRate(音量):-50 .. 100 之间的整数
- pitchRate(音调):-12 .. 12 之间的整数
仅使用用户设置的字段构建 audioConfig。
步骤 4:可选时长提示
Question: "要指定目标时长吗?(用于积分预估并提示模型生成「约 N 秒」)"
Options:
- "不指定" — Omit durationHint
- "指定秒数" — Collect an integer in 1 .. 110
步骤 5:费用说明 + 确认
计费:按实际生成时长(秒)计费,0.1125 积分/秒,向上取整,最低 1 积分。 创建时只检查余额,不预扣费用;音频生成后按实际时长结算。
durationHint可用于粗略估算 (约为ceil(durationHint × 0.1125)积分,实际以音频生成时长为准)。 限流:60 秒内最多生成 5 次。
提供摘要,并在调用 generate 前等待用户明确确认:
准备生成音频:
文本: {text 摘要}
模式: {纯文本/音效 | 单音色(ListenHub/官方) | 多音色对白 | 参考音频克隆 | 图片→音频}
voices: {无 | N 项}
image: {无 | url/data}
audioConfig: {默认 mp3 | 调整后的字段}
durationHint: {无 | N 秒}
预估: 约 {ceil(durationHint×0.1125) or "未指定时长,无预估"} 积分(按实结算)
确认生成?
执行与轮询
提交(POST /v1/listenhub-voice/generate → 202)
根据收集到的值构建 JSON 请求体,然后发送 POST 请求。响应状态码为 202,包含
data.taskId 和 data.status = "pending"。
BODY=$(jq -n \
--arg text "$TEXT" \
'{ model: "listenhub-voice-1.0", text: $text }')
# Add voices / image / audioConfig / durationHint / watermark only if set, e.g.:
# BODY=$(echo "$BODY" | jq --argjson v "$VOICES_JSON" '. + {voices: $v}')
# BODY=$(echo "$BODY" | jq --argjson img "$IMAGE_JSON" '. + {image: $img}')
# BODY=$(echo "$BODY" | jq --argjson ac "$AUDIOCONFIG_JSON" '. + {audioConfig: $ac}')
# BODY=$(echo "$BODY" | jq --argjson dh "$DURATION_HINT" '. + {durationHint: $dh}')
RESP=$(curl -sS -X POST "$API_BASE/v1/listenhub-voice/generate" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "$BODY")
TASK_ID=$(echo "$RESP" | jq -r '.data.taskId // empty')
如果 TASK_ID 为空,则显示业务错误(data 中包含 33xxx 错误代码,参见
错误处理)。否则显示:“任务已提交,ID: {TASK_ID},正在生成中…”
轮询(GET /v1/listenhub-voice/tasks/{taskId})
使用 run_in_background: true 运行。持续轮询,直到状态为 success / failed:
for i in $(seq 1 120); do
RESULT=$(curl -sS "$API_BASE/v1/listenhub-voice/tasks/$TASK_ID" \
-H "Authorization: Bearer $API_KEY" | jq -c '.data')
STATUS=$(echo "$RESULT" | jq -r '.status')
case "$STATUS" in
success) echo "$RESULT"; exit 0 ;;
failed) echo "FAILED: $RESULT" >&2; exit 1 ;;
*) sleep 5 ;;
esac
done
echo "TIMEOUT" >&2; exit 2
状态流转:pending → generating → uploading → success | failed。
(仅有这 5 种公开状态,不要假定存在其他内部状态。)
结果展示
状态为 success 时,解析 ListenHubVoiceTask:
AUDIO_URL=$(echo "$RESULT" | jq -r '.audioUrl')
AUDIO_DURATION=$(echo "$RESULT" | jq -r '.audioDuration')
CREDIT_CHARGED=$(echo "$RESULT" | jq -r '.creditCharged')
从配置中读取 OUTPUT_MODE,并遵循 shared/output-mode.md。
inline 或 both — 显示:
音频已生成!
URL: {audioUrl}
时长: {audioDuration}s(即计费时长)
消耗: {creditCharged} 积分
download 或 both — 根据主题生成 slug,并保存到当前工作目录,遵循
shared/config-pattern.md § 工件命名(扩展名 = 所选的 format,默认为 mp3):
SLUG="{topic-slug}"
EXT="${FORMAT:-mp3}"
NAME="${SLUG}.${EXT}"
BASE="${NAME%.*}"; i=2
while [ -e "$NAME" ]; do NAME="${BASE}-${i}.${EXT}"; i=$((i+1)); done
curl -sS -o "$NAME" "$AUDIO_URL"
echo "已保存到当前目录:$NAME"
状态为 failed 时:读取 errorMessage(仅失败时存在)并显示;建议检查
脚本 / 语音 / 图片后重试。
超时时:告知用户稍后通过
GET /v1/listenhub-voice/tasks/{taskId} 查询。
查询历史任务
列出最近的任务(分页,最新的排在前面):
# List (page/pageSize/status/keyword all optional)
curl -sS "$API_BASE/v1/listenhub-voice/tasks?page=1&pageSize=20" \
-H "Authorization: Bearer $API_KEY" | jq '.data'
# Filter by status + fuzzy keyword on the script text (keyword ≤ 64 chars)
curl -sS "$API_BASE/v1/listenhub-voice/tasks?status=success&keyword=对白" \
-H "Authorization: Bearer $API_KEY" | jq '.data.items'
# Get one task
curl -sS "$API_BASE/v1/listenhub-voice/tasks/$TASK_ID" \
-H "Authorization: Bearer $API_KEY" | jq '.data'
列表响应中的 data:{ items: [ListenHubVoiceTask], page, pageSize, total }。
status 筛选条件接受 pending | generating | uploading | success | failed。
API 契约(3 个公开端点)
所有端点都需要 Authorization: Bearer lh_sk_...。
POST /v1/listenhub-voice/generate(异步,返回 202)
请求体:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 否 | 枚举:仅支持 listenhub-voice-1.0(默认 listenhub-voice-1.0) |
text | string | 是 | 去除首尾空格,最多 1400 个字符;@音频N 前缀用于指定多语音行 |
voices | array (1–3) | 否 | 每个项为 {type} +(id 或 url);见下文。与 image 互斥 |
image | object | 否 | url 或 data(必须且只能有一个);最多 1 张,≤10MB,jpeg/png/webp。与 voices 互斥 |
audioConfig | object | 否 | speechRate -50..100,loudnessRate -50..100,pitchRate -12..12,format mp3|wav|pcm|ogg_opus(默认 mp3) |
durationHint | number | 否 | 1..110(目标时长,单位秒,用于估算并作为模型提示) |
watermark | boolean | 否 | 添加水印 |
voices[] 项:
{ "type": "speaker", "id": "<code>" }— 必须提供id。ListenHub 语音代码 (来自GET /v1/speakers/list)或官方voice_type。服务器会自动检测。{ "type": "reference", "url": "<http(s) url>" }— 必须提供url。公开音频, ≤30s,≤10MB,wav/mp3/pcm/ogg_opus。- 多语音(超过 1 项):每项都必须支持参考音频;官方
voice_type仅支持单语音。
响应 202:{ data: { taskId, status: "pending" } }。
计费:按实际时长每秒 0.1125 积分(向上取整,最低 1)。限流:每 60 秒最多 5 次。
GET /v1/listenhub-voice/tasks(列出任务,最新的排在前面)
查询参数:page(默认 1)、pageSize(默认 20,最大 100)、
status(pending|generating|uploading|success|failed)、keyword(≤64,模糊匹配脚本文本)。
响应中的 data:{ items: [ListenHubVoiceTask], page, pageSize, total }。
GET /v1/listenhub-voice/tasks/{taskId}(详情,仅限本人任务)
响应中的 data:单个 ListenHubVoiceTask。
ListenHubVoiceTask(列表项和详情使用相同契约)
| 字段 | 说明 |
|---|---|
id | 任务 ID |
status | pending → generating → uploading → success | failed |
model | listenhub-voice-1.0 |
params | 已清理的输入参数(不含音频/图片二进制数据) |
audioUrl | 输出音频 URL — 仅在 success 时存在 |
audioDuration | 输出时长,单位为秒 = 计费时长 |
creditCharged | 实际扣除的积分(0 = 未扣除) |
creditRefunded | 失败时退还的积分(仅用于对账) |
errorMessage | 失败原因 — 仅在 failed 时存在 |
createdAt / updatedAt | 毫秒级时间戳 |
此技能有意不涵盖以下端点:
/v1/listenhub-voice/voices和/v1/listenhub-voice/estimate-credits。如需获取voices[].id对应的 ListenHub 音色代码, 请使用GET /v1/speakers/list。
错误处理
标准 HTTP/CLI 错误语义,以及 data 负载中的业务错误:
| 代码 | 含义 | 操作 |
|---|---|---|
| 0 | 成功 | 解析 JSON 输出 |
| 1 | 一般错误 | 向用户显示 stderr / 响应正文 |
| 2 | 身份验证错误 | 通过 listenhub openapi config show 或 LISTENHUB_API_KEY 检查 API Key(lh_sk_...) |
| 3 | 超时 | 建议稍后检查任务状态 |
生成请求返回 400 时,data 中会包含业务错误(积分不足、速率限制、验证失败等)——按照 shared/cli-patterns.md 中的说明展示 33xxx 业务错误代码。
组合使用
| 方向 | 说明 |
|---|---|
listenhub 路由器 → listenhub-voice | 用户通过 /listenhub 提及端到端音频 / 音效 / 多音色对白 / 图片转音频时进行路由 |
listenhub-cli 路由器 → listenhub-voice | 通过 /listenhub-cli 进行相同的路由 |
speakers (/v1/speakers/list) → listenhub-voice | 提供 voices[].id 对应的 ListenHub 音色代码(type: speaker) |
listenhub-voice →(无) | 独立的终端技能,无下游依赖 |
示例
所有示例均使用 -H "Authorization: Bearer lh_sk_..." 进行身份验证(为简洁起见,以下省略)。
单音色旁白(已注册音色)
“用这个 ListenHub 音色把这段文本读出来”
curl -sS -X POST "$API_BASE/v1/listenhub-voice/generate" \
-H "Content-Type: application/json" \
-d '{
"model": "listenhub-voice-1.0",
"text": "欢迎收听今天的节目。",
"voices": [{ "type": "speaker", "id": "<listenhub-voice-code>" }]
}'
参考音频克隆
“用这段参考音频的音色来念”
curl -sS -X POST "$API_BASE/v1/listenhub-voice/generate" \
-H "Content-Type: application/json" \
-d '{
"model": "listenhub-voice-1.0",
"text": "这是用参考音频克隆出来的声音。",
"voices": [{ "type": "reference", "url": "https://example.com/voice.mp3" }]
}'
多音色对白(@音频N)
“做一段两个人的对白”
curl -sS -X POST "$API_BASE/v1/listenhub-voice/generate" \
-H "Content-Type: application/json" \
-d '{
"model": "listenhub-voice-1.0",
"text": "@音频1 你今天怎么样?\n@音频2 还不错,刚录完一集播客。",
"voices": [
{ "type": "reference", "url": "https://example.com/host.mp3" },
{ "type": "reference", "url": "https://example.com/guest.mp3" }
]
}'
图片 → 音频
“根据这张图片生成一段音频”
curl -sS -X POST "$API_BASE/v1/listenhub-voice/generate" \
-H "Content-Type: application/json" \
-d '{
"model": "listenhub-voice-1.0",
"text": "为这张图片配一段氛围音频。",
"image": { "url": "https://example.com/scene.jpg" }
}'
纯音效
“生成一段下雨打雷的音效”
curl -sS -X POST "$API_BASE/v1/listenhub-voice/generate" \
-H "Content-Type: application/json" \
-d '{
"model": "listenhub-voice-1.0",
"text": "持续的中雨声,远处偶尔有雷声滚过,约 15 秒。",
"durationHint": 15,
"audioConfig": { "format": "mp3" }
}'
API 参考
- CLI 身份验证:
shared/cli-authentication.md - CLI 执行模式:
shared/cli-patterns.md - 配置模式:
shared/config-pattern.md - 输出模式:
shared/output-mode.md - 音色选择(ListenHub 音色代码):
shared/speaker-selection.md