travahacker commited on
Commit
18fd051
·
1 Parent(s): 8ceb1f3

Add transcrição YouTube com Whisper (ZeroGPU)

Browse files
Files changed (4) hide show
  1. README.md +27 -7
  2. app.py +135 -0
  3. packages.txt +1 -0
  4. requirements.txt +3 -0
README.md CHANGED
@@ -1,13 +1,33 @@
1
  ---
2
- title: IA Youtube Transcript
3
- emoji: 📈
4
- colorFrom: green
5
- colorTo: gray
6
  sdk: gradio
7
- sdk_version: 6.5.1
8
- python_version: '3.12'
9
  app_file: app.py
 
10
  pinned: false
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Transcrição YouTube
3
+ emoji: 🎙️
4
+ colorFrom: blue
5
+ colorTo: purple
6
  sdk: gradio
7
+ sdk_version: 4.44.0
 
8
  app_file: app.py
9
+ hardware: zerogpu
10
  pinned: false
11
+ license: mit
12
  ---
13
 
14
+ # Transcrição YouTube com Whisper
15
+
16
+ Cola o link do YouTube, escolhe o modelo Whisper e transcreve. **100% local na GPU** (ZeroGPU).
17
+
18
+ ## Como usar
19
+
20
+ 1. Cole o link do vídeo
21
+ 2. Escolha o modelo (small = bom equilíbrio)
22
+ 3. Clique em Transcrever
23
+ 4. Aguarde (pode levar 1–2 min na fila da GPU)
24
+
25
+ ## Requisitos
26
+
27
+ - **ZeroGPU**: Este Space usa ZeroGPU. Ao criar, selecione **ZeroGPU** no hardware.
28
+ - **Conta PRO** necessária para *criar* Spaces ZeroGPU. Qualquer um pode *usar* o Space.
29
+
30
+ ## Quota
31
+
32
+ - Conta grátis: ~3.5 min de GPU/dia
33
+ - PRO: ~25 min/dia
app.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Transcrição YouTube com Whisper — ZeroGPU Space
3
+
4
+ Cola o link, escolhe o modelo, transcreve. Usa ZeroGPU para processamento.
5
+ """
6
+ import subprocess
7
+ import tempfile
8
+ from pathlib import Path
9
+
10
+ import gradio as gr
11
+
12
+ # ZeroGPU: decorator é no-op fora do HF
13
+ try:
14
+ import spaces
15
+ except ImportError:
16
+ class _Spaces:
17
+ def GPU(self, fn=None, **kwargs):
18
+ def decorator(f):
19
+ return f
20
+ return decorator(fn) if fn else decorator
21
+ spaces = _Spaces()
22
+
23
+
24
+ def baixar_audio(url: str, pasta: Path) -> Path:
25
+ """Baixa áudio do YouTube com yt-dlp."""
26
+ pasta.mkdir(parents=True, exist_ok=True)
27
+ out = pasta / "audio.%(ext)s"
28
+ cmd = [
29
+ "yt-dlp", "-x", "--audio-format", "wav", "--audio-quality", "0",
30
+ "-o", str(out), "--no-playlist", url,
31
+ ]
32
+ subprocess.run(cmd, check=True, capture_output=True, text=True)
33
+ for ext in [".wav", ".m4a", ".webm", ".opus"]:
34
+ p = pasta / f"audio{ext}"
35
+ if p.exists():
36
+ return p
37
+ for f in pasta.iterdir():
38
+ if f.suffix.lower() in (".wav", ".m4a", ".webm", ".opus", ".mp3"):
39
+ return f
40
+ raise FileNotFoundError("Áudio não encontrado após download")
41
+
42
+
43
+ @spaces.GPU(duration=180)
44
+ def transcrever_gpu(url: str, modelo: str, idioma: str) -> str:
45
+ """
46
+ Transcreve vídeo do YouTube. Roda na GPU (ZeroGPU).
47
+ duration=180: vídeos até ~3min; aumente para vídeos mais longos.
48
+ """
49
+ from faster_whisper import WhisperModel
50
+
51
+ if not url or ("youtube.com" not in url and "youtu.be" not in url):
52
+ return "❌ Cole um link válido do YouTube."
53
+
54
+ with tempfile.TemporaryDirectory() as tmpdir:
55
+ pasta = Path(tmpdir)
56
+ try:
57
+ audio_path = baixar_audio(url, pasta)
58
+ except Exception as e:
59
+ return f"❌ Erro ao baixar: {e}"
60
+
61
+ model = WhisperModel(modelo, device="cuda", compute_type="float16")
62
+ lang = None if idioma == "Auto" else idioma.lower()
63
+
64
+ segments, info = model.transcribe(
65
+ str(audio_path),
66
+ language=lang,
67
+ beam_size=5,
68
+ vad_filter=True,
69
+ )
70
+
71
+ resultado = []
72
+ for seg in segments:
73
+ resultado.append({
74
+ "start": seg.start,
75
+ "end": seg.end,
76
+ "text": seg.text.strip(),
77
+ })
78
+
79
+ texto = "\n".join(s["text"] for s in resultado if s["text"])
80
+ if not texto:
81
+ return "⚠️ Nenhum texto transcrito (vídeo sem fala?)."
82
+
83
+ return f"Idioma detectado: {info.language}\n\n{texto}"
84
+
85
+
86
+ MODELOS = ["tiny", "base", "small", "medium", "large-v3"]
87
+ IDIOMAS = ["Auto", "pt", "en", "es", "fr"]
88
+
89
+ with gr.Blocks(
90
+ title="Transcrição YouTube",
91
+ theme=gr.themes.Soft(),
92
+ ) as demo:
93
+ gr.Markdown("# 🎙️ Transcrição YouTube")
94
+ gr.Markdown("Cola o link, escolhe o modelo Whisper. **ZeroGPU** — processamento gratuito na nuvem.")
95
+
96
+ with gr.Row():
97
+ url = gr.Textbox(
98
+ label="Link do YouTube",
99
+ placeholder="https://www.youtube.com/watch?v=...",
100
+ scale=3,
101
+ )
102
+ with gr.Row():
103
+ modelo = gr.Dropdown(
104
+ label="Modelo Whisper",
105
+ choices=MODELOS,
106
+ value="small",
107
+ info="small = bom equilíbrio; large-v3 = mais preciso (mais lento)",
108
+ )
109
+ idioma = gr.Dropdown(
110
+ label="Idioma",
111
+ choices=IDIOMAS,
112
+ value="Auto",
113
+ )
114
+
115
+ btn = gr.Button("Transcrever", variant="primary")
116
+
117
+ saida = gr.Textbox(
118
+ label="Transcrição",
119
+ lines=15,
120
+ max_lines=30,
121
+ )
122
+
123
+ btn.click(
124
+ fn=transcrever_gpu,
125
+ inputs=[url, modelo, idioma],
126
+ outputs=saida,
127
+ )
128
+
129
+ gr.Markdown("---")
130
+ gr.Markdown(
131
+ "**Uso de quota ZeroGPU:** ~3.5 min/dia (conta grátis). "
132
+ "A transcrição pode levar 1–2 min para iniciar (fila da GPU)."
133
+ )
134
+
135
+ demo.launch()
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ffmpeg
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio>=4.0.0
2
+ faster-whisper>=1.0.0
3
+ yt-dlp>=2024.1.0