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:
208
two_game_extractor.py
Normal file
208
two_game_extractor.py
Normal file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
TWO-GAME HIGHLIGHT EXTRACTOR
|
||||
Extrae múltiples highlights de los 2 juegos: Diana y Mundo
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
def extract_game_highlights():
|
||||
"""Extrae highlights de Diana y Mundo por separado."""
|
||||
|
||||
print("=" * 60)
|
||||
print("TWO-GAME HIGHLIGHT EXTRACTOR")
|
||||
print("=" * 60)
|
||||
|
||||
with open("transcripcion_rage.json", "r") as f:
|
||||
trans = json.load(f)
|
||||
|
||||
# Identificar segmentos por campeón
|
||||
diana_segments = []
|
||||
mundo_segments = []
|
||||
|
||||
for seg in trans["segments"]:
|
||||
text = seg["text"].lower()
|
||||
|
||||
if "diana" in text:
|
||||
diana_segments.append(seg)
|
||||
elif "mundo" in text or "warwick" in text:
|
||||
mundo_segments.append(seg)
|
||||
|
||||
print(f"Segmentos mencionando Diana: {len(diana_segments)}")
|
||||
print(f"Segmentos mencionando Mundo/Warwick: {len(mundo_segments)}")
|
||||
|
||||
# Encontrar rangos de tiempo
|
||||
if diana_segments:
|
||||
diana_start = min(s["start"] for s in diana_segments)
|
||||
diana_end = max(s["end"] for s in diana_segments)
|
||||
print(f"\nJuego Diana: {diana_start / 60:.0f}m - {diana_end / 60:.0f}m")
|
||||
else:
|
||||
diana_start, diana_end = 0, 0
|
||||
|
||||
if mundo_segments:
|
||||
mundo_start = min(s["start"] for s in mundo_segments)
|
||||
mundo_end = max(s["end"] for s in mundo_segments)
|
||||
print(f"Juego Mundo: {mundo_start / 60:.0f}m - {mundo_end / 60:.0f}m")
|
||||
else:
|
||||
mundo_start, mundo_end = 0, 0
|
||||
|
||||
# Buscar momentos épicos en cada juego
|
||||
def find_moments_in_range(segments, game_name, start_time, end_time, min_score=6):
|
||||
"""Busca momentos épicos en un rango específico."""
|
||||
|
||||
moments = []
|
||||
|
||||
rage_patterns = [
|
||||
(r"\bputa\w*", 10, "EXTREME"),
|
||||
(r"\bme mataron\b", 12, "DEATH"),
|
||||
(r"\bme mori\b", 12, "DEATH"),
|
||||
(r"\bmierda\b", 8, "RAGE"),
|
||||
(r"\bjoder\b", 8, "RAGE"),
|
||||
(r"\bretrasad\w*", 9, "INSULT"),
|
||||
(r"\bimbecil\b", 9, "INSULT"),
|
||||
(r"\bla cague\b", 8, "FAIL"),
|
||||
(r"\bnooo+\b", 6, "FRUSTRATION"),
|
||||
]
|
||||
|
||||
for seg in segments:
|
||||
if seg["start"] < start_time or seg["end"] > end_time:
|
||||
continue
|
||||
|
||||
text = seg["text"].lower()
|
||||
score = 0
|
||||
reasons = []
|
||||
|
||||
for pattern, points, reason in rage_patterns:
|
||||
if re.search(pattern, text, re.IGNORECASE):
|
||||
score += points
|
||||
if reason not in reasons:
|
||||
reasons.append(reason)
|
||||
|
||||
if score >= min_score:
|
||||
moments.append(
|
||||
{
|
||||
"start": seg["start"],
|
||||
"end": seg["end"],
|
||||
"score": score,
|
||||
"text": seg["text"][:70],
|
||||
"reasons": reasons,
|
||||
"game": game_name,
|
||||
}
|
||||
)
|
||||
|
||||
return moments
|
||||
|
||||
# Buscar en Diana
|
||||
print(f"\n=== JUEGO DIANA ===")
|
||||
diana_moments = find_moments_in_range(
|
||||
trans["segments"],
|
||||
"Diana",
|
||||
max(455, diana_start - 300), # 5 min antes de primera mención
|
||||
diana_end + 300, # 5 min después
|
||||
min_score=5,
|
||||
)
|
||||
print(f"Momentos encontrados: {len(diana_moments)}")
|
||||
|
||||
# Buscar en Mundo
|
||||
print(f"\n=== JUEGO MUNDO ===")
|
||||
mundo_moments = find_moments_in_range(
|
||||
trans["segments"],
|
||||
"Mundo",
|
||||
max(455, mundo_start - 300),
|
||||
mundo_end + 300,
|
||||
min_score=5,
|
||||
)
|
||||
print(f"Momentos encontrados: {len(mundo_moments)}")
|
||||
|
||||
# Ordenar por score
|
||||
diana_moments.sort(key=lambda x: -x["score"])
|
||||
mundo_moments.sort(key=lambda x: -x["score"])
|
||||
|
||||
# Tomar top 6 de cada juego
|
||||
best_diana = diana_moments[:6]
|
||||
best_mundo = mundo_moments[:6]
|
||||
|
||||
print(f"\nMejores momentos Diana: {len(best_diana)}")
|
||||
for i, m in enumerate(best_diana, 1):
|
||||
mins = int(m["start"]) // 60
|
||||
secs = int(m["start"]) % 60
|
||||
print(
|
||||
f" {i}. {mins:02d}:{secs:02d} [Score: {m['score']}] {'/'.join(m['reasons'])}"
|
||||
)
|
||||
|
||||
print(f"\nMejores momentos Mundo: {len(best_mundo)}")
|
||||
for i, m in enumerate(best_mundo, 1):
|
||||
mins = int(m["start"]) // 60
|
||||
secs = int(m["start"]) % 60
|
||||
print(
|
||||
f" {i}. {mins:02d}:{secs:02d} [Score: {m['score']}] {'/'.join(m['reasons'])}"
|
||||
)
|
||||
|
||||
# Combinar y crear clips
|
||||
all_moments = best_diana + best_mundo
|
||||
|
||||
# Crear clips extendidos
|
||||
clips = []
|
||||
for m in all_moments:
|
||||
start = max(455, int(m["start"]) - 10)
|
||||
end = min(8237, int(m["end"]) + 15)
|
||||
if end - start >= 15:
|
||||
clips.append(
|
||||
{
|
||||
"start": start,
|
||||
"end": end,
|
||||
"score": m["score"],
|
||||
"reasons": m["reasons"],
|
||||
"game": m["game"],
|
||||
}
|
||||
)
|
||||
|
||||
# Eliminar solapamientos
|
||||
clips.sort(key=lambda x: x["start"])
|
||||
filtered = []
|
||||
for clip in clips:
|
||||
if not filtered:
|
||||
filtered.append(clip)
|
||||
else:
|
||||
last = filtered[-1]
|
||||
if clip["start"] <= last["end"] + 5:
|
||||
# Fusionar
|
||||
last["end"] = max(last["end"], clip["end"])
|
||||
last["score"] = max(last["score"], clip["score"])
|
||||
last["reasons"] = list(set(last["reasons"] + clip["reasons"]))
|
||||
if clip["game"] not in last["game"]:
|
||||
last["game"] += "/" + clip["game"]
|
||||
else:
|
||||
filtered.append(clip)
|
||||
|
||||
# Ordenar por tiempo
|
||||
filtered.sort(key=lambda x: x["start"])
|
||||
|
||||
print(f"\n{'=' * 60}")
|
||||
print(f"TOTAL: {len(filtered)} clips")
|
||||
total_dur = sum(c["end"] - c["start"] for c in filtered)
|
||||
print(f"Duración: {total_dur}s ({total_dur // 60}m {total_dur % 60}s)")
|
||||
print(f"{'=' * 60}")
|
||||
|
||||
print(f"\nTimeline final:")
|
||||
for i, c in enumerate(filtered, 1):
|
||||
mins, secs = divmod(c["start"], 60)
|
||||
dur = c["end"] - c["start"]
|
||||
print(
|
||||
f"{i:2d}. {mins:02d}:{secs:02d} - {dur}s [{c['game']}] {'/'.join(c['reasons'])}"
|
||||
)
|
||||
|
||||
return filtered
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
clips = extract_game_highlights()
|
||||
|
||||
# Guardar
|
||||
highlights = [[c["start"], c["end"]] for c in clips]
|
||||
with open("highlights_two_games.json", "w") as f:
|
||||
json.dump(highlights, f)
|
||||
|
||||
print(f"\nGuardado en highlights_two_games.json")
|
||||
Reference in New Issue
Block a user