76 lines
2.2 KiB
Python
76 lines
2.2 KiB
Python
"""Alibaba Qwen TTS backend for narration audio generation."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from tts_backends.backend_common import download_audio, post_json, read_api_key
|
|
|
|
|
|
DEFAULT_ENDPOINT = "https://dashscope-intl.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
|
|
DEFAULT_MODEL = "qwen3-tts-flash"
|
|
|
|
|
|
def output_extension() -> str:
|
|
return ".wav"
|
|
|
|
|
|
def read_qwen_api_key(env_name: str | None = None) -> str:
|
|
if env_name:
|
|
return read_api_key(env_name, label="Qwen/DashScope")
|
|
return read_api_key("QWEN_API_KEY", "DASHSCOPE_API_KEY", label="Qwen/DashScope")
|
|
|
|
|
|
def resolve_url(base_url: str | None = None) -> str:
|
|
base = (base_url or os.environ.get("QWEN_TTS_BASE_URL") or DEFAULT_ENDPOINT).rstrip("/")
|
|
if base.endswith("/generation"):
|
|
return base
|
|
return base + "/api/v1/services/aigc/multimodal-generation/generation"
|
|
|
|
|
|
def generate(
|
|
text: str,
|
|
output_path: Path,
|
|
*,
|
|
api_key: str,
|
|
voice_id: str,
|
|
model: str,
|
|
language_type: str,
|
|
instructions: str | None,
|
|
optimize_instructions: bool | None,
|
|
base_url: str | None,
|
|
) -> None:
|
|
input_payload: dict[str, object] = {
|
|
"text": text,
|
|
"voice": voice_id,
|
|
}
|
|
if language_type:
|
|
input_payload["language_type"] = language_type
|
|
if instructions:
|
|
input_payload["instructions"] = instructions
|
|
if optimize_instructions is not None:
|
|
input_payload["optimize_instructions"] = optimize_instructions
|
|
|
|
data = post_json(
|
|
resolve_url(base_url),
|
|
headers={"Authorization": f"Bearer {api_key}"},
|
|
payload={
|
|
"model": model,
|
|
"input": input_payload,
|
|
},
|
|
timeout=180,
|
|
)
|
|
audio = (data.get("output") or {}).get("audio") or {}
|
|
audio_url = audio.get("url")
|
|
if not audio_url:
|
|
raise RuntimeError(f"Qwen TTS response missing audio URL: {data}")
|
|
download_audio(audio_url, output_path)
|
|
|
|
|
|
def print_voices() -> None:
|
|
print("Qwen TTS voices are selected by voice.")
|
|
print("Use a system voice name or a cloned voice from Qwen voice cloning.")
|
|
print("Example system voice from Alibaba Cloud docs: Cherry")
|
|
print("Current Qwen TTS responses do not include word/character timestamps.")
|