Files
twitch-highlight-detector/pipeline_dos_pasadas.py
renato97 00180d0b1c Sistema completo de detección de highlights con VLM y análisis de gameplay
- Implementación de detector híbrido (Whisper + Chat + Audio + VLM)
- Sistema de detección de gameplay real vs hablando
- Scene detection con FFmpeg
- Soporte para RTX 3050 y RX 6800 XT
- Guía completa en 6800xt.md para próxima IA
- Scripts de filtrado visual y análisis de contexto
- Pipeline automatizado de generación de videos
2026-02-19 17:38:14 +00:00

218 lines
6.9 KiB
Python

#!/usr/bin/env python3
"""
Workflow de dos pasadas para highlights:
1. 360p (rápido) → Previsualización → Confirmación usuario
2. 1080p (calidad) → Video final
"""
import subprocess
import json
import sys
import logging
from pathlib import Path
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def download_video(video_id, quality="360p", output="video.mp4"):
"""Descarga video con streamlink"""
logger.info(f"Descargando video en {quality}...")
# Mapeo de calidad
quality_map = {
"360p": "360p,480p,best",
"1080p": "1080p,720p,best"
}
cmd = [
"streamlink",
f"https://www.twitch.tv/videos/{video_id}",
quality_map[quality],
"-o", output
]
result = subprocess.run(cmd, capture_output=True)
if result.returncode != 0:
logger.error(f"Error descargando video: {result.stderr.decode()}")
return False
return True
def download_chat(video_id, output="chat.json"):
"""Descarga chat con TwitchDownloaderCLI"""
logger.info(f"Descargando chat...")
cmd = ["dotnet", "/tmp/TDC_output/TwitchDownloaderCLI.dll",
"chatdownload", "--id", video_id, "-o", output]
result = subprocess.run(cmd, capture_output=True)
return result.returncode == 0
def detect_highlights(video, chat, output="highlights.json",
threshold=0.8, min_duration=5):
"""Detecta highlights con GPU"""
logger.info(f"Detectando highlights (threshold={threshold}, min_duration={min_duration})...")
cmd = [
"python3", "detector_gpu.py",
"--video", video,
"--chat", chat,
"--output", output,
"--threshold", str(threshold),
"--min-duration", str(min_duration),
"--device", "cuda"
]
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
# Cargar resultados
with open(output, 'r') as f:
highlights = json.load(f)
return highlights
def generate_summary(video, highlights, output, padding=5):
"""Genera video resumen"""
logger.info(f"Generando video resumen ({len(highlights)} clips)...")
cmd = [
"python3", "generate_video.py",
"--video", video,
"--highlights", highlights,
"--output", output,
"--padding", str(padding)
]
result = subprocess.run(cmd, capture_output=True, text=True)
print(result.stdout)
return result.returncode == 0
def format_timestamp(seconds):
"""Formatea segundos a HH:MM:SS"""
hours = seconds // 3600
minutes = (seconds % 3600) // 60
secs = seconds % 60
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
def show_highlights(highlights):
"""Muestra resumen de highlights"""
total_duration = sum(e - s for s, e in highlights)
print("\n" + "=" * 60)
print("HIGHLIGHTS DETECTADOS".center(60))
print("=" * 60)
print(f"Total: {len(highlights)} clips")
print(f"Duración total: {total_duration}s ({total_duration/60:.1f} minutos)")
print("-" * 60)
for i, (start, end) in enumerate(highlights[:20], 1):
duration = end - start
print(f"{i:2d}. {format_timestamp(start)} - {format_timestamp(end)} ({duration}s)")
if len(highlights) > 20:
print(f"... y {len(highlights) - 20} más")
print("=" * 60)
def confirm_action():
"""Pide confirmación al usuario"""
response = input("\n¿Generar versión en 1080p? (s/n): ").strip().lower()
return response in ['s', 'si', 'y', 'yes']
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--video-id", required=True)
parser.add_argument("--threshold", type=float, default=0.8)
parser.add_argument("--min-duration", type=int, default=8)
parser.add_argument("--skip-360p", action="store_true")
parser.add_argument("--force-1080p", action="store_true")
args = parser.parse_args()
video_id = args.video_id
if args.force_1080p:
# Directo a 1080p
logger.info("Modo: Generar directamente en 1080p")
video_file = f"stream_{video_id}_1080p.mp4"
chat_file = f"chat_{video_id}.json"
highlights_file = f"highlights_{video_id}.json"
output_file = f"resumen_{video_id}_1080p.mp4"
if not download_video(video_id, "1080p", video_file):
return 1
if not download_chat(video_id, chat_file):
return 1
highlights = detect_highlights(video_file, chat_file, highlights_file,
args.threshold, args.min_duration)
show_highlights(highlights)
generate_summary(video_file, highlights_file, output_file)
print(f"\n✅ Video final: {output_file}")
elif not args.skip_360p:
# PASADA 1: 360p (previsualización rápida)
logger.info("PASADA 1: Procesando en 360p para previsualización")
video_360 = f"stream_{video_id}_360p.mp4"
chat_file = f"chat_{video_id}.json"
highlights_file = f"highlights_{video_id}.json"
output_360 = f"preview_{video_id}_360p.mp4"
# Descargar 360p
if not download_video(video_id, "360p", video_360):
return 1
# Descargar chat
if not download_chat(video_id, chat_file):
return 1
# Detectar highlights
highlights = detect_highlights(video_360, chat_file, highlights_file,
args.threshold, args.min_duration)
if not highlights:
print("❌ No se detectaron highlights. Intenta con threshold más bajo.")
return 1
# Mostrar resultados
show_highlights(highlights)
# Generar previsualización 360p
generate_summary(video_360, highlights_file, output_360)
print(f"\n📺 Previsualización: {output_360}")
# Confirmar para 1080p
if confirm_action():
# PASADA 2: 1080p (calidad final)
logger.info("PASADA 2: Procesando en 1080p para calidad final")
video_1080 = f"stream_{video_id}_1080p.mp4"
output_1080 = f"resumen_{video_id}_1080p.mp4"
print(f"\n⏳ Descargando video en 1080p...")
if not download_video(video_id, "1080p", video_1080):
print("❌ Error descargando en 1080p. Puedes usar el video 360p.")
return 1
# Reusar highlights ya detectados
generate_summary(video_1080, highlights_file, output_1080)
print(f"\n✅ Video final 1080p: {output_1080}")
print(f"📺 Previsualización 360p: {output_360}")
print(f"📊 Highlights: {highlights_file}")
else:
print("\n✅ Proceso cancelado. Puedes usar:")
print(f" - Video 360p: {video_360}")
print(f" - Previsualización: {output_360}")
print(f" - Highlights JSON: {highlights_file}")
else:
print("Usa --force-1080p para generar directamente en 1080p")
return 0
if __name__ == "__main__":
sys.exit(main())