mcpField
L
listenhub-voice

listenhub-voice

github.com/marswaveai创意与媒体81162 次安装5 周前更新
代码仓库

关于 listenhub-voice

此 skill 使用 ListenHub-Voice-1.0 将文本或图片生成完整音频。它支持文本描述的音效、单人或多人对白及参考音频克隆,并通过异步任务生成。

主要功能

  1. 01从文本或图片生成音频
  2. 02合成文本描述的音效
  3. 03生成单人或多人对白
  4. 04克隆参考音频中的音色
  5. 05设置音频格式和时长提示

适用场景

  1. 01将脚本转换为含音效的音频
  2. 02用不同参考音色制作对白
  3. 03根据图片生成音频
  4. 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 个端点契约
每个多选步骤都必须使用 AskUserQuestion 工具——不得以纯文本列出选项。每次只提一个问题。等待用户回答后再继续下一步。收集完所有参数后,总结用户的选择并请其确认。在用户明确确认之前,不得调用生成端点。 ## 步骤 -1:CLI 命令门控(ListenHub Voice HTTP 回退)

⚠️ CLI 状态:listenhub-cli 尚未提供 listenhub-voice 子命令。 因此,以下示例均直接使用 curl 调用 OpenAPI HTTP 契约,并通过 Bearer API Key(lh_sk_...)进行身份验证。当 listenhub-voice CLI 子命令推出后,应更新此技能,优先使用该命令(仿照 /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"')
设置流程(仅由用户发起的重新配置)

仅当用户明确要求重新配置时才运行。询问:

  1. 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)

请求体:

字段类型必填说明
modelstring否枚举:仅支持 listenhub-voice-1.0(默认 listenhub-voice-1.0)
textstring是去除首尾空格,最多 1400 个字符;@音频N 前缀用于指定多语音行
voicesarray (1–3)否每个项为 {type} +(id 或 url);见下文。与 image 互斥
imageobject否url 或 data(必须且只能有一个);最多 1 张,≤10MB,jpeg/png/webp。与 voices 互斥
audioConfigobject否speechRate -50..100,loudnessRate -50..100,pitchRate -12..12,format mp3|wav|pcm|ogg_opus(默认 mp3)
durationHintnumber否1..110(目标时长,单位秒,用于估算并作为模型提示)
watermarkboolean否添加水印

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
statuspending → generating → uploading → success | failed
modellistenhub-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

评论

支持 Markdown