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