Andro0s commited on
Commit
acd7eaf
·
verified ·
1 Parent(s): 4e273b2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -63
app.py CHANGED
@@ -5,15 +5,16 @@ import tempfile
5
  from pydub import AudioSegment
6
  import subprocess
7
 
8
- # Cargar modelo
9
  print("Cargando modelo Whisper...")
10
- model = whisper.load_model("base")
11
  print("Modelo cargado.")
12
 
 
13
  def extract_audio_from_video(video_path):
14
  """Extrae audio de video usando ffmpeg"""
15
  audio_path = tempfile.mktemp(suffix='.wav')
16
-
17
  command = [
18
  'ffmpeg',
19
  '-i', video_path,
@@ -21,88 +22,81 @@ def extract_audio_from_video(video_path):
21
  '-acodec', 'pcm_s16le',
22
  '-ar', '16000',
23
  '-ac', '1',
24
- '-y', # Sobrescribir si existe
25
  audio_path
26
  ]
27
-
28
  result = subprocess.run(command, capture_output=True, text=True)
29
  if result.returncode != 0:
30
  raise Exception(f"Error extrayendo audio: {result.stderr}")
31
-
 
 
 
 
 
 
 
 
 
32
  return audio_path
33
 
34
- def split_audio(audio_path, chunk_length_ms=30000):
35
- """Divide el audio en chunks"""
36
- audio = AudioSegment.from_wav(audio_path)
37
- chunks = []
38
-
39
- for i in range(0, len(audio), chunk_length_ms):
40
- chunk = audio[i:i + chunk_length_ms]
41
- chunk_path = tempfile.mktemp(suffix=f'_chunk_{i}.wav')
42
- chunk.export(chunk_path, format="wav")
43
- chunks.append(chunk_path)
44
-
45
- return chunks
46
 
47
  def transcribir_archivo(archivo):
48
  """Función principal de transcripción"""
49
  if archivo is None:
50
- yield "Por favor sube un archivo", ""
51
  return
52
-
53
- texto_completo = []
54
  archivos_temp = []
55
-
56
  try:
57
  extension = os.path.splitext(archivo)[1].lower()
58
  es_video = extension in ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.mpg', '.mpeg']
59
-
60
  yield "Procesando archivo...", ""
61
-
62
- # Extraer audio si es video
63
  if es_video:
64
  yield "Extrayendo audio del video...", ""
65
  audio_path = extract_audio_from_video(archivo)
66
- archivos_temp.append(audio_path)
67
  else:
68
- # Convertir a wav
69
- yield "Convirtiendo audio...", ""
70
- audio = AudioSegment.from_file(archivo)
71
- audio_path = tempfile.mktemp(suffix='.wav')
72
- audio.export(audio_path, format="wav", parameters=["-ar", "16000", "-ac", "1"])
73
- archivos_temp.append(audio_path)
74
-
75
- # Verificar duración
76
  audio = AudioSegment.from_wav(audio_path)
77
  duracion_total = len(audio) / 1000
78
-
79
- if duracion_total > 30:
80
- yield f"Dividiendo audio en partes (duración: {duracion_total:.1f}s)...", ""
81
- chunks = split_audio(audio_path, 30000)
82
- archivos_temp.extend(chunks)
83
- else:
84
- chunks = [audio_path]
85
-
86
- # Transcribir
87
- total_chunks = len(chunks)
88
- for i, chunk_path in enumerate(chunks):
89
- yield f"Transcribiendo parte {i+1} de {total_chunks}...", "\n\n".join(texto_completo)
90
-
91
- resultado = model.transcribe(
92
- chunk_path,
93
- language="es",
94
- task="transcribe"
95
- )
96
- texto_completo.append(resultado["text"])
97
-
98
- texto_final = "\n\n".join(texto_completo)
 
99
  yield "¡Transcripción completada!", texto_final
100
-
101
  except Exception as e:
102
  yield f"Error: {str(e)}", ""
103
-
104
  finally:
105
- # Limpiar
106
  for temp_file in archivos_temp:
107
  try:
108
  if os.path.exists(temp_file):
@@ -110,14 +104,16 @@ def transcribir_archivo(archivo):
110
  except:
111
  pass
112
 
 
113
  # Interfaz Gradio
114
  with gr.Blocks(title="Transcriptor de Video/Audio") as demo:
115
  gr.Markdown("""
116
  # 🎙️ Transcriptor de Video y Audio
 
117
 
118
- Sube un video o archivo de audio y obtén la transcripción en texto.
119
  """)
120
-
121
  with gr.Row():
122
  with gr.Column():
123
  archivo_input = gr.File(
@@ -125,15 +121,16 @@ with gr.Blocks(title="Transcriptor de Video/Audio") as demo:
125
  file_types=["video", "audio"]
126
  )
127
  btn_transcribir = gr.Button("🚀 Transcribir", variant="primary")
128
-
129
  with gr.Column():
130
  estado = gr.Textbox(label="Estado", interactive=False)
