Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# app.py
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from TTS.api import TTS
|
| 4 |
+
import os
|
| 5 |
+
import torch
|
| 6 |
+
import numpy as np
|
| 7 |
+
import soundfile as sf
|
| 8 |
+
import uuid
|
| 9 |
+
|
| 10 |
+
# Define o dispositivo a ser usado (GPU se disponível, caso contrário CPU)
|
| 11 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 12 |
+
|
| 13 |
+
# Carrega o modelo Coqui XTTS
|
| 14 |
+
# O modelo XTTS-v2 é grande e será baixado na primeira execução.
|
| 15 |
+
# Certifique-se de que seu Hugging Face Space tenha RAM e disco suficientes.
|
| 16 |
+
print(f"Carregando modelo Coqui XTTS no dispositivo: {device}...")
|
| 17 |
+
try:
|
| 18 |
+
tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to(device)
|
| 19 |
+
print("Modelo Coqui XTTS carregado com sucesso!")
|
| 20 |
+
except Exception as e:
|
| 21 |
+
print(f"Erro ao carregar o modelo Coqui XTTS: {e}")
|
| 22 |
+
print("Por favor, verifique sua conexão com a internet e os recursos do sistema.")
|
| 23 |
+
tts = None # Define tts como None para lidar com erros de carregamento
|
| 24 |
+
|
| 25 |
+
# Diretorio para armazenar vozes clonadas temporariamente
|
| 26 |
+
CLONED_VOICES_DIR = "cloned_voices"
|
| 27 |
+
os.makedirs(CLONED_VOICES_DIR, exist_ok=True)
|
| 28 |
+
|
| 29 |
+
# Função para gerar fala
|
| 30 |
+
def generate_speech(text, speaker_name="default_speaker", custom_speaker_audio=None):
|
| 31 |
+
if tts is None:
|
| 32 |
+
return None, "Erro: Modelo TTS não carregado. Verifique os logs do servidor."
|
| 33 |
+
|
| 34 |
+
output_path = f"output_audio_{uuid.uuid4()}.wav"
|
| 35 |
+
try:
|
| 36 |
+
if custom_speaker_audio:
|
| 37 |
+
# Se um áudio de speaker personalizado for fornecido, use-o para clonagem
|
| 38 |
+
# A clonagem de voz real com XTTS envolve criar um embedding a partir do áudio
|
| 39 |
+
# e usá-lo para a síntese.
|
| 40 |
+
# Aqui, estamos usando o `speaker_wav` diretamente.
|
| 41 |
+
tts.tts_to_file(
|
| 42 |
+
text=text,
|
| 43 |
+
speaker_wav=custom_speaker_audio,
|
| 44 |
+
file_path=output_path,
|
| 45 |
+
language="pt-br"
|
| 46 |
+
)
|
| 47 |
+
message = f"Fala gerada com voz personalizada a partir de: {os.path.basename(custom_speaker_audio)}"
|
| 48 |
+
else:
|
| 49 |
+
# Para vozes predefinidas (ou vozes clonadas salvas anteriormente, se implementado)
|
| 50 |
+
# XTTS v2 não tem nomes de speaker predefinidos da mesma forma que outros modelos TTS.
|
| 51 |
+
# Para simular isso, podemos usar um speaker_wav padrão ou um speaker_id se tivéssemos embeddings pré-salvos.
|
| 52 |
+
# Para este exemplo, vamos usar um speaker_wav de exemplo ou o padrão.
|
| 53 |
+
# Em um cenário real, você teria arquivos de áudio de referência para cada "voz predefinida".
|
| 54 |
+
# Para simplificar, vamos usar um speaker_wav de exemplo para demonstrar.
|
| 55 |
+
# Você pode substituir isso por um caminho para um arquivo .wav real para sua voz padrão.
|
| 56 |
+
example_speaker_wav = "example_speaker.wav" # Crie este arquivo se quiser uma voz padrão específica
|
| 57 |
+
if not os.path.exists(example_speaker_wav):
|
| 58 |
+
# Cria um arquivo de áudio de exemplo se não existir
|
| 59 |
+
# Isso é apenas para garantir que o `speaker_wav` tenha algo para usar
|
| 60 |
+
sample_rate = 22050
|
| 61 |
+
duration = 3 # segundos
|
| 62 |
+
frequency = 440 # Hz
|
| 63 |
+
t = np.linspace(0, duration, int(sample_rate * duration), endpoint=False)
|
| 64 |
+
audio_data = 0.5 * np.sin(2 * np.pi * frequency * t)
|
| 65 |
+
sf.write(example_speaker_wav, audio_data.astype(np.float32), sample_rate)
|
| 66 |
+
|
| 67 |
+
tts.tts_to_file(
|
| 68 |
+
text=text,
|
| 69 |
+
speaker_wav=example_speaker_wav, # Usando um speaker_wav de exemplo
|
| 70 |
+
file_path=output_path,
|
| 71 |
+
language="pt-br"
|
| 72 |
+
)
|
| 73 |
+
message = f"Fala gerada com a voz: {speaker_name}"
|
| 74 |
+
|
| 75 |
+
return output_path, message
|
| 76 |
+
except Exception as e:
|
| 77 |
+
print(f"Erro na geração de fala: {e}")
|
| 78 |
+
return None, f"Erro ao gerar fala: {e}"
|
| 79 |
+
|
| 80 |
+
# Função para lidar com a clonagem de voz (gera um novo speaker_wav temporário)
|
| 81 |
+
def clone_voice(audio_file):
|
| 82 |
+
if audio_file is None:
|
| 83 |
+
return None, "Por favor, carregue um arquivo de áudio para clonar."
|
| 84 |
+
|
| 85 |
+
# Em um cenário real, você processaria este áudio para criar um embedding de speaker
|
| 86 |
+
# e o salvaria para uso futuro. Para esta demonstração, vamos apenas
|
| 87 |
+
# retornar o caminho do arquivo de áudio carregado como o "speaker_wav" para o TTS.
|
| 88 |
+
|
| 89 |
+
# O arquivo carregado pelo Gradio já está em um caminho temporário.
|
| 90 |
+
# Podemos apenas usá-lo diretamente ou movê-lo para CLONED_VOICES_DIR se quisermos persistir.
|
| 91 |
+
# Para esta demo, vamos usar o caminho temporário diretamente.
|
| 92 |
+
|
| 93 |
+
message = f"Áudio '{os.path.basename(audio_file)}' carregado para clonagem. Use-o na seção 'Texto para Fala'."
|
| 94 |
+
return audio_file, message
|
| 95 |
+
|
| 96 |
+
# Interface Gradio
|
| 97 |
+
with gr.Blocks() as demo:
|
| 98 |
+
gr.Markdown(
|
| 99 |
+
"""
|
| 100 |
+
# <p align='center'>Coqui XTTS - Síntese e Clonagem de Voz (PT-BR)</p>
|
| 101 |
+
<p align='center'>Este aplicativo demonstra a síntese de fala e a simulação de clonagem de voz usando o modelo Coqui XTTS v2.</p>
|
| 102 |
+
"""
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
with gr.Tab("Texto para Fala"):
|
| 106 |
+
text_input = gr.Textbox(label="Digite seu Texto", lines=5, placeholder="Olá! Este é um teste do Coqui XTTS em português brasileiro.")
|
| 107 |
+
|
| 108 |
+
# XTTS v2 não tem nomes de speaker predefinidos da mesma forma que outros modelos TTS.
|
| 109 |
+
# Para simular a seleção de voz, vamos usar um placeholder e a opção de áudio customizado.
|
| 110 |
+
# Em uma aplicação real, você listaria os IDs de speaker de vozes clonadas ou pré-treinadas aqui.
|
| 111 |
+
speaker_selector = gr.Radio(
|
| 112 |
+
["Voz Padrão (Exemplo)", "Usar Áudio Clonado Abaixo"],
|
| 113 |
+
label="Selecione a Voz",
|
| 114 |
+
value="Voz Padrão (Exemplo)"
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
# Campo oculto para passar o áudio clonado para a função generate_speech
|
| 118 |
+
cloned_audio_path_tts = gr.State(None)
|
| 119 |
+
|
| 120 |
+
tts_output_audio = gr.Audio(label="Áudio Gerado", type="filepath")
|
| 121 |
+
tts_message = gr.Textbox(label="Mensagem", interactive=False)
|
| 122 |
+
tts_button = gr.Button("Gerar Fala")
|
| 123 |
+
|
| 124 |
+
tts_button.click(
|
| 125 |
+
fn=lambda text, speaker, cloned_audio: generate_speech(
|
| 126 |
+
text,
|
| 127 |
+
"default_speaker" if speaker == "Voz Padrão (Exemplo)" else "custom_speaker",
|
| 128 |
+
cloned_audio if speaker == "Usar Áudio Clonado Abaixo" else None
|
| 129 |
+
),
|
| 130 |
+
inputs=[text_input, speaker_selector, cloned_audio_path_tts],
|
| 131 |
+
outputs=[tts_output_audio, tts_message]
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
with gr.Tab("Clonagem de Voz"):
|
| 135 |
+
gr.Markdown(
|
| 136 |
+
"""
|
| 137 |
+
Carregue um arquivo de áudio (preferencialmente limpo e com uma única voz) para "clonar" a voz.
|
| 138 |
+
Após o carregamento, você poderá usar esta voz na seção "Texto para Fala".
|
| 139 |
+
"""
|
| 140 |
+
)
|
| 141 |
+
cloning_input_audio = gr.Audio(label="Carregar Áudio para Clonagem", type="filepath")
|
| 142 |
+
cloning_output_message = gr.Textbox(label="Status da Clonagem", interactive=False)
|
| 143 |
+
cloning_button = gr.Button("Processar Áudio para Clonagem")
|
| 144 |
+
|
| 145 |
+
cloning_button.click(
|
| 146 |
+
fn=clone_voice,
|
| 147 |
+
inputs=[cloning_input_audio],
|
| 148 |
+
outputs=[cloned_audio_path_tts, cloning_output_message] # Atualiza o estado para TTS
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
# Lança a interface Gradio
|
| 152 |
+
if __name__ == "__main__":
|
| 153 |
+
demo.launch()
|