mirror of
https://github.com/linyqh/NarratoAI.git
synced 2026-08-07 05:18:45 +00:00
feat(indextts2, webui): 完善 IndexTTS2 支持,新增参考音频选择与预览功能
修改内容包括: - 修正缺失参考音频的错误提示文本 - 更新示例配置文件,新增参考音频来源配置项并将 IndexTTS2 设为默认TTS引擎 - 更新语音服务模块的注释与文档字符串 - 新增多语言适配文案,支持新UI的所有提示内容 - 重构 IndexTTS2 设置页面:支持从资源目录选择音频、上传本地音频、预览音频效果 - 调整TTS引擎选项的排序与默认选中项
This commit is contained in:
parent
0bd001ce33
commit
5b2487e879
@ -71,7 +71,7 @@ def _normalize_indextts2_reference_audio(params: VideoClipParams) -> None:
|
|||||||
logger.info(f"IndexTTS2 使用配置中的参考音频: {configured_ref}")
|
logger.info(f"IndexTTS2 使用配置中的参考音频: {configured_ref}")
|
||||||
return
|
return
|
||||||
|
|
||||||
raise ValueError("IndexTTS2 参考音频不存在,请在音频设置中上传或填写有效的参考音频路径")
|
raise ValueError("IndexTTS2 参考音频不存在,请在音频设置中上传或选择有效的参考音频")
|
||||||
|
|
||||||
|
|
||||||
def start_export_jianying_draft(task_id: str, params: VideoClipParams):
|
def start_export_jianying_draft(task_id: str, params: VideoClipParams):
|
||||||
|
|||||||
@ -2236,7 +2236,7 @@ def indextts2_tts(text: str, voice_name: str, voice_file: str, speed: float = 1.
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
text: 要转换的文本
|
text: 要转换的文本
|
||||||
voice_name: 参考音频路径(格式:indextts2:path/to/audio.wav)
|
voice_name: 参考音频文件(格式:indextts2:path/to/audio.wav)
|
||||||
voice_file: 输出音频文件路径
|
voice_file: 输出音频文件路径
|
||||||
speed: 语音速度(此引擎暂不支持速度调节)
|
speed: 语音速度(此引擎暂不支持速度调节)
|
||||||
|
|
||||||
@ -2253,7 +2253,7 @@ def indextts2_tts(text: str, voice_name: str, voice_file: str, speed: float = 1.
|
|||||||
num_beams = config.indextts2.get("num_beams", 3)
|
num_beams = config.indextts2.get("num_beams", 3)
|
||||||
repetition_penalty = config.indextts2.get("repetition_penalty", 10.0)
|
repetition_penalty = config.indextts2.get("repetition_penalty", 10.0)
|
||||||
|
|
||||||
# 解析参考音频路径
|
# 解析参考音频文件
|
||||||
reference_audio_path = parse_indextts2_voice(voice_name)
|
reference_audio_path = parse_indextts2_voice(voice_name)
|
||||||
|
|
||||||
if not reference_audio_path or not os.path.exists(reference_audio_path):
|
if not reference_audio_path or not os.path.exists(reference_audio_path):
|
||||||
|
|||||||
@ -120,7 +120,8 @@
|
|||||||
# 默认 API 地址(本地部署)
|
# 默认 API 地址(本地部署)
|
||||||
api_url = "http://127.0.0.1:8081/tts"
|
api_url = "http://127.0.0.1:8081/tts"
|
||||||
|
|
||||||
# 默认参考音频路径(可选)
|
# 默认参考音频(可选)
|
||||||
|
reference_audio_source = "resource"
|
||||||
# reference_audio = "/path/to/reference_audio.wav"
|
# reference_audio = "/path/to/reference_audio.wav"
|
||||||
|
|
||||||
# 推理模式:普通推理 / 快速推理
|
# 推理模式:普通推理 / 快速推理
|
||||||
@ -151,8 +152,8 @@
|
|||||||
silence_duration = 0.125
|
silence_duration = 0.125
|
||||||
|
|
||||||
[ui]
|
[ui]
|
||||||
# TTS引擎选择 (edge_tts, azure_speech, soulvoice, tencent_tts, tts_qwen, doubaotts)
|
# TTS引擎选择 (indextts2, edge_tts, qwen3_tts, tencent_tts, doubaotts, azure_speech)
|
||||||
tts_engine = "edge_tts"
|
tts_engine = "indextts2"
|
||||||
|
|
||||||
# Edge TTS 配置
|
# Edge TTS 配置
|
||||||
edge_voice_name = "zh-CN-XiaoyiNeural-Female"
|
edge_voice_name = "zh-CN-XiaoyiNeural-Female"
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import streamlit as st
|
import streamlit as st
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from app.config import config
|
from app.config import config
|
||||||
from app.services import voice
|
from app.services import voice
|
||||||
@ -8,6 +9,35 @@ from app.utils import utils
|
|||||||
from webui.utils.cache import get_songs_cache
|
from webui.utils.cache import get_songs_cache
|
||||||
|
|
||||||
|
|
||||||
|
INDEXTTS2_REFERENCE_AUDIO_SOURCE_DIR = "/Users/viccy/Downloads/tts-mp3-clone/mp3"
|
||||||
|
INDEXTTS2_REFERENCE_AUDIO_COPY_SUBDIR = "indextts2_refs"
|
||||||
|
INDEXTTS2_REFERENCE_AUDIO_MAP = [
|
||||||
|
("yingshijieshuo-zh-male.mp3", "影视解说", "Film Narration"),
|
||||||
|
("maikeashe-zh-male.mp3", "麦克阿瑟", "Macintosh"),
|
||||||
|
("dong-yuhui-zh-male.mp3", "董宇辉", "Dong Yuhui"),
|
||||||
|
("fangzhenren-ad-fake-news-zh-male.mp3", "仿真人", "Realistic Human"),
|
||||||
|
("fengyin-jilupian-jieshuo-zh-male.mp3", "风吟纪录片解说", "Fengyin Documentary Narration"),
|
||||||
|
("guwo-dianying-jieshuo-zh-male.mp3", "顾我电影解说", "Guwo Film Narration"),
|
||||||
|
("jia-xiaojun-final-zh-male.mp3", "贾小军", "Jia Xiaojun"),
|
||||||
|
("junshi-zh-male.mp3", "军事解说", "Military Narration"),
|
||||||
|
("qi-tongwei-v2-zh-male.mp3", "祁同伟", "Qi Tongwei"),
|
||||||
|
("saima-niang-mambo-oye-zh-female.mp3", "赛马娘曼波欧耶版", "Uma Musume Mambo Oye Version"),
|
||||||
|
("shejian-shangde-zhongguo-zh-male.mp3", "舌尖上的中国", "A Bite of China"),
|
||||||
|
("xiaoming-jianmo-zh-male.mp3", "小明剑魔", "Xiaoming Sword Demon"),
|
||||||
|
("xin-youxi-jieshuo-zh-male.mp3", "新游戏解说", "New Game Narration"),
|
||||||
|
("xinzhong-zhicheng-zh-male.mp3", "心中之城", "City in the Heart"),
|
||||||
|
("alex-chikna-en-male.mp3", "亚历克斯", "Alex Chikna"),
|
||||||
|
("alle-en-unknown.mp3", "艾莉", "ALLE"),
|
||||||
|
("calm-normal-en-unknown.mp3", "沉稳男声", "Calm Normal"),
|
||||||
|
("donald-j-trump-noise-reduction-en-male.mp3", "唐纳德·特朗普", "Donald J. Trump"),
|
||||||
|
("elite-en-unknown.mp3", "精英男声", "ELITE"),
|
||||||
|
("horror-en-unknown.mp3", "惊悚男声", "Horror"),
|
||||||
|
("meiqu-kelong-en-unknown.mp3", "美式男声", "US Clone"),
|
||||||
|
("sarah-en-female.mp3", "莎拉", "Sarah"),
|
||||||
|
]
|
||||||
|
INDEXTTS2_REFERENCE_AUDIO_EXTENSIONS = (".mp3", ".wav", ".flac", ".m4a", ".aac", ".ogg")
|
||||||
|
|
||||||
|
|
||||||
def get_soulvoice_voices():
|
def get_soulvoice_voices():
|
||||||
"""获取 SoulVoice 语音列表"""
|
"""获取 SoulVoice 语音列表"""
|
||||||
# 检查是否配置了 SoulVoice API key
|
# 检查是否配置了 SoulVoice API key
|
||||||
@ -22,12 +52,12 @@ def get_soulvoice_voices():
|
|||||||
def get_tts_engine_options(tr=lambda key: key):
|
def get_tts_engine_options(tr=lambda key: key):
|
||||||
"""获取TTS引擎选项"""
|
"""获取TTS引擎选项"""
|
||||||
return {
|
return {
|
||||||
|
"indextts2": "IndexTTS2",
|
||||||
"edge_tts": "Edge TTS",
|
"edge_tts": "Edge TTS",
|
||||||
"azure_speech": "Azure Speech Services",
|
|
||||||
"tencent_tts": tr("Tencent Cloud TTS"),
|
|
||||||
"qwen3_tts": tr("Tongyi Qwen3 TTS"),
|
"qwen3_tts": tr("Tongyi Qwen3 TTS"),
|
||||||
"indextts2": tr("IndexTTS2 Voice Clone"),
|
"tencent_tts": tr("Tencent Cloud TTS"),
|
||||||
"doubaotts": tr("Doubao TTS")
|
"doubaotts": tr("Doubao TTS"),
|
||||||
|
"azure_speech": "Azure Speech Services"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -59,9 +89,9 @@ def get_tts_engine_descriptions(tr=lambda key: key):
|
|||||||
"registration": "https://dashscope.aliyuncs.com/"
|
"registration": "https://dashscope.aliyuncs.com/"
|
||||||
},
|
},
|
||||||
"indextts2": {
|
"indextts2": {
|
||||||
"title": tr("IndexTTS2 Voice Clone"),
|
"title": "IndexTTS2",
|
||||||
"features": tr("IndexTTS2 features"),
|
"features": tr("IndexTTS2 features"),
|
||||||
"use_case": tr("IndexTTS2 download link"),
|
"use_case": tr("IndexTTS2 use case"),
|
||||||
"registration": None
|
"registration": None
|
||||||
},
|
},
|
||||||
"doubaotts": {
|
"doubaotts": {
|
||||||
@ -73,6 +103,143 @@ def get_tts_engine_descriptions(tr=lambda key: key):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def infer_indextts2_reference_audio_language(filename):
|
||||||
|
"""根据文件名推断参考音频语言"""
|
||||||
|
lower_filename = filename.lower()
|
||||||
|
if "-zh-" in lower_filename:
|
||||||
|
return "zh"
|
||||||
|
if "-en-" in lower_filename:
|
||||||
|
return "en"
|
||||||
|
return "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
def get_indextts2_reference_audio_options():
|
||||||
|
"""获取本地 IndexTTS2 参考音频选项"""
|
||||||
|
options = []
|
||||||
|
mapped_files = set()
|
||||||
|
|
||||||
|
for filename, zh_name, en_name in INDEXTTS2_REFERENCE_AUDIO_MAP:
|
||||||
|
audio_path = os.path.join(INDEXTTS2_REFERENCE_AUDIO_SOURCE_DIR, filename)
|
||||||
|
if os.path.isfile(audio_path):
|
||||||
|
options.append({
|
||||||
|
"filename": filename,
|
||||||
|
"path": audio_path,
|
||||||
|
"zh": zh_name,
|
||||||
|
"en": en_name,
|
||||||
|
"language": infer_indextts2_reference_audio_language(filename),
|
||||||
|
})
|
||||||
|
mapped_files.add(filename)
|
||||||
|
|
||||||
|
if os.path.isdir(INDEXTTS2_REFERENCE_AUDIO_SOURCE_DIR):
|
||||||
|
for filename in sorted(os.listdir(INDEXTTS2_REFERENCE_AUDIO_SOURCE_DIR)):
|
||||||
|
if filename in mapped_files:
|
||||||
|
continue
|
||||||
|
if not filename.lower().endswith(INDEXTTS2_REFERENCE_AUDIO_EXTENSIONS):
|
||||||
|
continue
|
||||||
|
audio_path = os.path.join(INDEXTTS2_REFERENCE_AUDIO_SOURCE_DIR, filename)
|
||||||
|
if not os.path.isfile(audio_path):
|
||||||
|
continue
|
||||||
|
fallback_name = os.path.splitext(filename)[0]
|
||||||
|
options.append({
|
||||||
|
"filename": filename,
|
||||||
|
"path": audio_path,
|
||||||
|
"zh": fallback_name,
|
||||||
|
"en": fallback_name,
|
||||||
|
"language": infer_indextts2_reference_audio_language(filename),
|
||||||
|
})
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def format_indextts2_reference_audio_option(option):
|
||||||
|
"""格式化 IndexTTS2 参考音频下拉显示名"""
|
||||||
|
zh_name = option.get("zh", "")
|
||||||
|
en_name = option.get("en", "")
|
||||||
|
language = option.get("language", "unknown")
|
||||||
|
ui_language = str(st.session_state.get("ui_language", "zh-CN")).lower()
|
||||||
|
|
||||||
|
if ui_language.startswith("en"):
|
||||||
|
display_name = en_name or zh_name or option.get("filename", "")
|
||||||
|
language_labels = {
|
||||||
|
"zh": "Chinese",
|
||||||
|
"en": "English",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
display_name = zh_name or en_name or option.get("filename", "")
|
||||||
|
language_labels = {
|
||||||
|
"zh": "中文",
|
||||||
|
"en": "英文",
|
||||||
|
}
|
||||||
|
|
||||||
|
language_label = language_labels.get(language)
|
||||||
|
if not language_label:
|
||||||
|
return display_name
|
||||||
|
|
||||||
|
return f"{display_name} ({language_label})"
|
||||||
|
|
||||||
|
|
||||||
|
def get_indextts2_reference_audio_index(options, saved_reference_audio):
|
||||||
|
"""根据已保存的参考音频文件匹配下拉选项索引"""
|
||||||
|
if not options:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
saved_filename = os.path.basename(saved_reference_audio or "")
|
||||||
|
for index, option in enumerate(options):
|
||||||
|
if option["filename"] == saved_filename:
|
||||||
|
return index
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def copy_indextts2_reference_audio(source_path):
|
||||||
|
"""复制一份参考音频到项目存储目录,并返回复制后的路径"""
|
||||||
|
if not source_path or not os.path.isfile(source_path):
|
||||||
|
return ""
|
||||||
|
|
||||||
|
target_dir = utils.storage_dir(INDEXTTS2_REFERENCE_AUDIO_COPY_SUBDIR, create=True)
|
||||||
|
target_path = os.path.join(target_dir, os.path.basename(source_path))
|
||||||
|
|
||||||
|
if os.path.abspath(source_path) == os.path.abspath(target_path):
|
||||||
|
return target_path
|
||||||
|
|
||||||
|
should_copy = True
|
||||||
|
if os.path.exists(target_path):
|
||||||
|
should_copy = os.path.getsize(source_path) != os.path.getsize(target_path)
|
||||||
|
|
||||||
|
if should_copy:
|
||||||
|
shutil.copy2(source_path, target_path)
|
||||||
|
|
||||||
|
return target_path
|
||||||
|
|
||||||
|
|
||||||
|
def get_audio_mime_type(audio_path):
|
||||||
|
"""根据音频文件扩展名返回 MIME 类型"""
|
||||||
|
extension = os.path.splitext(audio_path or "")[1].lower()
|
||||||
|
if extension == ".wav":
|
||||||
|
return "audio/wav"
|
||||||
|
if extension == ".ogg":
|
||||||
|
return "audio/ogg"
|
||||||
|
if extension == ".m4a":
|
||||||
|
return "audio/mp4"
|
||||||
|
if extension == ".aac":
|
||||||
|
return "audio/aac"
|
||||||
|
return "audio/mp3"
|
||||||
|
|
||||||
|
|
||||||
|
def render_reference_audio_preview_button(reference_audio, key, tr):
|
||||||
|
"""渲染参考音频试听按钮"""
|
||||||
|
can_preview = bool(reference_audio and os.path.isfile(reference_audio))
|
||||||
|
if st.button(
|
||||||
|
" ",
|
||||||
|
key=key,
|
||||||
|
icon=":material/play_arrow:",
|
||||||
|
help=tr("Preview Reference Audio Help"),
|
||||||
|
disabled=not can_preview,
|
||||||
|
use_container_width=True,
|
||||||
|
):
|
||||||
|
st.session_state["indextts2_reference_audio_preview_path"] = reference_audio
|
||||||
|
|
||||||
|
|
||||||
def is_valid_azure_voice_name(voice_name: str) -> bool:
|
def is_valid_azure_voice_name(voice_name: str) -> bool:
|
||||||
"""检查是否为有效的Azure音色名称格式"""
|
"""检查是否为有效的Azure音色名称格式"""
|
||||||
if not voice_name or not isinstance(voice_name, str):
|
if not voice_name or not isinstance(voice_name, str):
|
||||||
@ -109,11 +276,11 @@ def render_tts_settings(tr):
|
|||||||
engine_descriptions = get_tts_engine_descriptions(tr)
|
engine_descriptions = get_tts_engine_descriptions(tr)
|
||||||
|
|
||||||
# 获取保存的TTS引擎设置
|
# 获取保存的TTS引擎设置
|
||||||
saved_tts_engine = config.ui.get("tts_engine", "edge_tts")
|
saved_tts_engine = config.ui.get("tts_engine", "indextts2")
|
||||||
|
|
||||||
# 确保保存的引擎在可用选项中
|
# 确保保存的引擎在可用选项中
|
||||||
if saved_tts_engine not in engine_options:
|
if saved_tts_engine not in engine_options:
|
||||||
saved_tts_engine = "edge_tts"
|
saved_tts_engine = "indextts2"
|
||||||
|
|
||||||
# TTS引擎选择下拉框
|
# TTS引擎选择下拉框
|
||||||
selected_engine = st.selectbox(
|
selected_engine = st.selectbox(
|
||||||
@ -566,8 +733,6 @@ def render_qwen3_tts_settings(tr):
|
|||||||
|
|
||||||
def render_indextts2_tts_settings(tr):
|
def render_indextts2_tts_settings(tr):
|
||||||
"""渲染 IndexTTS2 TTS 设置"""
|
"""渲染 IndexTTS2 TTS 设置"""
|
||||||
import os
|
|
||||||
|
|
||||||
# API 地址配置
|
# API 地址配置
|
||||||
api_url = st.text_input(
|
api_url = st.text_input(
|
||||||
tr("API URL"),
|
tr("API URL"),
|
||||||
@ -575,29 +740,90 @@ def render_indextts2_tts_settings(tr):
|
|||||||
help=tr("IndexTTS2 API URL Help")
|
help=tr("IndexTTS2 API URL Help")
|
||||||
)
|
)
|
||||||
|
|
||||||
# 参考音频文件路径
|
saved_reference_audio = config.indextts2.get("reference_audio", "")
|
||||||
reference_audio = st.text_input(
|
reference_audio_source_options = {
|
||||||
tr("Reference Audio Path"),
|
tr("Select from Resource Directory"): "resource",
|
||||||
value=config.indextts2.get("reference_audio", ""),
|
tr("Upload Reference Audio"): "upload",
|
||||||
help=tr("Reference Audio Path Help")
|
}
|
||||||
|
reference_audio_source_labels = list(reference_audio_source_options.keys())
|
||||||
|
saved_reference_audio_source = config.indextts2.get("reference_audio_source", "resource")
|
||||||
|
if saved_reference_audio_source not in reference_audio_source_options.values():
|
||||||
|
saved_reference_audio_source = "resource"
|
||||||
|
default_reference_audio_source_label = next(
|
||||||
|
label
|
||||||
|
for label, source_value in reference_audio_source_options.items()
|
||||||
|
if source_value == saved_reference_audio_source
|
||||||
)
|
)
|
||||||
|
|
||||||
# 文件上传功能
|
st.markdown(f"**{tr('Reference Audio Path')}**")
|
||||||
uploaded_file = st.file_uploader(
|
reference_audio_source_label = st.pills(
|
||||||
tr("Upload Reference Audio File"),
|
tr("Reference Audio Source"),
|
||||||
type=["wav", "mp3"],
|
options=reference_audio_source_labels,
|
||||||
help=tr("Upload Reference Audio Help")
|
selection_mode="single",
|
||||||
|
default=default_reference_audio_source_label,
|
||||||
|
key="indextts2_reference_audio_source_selection",
|
||||||
|
help=tr("Reference Audio Source Help"),
|
||||||
|
label_visibility="collapsed",
|
||||||
|
width="stretch",
|
||||||
)
|
)
|
||||||
|
if not reference_audio_source_label:
|
||||||
|
reference_audio_source_label = default_reference_audio_source_label
|
||||||
|
reference_audio_source = reference_audio_source_options[reference_audio_source_label]
|
||||||
|
|
||||||
if uploaded_file is not None:
|
reference_audio = saved_reference_audio
|
||||||
# 保存上传的文件
|
reference_audio_options = get_indextts2_reference_audio_options()
|
||||||
import tempfile
|
if reference_audio_source == "resource" and reference_audio_options:
|
||||||
temp_dir = tempfile.gettempdir()
|
selected_audio_index = get_indextts2_reference_audio_index(reference_audio_options, saved_reference_audio)
|
||||||
audio_path = os.path.join(temp_dir, f"indextts2_ref_{uploaded_file.name}")
|
select_col, preview_col = st.columns([5, 1])
|
||||||
with open(audio_path, "wb") as f:
|
with select_col:
|
||||||
f.write(uploaded_file.getbuffer())
|
selected_audio_option = reference_audio_options[st.selectbox(
|
||||||
reference_audio = audio_path
|
tr("Reference Audio Path"),
|
||||||
st.success(tr("Audio uploaded").format(path=audio_path))
|
options=range(len(reference_audio_options)),
|
||||||
|
index=selected_audio_index,
|
||||||
|
format_func=lambda x: format_indextts2_reference_audio_option(reference_audio_options[x]),
|
||||||
|
help=tr("Reference Audio Path Help"),
|
||||||
|
label_visibility="collapsed"
|
||||||
|
)]
|
||||||
|
reference_audio = copy_indextts2_reference_audio(selected_audio_option["path"])
|
||||||
|
with preview_col:
|
||||||
|
render_reference_audio_preview_button(
|
||||||
|
reference_audio,
|
||||||
|
"indextts2_resource_reference_audio_preview",
|
||||||
|
tr,
|
||||||
|
)
|
||||||
|
elif reference_audio_source == "resource":
|
||||||
|
st.warning(tr("No Reference Audio Resources Found"))
|
||||||
|
|
||||||
|
if reference_audio_source == "upload":
|
||||||
|
if saved_reference_audio_source != "upload":
|
||||||
|
reference_audio = ""
|
||||||
|
upload_col, preview_col = st.columns([5, 1])
|
||||||
|
with upload_col:
|
||||||
|
uploaded_file = st.file_uploader(
|
||||||
|
tr("Upload Reference Audio File"),
|
||||||
|
type=["wav", "mp3"],
|
||||||
|
help=tr("Upload Reference Audio Help"),
|
||||||
|
label_visibility="collapsed"
|
||||||
|
)
|
||||||
|
|
||||||
|
if uploaded_file is not None:
|
||||||
|
target_dir = utils.storage_dir(INDEXTTS2_REFERENCE_AUDIO_COPY_SUBDIR, create=True)
|
||||||
|
audio_path = os.path.join(target_dir, f"uploaded_{uploaded_file.name}")
|
||||||
|
with open(audio_path, "wb") as f:
|
||||||
|
f.write(uploaded_file.getbuffer())
|
||||||
|
reference_audio = audio_path
|
||||||
|
st.success(tr("Audio uploaded").format(path=audio_path))
|
||||||
|
with preview_col:
|
||||||
|
render_reference_audio_preview_button(
|
||||||
|
reference_audio,
|
||||||
|
"indextts2_upload_reference_audio_preview",
|
||||||
|
tr,
|
||||||
|
)
|
||||||
|
|
||||||
|
preview_audio_path = st.session_state.get("indextts2_reference_audio_preview_path", "")
|
||||||
|
if preview_audio_path == reference_audio and os.path.isfile(preview_audio_path):
|
||||||
|
with open(preview_audio_path, "rb") as audio_file:
|
||||||
|
st.audio(audio_file.read(), format=get_audio_mime_type(preview_audio_path))
|
||||||
|
|
||||||
# 推理模式
|
# 推理模式
|
||||||
infer_mode_options = [
|
infer_mode_options = [
|
||||||
@ -676,6 +902,7 @@ def render_indextts2_tts_settings(tr):
|
|||||||
|
|
||||||
# 保存配置
|
# 保存配置
|
||||||
config.indextts2["api_url"] = api_url
|
config.indextts2["api_url"] = api_url
|
||||||
|
config.indextts2["reference_audio_source"] = reference_audio_source
|
||||||
config.indextts2["reference_audio"] = reference_audio
|
config.indextts2["reference_audio"] = reference_audio
|
||||||
config.indextts2["infer_mode"] = infer_mode
|
config.indextts2["infer_mode"] = infer_mode
|
||||||
config.indextts2["temperature"] = temperature
|
config.indextts2["temperature"] = temperature
|
||||||
@ -1175,5 +1402,5 @@ def get_audio_params():
|
|||||||
'bgm_type': st.session_state.get('bgm_type', 'random'),
|
'bgm_type': st.session_state.get('bgm_type', 'random'),
|
||||||
'bgm_file': st.session_state.get('bgm_file', ''),
|
'bgm_file': st.session_state.get('bgm_file', ''),
|
||||||
'bgm_volume': st.session_state.get('bgm_volume', AudioVolumeDefaults.BGM_VOLUME),
|
'bgm_volume': st.session_state.get('bgm_volume', AudioVolumeDefaults.BGM_VOLUME),
|
||||||
'tts_engine': st.session_state.get('tts_engine', "edge_tts"),
|
'tts_engine': st.session_state.get('tts_engine', "indextts2"),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -235,7 +235,8 @@
|
|||||||
"Tencent Cloud TTS use case": "Personal and enterprise users who need stable Chinese speech synthesis",
|
"Tencent Cloud TTS use case": "Personal and enterprise users who need stable Chinese speech synthesis",
|
||||||
"Tongyi Qwen3 TTS features": "Alibaba Cloud Tongyi Qwen speech synthesis with high-quality voices and multiple voice options.",
|
"Tongyi Qwen3 TTS features": "Alibaba Cloud Tongyi Qwen speech synthesis with high-quality voices and multiple voice options.",
|
||||||
"High-quality Chinese speech synthesis use case": "Users who need high-quality Chinese speech synthesis",
|
"High-quality Chinese speech synthesis use case": "Users who need high-quality Chinese speech synthesis",
|
||||||
"IndexTTS2 features": "Zero-shot voice cloning. Upload a reference audio file to synthesize speech with a matching voice. Requires local or private deployment.",
|
"IndexTTS2 features": "A locally or privately deployed voice-cloning engine. Choose a resource audio file or upload a reference audio file, then synthesize narration in that voice.",
|
||||||
|
"IndexTTS2 use case": "Best for fixed narrator voices, character dubbing, or generating multiple videos with the same voice. Start the IndexTTS2 API service before use. Deployment package: https://pan.quark.cn/s/0767c9bcefd5",
|
||||||
"IndexTTS2 download link": "Download link: https://pan.quark.cn/s/0767c9bcefd5",
|
"IndexTTS2 download link": "Download link: https://pan.quark.cn/s/0767c9bcefd5",
|
||||||
"Doubao TTS features": "Volcengine Doubao speech synthesis with multiple voices and emotions, plus fast access in mainland China.",
|
"Doubao TTS features": "Volcengine Doubao speech synthesis with multiple voices and emotions, plus fast access in mainland China.",
|
||||||
"Select TTS Engine": "Select TTS Engine",
|
"Select TTS Engine": "Select TTS Engine",
|
||||||
@ -387,9 +388,16 @@
|
|||||||
"Select Qwen3 TTS Voice": "Select a Qwen3 TTS voice",
|
"Select Qwen3 TTS Voice": "Select a Qwen3 TTS voice",
|
||||||
"API URL": "API URL",
|
"API URL": "API URL",
|
||||||
"IndexTTS2 API URL Help": "IndexTTS2 API service URL",
|
"IndexTTS2 API URL Help": "IndexTTS2 API service URL",
|
||||||
"Reference Audio Path": "Reference Audio Path",
|
"Reference Audio Source": "Reference Audio Source",
|
||||||
"Reference Audio Path Help": "Reference audio file path for voice cloning (WAV format, 3-10 seconds recommended)",
|
"Reference Audio Source Help": "Choose a reference audio from the resource directory or upload a new one.",
|
||||||
"Upload Reference Audio File": "Or Upload Reference Audio File",
|
"Select from Resource Directory": "Select from Resource Directory",
|
||||||
|
"Upload Reference Audio": "Upload Reference Audio",
|
||||||
|
"Reference Audio Path": "Reference Audio",
|
||||||
|
"Reference Audio Path Help": "Choose the reference audio for voice cloning (WAV/MP3, 3-10 seconds recommended)",
|
||||||
|
"No Reference Audio Resources Found": "No reference audio resources found. Please upload a reference audio file.",
|
||||||
|
"Preview Reference Audio": "Preview",
|
||||||
|
"Preview Reference Audio Help": "Play the selected reference audio.",
|
||||||
|
"Upload Reference Audio File": "Upload Reference Audio File",
|
||||||
"Upload Reference Audio Help": "Upload a clear audio clip for voice cloning",
|
"Upload Reference Audio Help": "Upload a clear audio clip for voice cloning",
|
||||||
"Audio uploaded": "✅ Audio uploaded: {path}",
|
"Audio uploaded": "✅ Audio uploaded: {path}",
|
||||||
"Inference Mode": "Inference Mode",
|
"Inference Mode": "Inference Mode",
|
||||||
|
|||||||
@ -216,7 +216,8 @@
|
|||||||
"Tencent Cloud TTS use case": "个人和企业用户,需要稳定的中文语音合成",
|
"Tencent Cloud TTS use case": "个人和企业用户,需要稳定的中文语音合成",
|
||||||
"Tongyi Qwen3 TTS features": "阿里云通义千问语音合成,音质优秀,支持多种音色",
|
"Tongyi Qwen3 TTS features": "阿里云通义千问语音合成,音质优秀,支持多种音色",
|
||||||
"High-quality Chinese speech synthesis use case": "需要高质量中文语音合成的用户",
|
"High-quality Chinese speech synthesis use case": "需要高质量中文语音合成的用户",
|
||||||
"IndexTTS2 features": "零样本语音克隆,上传参考音频即可合成相同音色的语音,需要本地或私有部署",
|
"IndexTTS2 features": "本地/私有部署的语音克隆引擎。选择资源目录音频或上传参考音频后,可按该音色合成旁白。",
|
||||||
|
"IndexTTS2 use case": "适合需要固定旁白音色、角色配音或批量生成同一音色视频的场景。使用前请先启动 IndexTTS2 API 服务;部署包下载:https://pan.quark.cn/s/0767c9bcefd5",
|
||||||
"IndexTTS2 download link": "下载地址:https://pan.quark.cn/s/0767c9bcefd5",
|
"IndexTTS2 download link": "下载地址:https://pan.quark.cn/s/0767c9bcefd5",
|
||||||
"Doubao TTS features": "火山引擎豆包语音合成,支持多种音色和情感,国内访问速度快",
|
"Doubao TTS features": "火山引擎豆包语音合成,支持多种音色和情感,国内访问速度快",
|
||||||
"Select TTS Engine": "选择 TTS 引擎",
|
"Select TTS Engine": "选择 TTS 引擎",
|
||||||
@ -369,9 +370,16 @@
|
|||||||
"Select Qwen3 TTS Voice": "选择 Qwen3 TTS 音色",
|
"Select Qwen3 TTS Voice": "选择 Qwen3 TTS 音色",
|
||||||
"API URL": "API 地址",
|
"API URL": "API 地址",
|
||||||
"IndexTTS2 API URL Help": "IndexTTS2 API 服务地址",
|
"IndexTTS2 API URL Help": "IndexTTS2 API 服务地址",
|
||||||
"Reference Audio Path": "参考音频路径",
|
"Reference Audio Source": "参考音频来源",
|
||||||
"Reference Audio Path Help": "用于语音克隆的参考音频文件路径(WAV 格式,建议 3-10 秒)",
|
"Reference Audio Source Help": "选择从资源目录选择参考音频,或上传新的参考音频",
|
||||||
"Upload Reference Audio File": "或上传参考音频文件",
|
"Select from Resource Directory": "从资源目录选择",
|
||||||
|
"Upload Reference Audio": "上传参考音频",
|
||||||
|
"Reference Audio Path": "参考音频",
|
||||||
|
"Reference Audio Path Help": "选择用于语音克隆的参考音频(WAV/MP3 格式,建议 3-10 秒)",
|
||||||
|
"No Reference Audio Resources Found": "未找到资源目录中的参考音频,请上传参考音频文件",
|
||||||
|
"Preview Reference Audio": "试听",
|
||||||
|
"Preview Reference Audio Help": "播放当前参考音频",
|
||||||
|
"Upload Reference Audio File": "上传参考音频文件",
|
||||||
"Upload Reference Audio Help": "上传一段清晰的音频用于语音克隆",
|
"Upload Reference Audio Help": "上传一段清晰的音频用于语音克隆",
|
||||||
"Audio uploaded": "✅ 音频已上传: {path}",
|
"Audio uploaded": "✅ 音频已上传: {path}",
|
||||||
"Inference Mode": "推理模式",
|
"Inference Mode": "推理模式",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user