Update app.py
Browse files
app.py
CHANGED
@@ -1,142 +1,127 @@
|
|
1 |
-
import gradio as gr
|
2 |
import os
|
3 |
-
import
|
4 |
-
import torchaudio
|
5 |
-
from transformers import (
|
6 |
-
WhisperProcessor, WhisperForConditionalGeneration,
|
7 |
-
MarianMTModel, MarianTokenizer,
|
8 |
-
SpeechT5Processor, SpeechT5ForTextToSpeech
|
9 |
-
)
|
10 |
-
import ffmpeg
|
11 |
import soundfile as sf
|
12 |
-
import
|
|
|
|
|
13 |
|
14 |
# Configurações
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
def
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
|
|
84 |
try:
|
85 |
-
#
|
86 |
-
video_path
|
87 |
-
|
88 |
-
#
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
)
|
98 |
-
|
99 |
-
# Etapa 2: Transcrição paralela
|
100 |
-
progress(0.3, "Transcrevendo...")
|
101 |
-
transcription = transcribe_audio(audio_path)
|
102 |
-
|
103 |
-
# Etapa 3: Tradução em lote
|
104 |
-
progress(0.5, "Traduzindo...")
|
105 |
-
translated_text = translate_text(transcription)
|
106 |
-
|
107 |
-
# Etapa 4: Síntese de voz acelerada
|
108 |
-
progress(0.7, "Sintetizando voz...")
|
109 |
-
synthesized_audio = os.path.join(UPLOAD_FOLDER, "synthesized_audio.wav")
|
110 |
-
synthesize_speech(translated_text, synthesized_audio)
|
111 |
-
|
112 |
-
# Etapa 5: Processamento final do vídeo
|
113 |
-
progress(0.9, "Montando vídeo...")
|
114 |
-
output_path = os.path.join(OUTPUT_FOLDER, "video_traduzido.mp4")
|
115 |
-
(
|
116 |
-
ffmpeg
|
117 |
-
.input(video_path)
|
118 |
-
.output(output_path, vcodec='copy', acodec='copy', map='0:v:0')
|
119 |
-
.input(synthesized_audio)
|
120 |
-
.global_args('-loglevel', 'error')
|
121 |
-
.run(overwrite_output=True)
|
122 |
-
)
|
123 |
-
|
124 |
-
return output_path
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
except Exception as e:
|
127 |
-
return f"Erro: {
|
128 |
|
129 |
-
#
|
130 |
iface = gr.Interface(
|
131 |
-
fn=
|
132 |
-
inputs=gr.Video(label="
|
133 |
outputs=gr.Video(label="Vídeo Traduzido"),
|
134 |
-
title="
|
135 |
-
description="
|
136 |
-
allow_flagging="never"
|
137 |
)
|
138 |
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
|
|
|
|
1 |
import os
|
2 |
+
import subprocess
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
import soundfile as sf
|
4 |
+
from transformers import WhisperProcessor, WhisperForConditionalGeneration, MarianMTModel, MarianTokenizer
|
5 |
+
from gtts import gTTS
|
6 |
+
import gradio as gr
|
7 |
|
8 |
# Configurações
|
9 |
+
WHISPER_MODEL = "openai/whisper-medium"
|
10 |
+
TRANSLATION_MODEL = "Helsinki-NLP/opus-mt-en-pt"
|
11 |
+
TEMP_AUDIO_FILE = "temp_audio.wav"
|
12 |
+
TEMP_TRANSLATED_AUDIO = "translated_audio.mp3"
|
13 |
+
OUTPUT_VIDEO = "output_video.mp4"
|
14 |
+
|
15 |
+
def extract_audio(video_path: str, output_audio_path: str) -> None:
|
16 |
+
"""
|
17 |
+
Extrai o áudio de um vídeo usando FFmpeg.
|
18 |
+
"""
|
19 |
+
try:
|
20 |
+
command = [
|
21 |
+
"ffmpeg", "-i", video_path, "-q:a", "0", "-map", "a", output_audio_path, "-y"
|
22 |
+
]
|
23 |
+
subprocess.run(command, check=True)
|
24 |
+
except subprocess.CalledProcessError as e:
|
25 |
+
raise Exception(f"Erro ao extrair áudio: {e}")
|
26 |
+
|
27 |
+
def transcribe_audio(audio_path: str) -> str:
|
28 |
+
"""
|
29 |
+
Transcreve o áudio para texto usando o modelo Whisper.
|
30 |
+
"""
|
31 |
+
try:
|
32 |
+
processor = WhisperProcessor.from_pretrained(WHISPER_MODEL)
|
33 |
+
model = WhisperForConditionalGeneration.from_pretrained(WHISPER_MODEL)
|
34 |
+
audio, _ = sf.read(audio_path)
|
35 |
+
input_features = processor(audio, sampling_rate=16000, return_tensors="pt").input_features
|
36 |
+
predicted_ids = model.generate(input_features)
|
37 |
+
transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
|
38 |
+
return transcription
|
39 |
+
except Exception as e:
|
40 |
+
raise Exception(f"Erro ao transcrever áudio: {e}")
|
41 |
+
|
42 |
+
def translate_text(text: str, source_lang: str = "en", target_lang: str = "pt") -> str:
|
43 |
+
"""
|
44 |
+
Traduz o texto para o idioma desejado usando o modelo MarianMT.
|
45 |
+
"""
|
46 |
+
try:
|
47 |
+
model_name = f"Helsinki-NLP/opus-mt-{source_lang}-{target_lang}"
|
48 |
+
tokenizer = MarianTokenizer.from_pretrained(model_name)
|
49 |
+
model = MarianMTModel.from_pretrained(model_name)
|
50 |
+
translated = model.generate(**tokenizer(text, return_tensors="pt", padding=True))
|
51 |
+
translation = tokenizer.decode(translated[0], skip_special_tokens=True)
|
52 |
+
return translation
|
53 |
+
except Exception as e:
|
54 |
+
raise Exception(f"Erro ao traduzir texto: {e}")
|
55 |
+
|
56 |
+
def text_to_speech(text: str, output_audio_path: str, lang: str = "pt") -> None:
|
57 |
+
"""
|
58 |
+
Converte texto em áudio usando gTTS.
|
59 |
+
"""
|
60 |
+
try:
|
61 |
+
tts = gTTS(text, lang=lang)
|
62 |
+
tts.save(output_audio_path)
|
63 |
+
except Exception as e:
|
64 |
+
raise Exception(f"Erro ao gerar áudio: {e}")
|
65 |
+
|
66 |
+
def merge_audio_video(video_path: str, audio_path: str, output_path: str) -> None:
|
67 |
+
"""
|
68 |
+
Combina o áudio traduzido com o vídeo original usando FFmpeg.
|
69 |
+
"""
|
70 |
+
try:
|
71 |
+
command = [
|
72 |
+
"ffmpeg", "-i", video_path, "-i", audio_path, "-c:v", "copy", "-map", "0:v:0", "-map", "1:a:0", "-shortest", output_path, "-y"
|
73 |
+
]
|
74 |
+
subprocess.run(command, check=True)
|
75 |
+
except subprocess.CalledProcessError as e:
|
76 |
+
raise Exception(f"Erro ao combinar áudio e vídeo: {e}")
|
77 |
+
|
78 |
+
def translate_video(video_path: str) -> str:
|
79 |
+
"""
|
80 |
+
Função principal que orquestra a tradução do vídeo.
|
81 |
+
"""
|
82 |
try:
|
83 |
+
# 1. Extrair áudio do vídeo
|
84 |
+
extract_audio(video_path, TEMP_AUDIO_FILE)
|
85 |
+
|
86 |
+
# 2. Transcrever áudio para texto
|
87 |
+
transcription = transcribe_audio(TEMP_AUDIO_FILE)
|
88 |
+
print(f"Transcrição: {transcription}")
|
89 |
+
|
90 |
+
# 3. Traduzir texto para português
|
91 |
+
translation = translate_text(transcription)
|
92 |
+
print(f"Tradução: {translation}")
|
93 |
+
|
94 |
+
# 4. Converter texto traduzido em áudio
|
95 |
+
text_to_speech(translation, TEMP_TRANSLATED_AUDIO)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
+
# 5. Combinar áudio traduzido com vídeo original
|
98 |
+
merge_audio_video(video_path, TEMP_TRANSLATED_AUDIO, OUTPUT_VIDEO)
|
99 |
+
|
100 |
+
# 6. Limpar arquivos temporários
|
101 |
+
os.remove(TEMP_AUDIO_FILE)
|
102 |
+
os.remove(TEMP_TRANSLATED_AUDIO)
|
103 |
+
|
104 |
+
return OUTPUT_VIDEO
|
105 |
+
except Exception as e:
|
106 |
+
print(f"Erro durante o processamento: {e}")
|
107 |
+
raise
|
108 |
+
|
109 |
+
# Interface Gradio
|
110 |
+
def gradio_interface(video):
|
111 |
+
try:
|
112 |
+
output_video = translate_video(video)
|
113 |
+
return output_video
|
114 |
except Exception as e:
|
115 |
+
return f"Erro: {e}"
|
116 |
|
117 |
+
# Configuração da interface
|
118 |
iface = gr.Interface(
|
119 |
+
fn=gradio_interface,
|
120 |
+
inputs=gr.Video(label="Upload do Vídeo"),
|
121 |
outputs=gr.Video(label="Vídeo Traduzido"),
|
122 |
+
title="Tradutor de Vídeos para Português",
|
123 |
+
description="Faça upload de um vídeo em qualquer idioma e receba o vídeo com áudio traduzido para português."
|
|
|
124 |
)
|
125 |
|
126 |
+
# Iniciar a interface
|
127 |
+
iface.launch()
|
|
|
|