""" Transcrição de áudio — ZeroGPU Space Envie um arquivo de áudio (mp3, wav, m4a, etc.) e transcreva com Whisper. """ import tempfile from pathlib import Path import gradio as gr # ZeroGPU: decorator é no-op fora do HF try: import spaces except ImportError: class _Spaces: def GPU(self, fn=None, **kwargs): def decorator(f): return f return decorator(fn) if fn else decorator spaces = _Spaces() def _fmt_tempo(segundos: float) -> str: """Formata segundos como MM:SS ou HH:MM:SS.""" h = int(segundos // 3600) m = int((segundos % 3600) // 60) s = int(segundos % 60) if h > 0: return f"{h:01d}:{m:02d}:{s:02d}" return f"{m:01d}:{s:02d}" @spaces.GPU(duration=180) def transcrever(audio, modelo: str, idioma: str) -> str: """Transcreve áudio enviado com Whisper.""" try: from faster_whisper import WhisperModel path = None if isinstance(audio, str) and audio and Path(audio).exists(): path = str(audio) elif hasattr(audio, "name"): p = getattr(audio, "name", None) if p and Path(str(p)).exists(): path = str(p) elif isinstance(audio, bytes) and audio: with tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) as f: f.write(audio) path = f.name if not path: return "❌ Envie um arquivo de áudio." model = WhisperModel(modelo, device="cuda", compute_type="float16") lang = None if idioma == "Auto" else idioma.lower() segments, info = model.transcribe( path, language=lang, beam_size=5, vad_filter=True, ) resultado = [] for seg in segments: resultado.append({ "start": seg.start, "end": seg.end, "text": seg.text.strip(), }) # Timestamp + parágrafos: [MM:SS] texto, linha em branco quando pausa > 1.5s PAUSA_PARAGRAFO = 1.5 linhas = [] prev_end = 0 for s in resultado: if not s["text"]: continue if prev_end > 0 and (s["start"] - prev_end) > PAUSA_PARAGRAFO: linhas.append("") # linha em branco = novo parágrafo ts = _fmt_tempo(s["start"]) linhas.append(f"[{ts}] {s['text']}") prev_end = s["end"] texto = "\n".join(linhas) if not texto: return "⚠️ Nenhum texto transcrito (áudio sem fala?)." return f"Idioma detectado: {info.language}\n\n{texto}" except Exception as e: return f"❌ Erro: {type(e).__name__}: {e}" MODELOS = ["tiny", "base", "small", "medium", "large-v3"] IDIOMAS = ["Auto", "pt", "en", "es", "fr"] with gr.Blocks( title="Transcrição de áudio", theme=gr.themes.Soft(), ) as demo: gr.Markdown("# 🎙️ Transcrição de áudio") gr.Markdown( "Envie um arquivo de áudio (mp3, wav, m4a, webm, etc.) e transcreva com Whisper. " "**ZeroGPU** — processamento gratuito na nuvem." ) with gr.Row(): audio = gr.File( label="Áudio", file_types=[".mp3", ".wav", ".m4a", ".webm", ".opus", ".ogg", ".flac"], ) with gr.Row(): modelo = gr.Dropdown( label="Modelo Whisper", choices=MODELOS, value="small", info="small = bom equilíbrio; large-v3 = mais preciso (mais lento)", ) idioma = gr.Dropdown( label="Idioma", choices=IDIOMAS, value="Auto", ) btn = gr.Button("Transcrever", variant="primary") saida = gr.Textbox( label="Transcrição", lines=15, max_lines=30, ) btn.click( fn=transcrever, inputs=[audio, modelo, idioma], outputs=saida, ) gr.Markdown("---") gr.Markdown( "A transcrição pode levar 1–2 min para iniciar (fila da GPU)." ) demo.launch(show_error=True, share=True)