feat(voice): switch TTS to Seed 2.0 uranus voices

Use classic male/female and sunny-sweet speakers with seed-tts-2.0 resource id.
This commit is contained in:
Zhengshou Lai
2026-07-26 01:07:06 +08:00
parent d428436fca
commit 8f60860419
3 changed files with 28 additions and 16 deletions
+2 -2
View File
@@ -68,10 +68,10 @@ mytoolkit env export # 导出为 shell export 语句
```bash ```bash
mytoolkit voice tts "你好,世界" mytoolkit voice tts "你好,世界"
mytoolkit voice tts -f script.txt mytoolkit voice tts -f script.txt
mytoolkit voice tts "文本" -v zh_male_wennuanahu_moon_bigtts --format mp3 --speed 10 -o output.mp3 mytoolkit voice tts "文本" -v zh_female_xiaohe_uranus_bigtts --format mp3 --speed 10 -o output.mp3
``` ```
可用音色:`zh_female_cancan_mars_bigtts``zh_female_shuangkuaisisi_moon_bigtts``zh_male_wennuanahu_moon_bigtts`(默认)、`zh_male_sunwukong_moon_bigtts` 可用音色:`zh_male_m191_uranus_bigtts`(经典男声)`zh_female_xiaohe_uranus_bigtts`经典女声,默认)、`ICL_uranus_zh_female_yuanqitianmei_tob`(阳光甜妹)
格式:`mp3`(默认)、`wav``pcm` 格式:`mp3`(默认)、`wav``pcm`
+19 -7
View File
@@ -5,24 +5,36 @@ import json
import uuid import uuid
from pathlib import Path from pathlib import Path
_RESOURCE_ID = "volc.service_type.10029" # TTS 1.0 (moon/mars) vs 2.0 (uranus / ICL_uranus)
_RESOURCE_TTS_1 = "volc.service_type.10029"
_RESOURCE_TTS_2 = "seed-tts-2.0"
_ENDPOINT = "wss://openspeech.bytedance.com/api/v3/tts/unidirectional/stream" _ENDPOINT = "wss://openspeech.bytedance.com/api/v3/tts/unidirectional/stream"
# Product labels: 经典男声 / 经典女声 / 阳光甜妹
_VOICE_CHOICES = [ _VOICE_CHOICES = [
"zh_female_cancan_mars_bigtts", "zh_male_m191_uranus_bigtts",
"zh_female_shuangkuaisisi_moon_bigtts", "zh_female_xiaohe_uranus_bigtts",
"zh_male_wennuanahu_moon_bigtts", "ICL_uranus_zh_female_yuanqitianmei_tob",
"zh_male_sunwukong_moon_bigtts",
] ]
_DEFAULT_VOICE = "zh_female_xiaohe_uranus_bigtts"
_FORMAT_CHOICES = ["mp3", "wav", "pcm"] _FORMAT_CHOICES = ["mp3", "wav", "pcm"]
def resource_id_for_speaker(speaker: str) -> str:
"""Pick Volcengine resource id for a speaker."""
s = speaker or ""
if "uranus" in s or s.startswith("ICL_uranus_"):
return _RESOURCE_TTS_2
return _RESOURCE_TTS_1
def synthesize_tts( def synthesize_tts(
appid: str, appid: str,
token: str, token: str,
text: str, text: str,
speaker: str = "zh_male_wennuanahu_moon_bigtts", speaker: str = _DEFAULT_VOICE,
fmt: str = "mp3", fmt: str = "mp3",
speech_rate: int = 0, speech_rate: int = 0,
output_path: str = "output.mp3", output_path: str = "output.mp3",
@@ -42,7 +54,7 @@ def synthesize_tts(
headers = { headers = {
"X-Api-App-Id": appid, "X-Api-App-Id": appid,
"X-Api-Access-Key": token, "X-Api-Access-Key": token,
"X-Api-Resource-Id": _RESOURCE_ID, "X-Api-Resource-Id": resource_id_for_speaker(speaker),
"X-Api-Connect-Id": str(uuid.uuid4()), "X-Api-Connect-Id": str(uuid.uuid4()),
} }
+7 -7
View File
@@ -13,11 +13,11 @@ from mytoolkit.config import config
from mytoolkit.utils import handle_errors from mytoolkit.utils import handle_errors
_VOICE_CHOICES = [ _VOICE_CHOICES = [
"zh_female_cancan_mars_bigtts", "zh_male_m191_uranus_bigtts", # 经典男声 (云舟 2.0)
"zh_female_shuangkuaisisi_moon_bigtts", "zh_female_xiaohe_uranus_bigtts", # 经典女声 (小何 2.0)
"zh_male_wennuanahu_moon_bigtts", "ICL_uranus_zh_female_yuanqitianmei_tob", # 阳光甜妹 (元气甜妹 2.0)
"zh_male_sunwukong_moon_bigtts",
] ]
_DEFAULT_VOICE = "zh_female_xiaohe_uranus_bigtts"
_FORMAT_CHOICES = ["mp3", "wav", "pcm"] _FORMAT_CHOICES = ["mp3", "wav", "pcm"]
@@ -73,7 +73,7 @@ def voice():
"--voice", "--voice",
"speaker", "speaker",
type=click.Choice(_VOICE_CHOICES), type=click.Choice(_VOICE_CHOICES),
default="zh_male_wennuanahu_moon_bigtts", default=_DEFAULT_VOICE,
help="音色", help="音色",
) )
@click.option("--format", "fmt", type=click.Choice(_FORMAT_CHOICES), default="mp3", help="输出格式") @click.option("--format", "fmt", type=click.Choice(_FORMAT_CHOICES), default="mp3", help="输出格式")
@@ -185,7 +185,7 @@ def _natural_sort_key(path: Path):
@voice.command("tts-batch") @voice.command("tts-batch")
@click.argument("text_dir", type=click.Path(exists=True, file_okay=False)) @click.argument("text_dir", type=click.Path(exists=True, file_okay=False))
@click.option("--voice", "speaker", type=click.Choice(_VOICE_CHOICES), default="zh_male_wennuanahu_moon_bigtts") @click.option("--voice", "speaker", type=click.Choice(_VOICE_CHOICES), default=_DEFAULT_VOICE)
@click.option("--output-dir", "-o", type=click.Path(), help="输出目录(默认与输入相同)") @click.option("--output-dir", "-o", type=click.Path(), help="输出目录(默认与输入相同)")
@click.option("--format", "fmt", type=click.Choice(_FORMAT_CHOICES), default="mp3") @click.option("--format", "fmt", type=click.Choice(_FORMAT_CHOICES), default="mp3")
@handle_errors @handle_errors
@@ -213,7 +213,7 @@ def tts_batch_cmd(text_dir, speaker, output_dir, fmt):
@voice.command("tts-script") @voice.command("tts-script")
@click.argument("script", type=click.Path(exists=True)) @click.argument("script", type=click.Path(exists=True))
@click.option("--output-dir", "-o", type=click.Path(), default="audio") @click.option("--output-dir", "-o", type=click.Path(), default="audio")
@click.option("--voice", "speaker", type=click.Choice(_VOICE_CHOICES), default="zh_male_wennuanahu_moon_bigtts") @click.option("--voice", "speaker", type=click.Choice(_VOICE_CHOICES), default=_DEFAULT_VOICE)
@click.option("--prefix", "-p", default="page") @click.option("--prefix", "-p", default="page")
@click.option("--zero-pad", "-z", type=int, default=2) @click.option("--zero-pad", "-z", type=int, default=2)
@click.option("--format", "fmt", type=click.Choice(_FORMAT_CHOICES), default="mp3") @click.option("--format", "fmt", type=click.Choice(_FORMAT_CHOICES), default="mp3")