Spaces:
Running
Running
Upload 3 files
Browse files- app.py +44 -49
- edgeTTS.py +2 -1
- tiktokTTS.py +2 -1
app.py
CHANGED
|
@@ -188,14 +188,12 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="green", secondary_hue="blue"
|
|
| 188 |
)
|
| 189 |
|
| 190 |
with gr.TabItem("Ler .SRT"):
|
| 191 |
-
gr.Markdown("Gere áudio sincronizado a partir de um arquivo .SRT
|
| 192 |
|
|
|
|
| 193 |
with gr.Tabs():
|
| 194 |
with gr.TabItem("Gerar áudio"):
|
| 195 |
-
# ADICIONADO: Seletor de provedor para SRT
|
| 196 |
provider_choice_srt = gr.Radio(choices=["Edge-TTS", "TikTok"], value="Edge-TTS", label="Escolha o Provedor de TTS", interactive=TIKTOK_TTS_AVAILABLE)
|
| 197 |
-
|
| 198 |
-
# --- UI do Edge-TTS para SRT ---
|
| 199 |
with gr.Column(visible=True) as edge_tts_ui_srt:
|
| 200 |
gr.Markdown("A velocidade é ajustada automaticamente para cada legenda.")
|
| 201 |
with gr.Row():
|
|
@@ -207,7 +205,6 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="green", secondary_hue="blue"
|
|
| 207 |
pitch_input_srt = gr.Slider(-100, 100, label="Tom (Hz)", value=0, interactive=True)
|
| 208 |
volume_input_srt = gr.Slider(-99, 200, label="Volume (%)", value=0, interactive=True)
|
| 209 |
|
| 210 |
-
# --- UI do TikTok para SRT ---
|
| 211 |
with gr.Column(visible=False) as tiktok_tts_ui_srt:
|
| 212 |
gr.Markdown("A velocidade do áudio será ajustada automaticamente para cada legenda. Tom e volume não são aplicáveis.")
|
| 213 |
with gr.Row():
|
|
@@ -215,66 +212,64 @@ with gr.Blocks(theme=gr.themes.Default(primary_hue="green", secondary_hue="blue"
|
|
| 215 |
initial_tiktok_voices_srt = get_tiktok_voice_options(tiktok_available_categories[0])
|
| 216 |
tiktok_voice_model_input_srt = gr.Dropdown(choices=initial_tiktok_voices_srt, label="Modelo de Voz", value=initial_tiktok_voices_srt[0] if initial_tiktok_voices_srt else None)
|
| 217 |
|
| 218 |
-
# --- Componentes Comuns ---
|
| 219 |
srt_input = gr.File(label="Arquivo SRT", file_types=[".srt"], type="filepath")
|
| 220 |
audio_output_srt = gr.Audio(label="Resultado", type="filepath", interactive=False, show_download_button=True)
|
| 221 |
progress_bar_srt = gr.Progress(track_tqdm=True)
|
| 222 |
-
|
| 223 |
gr.Examples(
|
| 224 |
examples=load_samples(),
|
| 225 |
-
inputs=[srt_input, audio_output_srt],
|
| 226 |
-
|
| 227 |
-
label="Exemplos (Clique para carregar)",
|
| 228 |
-
# A função fn=lambda x,y: (x,y) é um truque para carregar os dados diretamente
|
| 229 |
-
fn=lambda srt_path, audio_path: (srt_path, audio_path)
|
| 230 |
)
|
| 231 |
-
|
| 232 |
with gr.Row():
|
| 233 |
srt_button = gr.Button(value="Gerar Áudio")
|
| 234 |
-
clear_button_srt = gr.ClearButton(srt_input, value='Limpar')
|
| 235 |
-
|
| 236 |
-
# --- Lógica e Event Handlers ---
|
| 237 |
-
def switch_provider_ui_srt(provider):
|
| 238 |
-
return gr.update(visible=provider == "Edge-TTS"), gr.update(visible=provider == "TikTok")
|
| 239 |
-
|
| 240 |
-
provider_choice_srt.change(fn=switch_provider_ui_srt, inputs=provider_choice_srt, outputs=[edge_tts_ui_srt, tiktok_tts_ui_srt])
|
| 241 |
-
language_input_srt.change(fn=lambda lang: update_edge_voice_options(lang, edge_voices_data), inputs=language_input_srt, outputs=voice_model_input_srt)
|
| 242 |
-
tiktok_category_input_srt.change(fn=update_tiktok_voice_options, inputs=tiktok_category_input_srt, outputs=tiktok_voice_model_input_srt)
|
| 243 |
-
|
| 244 |
-
def controlador_srt_principal(provider, srt_file, edge_voice, pitch, volume, tiktok_voice, progress=gr.Progress(track_tqdm=True)):
|
| 245 |
-
"""
|
| 246 |
-
Função roteadora que recebe o rastreador de progresso do Gradio
|
| 247 |
-
e o passa para os controladores específicos do provedor.
|
| 248 |
-
"""
|
| 249 |
-
if provider == "Edge-TTS":
|
| 250 |
-
audio_file = controlador_process_srt_file(srt_file, edge_voice, pitch, volume, srt_temp_deleta, progress=progress)
|
| 251 |
-
else: # TikTok
|
| 252 |
-
audio_file = controlador_process_srt_file_tiktok(srt_file, tiktok_voice, srt_temp_deleta, progress=progress)
|
| 253 |
-
|
| 254 |
-
return audio_file, gr.update(choices=listar_audios())
|
| 255 |
-
|
| 256 |
-
# MODIFICADO: A chamada de clique permanece a mesma, o Gradio injeta o `progress` automaticamente
|
| 257 |
-
srt_button.click(
|
| 258 |
-
fn=controlador_srt_principal,
|
| 259 |
-
inputs=[provider_choice_srt, srt_input, voice_model_input_srt, pitch_input_srt, volume_input_srt, tiktok_voice_model_input_srt],
|
| 260 |
-
outputs=[audio_output_srt, audio_list_target],
|
| 261 |
-
queue=True
|
| 262 |
-
)
|
| 263 |
|
| 264 |
with gr.TabItem("Arquivos gerados"):
|
| 265 |
audio_list = gr.Dropdown(label="Arquivos de áudio", choices=listar_audios(), interactive=True)
|
| 266 |
-
audio_list_target.change(lambda x: x, inputs=[audio_list_target], outputs=[audio_list])
|
| 267 |
play_button = gr.Button(value="Tocar")
|
| 268 |
refresh_button = gr.Button(value="Atualizar Lista")
|
| 269 |
audio_player = gr.Audio(label="Reproduzir", type="filepath", interactive=False, show_download_button=True)
|
| 270 |
status_message = gr.Textbox(label="Status", interactive=False, visible=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 271 |
|
| 272 |
-
def update_audio_list():
|
| 273 |
-
arquivos = listar_audios()
|
| 274 |
-
return gr.update(choices=arquivos, value=None), "Lista atualizada."
|
| 275 |
-
|
| 276 |
-
refresh_button.click(fn=update_audio_list, outputs=[audio_list, status_message], queue=True)
|
| 277 |
-
play_button.click(fn=tocar_audio, inputs=[audio_list], outputs=[audio_player], queue=True)
|
| 278 |
gr.Markdown("""
|
| 279 |
<hr>
|
| 280 |
<div style='text-align: center; font-size: 0.9em; color: #777;'>
|
|
|
|
| 188 |
)
|
| 189 |
|
| 190 |
with gr.TabItem("Ler .SRT"):
|
| 191 |
+
gr.Markdown("Gere áudio sincronizado a partir de um arquivo .SRT ou carregue um de nossos exemplos.")
|
| 192 |
|
| 193 |
+
# --- Etapa 1: Definir TODOS os componentes de ambas as abas ---
|
| 194 |
with gr.Tabs():
|
| 195 |
with gr.TabItem("Gerar áudio"):
|
|
|
|
| 196 |
provider_choice_srt = gr.Radio(choices=["Edge-TTS", "TikTok"], value="Edge-TTS", label="Escolha o Provedor de TTS", interactive=TIKTOK_TTS_AVAILABLE)
|
|
|
|
|
|
|
| 197 |
with gr.Column(visible=True) as edge_tts_ui_srt:
|
| 198 |
gr.Markdown("A velocidade é ajustada automaticamente para cada legenda.")
|
| 199 |
with gr.Row():
|
|
|
|
| 205 |
pitch_input_srt = gr.Slider(-100, 100, label="Tom (Hz)", value=0, interactive=True)
|
| 206 |
volume_input_srt = gr.Slider(-99, 200, label="Volume (%)", value=0, interactive=True)
|
| 207 |
|
|
|
|
| 208 |
with gr.Column(visible=False) as tiktok_tts_ui_srt:
|
| 209 |
gr.Markdown("A velocidade do áudio será ajustada automaticamente para cada legenda. Tom e volume não são aplicáveis.")
|
| 210 |
with gr.Row():
|
|
|
|
| 212 |
initial_tiktok_voices_srt = get_tiktok_voice_options(tiktok_available_categories[0])
|
| 213 |
tiktok_voice_model_input_srt = gr.Dropdown(choices=initial_tiktok_voices_srt, label="Modelo de Voz", value=initial_tiktok_voices_srt[0] if initial_tiktok_voices_srt else None)
|
| 214 |
|
|
|
|
| 215 |
srt_input = gr.File(label="Arquivo SRT", file_types=[".srt"], type="filepath")
|
| 216 |
audio_output_srt = gr.Audio(label="Resultado", type="filepath", interactive=False, show_download_button=True)
|
| 217 |
progress_bar_srt = gr.Progress(track_tqdm=True)
|
| 218 |
+
|
| 219 |
gr.Examples(
|
| 220 |
examples=load_samples(),
|
| 221 |
+
inputs=[srt_input, audio_output_srt], outputs=[srt_input, audio_output_srt],
|
| 222 |
+
label="Exemplos (Clique para carregar)", fn=lambda srt, audio: (srt, audio)
|
|
|
|
|
|
|
|
|
|
| 223 |
)
|
| 224 |
+
|
| 225 |
with gr.Row():
|
| 226 |
srt_button = gr.Button(value="Gerar Áudio")
|
| 227 |
+
clear_button_srt = gr.ClearButton(components=[srt_input, audio_output_srt], value='Limpar')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
|
| 229 |
with gr.TabItem("Arquivos gerados"):
|
| 230 |
audio_list = gr.Dropdown(label="Arquivos de áudio", choices=listar_audios(), interactive=True)
|
|
|
|
| 231 |
play_button = gr.Button(value="Tocar")
|
| 232 |
refresh_button = gr.Button(value="Atualizar Lista")
|
| 233 |
audio_player = gr.Audio(label="Reproduzir", type="filepath", interactive=False, show_download_button=True)
|
| 234 |
status_message = gr.Textbox(label="Status", interactive=False, visible=True)
|
| 235 |
+
|
| 236 |
+
# --- Etapa 2: Definir TODAS as funções de evento e lógicas ---
|
| 237 |
+
|
| 238 |
+
# Lógica para a aba "Gerar áudio"
|
| 239 |
+
def switch_provider_ui_srt(provider):
|
| 240 |
+
return gr.update(visible=provider == "Edge-TTS"), gr.update(visible=provider == "TikTok")
|
| 241 |
+
|
| 242 |
+
def controlador_srt_principal(provider, srt_file, edge_voice, pitch, volume, tiktok_voice, progress=gr.Progress(track_tqdm=True)):
|
| 243 |
+
if provider == "Edge-TTS":
|
| 244 |
+
audio_file = controlador_process_srt_file(srt_file, edge_voice, pitch, volume, srt_temp_deleta, progress=progress)
|
| 245 |
+
else:
|
| 246 |
+
audio_file = controlador_process_srt_file_tiktok(srt_file, tiktok_voice, srt_temp_deleta, progress=progress)
|
| 247 |
+
return audio_file, gr.update(choices=listar_audios())
|
| 248 |
+
|
| 249 |
+
# Lógica para a aba "Arquivos gerados"
|
| 250 |
+
def update_audio_list():
|
| 251 |
+
arquivos = listar_audios()
|
| 252 |
+
return gr.update(choices=arquivos, value=None), "Lista atualizada."
|
| 253 |
+
|
| 254 |
+
# --- Etapa 3: Conectar TODOS os eventos aos seus componentes ---
|
| 255 |
+
|
| 256 |
+
# Eventos da aba "Gerar áudio"
|
| 257 |
+
provider_choice_srt.change(fn=switch_provider_ui_srt, inputs=provider_choice_srt, outputs=[edge_tts_ui_srt, tiktok_tts_ui_srt])
|
| 258 |
+
language_input_srt.change(fn=lambda lang: update_edge_voice_options(lang, edge_voices_data), inputs=language_input_srt, outputs=voice_model_input_srt)
|
| 259 |
+
tiktok_category_input_srt.change(fn=update_tiktok_voice_options, inputs=tiktok_category_input_srt, outputs=tiktok_voice_model_input_srt)
|
| 260 |
+
|
| 261 |
+
# Evento principal do botão de gerar
|
| 262 |
+
srt_button.click(
|
| 263 |
+
fn=controlador_srt_principal,
|
| 264 |
+
inputs=[provider_choice_srt, srt_input, voice_model_input_srt, pitch_input_srt, volume_input_srt, tiktok_voice_model_input_srt],
|
| 265 |
+
outputs=[audio_output_srt, audio_list],
|
| 266 |
+
queue=True
|
| 267 |
+
)
|
| 268 |
+
|
| 269 |
+
# Eventos da aba "Arquivos gerados"
|
| 270 |
+
refresh_button.click(fn=update_audio_list, outputs=[audio_list, status_message], queue=True)
|
| 271 |
+
play_button.click(fn=tocar_audio, inputs=[audio_list], outputs=[audio_player], queue=True)
|
| 272 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 273 |
gr.Markdown("""
|
| 274 |
<hr>
|
| 275 |
<div style='text-align: center; font-size: 0.9em; color: #777;'>
|
edgeTTS.py
CHANGED
|
@@ -125,6 +125,7 @@ async def process_srt_file(srt_file_path, voice, output_dir_str, pitch, volume,
|
|
| 125 |
def controlador_process_srt_file(srt_file, voice_model_input, pitch, volume, srt_temp_deleta, progress=None):
|
| 126 |
if not srt_file: return None
|
| 127 |
actual_voice = extract_voice_name(voice_model_input)
|
| 128 |
-
|
|
|
|
| 129 |
|
| 130 |
return asyncio.run(process_srt_file(srt_file.name, actual_voice, output_dir, pitch, volume, srt_temp_deleta))
|
|
|
|
| 125 |
def controlador_process_srt_file(srt_file, voice_model_input, pitch, volume, srt_temp_deleta, progress=None):
|
| 126 |
if not srt_file: return None
|
| 127 |
actual_voice = extract_voice_name(voice_model_input)
|
| 128 |
+
srt_filename_stem = Path(srt_file.name).stem
|
| 129 |
+
output_dir = f"output/srt_temp_{srt_filename_stem}"
|
| 130 |
|
| 131 |
return asyncio.run(process_srt_file(srt_file.name, actual_voice, output_dir, pitch, volume, srt_temp_deleta))
|
tiktokTTS.py
CHANGED
|
@@ -133,7 +133,8 @@ async def process_srt_file_tiktok(srt_file_path, voice_str, output_dir_str, srt_
|
|
| 133 |
|
| 134 |
def controlador_process_srt_file_tiktok(srt_file, voice_str, srt_temp_deleta, progress=None):
|
| 135 |
if not srt_file: return None
|
| 136 |
-
|
|
|
|
| 137 |
|
| 138 |
try:
|
| 139 |
return asyncio.run(process_srt_file_tiktok(srt_file.name, voice_str, output_dir, srt_temp_deleta, progress=progress))
|
|
|
|
| 133 |
|
| 134 |
def controlador_process_srt_file_tiktok(srt_file, voice_str, srt_temp_deleta, progress=None):
|
| 135 |
if not srt_file: return None
|
| 136 |
+
srt_filename_stem = Path(srt_file.name).stem
|
| 137 |
+
output_dir = f"output/srt_temp_{srt_filename_stem}"
|
| 138 |
|
| 139 |
try:
|
| 140 |
return asyncio.run(process_srt_file_tiktok(srt_file.name, voice_str, output_dir, srt_temp_deleta, progress=progress))
|