RXTIME commited on
Commit
39b8c2e
·
verified ·
1 Parent(s): 9833fb2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -90
app.py CHANGED
@@ -4,124 +4,135 @@ import torch
4
  import torchaudio
5
  from transformers import (
6
  WhisperProcessor, WhisperForConditionalGeneration,
7
- SpeechT5Processor, SpeechT5ForTextToSpeech,
8
- MarianMTModel, MarianTokenizer
9
  )
10
  import ffmpeg
11
  import soundfile as sf
 
12
 
13
  # Configurações
14
  UPLOAD_FOLDER = "uploads"
15
  OUTPUT_FOLDER = "outputs"
 
 
16
 
17
- if not os.path.exists(UPLOAD_FOLDER):
18
- os.makedirs(UPLOAD_FOLDER)
19
- if not os.path.exists(OUTPUT_FOLDER):
20
- os.makedirs(OUTPUT_FOLDER)
21
-
22
- # Verificar se a GPU está disponível
23
  device = "cuda" if torch.cuda.is_available() else "cpu"
24
- print(f"Usando dispositivo: {device}")
 
 
 
 
 
25
 
26
- # Inicializar modelos
27
- whisper_processor = WhisperProcessor.from_pretrained("openai/whisper-small")
28
- whisper_model = WhisperForConditionalGeneration.from_pretrained("openai/whisper-small").to(device)
 
29
 
30
- tts_processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
31
- tts_model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts").to(device)
32
 
33
- # Usar um modelo alternativo de tradução
34
- translation_model_name = "Helsinki-NLP/opus-mt-tc-big-en-pt"
35
- translation_tokenizer = MarianTokenizer.from_pretrained(translation_model_name)
36
- translation_model = MarianMTModel.from_pretrained(translation_model_name).to(device)
37
 
38
- # Funções auxiliares
39
  def transcribe_audio(audio_path):
40
  waveform, sample_rate = torchaudio.load(audio_path)
41
  waveform = waveform.to(device)
42
- inputs = whisper_processor(waveform.squeeze().cpu().numpy(), sampling_rate=sample_rate, return_tensors="pt").to(device)
43
- with torch.no_grad():
44
- predicted_ids = whisper_model.generate(inputs.input_features)
45
- transcription = whisper_processor.batch_decode(predicted_ids, skip_special_tokens=True)
46
- return transcription[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
  def synthesize_speech(text, output_path):
49
  inputs = tts_processor(text, return_tensors="pt").to(device)
50
- with torch.no_grad():
51
  speech = tts_model.generate_speech(inputs["input_ids"], tts_model.speaker_embeddings)
52
- sf.write(output_path, speech.cpu().numpy(), samplerate=22050)
53
-
54
- def translate_text(text, target_language="pt"):
55
- inputs = translation_tokenizer(text, return_tensors="pt", truncation=True).to(device)
56
- with torch.no_grad():
57
- translated_ids = translation_model.generate(**inputs)
58
- translated_text = translation_tokenizer.decode(translated_ids[0], skip_special_tokens=True)
59
- return translated_text
60
-
61
- def extract_audio(video_path, audio_path):
62
- ffmpeg.input(video_path).output(audio_path, ac=1, ar="16000").run(overwrite_output=True)
63
-
64
- def replace_audio_in_video(video_path, audio_path, output_path):
65
- # Extrair a taxa de amostragem do áudio original
66
- probe = ffmpeg.probe(video_path)
67
- audio_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'audio'), None)
68
- original_sample_rate = int(audio_stream['sample_rate'])
69
-
70
- # Converter o áudio sintetizado para a taxa de amostragem do vídeo original
71
- converted_audio_path = os.path.join(UPLOAD_FOLDER, "converted_audio.wav")
72
- ffmpeg.input(audio_path).output(converted_audio_path, ar=original_sample_rate).run(overwrite_output=True)
73
-
74
- # Substituir o áudio no vídeo
75
- video = ffmpeg.input(video_path)
76
- audio = ffmpeg.input(converted_audio_path)
77
- ffmpeg.output(video.video, audio.audio, output_path, vcodec="copy", acodec="aac").run(overwrite_output=True)
78
-
79
- # Função principal para Gradio
80
  def translate_video(video, progress=gr.Progress()):
81
  try:
