import subprocess import os import json import gradio as gr from pydub import AudioSegment from header import badges, description from pydub.silence import split_on_silence from get_voices import get_voices #from adjust import remove_silence, controlador_generate_audio, generate_audio # Load voices from JSON file def load_voices(): with open('voices.json', 'r', encoding='utf-8') as f: return json.load(f) # Get formatted voice options for specific language def get_voice_options(language, voices_data): if language in voices_data: return [f"{voice['name']} | {voice['gender']}" for voice in voices_data[language]] return [] # Extract voice name from formatted string def extract_voice_name(formatted_voice): return formatted_voice.split(" | ")[0] def update_voice_options(language): voices_data = load_voices() voice_options = get_voice_options(language, voices_data) # Retorna apenas a lista de opções e o primeiro valor if voice_options: return gr.Dropdown(choices=voice_options, value=voice_options[0]) return gr.Dropdown(choices=[], value=None) def update_voices_and_refresh(): # Execute get_voices to update the voices.json file get_voices() # Reload the voices data voices_data = load_voices() available_languages = list(voices_data.keys()) # Get initial voices for the first language initial_voices = get_voice_options(available_languages[0], voices_data) if available_languages else [] return ( gr.Dropdown(choices=available_languages, value=available_languages[0] if available_languages else None), gr.Dropdown(choices=initial_voices, value=initial_voices[0] if initial_voices else None) ) def remove_silence(input_file, output_file): audio = AudioSegment.from_wav(input_file) # Encontra os segmentos de áudio que não são silêncio segments = split_on_silence(audio, min_silence_len=500, silence_thresh=-40) # Concatena os segmentos de áudio não silenciosos non_silent_audio = AudioSegment.silent(duration=0) for segment in segments: non_silent_audio += segment # Salva o áudio sem as partes de silêncio non_silent_audio.export(output_file, format="wav") def controlador_generate_audio(audio_input, voice_model_input, speed_input, pitch_input, volume_input, checkbox_cortar_silencio): # Gerar áudio audio_file = generate_audio(audio_input, voice_model_input, speed_input, pitch_input, volume_input) if audio_file: print("Áudio gerado com sucesso:", audio_file) # Verificar se o checkbox de cortar silêncio está marcado if checkbox_cortar_silencio: print("Cortando silêncio...") # Remover silêncio do áudio remove_silence(audio_file, audio_file) print("Silêncio removido com sucesso!") else: print("Erro ao gerar áudio.") return audio_file # Retornar o caminho do arquivo de áudio def generate_audio(texto, modelo_de_voz, velocidade, tom, volume): # Extract actual voice name from formatted string if necessary actual_voice = extract_voice_name(modelo_de_voz) # Format parameters with proper signs if velocidade >= 0: rate_str = f"+{velocidade}%" else: rate_str = f"{velocidade}%" if tom >= 0: pitch_str = f"+{tom}Hz" else: pitch_str = f"{tom}Hz" if volume >= 0: volume_str = f"+{volume}%" else: volume_str = f"{volume}%" output_dir = "output" os.makedirs(output_dir, exist_ok=True) mp3_output_file = os.path.join(output_dir, "new_audio.mp3") cmd = [ "edge-tts", "--rate=" + rate_str, "--pitch=" + pitch_str, "--volume=" + volume_str, "-v", actual_voice, "-t", texto, "--write-media", mp3_output_file ] print("Gerando áudio...") try: subprocess.run(cmd, check=True) except subprocess.CalledProcessError as e: print("Erro ao gerar áudio:", e) return None print("Áudio gerado com sucesso!") wav_output_file = os.path.join(output_dir, "new_audio.wav") audio = AudioSegment.from_mp3(mp3_output_file) audio.export(wav_output_file, format="wav") return wav_output_file def generate_audio_from_file(file_path, modelo_de_voz, velocidade, tom, volume): # Extrai o nome real da voz formatada, se necessário actual_voice = extract_voice_name(modelo_de_voz) # Formatação dos parâmetros com sinais adequados rate_str = f"+{velocidade}%" if velocidade >= 0 else f"{velocidade}%" pitch_str = f"+{tom}Hz" if tom >= 0 else f"{tom}Hz" volume_str = f"+{volume}%" if volume >= 0 else f"{volume}%" output_dir = "output" os.makedirs(output_dir, exist_ok=True) mp3_output_file = os.path.join(output_dir, "new_audio.mp3") # Usar -f FILE para passar o caminho do arquivo de texto cmd = [ "edge-tts", "-f", file_path, # Certificar que o conteúdo do arquivo seja texto puro "--rate=" + rate_str, "--pitch=" + pitch_str, "--volume=" + volume_str, "-v", actual_voice, "--write-media", mp3_output_file ] print("Gerando áudio do arquivo...") try: subprocess.run(cmd, check=True) except subprocess.CalledProcessError as e: print("Erro ao gerar áudio:", e) return None print("Áudio gerado com sucesso!") wav_output_file = os.path.join(output_dir, "new_audio.wav") audio = AudioSegment.from_mp3(mp3_output_file) audio.export(wav_output_file, format="wav") return wav_output_file def controlador_generate_audio_from_file(file, voice_model_input, speed_input, pitch_input, volume_input, checkbox_cortar_silencio): if file is None: return None # Neste caso, o 'file' já é o caminho do arquivo, então não precisa reescrever temp_file_path = file # Caminho do arquivo que você recebe do Gradio # Gerar o áudio audio_file = generate_audio_from_file(temp_file_path, voice_model_input, speed_input, pitch_input, volume_input) if audio_file: print("Áudio gerado com sucesso:", audio_file) if checkbox_cortar_silencio: print("Cortando silêncio...") remove_silence(audio_file, audio_file) print("Silêncio removido com sucesso!") else: print("Erro ao gerar áudio.") return audio_file with gr.Blocks(theme=gr.themes.Default(primary_hue="green", secondary_hue="blue"), title="QuickTTS") as iface: gr.Markdown(badges) gr.Markdown(description) voices_data = load_voices() available_languages = list(voices_data.keys()) with gr.Tabs(): with gr.TabItem("Edge-TTS"): gr.Markdown("É ilimitado, podendo até mesmo colocar um livro inteiro, mas claro, tem a questão de tempo, quanto maior o texto, mais demorado é, dublagem por SRT talvez um dia eu bote.") with gr.Row(): # Language selection dropdown language_input = gr.Dropdown( choices=available_languages, label="Idioma", value=available_languages[52] if available_languages else None ) # Voice model dropdown (will be updated based on language selection) initial_voices = get_voice_options(available_languages[52], voices_data) if available_languages else [] voice_model_input = gr.Dropdown( choices=initial_voices, label="Modelo de Voz", value=initial_voices[0] if initial_voices else None ) # Connect language selection to voice model update language_input.change( fn=update_voice_options, inputs=[language_input], outputs=[voice_model_input] ) audio_input = gr.Textbox(label="Texto", value='Texto de exemplo!', interactive=True) with gr.Row(): with gr.Column(): speed_input = gr.Slider( minimum=-200, maximum=200, label="Velocidade (%)", value=0, interactive=True ) with gr.Column(): pitch_input = gr.Slider( minimum=-100, maximum=100, label="Tom (Hz)", value=0, interactive=True ) with gr.Column(): volume_input = gr.Slider( minimum=-99, maximum=100, label="Volume (%)", value=0, interactive=True ) checkbox_cortar_silencio = gr.Checkbox(label="Cortar Silencio", interactive=True) audio_output = gr.Audio(label="Resultado", type="filepath", interactive=False) with gr.Row(): edgetts_button = gr.Button(value="Falar") edgetts_button.click( controlador_generate_audio, inputs=[ audio_input, voice_model_input, speed_input, pitch_input, # New input volume_input, # New input checkbox_cortar_silencio ], outputs=[audio_output] ) clear_button = gr.ClearButton(audio_input, value='Limpar') # Add update voices button at the top update_voices_btn = gr.Button(value="Atualizar Lista de Vozes") # Connect update voices button to refresh function update_voices_btn.click( fn=update_voices_and_refresh, inputs=[], outputs=[language_input, voice_model_input] ) gr.Markdown("Agradecimentos a rany2 pelo Edge-TTS") with gr.TabItem("Lote (Arquivo txt)"): gr.Markdown("Carregar texto de um arquivo") # Language and voice selection (same as first tab) with gr.Row(): language_input_file = gr.Dropdown( choices=available_languages, label="Idioma", value=available_languages[52] if available_languages else None ) initial_voices = get_voice_options(available_languages[52], voices_data) if available_languages else [] voice_model_input_file = gr.Dropdown( choices=initial_voices, label="Modelo de Voz", value=initial_voices[0] if initial_voices else None ) language_input_file.change( fn=update_voice_options, inputs=[language_input_file], outputs=[voice_model_input_file] ) gr.Markdown("O programa vai ler linha por linha e entregar em um único áudio") # File input file_input = gr.File( label="Arquivo de Texto", file_types=[".txt"], type="filepath" ) with gr.Row(): with gr.Column(): speed_input_file = gr.Slider( minimum=-200, maximum=200, label="Velocidade (%)", value=0, interactive=True ) with gr.Column(): pitch_input_file = gr.Slider( minimum=-100, maximum=100, label="Tom (Hz)", value=0, interactive=True ) with gr.Column(): volume_input_file = gr.Slider( minimum=-99, maximum=100, label="Volume (%)", value=0, interactive=True ) checkbox_cortar_silencio_file = gr.Checkbox(label="Cortar Silencio", interactive=True) audio_output_file = gr.Audio(label="Resultado", type="filepath", interactive=False) with gr.Row(): edgetts_button_file = gr.Button(value="Falar") edgetts_button_file.click( controlador_generate_audio_from_file, inputs=[ file_input, voice_model_input_file, speed_input_file, pitch_input_file, volume_input_file, checkbox_cortar_silencio_file ], outputs=[audio_output_file] ) clear_button_file = gr.ClearButton(file_input, value='Limpar') gr.Markdown("Agradecimentos a rany2 pelo Edge-TTS") gr.Markdown(""" Desenvolvido por Rafael Godoy
Apoie o projeto pelo https://nubank.com.br/pagar/1ls6a4/0QpSSbWBSq, qualquer valor é bem vindo. """) iface.launch()