Subtitulación automática con python

1. Verifica que Whisper está instalado correctamente

Ejecuta en la terminal el siguiente comando para asegurarte de que tienes instalado el paquete correcto:

pip install -U openai-whisper

Nota: El paquete correcto es openai-whisper, no whisper.

2. Prueba el entorno de instalación

Asegúrate de estar usando el entorno de Python correcto donde instalaste Whisper. Para verificar, ejecuta en terminal:

pip show openai-whisper

Deberías ver algo como:

Name: openai-whisper
Version: X.X.X
Location: /ruta/de/instalacion/

Si no aparece, puede que Whisper esté instalado en otro entorno virtual. Asegúrate de activar el entorno correcto antes de ejecutar el script.

3. Prueba la carga del modelo

Abre una sesión de Python e intenta lo siguiente:

import whisper
model = whisper.load_model("base")
print("Modelo cargado correctamente")

Si esto funciona sin errores, entonces el problema está en tu script o en cómo lo estás ejecutando.

El python

import whisper
import os

def split_text_with_timing(text, start, end, word_limit=3, char_limit=35):
    """
    Divide un texto en fragmentos limitados por palabras o caracteres, ajustando los tiempos.
    """
    words = text.split()
    total_words = len(words)
    segments = []
    temp = []
    char_count = 0

    duration_per_word = (end - start) / total_words
    segment_start = start

    for index, word in enumerate(words):
        if len(temp) < word_limit and char_count + len(word) <= char_limit:
            temp.append(word)
            char_count += len(word) + 1  # +1 por el espacio
        else:
            segment_end = segment_start + len(temp) * duration_per_word
            segments.append((" ".join(temp), segment_start, segment_end))
            temp = [word]
            char_count = len(word)
            segment_start = segment_end

    # Añade el último segmento
    if temp:
        segment_end = segment_start + len(temp) * duration_per_word
        segments.append((" ".join(temp), segment_start, segment_end))

    return segments

def transcribe_with_limited_output(input_file, output_file, word_limit=3, char_limit=35):
    """
    Transcribe un audio y limita las líneas a un número de palabras o caracteres,
    ajustando los tiempos correctamente.
    """
    model = whisper.load_model("base")
    result = model.transcribe(input_file)

    with open(output_file, 'w') as f:
        for i, segment in enumerate(result['segments']):
            start = segment['start']
            end = segment['end']
            text = segment['text']

            # Divide el texto según los límites y ajusta los tiempos
            lines_with_timing = split_text_with_timing(text, start, end, word_limit, char_limit)

            for line, line_start, line_end in lines_with_timing:
                f.write(f"{i}\n")
                f.write(f"{format_time(line_start)} --> {format_time(line_end)}\n")
                f.write(f"{line}\n\n")

def format_time(seconds):
    """
    Convierte un tiempo en segundos a formato SRT (hh:mm:ss,ms).
    """
    ms = int((seconds % 1) * 1000)
    seconds = int(seconds)
    mins, secs = divmod(seconds, 60)
    hours, mins = divmod(mins, 60)
    return f"{hours:02}:{mins:02}:{secs:02},{ms:03}"

if __name__ == "__main__":
    input_file = "tu_audio.mp3"  # Cambia a tu archivo de audio
    output_file = "output_limited.srt"  # Archivo de salida
    transcribe_with_limited_output(input_file, output_file)
    print("Transcripción completada con tiempos ajustados.")

Cómo Funciona

  1. Función split_text:
    • Divide el texto en fragmentos según los límites especificados.
    • Usa tanto el límite de palabras como el de caracteres para ajustar cada línea.
  2. Modificaciones en la Transcripción:
    • Procesa cada segmento generado por Whisper.
    • Divide el texto del segmento en varias líneas si excede los límites.
  3. Salida en Formato SRT:
    • Genera un archivo SRT donde cada línea respeta el límite de palabras o caracteres.

Personalización

  • Cambia los valores de word_limit y char_limit según tus necesidades.
  • El código escribe un archivo SRT (output_limited.srt) con los subtítulos ajustados.