131
  resultado = gr.Textbox(
132
  label="Transcripción",
133
  lines=15,
134
- interactive=True
 
135
  )
136
-
137
  btn_transcribir.click(
138
  fn=transcribir_archivo,
139
  inputs=archivo_input,
 
5
  from pydub import AudioSegment
6
  import subprocess
7
 
8
+ # Cargar modelo - "small" funciona mucho mejor que "base" para español
9
  print("Cargando modelo Whisper...")
10
+ model = whisper.load_model("small")
11
  print("Modelo cargado.")
12
 
13
+
14
  def extract_audio_from_video(video_path):
15
  """Extrae audio de video usando ffmpeg"""
16
  audio_path = tempfile.mktemp(suffix='.wav')
17
+
18
  command = [
19
  'ffmpeg',
20
  '-i', video_path,
 
22
  '-acodec', 'pcm_s16le',
23
  '-ar', '16000',
24
  '-ac', '1',
25
+ '-y',
26
  audio_path
27
  ]
28
+
29
  result = subprocess.run(command, capture_output=True, text=True)
30
  if result.returncode != 0:
31
  raise Exception(f"Error extrayendo audio: {result.stderr}")
32
+
33
+ return audio_path
34
+
35
+
36
+ def convert_to_wav(input_path):
37
+ """Convierte cualquier audio a WAV 16kHz mono"""
38
+ audio = AudioSegment.from_file(input_path)
39
+ audio_path = tempfile.mktemp(suffix='.wav')
40
+ audio = audio.set_frame_rate(16000).set_channels(1)
41
+ audio.export(audio_path, format="wav")
42
  return audio_path
43
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  def transcribir_archivo(archivo):
46
  """Función principal de transcripción"""
47
  if archivo is None:
48
+ yield "Por favor sube un archivo.", ""
49
  return
50
+
 
51
  archivos_temp = []
52
+
53
  try:
54
  extension = os.path.splitext(archivo)[1].lower()
55
  es_video = extension in ['.mp4', '.avi', '.mov', '.mkv', '.webm', '.mpg', '.mpeg']
56
+
57
  yield "Procesando archivo...", ""
58
+
59
+ # Paso 1: obtener WAV limpio
60
  if es_video:
61
  yield "Extrayendo audio del video...", ""
62
  audio_path = extract_audio_from_video(archivo)
 
63
  else:
64
+ yield "Convirtiendo audio a WAV...", ""
65
+ audio_path = convert_to_wav(archivo)
66
+
67
+ archivos_temp.append(audio_path)
68
+
69
+ # Paso 2: verificar duración
 
 
70
  audio = AudioSegment.from_wav(audio_path)
71
  duracion_total = len(audio) / 1000
72
+ yield f"Audio listo. Duración: {duracion_total:.1f}s. Iniciando transcripción...", ""
73
+
74
+ # Paso 3: transcribir directamente con Whisper
75
+ # Whisper maneja internamente audios largos (sliding window de 30s)
76
+ # sin necesidad de dividir manualmente, lo que mejora la coherencia
77
+ resultado = model.transcribe(
78
+ audio_path,
79
+ language="es",
80
+ task="transcribe",
81
+ fp16=False, # Necesario en CPU (Hugging Face free tier)
82
+ temperature=0, # Más determinista, menos alucinaciones
83
+ best_of=1,
84
+ beam_size=5,
85
+ verbose=False
86
+ )
87
+
88
+ texto_final = resultado["text"].strip()
89
+
90
+ if not texto_final:
91
+ yield "La transcripción quedó vacía. Verifica que el audio tenga voz clara.", ""
92
+ return
93
+
94
  yield "¡Transcripción completada!", texto_final
95
+
96
  except Exception as e:
97
  yield f"Error: {str(e)}", ""
98
+
99
  finally:
 
100
  for temp_file in archivos_temp:
101
  try:
102
  if os.path.exists(temp_file):
 
104
  except:
105
  pass
106
 
107
+
108
  # Interfaz Gradio
109
  with gr.Blocks(title="Transcriptor de Video/Audio") as demo:
110
  gr.Markdown("""
111
  # 🎙️ Transcriptor de Video y Audio
112
+ Sube un video o archivo de audio y obtén la transcripción en español.
113
 
114
+ **Formatos soportados:** MP4, AVI, MOV, MKV, MP3, WAV, M4A, OGG, WEBM
115
  """)
116
+
117
  with gr.Row():
118
  with gr.Column():
119
  archivo_input = gr.File(
 
121
  file_types=["video", "audio"]
122
  )
123
  btn_transcribir = gr.Button("🚀 Transcribir", variant="primary")
124
+
125
  with gr.Column():
126
  estado = gr.Textbox(label="Estado", interactive=False)
127
  resultado = gr.Textbox(
128
  label="Transcripción",
129
  lines=15,
130
+ interactive=True,
131
+ placeholder="La transcripción aparecerá aquí..."
132
  )
133
+
134
  btn_transcribir.click(
135
  fn=transcribir_archivo,
136
  inputs=archivo_input,