Files
twitch-highlight-detector/detector_minimax.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

197 lines
6.5 KiB
Python

#!/usr/bin/env python3
"""
Detector de highlights usando minimax API (OpenAI compatible).
Analiza la transcripción de Whisper para encontrar momentos interesantes.
"""
import json
import logging
import os
import sys
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Importar OpenAI SDK
try:
from openai import OpenAI
except ImportError:
print("Instalando openai...")
import subprocess
subprocess.check_call([sys.executable, "-m", "pip", "install", "openai", "--break-system-packages", "-q"])
from openai import OpenAI
def detect_with_minimax(transcripcion_json, output_json="highlights_minimax.json"):
"""
Carga la transcripción y usa minimax para encontrar highlights.
"""
# Obtener credenciales de variables de entorno (OpenAI compatible)
base_url = os.environ.get("OPENAI_BASE_URL", "https://api.minimax.io/v1")
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
logger.error("Se necesita OPENAI_API_KEY")
return None
logger.info(f"Usando endpoint: {base_url}")
logger.info(f"Cargando transcripción de {transcripcion_json}...")
with open(transcripcion_json, 'r', encoding='utf-8') as f:
transcripcion_data = json.load(f)
# Crear un resumen estructurado para la IA
segments = transcripcion_data.get("segments", [])
# Crear transcripción con timestamps
transcript_lines = []
for seg in segments[:800]: # Limitar segmentos
start = int(seg["start"])
end = int(seg["end"])
text = seg["text"].strip()
if len(text) > 3: # Filtrar textos muy cortos
mins = start // 60
secs = start % 60
timestamp = f"[{mins:02d}:{secs:02d}]"
transcript_lines.append(f"{timestamp} {text}")
full_text = "\n".join(transcript_lines)
logger.info(f"Enviando a minimax ({len(full_text)} caracteres)...")
# Crear cliente OpenAI con endpoint de minimax
client = OpenAI(
base_url=base_url,
api_key=api_key
)
prompt = f"""Eres un experto editor de highlights de gaming (Twitch/YouTube). Tu especialidad es identificar MOMENTOS ÉPICOS y VIRALES.
TRANSCRIPCIÓN DEL STREAM:
{full_text}
TU ÚNICA MISIÓN:
Encuentra 20-30 CLIPS CORTOS (15-30 segundos cada uno) que sean VIRALICOS.
SOLO busca estos tipos de momentos:
1. **JUGADAS ÉPICAS**: Multi-kills, clutches, jugadas increíbles, moments de gran habilidad
2. **RISAS/GRACIAS**: Momentos donde el streamer se ríe a carcajadas, algo gracioso pasa
3. **REACCIONES ÉPICAS**: Gritos de emoción, sorpresa extrema, momentos de "¡NO LO PUEDO CREER!"
LO QUE DEBES EVITAR ABSOLUTAMENTE:
❌ Quejas/rage sobre el juego (insultos, frustración)
❌ Hablar de cargar partidas, esperar, problemas técnicos
❌ Conversaciones normales/aburridas
❌ Análisis estratégicos aburridos
❌ Saludos, intros, despedidas
❌ Leer chat o spam
REGLAS CRÍTICAS:
- Cada clip debe durar 15-30 segundos MÁXIMO
- Cada clip debe tener una "recompensa" inmediata (risa, emoción, jugada épica)
- Prioriza CLARIDAD sobre cantidad: es mejor 10 clips geniales que 30 clips regulares
- Busca PATRONES específicos: "¡!", risas ("jajaja", "jeje"), gritos ("¡PUTA!", "¡QUE!", "¡NO!")
FORMATO DE RESPUESTA (solo JSON válido):
{{
"highlights": [
{{"start": 123, "end": 144, "reason": "razón muy breve"}},
{{"start": 456, "end": 477, "reason": "razón muy breve"}}
]
}}
Timestamps en SEGUNDOS del video."""
try:
response = client.chat.completions.create(
model="MiniMax-M2.5", # Modelo de minimax
messages=[
{"role": "system", "content": "Eres un experto editor de contenido de Twitch que identifica momentos memorables."},
{"role": "user", "content": prompt}
],
temperature=0.3,
max_tokens=4096
)
content = response.choices[0].message.content
# Buscar JSON en la respuesta
import re
json_match = re.search(r'\{[\s\S]*\}', content)
if json_match:
result = json.loads(json_match.group())
else:
logger.error("No se encontró JSON válido en la respuesta")
logger.debug(f"Respuesta: {content}")
return None
except Exception as e:
logger.error(f"Error llamando API minimax: {e}")
import traceback
traceback.print_exc()
return None
if result and "highlights" in result:
highlights = result["highlights"]
# Validar y filtrar highlights
valid_intervals = []
for h in highlights:
start = int(h["start"])
end = int(h["end"])
duration = end - start
# Filtrar: duración entre 12 y 45 segundos (clips muy cortos)
if 12 <= duration <= 45:
valid_intervals.append({
"start": start,
"end": end,
"reason": h.get("reason", "N/A")
})
# Convertir a formato de intervalos
intervals = [[h["start"], h["end"]] for h in valid_intervals]
# Guardar con detalles
with open(output_json, 'w') as f:
json.dump({"intervals": intervals, "details": valid_intervals}, f, indent=2)
logger.info(f"Guardado en {output_json}")
# Imprimir resumen
print(f"\n{'='*70}")
print(f"HIGHLIGHTS DETECTADOS POR minimax".center(70))
print(f"{'='*70}")
print(f"Total: {len(intervals)} clips")
print(f"Duración total: {sum(e-s for s,e in intervals)}s ({sum(e-s for s,e in intervals)/60:.1f} min)")
print(f"{'-'*70}")
for i, h in enumerate(valid_intervals, 1):
start = h["start"]
end = h["end"]
duration = end - start
hours = start // 3600
mins = (start % 3600) // 60
secs = start % 60
reason = h["reason"]
print(f"{i:2d}. {hours:02d}:{mins:02d}:{secs:02d} - {duration}s - {reason}")
print(f"{'='*70}")
return intervals
else:
logger.error("No se pudo obtener highlights de minimax")
return None
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--transcripcion", required=True, help="Archivo JSON de transcripción de Whisper")
parser.add_argument("--output", default="highlights_minimax.json")
args = parser.parse_args()
detect_with_minimax(args.transcripcion, args.output)
if __name__ == "__main__":
main()