Y si ya tenemos el subtitulado y solo necesitamos dividirlo en palabras

import re

def parse_srt(srt_file):
    """
    Analiza un archivo SRT y devuelve una lista de segmentos con tiempos y textos.
    """
    with open(srt_file, 'r') as f:
        content = f.read()

    pattern = re.compile(r'(\d+)\n(\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3})\n(.*?)\n\n', re.DOTALL)
    matches = pattern.findall(content)

    segments = []
    for match in matches:
        index = int(match[0])
        start = parse_time(match[1])
        end = parse_time(match[2])
        text = match[3].replace('\n', ' ')  # Asegúrate de que el texto esté en una línea
        segments.append((index, start, end, text))
    return segments

def parse_time(timestamp):
    """
    Convierte un timestamp en formato SRT a segundos.
    """
    hours, minutes, seconds = map(float, re.split('[:,]', timestamp))
    return hours * 3600 + minutes * 60 + seconds

def format_time(seconds):
    """
    Convierte un tiempo en segundos al formato SRT (hh:mm:ss,ms).
    """
    ms = int((seconds % 1) * 1000)
    seconds = int(seconds)
    mins, secs = divmod(seconds, 60)
    hours, mins = divmod(mins, 60)
    return f"{hours:02}:{mins:02}:{secs:02},{ms:03}"

def split_text_with_timing(text, start, end, word_limit=3, char_limit=35):
    """
    Divide un texto en fragmentos limitados por palabras o caracteres, ajustando los tiempos.
    """
    words = text.split()
    total_words = len(words)
    segments = []
    temp = []
    char_count = 0

    duration_per_word = (end - start) / total_words
    segment_start = start

    for index, word in enumerate(words):
        if len(temp) < word_limit and char_count + len(word) <= char_limit:
            temp.append(word)
            char_count += len(word) + 1  # +1 por el espacio
        else:
            segment_end = segment_start + len(temp) * duration_per_word
            segments.append((" ".join(temp), segment_start, segment_end))
            temp = [word]
            char_count = len(word)
            segment_start = segment_end

    # Añade el último segmento
    if temp:
        segment_end = segment_start + len(temp) * duration_per_word
        segments.append((" ".join(temp), segment_start, segment_end))

    return segments

def split_srt(input_file, output_file, word_limit=3, char_limit=35):
    """
    Lee un archivo SRT, divide los segmentos según los límites especificados,
    y escribe el nuevo archivo SRT ajustado.
    """
    segments = parse_srt(input_file)

    with open(output_file, 'w') as f:
        count = 1
        for _, start, end, text in segments:
            # Divide el texto y ajusta los tiempos
            lines_with_timing = split_text_with_timing(text, start, end, word_limit, char_limit)

            for line, line_start, line_end in lines_with_timing:
                f.write(f"{count}\n")
                f.write(f"{format_time(line_start)} --> {format_time(line_end)}\n")
                f.write(f"{line}\n\n")
                count += 1

if __name__ == "__main__":
    input_srt = "input.srt"  # Cambia por tu archivo SRT
    output_srt = "output_split.srt"  # Archivo SRT de salida
    split_srt(input_srt, output_srt)
    print("Segmentación completada.")

Explicación del Código

  1. parse_srt:
    • Lee y analiza el archivo SRT para extraer los índices, tiempos de inicio y fin, y el texto.
  2. split_text_with_timing:
    • Divide el texto de cada segmento en partes más cortas, ajustando los tiempos proporcionalmente.
  3. split_srt:
    • Procesa el SRT de entrada, divide los segmentos según los límites de palabras y caracteres, y escribe un nuevo archivo SRT.
  4. format_time y parse_time:
    • Convierte entre los formatos de tiempo en segundos y SRT (hh:mm:ss,ms).

Parámetros Configurables

  • word_limit: Máximo número de palabras por línea.
  • char_limit: Máximo número de caracteres por línea.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Scroll to Top