"""Funciones helper para sintetizar desde SRT. Este módulo mantiene compatibilidad con la antigua utilidad `srt_to_kokoro.py`. Contiene `parse_srt_file` y `synth_chunk` delegando a infra.kokoro_utils. Se incluye una función `synthesize_from_srt` que documenta la compatibilidad con `KokoroHttpClient` (nombre esperado por otros módulos). """ from __future__ import annotations from typing import Any from whisper_project.infra.kokoro_utils import parse_srt_file as _parse_srt_file, synth_chunk as _synth_chunk def parse_srt_file(path: str): """Parsea un .srt y devuelve la lista de subtítulos. Delegado a `whisper_project.infra.kokoro_utils.parse_srt_file`. """ return _parse_srt_file(path) def synth_chunk(endpoint: str, text: str, headers: dict, payload_template: Any, timeout: int = 60) -> bytes: """Envía texto al endpoint y devuelve bytes de audio. Delegado a `whisper_project.infra.kokoro_utils.synth_chunk`. """ return _synth_chunk(endpoint, text, headers, payload_template, timeout=timeout) def synthesize_from_srt(srt_path: str, out_wav: str, endpoint: str = "", api_key: str = ""): """Compat layer: función con el nombre esperado por scripts legacy. Nota: la implementación completa se encuentra ahora en `KokoroHttpClient`. Esta función delega a `parse_srt_file` y `synth_chunk` si se necesita. """ raise NotImplementedError("Use KokoroHttpClient.synthesize_from_srt or the infra adapter instead") __all__ = ["parse_srt_file", "synth_chunk", "synthesize_from_srt"] #!/usr/bin/env python3 """ srt_to_kokoro.py Leer un archivo .srt y sintetizar cada subtítulo usando una API OpenAPI-compatible (p. ej. Kokoro). - Intenta autodetectar un endpoint de síntesis en `--openapi` (URL JSON) buscando paths que contengan 'synth'|'tts'|'text' y que acepten POST. - Alternativamente usa `--endpoint` y un `--payload-template` con {text} como placeholder. - Guarda fragmentos temporales y los concatena con ffmpeg en un único WAV de salida. Dependencias: requests, srt (pip install requests srt) Requiere ffmpeg en PATH. Ejemplos: python srt_to_kokoro.py --srt subs.srt --openapi "https://kokoro.../openapi.json" --voice "alloy" --out out.wav --api-key "TOKEN" python srt_to_kokoro.py --srt subs.srt --endpoint "https://kokoro.../v1/synthesize" --payload-template '{"text": "{text}", "voice": "alloy"}' --out out.wav """ import argparse import os import shutil import subprocess import sys import tempfile from typing import Optional """ Thin wrapper CLI que delega en `KokoroHttpClient.synthesize_from_srt`. Conserva la interfaz CLI previa para compatibilidad, pero internamente usa el cliente HTTP nativo definido en `whisper_project.infra.kokoro_adapter`. """ import argparse import os import sys import tempfile from whisper_project.infra.kokoro_adapter import KokoroHttpClient def main(): p = argparse.ArgumentParser() p.add_argument("--srt", required=True, help="Ruta al archivo .srt traducido") p.add_argument("--endpoint", required=False, help="URL directa del endpoint de síntesis (opcional)") p.add_argument("--api-key", required=False, help="Valor para autorización (se envía como header Authorization: Bearer )") p.add_argument("--voice", default="em_alex") p.add_argument("--model", default="model") p.add_argument("--out", required=True, help="Ruta de salida WAV final") p.add_argument("--video", required=False, help="Ruta al vídeo original (opcional)") p.add_argument("--align", action="store_true", help="Alinear segmentos con timestamps del SRT") p.add_argument("--keep-chunks", action="store_true") p.add_argument("--mix-with-original", action="store_true") p.add_argument("--mix-background-volume", type=float, default=0.2) p.add_argument("--replace-original", action="store_true") args = p.parse_args() # Construir cliente Kokoro HTTP y delegar la síntesis completa endpoint = args.endpoint or os.environ.get("KOKORO_ENDPOINT") api_key = args.api_key or os.environ.get("KOKORO_API_KEY") if not endpoint: print("Debe proporcionar --endpoint o la variable de entorno KOKORO_ENDPOINT", file=sys.stderr) sys.exit(2) client = KokoroHttpClient(endpoint, api_key=api_key, voice=args.voice, model=args.model) try: client.synthesize_from_srt( srt_path=args.srt, out_wav=args.out, video=args.video, align=args.align, keep_chunks=args.keep_chunks, mix_with_original=args.mix_with_original, mix_background_volume=args.mix_background_volume, ) print(f"Archivo final generado en: {args.out}") except Exception as e: print(f"Error durante la síntesis desde SRT: {e}", file=sys.stderr) sys.exit(1) if __name__ == '__main__': main()