返回 ppt-master
backend_cosyvoice.py
根目录 / skills / ppt-master / scripts / tts_backends / backend_cosyvoice.py
1 """Alibaba CosyVoice backend for narration audio generation."""
2
3 from __future__ import annotations
4
5 import os
6 from pathlib import Path
7
8 from tts_backends.backend_common import download_audio, extension_from_format, post_json, read_api_key
9
10
11 DEFAULT_ENDPOINT = "https://dashscope.aliyuncs.com/api/v1/services/audio/tts/SpeechSynthesizer"
12 DEFAULT_MODEL = "cosyvoice-v3-flash"
13
14
15 def output_extension(audio_format: str) -> str:
16 return extension_from_format(audio_format)
17
18
19 def read_cosyvoice_api_key(env_name: str) -> str:
20 env_names = tuple(dict.fromkeys([env_name, "COSYVOICE_API_KEY", "DASHSCOPE_API_KEY"]))
21 return read_api_key(*env_names, label="CosyVoice/DashScope")
22
23
24 def resolve_url(base_url: str | None = None) -> str:
25 base = (base_url or os.environ.get("COSYVOICE_TTS_BASE_URL") or DEFAULT_ENDPOINT).rstrip("/")
26 if base.endswith("/SpeechSynthesizer"):
27 return base
28 return base + "/api/v1/services/audio/tts/SpeechSynthesizer"
29
30
31 def generate(
32 text: str,
33 output_path: Path,
34 *,
35 api_key: str,
36 voice_id: str,
37 model: str,
38 audio_format: str,
39 sample_rate: int,
40 volume: int | None,
41 rate: float | None,
42 pitch: float | None,
43 instruction: str | None,
44 language_hint: str | None,
45 base_url: str | None,
46 ) -> None:
47 input_payload: dict[str, object] = {
48 "text": text,
49 "voice": voice_id,
50 "format": audio_format,
51 "sample_rate": sample_rate,
52 }
53 if volume is not None:
54 input_payload["volume"] = volume
55 if rate is not None:
56 input_payload["rate"] = rate
57 if pitch is not None:
58 input_payload["pitch"] = pitch
59 if instruction:
60 input_payload["instruction"] = instruction
61 if language_hint:
62 input_payload["language_hints"] = [language_hint]
63
64 data = post_json(
65 resolve_url(base_url),
66 headers={"Authorization": f"Bearer {api_key}"},
67 payload={
68 "model": model,
69 "input": input_payload,
70 },
71 timeout=180,
72 )
73 audio = (data.get("output") or {}).get("audio") or {}
74 audio_url = audio.get("url")
75 if not audio_url:
76 raise RuntimeError(f"CosyVoice response missing audio URL: {data}")
77 download_audio(audio_url, output_path)
78
79
80 def print_voices() -> None:
81 print("CosyVoice voices are selected by voice.")
82 print("Use a system voice name or a cloned/designed voice_id from CosyVoice.")
83 print("Example system voice from Alibaba Cloud docs: longanyang")
84
84 lines PYTHON