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
This commit is contained in:
179
smart_detector.py
Normal file
179
smart_detector.py
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SMART GAME DETECTOR
|
||||
Combina análisis de transcripción + reglas temporales para detectar gameplay real.
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import numpy as np
|
||||
|
||||
|
||||
def detect_games_smart(trans_file):
|
||||
"""Detecta juegos considerando patrones de League of Legends."""
|
||||
|
||||
with open(trans_file, "r") as f:
|
||||
trans = json.load(f)
|
||||
|
||||
print("=" * 60)
|
||||
print("SMART GAME DETECTOR")
|
||||
print("=" * 60)
|
||||
|
||||
# Buscar inicios de juego
|
||||
game_starts = []
|
||||
|
||||
for i, seg in enumerate(trans["segments"]):
|
||||
text = seg["text"].lower()
|
||||
|
||||
# Inicio típico de partida LoL
|
||||
if any(
|
||||
phrase in text
|
||||
for phrase in [
|
||||
"bienvenidos",
|
||||
"invocadores",
|
||||
"welcome",
|
||||
"empezamos",
|
||||
"vamos allá",
|
||||
"arrancamos",
|
||||
]
|
||||
):
|
||||
if seg["start"] > 120: # Después de intro
|
||||
game_starts.append(seg["start"])
|
||||
print(
|
||||
f"Posible inicio de juego en {seg['start'] // 60}m {seg['start'] % 60:.0f}s: {text[:50]}..."
|
||||
)
|
||||
|
||||
# También buscar por cambios de personaje/campeón
|
||||
champ_mentions = {}
|
||||
for seg in trans["segments"]:
|
||||
text = seg["text"].lower()
|
||||
# Buscar menciones de campeones
|
||||
champs = [
|
||||
"warwick",
|
||||
"diana",
|
||||
"mundo",
|
||||
"yasuo",
|
||||
"zed",
|
||||
"lee sin",
|
||||
"jhin",
|
||||
"lucian",
|
||||
]
|
||||
for champ in champs:
|
||||
if champ in text:
|
||||
if champ not in champ_mentions:
|
||||
champ_mentions[champ] = []
|
||||
champ_mentions[champ].append(seg["start"])
|
||||
|
||||
print(f"\nMenciones de campeones:")
|
||||
for champ, times in champ_mentions.items():
|
||||
if (
|
||||
len(times) > 5
|
||||
): # Mencionado varias veces = probablemente jugando ese campeón
|
||||
first = min(times)
|
||||
last = max(times)
|
||||
print(
|
||||
f" {champ}: {len(times)} veces, desde {first // 60}m hasta {last // 60}m"
|
||||
)
|
||||
|
||||
return game_starts, champ_mentions
|
||||
|
||||
|
||||
def extract_best_moments(trans_file, min_timestamp=455):
|
||||
"""Extrae los mejores momentos considerando contexto."""
|
||||
|
||||
with open(trans_file, "r") as f:
|
||||
trans = json.load(f)
|
||||
|
||||
# Dividir en bloques de 30 minutos (aprox duración de partida LoL)
|
||||
block_size = 30 * 60 # 30 minutos
|
||||
duration = trans["segments"][-1]["end"]
|
||||
|
||||
print(f"\nAnalizando {duration / 60:.0f} minutos en bloques de 30 min...")
|
||||
|
||||
all_moments = []
|
||||
|
||||
for block_start in range(int(min_timestamp), int(duration), block_size):
|
||||
block_end = min(block_start + block_size, int(duration))
|
||||
|
||||
# Buscar mejor momento en este bloque
|
||||
best_moment = None
|
||||
best_score = 0
|
||||
|
||||
for seg in trans["segments"]:
|
||||
if seg["start"] < block_start or seg["end"] > block_end:
|
||||
continue
|
||||
|
||||
text = seg["text"].lower()
|
||||
score = 0
|
||||
reasons = []
|
||||
|
||||
# Rage
|
||||
if re.search(r"\bputa\w*", text):
|
||||
score += 10
|
||||
reasons.append("RAGE")
|
||||
elif re.search(r"\bmierda\b", text):
|
||||
score += 7
|
||||
reasons.append("RAGE")
|
||||
|
||||
# Acción de juego
|
||||
if any(
|
||||
word in text
|
||||
for word in ["me mataron", "me mori", "kill", "mate", "muere"]
|
||||
):
|
||||
score += 8
|
||||
reasons.append("KILL")
|
||||
|
||||
if any(word in text for word in ["ulti", "flash", "teamfight", "pelea"]):
|
||||
score += 5
|
||||
reasons.append("SKILL")
|
||||
|
||||
# Frustración
|
||||
if any(word in text for word in ["joder", "hostia", "no puede ser"]):
|
||||
score += 4
|
||||
reasons.append("FRUSTRATION")
|
||||
|
||||
if score > best_score:
|
||||
best_score = score
|
||||
best_moment = {
|
||||
"time": seg["start"],
|
||||
"score": score,
|
||||
"text": seg["text"][:60],
|
||||
"reasons": reasons,
|
||||
"block": block_start,
|
||||
}
|
||||
|
||||
if best_moment and best_score >= 8:
|
||||
all_moments.append(best_moment)
|
||||
mins = int(best_moment["time"]) // 60
|
||||
secs = int(best_moment["time"]) % 60
|
||||
print(
|
||||
f" Bloque {len(all_moments)}: {mins:02d}:{secs:02d} [Score {best_score}] {'/'.join(reasons)}"
|
||||
)
|
||||
|
||||
return all_moments
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Detectar estructura
|
||||
game_starts, champs = detect_games_smart("transcripcion_rage.json")
|
||||
|
||||
# Extraer mejores momentos
|
||||
moments = extract_best_moments("transcripcion_rage.json")
|
||||
|
||||
print(f"\nTotal momentos encontrados: {len(moments)}")
|
||||
|
||||
# Crear clips
|
||||
clips = []
|
||||
for m in moments[:8]: # Máximo 8
|
||||
start = max(455, int(m["time"]) - 12)
|
||||
end = min(8237, int(m["time"]) + 20)
|
||||
clips.append([start, end])
|
||||
|
||||
# Guardar
|
||||
with open("highlights_smart.json", "w") as f:
|
||||
json.dump(clips, f)
|
||||
|
||||
print(f"\nClips guardados: {len(clips)}")
|
||||
for i, (s, e) in enumerate(clips, 1):
|
||||
mins, secs = divmod(s, 60)
|
||||
print(f"{i}. {mins:02d}:{secs:02d} - {e - s}s")
|
||||
Reference in New Issue
Block a user