209 lines
8.6 KiB
Python
209 lines
8.6 KiB
Python
# Copyright (C) 2025 AIDC-AI
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
Style configuration components for web UI (middle column)
|
|
"""
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import streamlit as st
|
|
from loguru import logger
|
|
|
|
from web.i18n import tr, get_language
|
|
from web.utils.async_helpers import run_async
|
|
from pixelle_video.config import config_manager
|
|
|
|
|
|
def render_style_config(pixelle_video):
|
|
"""Render style configuration section (middle column)"""
|
|
# TTS Section (moved from left column)
|
|
# ====================================================================
|
|
with st.container(border=True):
|
|
st.markdown(f"**{tr('section.tts')}**")
|
|
|
|
with st.expander(tr("help.feature_description"), expanded=False):
|
|
st.markdown(f"**{tr('help.what')}**")
|
|
st.markdown(tr("tts.what"))
|
|
st.markdown(f"**{tr('help.how')}**")
|
|
st.markdown(tr("tts.how"))
|
|
|
|
# Get TTS config
|
|
comfyui_config = config_manager.get_comfyui_config()
|
|
tts_config = comfyui_config["tts"]
|
|
|
|
# Inference mode selection
|
|
tts_mode = st.radio(
|
|
tr("tts.inference_mode"),
|
|
["local", "comfyui"],
|
|
horizontal=True,
|
|
format_func=lambda x: tr(f"tts.mode.{x}"),
|
|
index=0 if tts_config.get("inference_mode", "local") == "local" else 1,
|
|
key="digital_tts_inference_mode"
|
|
)
|
|
|
|
# Show hint based on mode
|
|
if tts_mode == "local":
|
|
st.caption(tr("tts.mode.local_hint"))
|
|
else:
|
|
st.caption(tr("tts.mode.comfyui_hint"))
|
|
|
|
# ================================================================
|
|
# Local Mode UI
|
|
# ================================================================
|
|
if tts_mode == "local":
|
|
# Import voice configuration
|
|
from pixelle_video.tts_voices import EDGE_TTS_VOICES, get_voice_display_name
|
|
|
|
# Get saved voice from config
|
|
local_config = tts_config.get("local", {})
|
|
saved_voice = local_config.get("voice", "zh-CN-YunjianNeural")
|
|
saved_speed = local_config.get("speed", 1.2)
|
|
|
|
# Build voice options with i18n
|
|
voice_options = []
|
|
voice_ids = []
|
|
default_voice_index = 0
|
|
|
|
for idx, voice_config in enumerate(EDGE_TTS_VOICES):
|
|
voice_id = voice_config["id"]
|
|
display_name = get_voice_display_name(voice_id, tr, get_language())
|
|
voice_options.append(display_name)
|
|
voice_ids.append(voice_id)
|
|
|
|
# Set default index if matches saved voice
|
|
if voice_id == saved_voice:
|
|
default_voice_index = idx
|
|
|
|
# Two-column layout: Voice | Speed
|
|
voice_col, speed_col = st.columns([1, 1])
|
|
|
|
with voice_col:
|
|
# Voice selector
|
|
selected_voice_display = st.selectbox(
|
|
tr("tts.voice_selector"),
|
|
voice_options,
|
|
index=default_voice_index,
|
|
key="digital_tts_local_voice"
|
|
)
|
|
|
|
# Get actual voice ID
|
|
selected_voice_index = voice_options.index(selected_voice_display)
|
|
selected_voice = voice_ids[selected_voice_index]
|
|
|
|
with speed_col:
|
|
# Speed slider
|
|
tts_speed = st.slider(
|
|
tr("tts.speed"),
|
|
min_value=0.5,
|
|
max_value=2.0,
|
|
value=saved_speed,
|
|
step=0.1,
|
|
format="%.1fx",
|
|
key="digital_tts_local_speed"
|
|
)
|
|
st.caption(tr("tts.speed_label", speed=f"{tts_speed:.1f}"))
|
|
|
|
# Variables for video generation
|
|
tts_workflow_key = None
|
|
ref_audio_path = None
|
|
|
|
# ================================================================
|
|
# ComfyUI Mode UI
|
|
# ================================================================
|
|
else: # comfyui mode
|
|
tts_workflow_key = "runninghub/tts_index2.json" # fallback
|
|
|
|
# Reference audio upload (optional, for voice cloning)
|
|
ref_audio_file = st.file_uploader(
|
|
tr("tts.ref_audio"),
|
|
type=["mp3", "wav", "flac", "m4a", "aac", "ogg"],
|
|
help=tr("tts.ref_audio_help"),
|
|
key="digital_ref_audio_upload"
|
|
)
|
|
|
|
# Save uploaded ref_audio to temp file if provided
|
|
ref_audio_path = None
|
|
if ref_audio_file is not None:
|
|
# Audio preview player (directly play uploaded file)
|
|
st.audio(ref_audio_file)
|
|
|
|
# Save to temp directory
|
|
temp_dir = Path("temp")
|
|
temp_dir.mkdir(exist_ok=True)
|
|
ref_audio_path = temp_dir / f"ref_audio_{ref_audio_file.name}"
|
|
with open(ref_audio_path, "wb") as f:
|
|
f.write(ref_audio_file.getbuffer())
|
|
|
|
# Variables for video generation
|
|
selected_voice = None
|
|
tts_speed = None
|
|
|
|
# ================================================================
|
|
# TTS Preview (works for both modes)
|
|
# ================================================================
|
|
with st.expander(tr("tts.preview_title"), expanded=False):
|
|
# Preview text input
|
|
preview_text = st.text_input(
|
|
tr("tts.preview_text"),
|
|
value="大家好,这是一段测试语音。",
|
|
placeholder=tr("tts.preview_text_placeholder"),
|
|
key="digital_tts_preview_text"
|
|
)
|
|
|
|
# Preview button
|
|
if st.button(tr("tts.preview_button"), key="gidital_preview_tts", use_container_width=True):
|
|
with st.spinner(tr("tts.previewing")):
|
|
try:
|
|
# Build TTS params based on mode
|
|
tts_params = {
|
|
"text": preview_text,
|
|
"inference_mode": tts_mode
|
|
}
|
|
|
|
if tts_mode == "local":
|
|
tts_params["voice"] = selected_voice
|
|
tts_params["speed"] = tts_speed
|
|
else: # comfyui
|
|
tts_params["workflow"] = tts_workflow_key
|
|
if ref_audio_path:
|
|
tts_params["ref_audio"] = str(ref_audio_path)
|
|
|
|
audio_path = run_async(pixelle_video.tts(**tts_params))
|
|
|
|
# Play the audio
|
|
if audio_path:
|
|
st.success(tr("tts.preview_success"))
|
|
if os.path.exists(audio_path):
|
|
st.audio(audio_path, format="audio/mp3")
|
|
elif audio_path.startswith('http'):
|
|
st.audio(audio_path)
|
|
else:
|
|
st.error("Failed to generate preview audio")
|
|
|
|
# Show file path
|
|
st.caption(f"📁 {audio_path}")
|
|
else:
|
|
st.error("Failed to generate preview audio")
|
|
except Exception as e:
|
|
st.error(tr("tts.preview_failed", error=str(e)))
|
|
logger.exception(e)
|
|
|
|
# Return all style configuration parameters (Simplified version only local TTS)
|
|
return {
|
|
"tts_inference_mode": tts_mode,
|
|
"tts_voice": selected_voice if tts_mode == "local" else None,
|
|
"tts_speed": tts_speed if tts_mode == "local" else None,
|
|
"tts_workflow": tts_workflow_key if tts_mode == "comfyui" else None,
|
|
"ref_audio": str(ref_audio_path) if ref_audio_path else None,
|
|
} |