RXTIME commited on
Commit
64e449c
·
verified ·
1 Parent(s): 91b2b2b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +115 -130
app.py CHANGED
@@ -1,142 +1,127 @@
1
- import gradio as gr
2
  import os
3
- import torch
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 numpy as np
 
 
13
 
14
  # Configurações
15
- UPLOAD_FOLDER = "uploads"
16
- OUTPUT_FOLDER = "outputs"
17
- os.makedirs(UPLOAD_FOLDER, exist_ok=True)
18
- os.makedirs(OUTPUT_FOLDER, exist_ok=True)
19
-
20
- # Configurar dispositivo (GPU se disponível)
21
- device = "cuda" if torch.cuda.is_available() else "cpu"
22
- torch.backends.cudnn.benchmark = True # Acelera GPU NVIDIA
23
-
24
- # Carregar modelos uma única vez (cache)
25
- WHISPER_MODEL = "openai/whisper-tiny" # Modelo mais rápido
26
- TRANSLATION_MODEL = "Helsinki-NLP/opus-mt-tc-big-en-pt" # Modelo alternativo
27
- TTS_MODEL = "microsoft/speecht5_tts"
28
-
29
- # Inicialização rápida dos modelos
30
- print("Carregando modelos...")
31
- whisper_processor = WhisperProcessor.from_pretrained(WHISPER_MODEL)
32
- whisper_model = WhisperForConditionalGeneration.from_pretrained(WHISPER_MODEL).to(device)
33
-
34
- translation_tokenizer = MarianTokenizer.from_pretrained(TRANSLATION_MODEL)
35
- translation_model = MarianMTModel.from_pretrained(TRANSLATION_MODEL).to(device)
36
-
37
- tts_processor = SpeechT5Processor.from_pretrained(TTS_MODEL)
38
- tts_model = SpeechT5ForTextToSpeech.from_pretrained(TTS_MODEL).to(device)
39
-
40
- # Funções otimizadas
41
- def transcribe_audio(audio_path):
42
- waveform, sample_rate = torchaudio.load(audio_path)
43
- waveform = waveform.to(device)
44
-
45
- # Processamento em chunks para áudios longos
46
- inputs = whisper_processor(
47
- waveform.squeeze().cpu().numpy(),
48
- sampling_rate=sample_rate,
49
- return_tensors="pt",
50
- chunk_length_s=30 # Processar em chunks de 30 segundos
51
- ).to(device)
52
-
53
- with torch.inference_mode():
54
- predicted_ids = whisper_model.generate(**inputs)
55
-
56
- return whisper_processor.batch_decode(predicted_ids, skip_special_tokens=True)[0]
57
-
58
- def translate_text(text):
59
- inputs = translation_tokenizer(text, return_tensors="pt", truncation=True).to(device)
60
- with torch.inference_mode():
61
- translated_ids = translation_model.generate(**inputs)
62
- return translation_tokenizer.decode(translated_ids[0], skip_special_tokens=True)
63
-
64
- def synthesize_speech(text, output_path):
65
- inputs = tts_processor(text, return_tensors="pt").to(device)
66
- with torch.inference_mode():
67
- speech = tts_model.generate_speech(inputs["input_ids"], tts_model.speaker_embeddings)
68
-
69
- # Converter para formato compatível com vídeo (44100 Hz, stereo)
70
- sf.write(output_path, np.tile(speech.cpu().numpy(), (2, 1)).T, 44100, subtype='PCM_16')
71
-
72
- def process_video(video_path, output_path):
73
- # Processamento paralelizado com FFmpeg
74
- (
75
- ffmpeg
76
- .input(video_path)
77
- .output(output_path, vcodec='copy', acodec='aac', strict='experimental')
78
- .global_args('-loglevel', 'error') # Reduzir logs
79
- .run(overwrite_output=True, cmd='ffmpeg')
80
- )
81
-
82
- # Fluxo principal otimizado
83
- def translate_video(video, progress=gr.Progress()):
 
 
 
 
84
  try:
85
- # O Gradio passa o caminho do arquivo como uma string
86
- video_path = video
87
-
88
- # Etapa 1: Extrair áudio
89
- progress(0.1, "Extraindo áudio...")
90
- audio_path = os.path.join(UPLOAD_FOLDER, "audio.wav")
91
- (
92
- ffmpeg
93
- .input(video_path)
94
- .output(audio_path, ac=1, ar=16000)
95
- .global_args('-loglevel', 'error')
96
- .run(overwrite_output=True)
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: {str(e)}"
128
 
129
- # Interface otimizada
130
  iface = gr.Interface(
131
- fn=translate_video,
132
- inputs=gr.Video(label="Vídeo de Entrada"),
133
  outputs=gr.Video(label="Vídeo Traduzido"),
134
- title="🚀 Tradutor de Vídeo Ultra-Rápido",
135
- description="Carregue um vídeo e receba a versão em português com áudio traduzido!",
136
- allow_flagging="never"
137
  )
138
 
139
- if __name__ == "__main__":
140
- iface.launch(server_port=7860, show_error=True)
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()