mirror of
https://github.com/linyqh/NarratoAI.git
synced 2026-07-23 06:28:25 +00:00
feat(edge-tts, webui): 新增动态获取音色列表功能,更新内置列表并简化UI
- 新增`get_all_edge_voices()`工具函数链,支持缓存与代理,拉取失败时回退到内置音色列表 - 更新内置音色文档与列表,修正部分命名并新增多语言神经音色及因纽特语相关音色 - 简化WebUI的Edge TTS设置界面,不再硬编码筛选音色,直接展示所有已加载的音色
This commit is contained in:
parent
a1b434fbda
commit
35477a933d
@ -6,6 +6,7 @@ import edge_tts
|
||||
import asyncio
|
||||
import requests
|
||||
import uuid
|
||||
from functools import lru_cache
|
||||
from loguru import logger
|
||||
from typing import List, Union, Tuple
|
||||
from datetime import datetime
|
||||
@ -282,7 +283,7 @@ Gender: Male
|
||||
Name: en-AU-NatashaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-AU-WilliamNeural
|
||||
Name: en-AU-WilliamMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-CA-ClaraNeural
|
||||
@ -369,21 +370,33 @@ Gender: Female
|
||||
Name: en-US-AndrewNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-AndrewMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-AriaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AvaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AvaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-BrianNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-BrianMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-ChristopherNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-EmmaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-EmmaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-EricNeural
|
||||
Gender: Male
|
||||
|
||||
@ -666,12 +679,24 @@ Gender: Male
|
||||
Name: it-IT-ElsaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: it-IT-GiuseppeNeural
|
||||
Name: it-IT-GiuseppeMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: it-IT-IsabellaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: iu-Cans-CA-SiqiniqNeural
|
||||
Gender: Female
|
||||
|
||||
Name: iu-Cans-CA-TaqqiqNeural
|
||||
Gender: Male
|
||||
|
||||
Name: iu-Latn-CA-SiqiniqNeural
|
||||
Gender: Female
|
||||
|
||||
Name: iu-Latn-CA-TaqqiqNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ja-JP-KeitaNeural
|
||||
Gender: Male
|
||||
|
||||
@ -708,7 +733,7 @@ Gender: Male
|
||||
Name: kn-IN-SapnaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ko-KR-HyunsuNeural
|
||||
Name: ko-KR-HyunsuMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ko-KR-InJoonNeural
|
||||
@ -822,7 +847,7 @@ Gender: Male
|
||||
Name: pt-BR-FranciscaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-BR-ThalitaNeural
|
||||
Name: pt-BR-ThalitaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-PT-DuarteNeural
|
||||
@ -1306,6 +1331,52 @@ def get_edge_tts_proxy() -> str | None:
|
||||
return proxy_url or None
|
||||
|
||||
|
||||
def _run_async_safely(coro_func, *args, **kwargs):
|
||||
"""在同步代码里安全运行异步 edge_tts 调用。"""
|
||||
def run_in_new_loop():
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
try:
|
||||
return loop.run_until_complete(coro_func(*args, **kwargs))
|
||||
finally:
|
||||
loop.close()
|
||||
asyncio.set_event_loop(None)
|
||||
|
||||
try:
|
||||
asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
return run_in_new_loop()
|
||||
|
||||
import concurrent.futures
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
|
||||
return executor.submit(run_in_new_loop).result()
|
||||
|
||||
|
||||
@lru_cache(maxsize=8)
|
||||
def _get_all_edge_voices_cached(proxy: str | None) -> list[str]:
|
||||
async def _list_voices():
|
||||
return await edge_tts.list_voices(proxy=proxy)
|
||||
|
||||
voices = []
|
||||
for item in _run_async_safely(_list_voices):
|
||||
name = item.get("ShortName", "").strip()
|
||||
gender = item.get("Gender", "").strip()
|
||||
if name and gender:
|
||||
voices.append(f"{name}-{gender}")
|
||||
|
||||
voices.sort()
|
||||
return voices
|
||||
|
||||
|
||||
def get_all_edge_voices() -> list[str]:
|
||||
"""获取 Edge TTS 当前支持的全部语言和音色,失败时回退到内置列表。"""
|
||||
try:
|
||||
return _get_all_edge_voices_cached(get_edge_tts_proxy())
|
||||
except Exception as e:
|
||||
logger.warning(f"获取 Edge TTS 在线音色列表失败,使用内置音色列表: {e}")
|
||||
return [v for v in get_all_azure_voices(filter_locals=[]) if "-V2" not in v]
|
||||
|
||||
|
||||
def azure_tts_v1(
|
||||
text: str, voice_name: str, voice_rate: float, voice_pitch: float, voice_file: str
|
||||
) -> Union[SubMaker, None]:
|
||||
|
||||
@ -199,7 +199,7 @@ Gender: Male
|
||||
Name: en-AU-NatashaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-AU-WilliamNeural
|
||||
Name: en-AU-WilliamMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-CA-ClaraNeural
|
||||
@ -286,21 +286,33 @@ Gender: Female
|
||||
Name: en-US-AndrewNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-AndrewMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-AriaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AvaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AvaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-BrianNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-BrianMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-ChristopherNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-EmmaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-EmmaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-EricNeural
|
||||
Gender: Male
|
||||
|
||||
@ -583,12 +595,24 @@ Gender: Male
|
||||
Name: it-IT-ElsaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: it-IT-GiuseppeNeural
|
||||
Name: it-IT-GiuseppeMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: it-IT-IsabellaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: iu-Cans-CA-SiqiniqNeural
|
||||
Gender: Female
|
||||
|
||||
Name: iu-Cans-CA-TaqqiqNeural
|
||||
Gender: Male
|
||||
|
||||
Name: iu-Latn-CA-SiqiniqNeural
|
||||
Gender: Female
|
||||
|
||||
Name: iu-Latn-CA-TaqqiqNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ja-JP-KeitaNeural
|
||||
Gender: Male
|
||||
|
||||
@ -625,7 +649,7 @@ Gender: Male
|
||||
Name: kn-IN-SapnaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ko-KR-HyunsuNeural
|
||||
Name: ko-KR-HyunsuMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ko-KR-InJoonNeural
|
||||
@ -739,7 +763,7 @@ Gender: Male
|
||||
Name: pt-BR-FranciscaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-BR-ThalitaNeural
|
||||
Name: pt-BR-ThalitaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-PT-DuarteNeural
|
||||
|
||||
@ -163,12 +163,8 @@ def render_tts_settings(tr):
|
||||
|
||||
def render_edge_tts_settings(tr):
|
||||
"""渲染 Edge TTS 引擎设置"""
|
||||
# 获取支持的语音列表
|
||||
support_locales = ["zh-CN", "en-US"]
|
||||
all_voices = voice.get_all_azure_voices(filter_locals=support_locales)
|
||||
|
||||
# 只保留标准版本的语音(Edge TTS专用,不包含V2)
|
||||
edge_voices = [v for v in all_voices if "-V2" not in v]
|
||||
# 获取 Edge TTS 支持的全部语言和音色
|
||||
edge_voices = voice.get_all_edge_voices()
|
||||
|
||||
# 创建友好的显示名称
|
||||
friendly_names = {}
|
||||
@ -189,7 +185,7 @@ def render_edge_tts_settings(tr):
|
||||
# 如果没找到匹配的,使用第一个
|
||||
saved_voice_name = edge_voices[0] if edge_voices else ""
|
||||
|
||||
# 音色选择下拉框(Edge TTS音色相对较少,保留下拉框)
|
||||
# 音色选择下拉框
|
||||
selected_friendly_name = st.selectbox(
|
||||
"音色选择",
|
||||
options=list(friendly_names.values()),
|
||||
@ -204,24 +200,12 @@ def render_edge_tts_settings(tr):
|
||||
|
||||
# 显示音色信息
|
||||
with st.expander("💡 Edge TTS 音色说明", expanded=False):
|
||||
st.write("**中文音色:**")
|
||||
zh_voices = [v for v in edge_voices if v.startswith("zh-CN")]
|
||||
for v in zh_voices:
|
||||
st.write(f"已加载 {len(edge_voices)} 个音色")
|
||||
for v in edge_voices:
|
||||
gender = "女声" if "Female" in v else "男声"
|
||||
name = v.replace("-Female", "").replace("-Male", "").replace("zh-CN-", "").replace("Neural", "")
|
||||
name = v.replace("-Female", "").replace("-Male", "").replace("Neural", "")
|
||||
st.write(f"• {name} ({gender})")
|
||||
|
||||
st.write("")
|
||||
st.write("**英文音色:**")
|
||||
en_voices = [v for v in edge_voices if v.startswith("en-US")][:5] # 只显示前5个
|
||||
for v in en_voices:
|
||||
gender = "女声" if "Female" in v else "男声"
|
||||
name = v.replace("-Female", "").replace("-Male", "").replace("en-US-", "").replace("Neural", "")
|
||||
st.write(f"• {name} ({gender})")
|
||||
|
||||
if len([v for v in edge_voices if v.startswith("en-US")]) > 5:
|
||||
st.write("• ... 更多英文音色")
|
||||
|
||||
config.ui["edge_voice_name"] = voice_name
|
||||
config.ui["voice_name"] = voice_name # 兼容性
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user