返回 Pixelle-Video
tts_voices.py
根目录 / pixelle_video / tts_voices.py
1 # Copyright (C) 2025 AIDC-AI
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
12
13 """
14 TTS Voice Configuration
15
16 Defines available voices for local Edge TTS inference.
17 """
18
19 from typing import List, Dict, Any
20
21
22 # Edge TTS voice presets for local inference
23 EDGE_TTS_VOICES: List[Dict[str, Any]] = [
24 # Chinese voices
25 {
26 "id": "zh-CN-XiaoxiaoNeural",
27 "label_key": "tts.voice.zh_CN_XiaoxiaoNeural",
28 "locale": "zh-CN",
29 "gender": "female"
30 },
31 {
32 "id": "zh-CN-XiaoyiNeural",
33 "label_key": "tts.voice.zh_CN_XiaoyiNeural",
34 "locale": "zh-CN",
35 "gender": "female"
36 },
37 {
38 "id": "zh-CN-YunjianNeural",
39 "label_key": "tts.voice.zh_CN_YunjianNeural",
40 "locale": "zh-CN",
41 "gender": "male"
42 },
43 {
44 "id": "zh-CN-YunxiNeural",
45 "label_key": "tts.voice.zh_CN_YunxiNeural",
46 "locale": "zh-CN",
47 "gender": "male"
48 },
49 {
50 "id": "zh-CN-YunyangNeural",
51 "label_key": "tts.voice.zh_CN_YunyangNeural",
52 "locale": "zh-CN",
53 "gender": "male"
54 },
55 {
56 "id": "zh-CN-YunyeNeural",
57 "label_key": "tts.voice.zh_CN_YunyeNeural",
58 "locale": "zh-CN",
59 "gender": "male"
60 },
61 {
62 "id": "zh-CN-YunfengNeural",
63 "label_key": "tts.voice.zh_CN_YunfengNeural",
64 "locale": "zh-CN",
65 "gender": "male"
66 },
67 {
68 "id": "zh-CN-liaoning-XiaobeiNeural",
69 "label_key": "tts.voice.zh_CN_liaoning_XiaobeiNeural",
70 "locale": "zh-CN",
71 "gender": "female"
72 },
73 {
74 "id": "en-US-AriaNeural",
75 "label_key": "tts.voice.en_US_AriaNeural",
76 "locale": "en-US",
77 "gender": "female"
78 },
79 {
80 "id": "en-US-JennyNeural",
81 "label_key": "tts.voice.en_US_JennyNeural",
82 "locale": "en-US",
83 "gender": "female"
84 },
85 {
86 "id": "en-US-GuyNeural",
87 "label_key": "tts.voice.en_US_GuyNeural",
88 "locale": "en-US",
89 "gender": "male"
90 },
91 {
92 "id": "en-US-DavisNeural",
93 "label_key": "tts.voice.en_US_DavisNeural",
94 "locale": "en-US",
95 "gender": "male"
96 },
97 {
98 "id": "en-GB-SoniaNeural",
99 "label_key": "tts.voice.en_GB_SoniaNeural",
100 "locale": "en-GB",
101 "gender": "female"
102 },
103 {
104 "id": "en-GB-RyanNeural",
105 "label_key": "tts.voice.en_GB_RyanNeural",
106 "locale": "en-GB",
107 "gender": "male"
108 },
109 {
110 "id": "ko-KR-InJoonNeural",
111 "label_key": "tts.voice.ko-KR-InJoonNeural",
112 "locale": "ko-KR",
113 "gender": "male"
114 },
115 {
116 "id": "ko-KR-SunHiNeural",
117 "label_key": "tts.voice.ko-KR-SunHiNeural",
118 "locale": "ko-KR",
119 "gender": "female"
120 },
121 {
122 "id": "fr-FR-EloiseNeural",
123 "label_key": "tts.voice.fr-FR-EloiseNeural",
124 "locale": "fr-FR",
125 "gender": "female"
126 },
127 {
128 "id": "fr-FR-HenriNeural",
129 "label_key": "tts.voice.fr-FR-HenriNeural",
130 "locale": "fr-FR",
131 "gender": "male"
132 },
133 {
134 "id": "pt-PT-DuarteNeural",
135 "label_key": "tts.voice.pt-PT-DuarteNeural",
136 "locale": "pt-PT",
137 "gender": "male"
138 },
139 {
140 "id": "pt-PT-RaquelNeural",
141 "label_key": "tts.voice.pt-PT-RaquelNeural",
142 "locale": "pt-PT",
143 "gender": "female"
144 },
145 {
146 "id": "de-DE-AmalaNeural",
147 "label_key": "tts.voice.de-DE-AmalaNeural",
148 "locale": "de-DE",
149 "gender": "female"
150 },
151 {
152 "id": "de-DE-ConradNeural",
153 "label_key": "tts.voice.de-DE-ConradNeural",
154 "locale": "de-DE",
155 "gender": "male"
156 },
157
158 # English voices
159 {
160 "id": "ru-RU-DmitryNeural",
161 "label_key": "tts.voice.ru-RU-DmitryNeural",
162 "locale": "ru-RU",
163 "gender": "male"
164 },
165 {
166 "id": "ru-RU-SvetlanaNeural",
167 "label_key": "tts.voice.ru-RU-SvetlanaNeural",
168 "locale": "ru-RU",
169 "gender": "female"
170 },
171 {
172 "id": "tr-TR-AhmetNeural",
173 "label_key": "tts.voice.tr-TR-AhmetNeural",
174 "locale": "tr-TR",
175 "gender": "male"
176 },
177 {
178 "id": "tr-TR-EmelNeural",
179 "label_key": "tts.voice.tr-TR-EmelNeural",
180 "locale": "tr-TR",
181 "gender": "female"
182 },
183 {
184 "id": "es-ES-AlvaroNeural",
185 "label_key": "tts.voice.es-ES-AlvaroNeural",
186 "locale": "es-ES",
187 "gender": "male"
188 },
189 {
190 "id": "es-ES-ElviraNeural",
191 "label_key": "tts.voice.es-ES-ElviraNeural",
192 "locale": "es-ES",
193 "gender": "female"
194 },
195 ]
196
197
198 def get_voice_display_name(voice_id: str, tr_func=None, locale: str = "zh_CN") -> str:
199 """
200 Get display name for voice
201
202 Args:
203 voice_id: Voice ID (e.g., "zh-CN-YunjianNeural")
204 tr_func: Translation function (optional)
205 locale: Current locale (default: "zh_CN")
206
207 Returns:
208 Display name (translated label if in Chinese, otherwise voice ID)
209 """
210 # Find voice config
211 voice_config = next((v for v in EDGE_TTS_VOICES if v["id"] == voice_id), None)
212
213 if not voice_config:
214 return voice_id
215
216 # If Chinese locale and translation function available, use translated label
217 if locale == "zh_CN" and tr_func:
218 label_key = voice_config["label_key"]
219 return tr_func(label_key)
220
221 # For other locales, return voice ID
222 return voice_id
223
224
225 def speed_to_rate(speed: float) -> str:
226 """
227 Convert speed multiplier to Edge TTS rate parameter
228
229 Args:
230 speed: Speed multiplier (1.0 = normal, 1.2 = 120%)
231
232 Returns:
233 Rate string (e.g., "+20%", "-10%")
234
235 Examples:
236 1.0 → "+0%"
237 1.2 → "+20%"
238 0.8 → "-20%"
239 """
240 percentage = int((speed - 1.0) * 100)
241 sign = "+" if percentage >= 0 else ""
242 return f"{sign}{percentage}%"
243
244
244 lines PYTHON