82
- # O Gradio passa o caminho do arquivo como uma string
83
- video_path = video
84
-
85
- # Extrair áudio
86
- progress(0.1, desc="Extraindo áudio do vídeo...")
87
  audio_path = os.path.join(UPLOAD_FOLDER, "audio.wav")
88
- extract_audio(video_path, audio_path)
89
-
90
- # Transcrever áudio
91
- progress(0.3, desc="Transcrevendo áudio...")
92
- transcribed_text = transcribe_audio(audio_path)
93
- print("Texto transcrito:", transcribed_text)
94
-
95
- # Traduzir texto
96
- progress(0.5, desc="Traduzindo texto...")
97
- translated_text = translate_text(transcribed_text, target_language="pt")
98
- print("Texto traduzido:", translated_text)
99
-
100
- # Sintetizar áudio
101
- progress(0.7, desc="Sintetizando áudio em português...")
102
- synthesized_audio_path = os.path.join(UPLOAD_FOLDER, "synthesized_audio.wav")
103
- synthesize_speech(translated_text, synthesized_audio_path)
104
-
105
- # Substituir áudio no vídeo
106
- progress(0.9, desc="Substituindo áudio no vídeo...")
107
- output_video_path = os.path.join(OUTPUT_FOLDER, "translated_video.mp4")
108
- replace_audio_in_video(video_path, synthesized_audio_path, output_video_path)
109
-
110
- # Finalizar progresso
111
- progress(1.0, desc="Concluído!")
112
- return output_video_path
 
 
 
 
 
 
 
 
 
113
 
114
  except Exception as e:
115
  return f"Erro: {str(e)}"
116
 
117
- # Interface Gradio
118
  iface = gr.Interface(
119
  fn=translate_video,
120
- inputs=gr.Video(),
121
- outputs=gr.Video(),
122
- title="Tradutor de Vídeo",
123
- description="Carregue um vídeo em qualquer idioma e ele será traduzido para português."
 
124
  )
125
 
126
- iface.launch()
127
-
 
 
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-en-pt"
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
+ # Etapa 1: Extrair áudio
86
+ progress(0.1, "Extraindo áudio...")
 
 
 
87
  audio_path = os.path.join(UPLOAD_FOLDER, "audio.wav")
88
+ (
89
+ ffmpeg
90
+ .input(video)
91
+ .output(audio_path, ac=1, ar=16000)
92
+ .global_args('-loglevel', 'error')
93
+ .run(overwrite_output=True)
94
+ )
95
+
96
+ # Etapa 2: Transcrição paralela
97
+ progress(0.3, "Transcrevendo...")
98
+ transcription = transcribe_audio(audio_path)
99
+
100
+ # Etapa 3: Tradução em lote
101
+ progress(0.5, "Traduzindo...")
102
+ translated_text = translate_text(transcription)
103
+
104
+ # Etapa 4: Síntese de voz acelerada
105
+ progress(0.7, "Sintetizando voz...")
106
+ synthesized_audio = os.path.join(UPLOAD_FOLDER, "synthesized_audio.wav")
107
+ synthesize_speech(translated_text, synthesized_audio)
108
+
109
+ # Etapa 5: Processamento final do vídeo
110
+ progress(0.9, "Montando vídeo...")
111
+ output_path = os.path.join(OUTPUT_FOLDER, "video_traduzido.mp4")
112
+ (
113
+ ffmpeg
114
+ .input(video)
115
+ .output(output_path, vcodec='copy', acodec='copy', map='0:v:0')
116
+ .input(synthesized_audio)
117
+ .global_args('-loglevel', 'error')
118
+ .run(overwrite_output=True)
119
+ )
120
+
121
+ return output_path
122
 
123
  except Exception as e:
124
  return f"Erro: {str(e)}"
125
 
126
+ # Interface otimizada
127
  iface = gr.Interface(
128
  fn=translate_video,
129
+ inputs=gr.Video(label="Vídeo de Entrada"),
130
+ outputs=gr.Video(label="Vídeo Traduzido"),
131
+ title="🚀 Tradutor de Vídeo Ultra-Rápido",
132
+ description="Carregue um vídeo e receba a versão em português com áudio traduzido!",
133
+ allow_flagging="never"
134
  )
135
 
136
+ if __name__ == "__main__":
137
+ iface.launch(server_port=7860, show_error=True)
138
+