RenanOF commited on
Commit
4aac447
·
verified ·
1 Parent(s): ebd09b4

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -0
app.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from transformers import pipeline
3
+ from pydub import AudioSegment
4
+ from pydub.utils import make_chunks
5
+ import tempfile
6
+ import os
7
+ import math
8
+
9
+ # --- Configurações ---
10
+ MODEL_NAME = "openai/whisper-base" # Ou "base", "small" - Cuidado com RAM/Tempo na CPU
11
+ CHUNK_LENGTH_MS = 30_000 # 30 segundos por chunk
12
+ MAX_FILE_SIZE_MB = 250 # Aumentado para ~120 min (ajuste conforme necessário)
13
+ TARGET_SAMPLE_RATE = 16000
14
+ # ---------------------
15
+
16
+ print(f"Carregando modelo Whisper: {MODEL_NAME}...")
17
+ # Inicialize o modelo Whisper
18
+ transcriber = pipeline(
19
+ "automatic-speech-recognition",
20
+ model=MODEL_NAME,
21
+ device="cpu" # Mantendo CPU conforme original
22
+ )
23
+ print("Modelo carregado.")
24
+
25
+ # Função para dividir áudios longos
26
+ def split_audio(audio_path, chunk_length=CHUNK_LENGTH_MS):
27
+ try:
28
+ audio = AudioSegment.from_file(audio_path)
29
+ print(f"Áudio carregado: Duração={audio.duration_seconds:.2f}s, Canais={audio.channels}, Taxa={audio.frame_rate}Hz")
30
+ chunks = make_chunks(audio, chunk_length)
31
+ print(f"Áudio dividido em {len(chunks)} chunks de ~{chunk_length/1000}s")
32
+ return chunks
33
+ except Exception as e:
34
+ print(f"Erro ao carregar ou dividir áudio: {e}")
35
+ raise # Re-lança a exceção para ser pega na função principal
36
+
37
+ # Função para comprimir/preparar áudio para Whisper
38
+ def prepare_audio(audio_path):
39
+ try:
40
+ audio = AudioSegment.from_file(audio_path)
41
+ # Converter para mono, taxa de amostragem alvo, profundidade de bits padrão (16)
42
+ prepared_audio = audio.set_frame_rate(TARGET_SAMPLE_RATE).set_channels(1).set_sample_width(2)
43
+
44
+ # Usar um arquivo temporário gerenciado pelo 'with' se possível
45
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_f:
46
+ prepared_path = temp_f.name
47
+
48
+ prepared_audio.export(prepared_path, format="wav")
49
+ print(f"Áudio preparado e salvo em: {prepared_path}")
50
+ return prepared_path
51
+ except Exception as e:
52
+ print(f"Erro ao preparar áudio: {e}")
53
+ raise
54
+
55
+ # Função para transcrever o áudio (agora como gerador para feedback)
56
+ def transcribe_audio_generator(audio_filepath):
57
+ if audio_filepath is None:
58
+ yield "Erro: Nenhum arquivo de áudio enviado."
59
+ return
60
+
61
+ try:
62
+ file_size_bytes = os.path.getsize(audio_filepath)
63
+ file_size_mb = file_size_bytes / (1024 * 1024)
64
+ print(f"Arquivo recebido: {audio_filepath}, Tamanho: {file_size_mb:.2f} MB")
65
+
66
+ # Verificar o tamanho do arquivo
67
+ if file_size_bytes > MAX_FILE_SIZE_MB * 1024 * 1024:
68
+ yield f"Erro: O arquivo excede o limite de {MAX_FILE_SIZE_MB} MB. Tamanho atual: {file_size_mb:.2f} MB."
69
+ return
70
+
71
+ yield f"Iniciando pré-processamento (pode levar um tempo)... Tamanho: {file_size_mb:.2f} MB"
72
+
73
+ prepared_audio_path = None
74
+ try:
75
+ prepared_audio_path = prepare_audio(audio_filepath)
76
+
77
+ yield f"Pré-processamento concluído. Dividindo em chunks..."
78
+ chunks = split_audio(prepared_audio_path)
79
+ total_chunks = len(chunks)
80
+
81
+ if total_chunks == 0:
82
+ yield "Erro: Não foi possível dividir o áudio em chunks."
83
+ return
84
+
85
+ full_transcription = []
86
+ yield f"Iniciando transcrição de {total_chunks} chunks (Modelo: {MODEL_NAME}). Isso pode demorar bastante..."
87
+
88
+ # Processar cada parte separadamente
89
+ for i, chunk in enumerate(chunks):
90
+ # Usar arquivo temporário para o chunk
91
+ with tempfile.NamedTemporaryFile(suffix=".wav", delete=True) as temp_chunk_file:
92
+ chunk.export(temp_chunk_file.name, format="wav")
93
+
94
+ # Transcrever o chunk
95
+ # Usar chunk_length para o pipeline pode ajudar em alguns casos
96
+ result = transcriber(
97
+ temp_chunk_file.name,
98
+ chunk_length_s=math.ceil(CHUNK_LENGTH_MS / 1000), # Whisper espera em segundos
99
+ return_timestamps=False # Mantido como False
100
+ )
101
+ transcription = result["text"]
102
+
103
+ # Adicionar ao resultado geral
104
+ chunk_label = f"[Chunk {i+1}/{total_chunks}]"
105
+ full_transcription.append(f"{chunk_label}: {transcription}")
106
+
107
+ # Atualizar a interface a cada chunk (ou a cada N chunks)
108
+ progress_update = f"Processando: {i+1}/{total_chunks} chunks...\n\n" + "\n".join(full_transcription)
109
+ yield progress_update
110
+
111
+ yield "Transcrição completa!\n\n" + "\n".join(full_transcription)
112
+
113
+ except Exception as e:
114
+ yield f"Erro durante o processamento: {str(e)}"
115
+ # Log detalhado do erro no console do servidor
116
+ import traceback
117
+ print("Erro detalhado:")
118
+ traceback.print_exc()
119
+
120
+ finally:
121
+ # Limpar o arquivo preparado se ele foi criado
122
+ if prepared_audio_path and os.path.exists(prepared_audio_path):
123
+ try:
124
+ os.remove(prepared_audio_path)
125
+ print(f"Arquivo temporário preparado removido: {prepared_audio_path}")
126
+ except OSError as e:
127
+ print(f"Erro ao remover arquivo temporário {prepared_audio_path}: {e}")
128
+ # O arquivo original (audio_filepath) é gerenciado pelo Gradio
129
+ # Os arquivos de chunk são gerenciados pelo 'with tempfile.NamedTemporaryFile'
130
+
131
+ except Exception as e:
132
+ yield f"Erro inesperado ao processar áudio: {str(e)}"
133
+ import traceback
134
+ print("Erro detalhado:")
135
+ traceback.print_exc()
136
+
137
+
138
+ # Interface gráfica com Gradio
139
+ with gr.Blocks() as demo:
140
+ gr.Markdown(f"# 🎙️ Whisper Transcription - Áudios Longos (até {MAX_FILE_SIZE_MB} MB)")
141
+ gr.Markdown(f"**Atenção:** Áudios muito longos podem levar **muito tempo** para processar (potencialmente horas), especialmente com o modelo `{MODEL_NAME}` na CPU.")
142
+
143
+ with gr.Row():
144
+ with gr.Column(scale=1):
145
+ gr.Markdown(f"### 1️⃣ Envie seu áudio (máx. {MAX_FILE_SIZE_MB} MB)")
146
+ audio_input = gr.Audio(type="filepath", label="Envie um arquivo de áudio")
147
+
148
+ with gr.Column(scale=1):
149
+ gr.Markdown("### 2️⃣ Resultado da transcrição (atualizado durante o processo)")
150
+ transcription_output = gr.Textbox(label="Transcrição", lines=20, interactive=False)
151
+
152
+ transcribe_button = gr.Button("🚀 Transcrever Áudio")
153
+
154
+ # Vincular ação ao botão - Usando a função geradora
155
+ transcribe_button.click(
156
+ fn=transcribe_audio_generator,
157
+ inputs=[audio_input],
158
+ outputs=[transcription_output]
159
+ )
160
+
161
+ # Rodar a aplicação
162
+ print("Iniciando interface Gradio...")
163
+ # share=True pode não funcionar bem com processos muito longos em ambientes gratuitos
164
+ demo.launch(share=False) # Recomendo testar localmente primeiro (share=False)
165
+ print("Interface disponível.")