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:
173
rage_in_gameplay.py
Normal file
173
rage_in_gameplay.py
Normal file
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
RAGE IN GAMEPLAY - Solo momentos de rage durante gameplay activo
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
|
||||
def find_rage_in_gameplay():
|
||||
"""Busca rage solo durante regiones de gameplay activo."""
|
||||
|
||||
print("=" * 60)
|
||||
print("RAGE IN GAMEPLAY DETECTOR")
|
||||
print("=" * 60)
|
||||
|
||||
# Cargar transcripción
|
||||
with open("transcripcion_rage.json", "r") as f:
|
||||
trans = json.load(f)
|
||||
|
||||
# Cargar regiones de gameplay
|
||||
with open("gameplay_regions.json", "r") as f:
|
||||
gameplay_regions = json.load(f)
|
||||
|
||||
print(f"Regiones de gameplay: {len(gameplay_regions)}")
|
||||
|
||||
# Convertir regiones a set para búsqueda rápida
|
||||
gameplay_seconds = set()
|
||||
for start, end in gameplay_regions:
|
||||
for i in range(start, end):
|
||||
gameplay_seconds.add(i)
|
||||
|
||||
print(f"Total segundos de gameplay: {len(gameplay_seconds)}")
|
||||
|
||||
# Patrones de rage
|
||||
rage_patterns = [
|
||||
(r"\bputa\w*", 10, "EXTREME"),
|
||||
(r"\bmierda\b", 8, "RAGE"),
|
||||
(r"\bjoder\b", 8, "RAGE"),
|
||||
(r"\bhostia\b", 7, "RAGE"),
|
||||
(r"\bme mataron\b", 12, "DEATH"),
|
||||
(r"\bme mori\b", 12, "DEATH"),
|
||||
(r"\bme matan\b", 10, "DEATH"),
|
||||
(r"\bmatenme\b", 10, "DEATH"),
|
||||
(r"\bla cague\b", 8, "FAIL"),
|
||||
(r"\bfall[eé]\b", 6, "FAIL"),
|
||||
(r"\bretrasad\w*", 9, "INSULT"),
|
||||
(r"\bimbecil\b", 9, "INSULT"),
|
||||
(r"\bestupid\w*", 8, "INSULT"),
|
||||
(r"\bnooo+\b", 6, "FRUSTRATION"),
|
||||
(r"\bno puede ser\b", 7, "FRUSTRATION"),
|
||||
]
|
||||
|
||||
# Buscar momentos de rage durante gameplay
|
||||
rage_moments = []
|
||||
|
||||
for seg in trans["segments"]:
|
||||
start = int(seg["start"])
|
||||
end = int(seg["end"])
|
||||
|
||||
# Verificar si hay gameplay durante este segmento
|
||||
overlap = sum(1 for i in range(start, end) if i in gameplay_seconds)
|
||||
if overlap < (end - start) * 0.3: # Menos del 30% en gameplay
|
||||
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 >= 6: # Mínimo significativo
|
||||
rage_moments.append(
|
||||
{
|
||||
"start": start,
|
||||
"end": end,
|
||||
"score": score,
|
||||
"text": seg["text"][:70],
|
||||
"reasons": reasons,
|
||||
"gameplay_pct": overlap / (end - start),
|
||||
}
|
||||
)
|
||||
|
||||
print(f"\nMomentos de rage durante gameplay: {len(rage_moments)}")
|
||||
|
||||
# Ordenar por score
|
||||
rage_moments.sort(key=lambda x: -x["score"])
|
||||
|
||||
# Mostrar top 15
|
||||
print("\nTop momentos:")
|
||||
for i, m in enumerate(rage_moments[:15], 1):
|
||||
mins = int(m["start"]) // 60
|
||||
secs = int(m["start"]) % 60
|
||||
print(
|
||||
f"{i:2d}. {mins:02d}:{secs:02d} [Score: {m['score']:2d}] "
|
||||
f"{'/'.join(m['reasons'])} - {m['text'][:50]}..."
|
||||
)
|
||||
|
||||
# Crear clips extendidos
|
||||
clips = []
|
||||
for m in rage_moments[:20]:
|
||||
# Extender solo dentro del gameplay activo
|
||||
clip_start = max(455, int(m["start"]) - 8)
|
||||
clip_end = min(8237, int(m["end"]) + 15)
|
||||
|
||||
# Verificar que esté dentro de gameplay
|
||||
valid_start = None
|
||||
valid_end = None
|
||||
|
||||
for g_start, g_end in gameplay_regions:
|
||||
if clip_start < g_end and clip_end > g_start:
|
||||
# Hay superposición
|
||||
valid_start = max(clip_start, g_start)
|
||||
valid_end = min(clip_end, g_end)
|
||||
break
|
||||
|
||||
if valid_start and valid_end and valid_end - valid_start >= 15:
|
||||
clips.append(
|
||||
{
|
||||
"start": int(valid_start),
|
||||
"end": int(valid_end),
|
||||
"score": m["score"],
|
||||
"reasons": m["reasons"],
|
||||
}
|
||||
)
|
||||
|
||||
# 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"]))
|
||||
else:
|
||||
filtered.append(clip)
|
||||
|
||||
# Tomar top 10
|
||||
filtered.sort(key=lambda x: -x["score"])
|
||||
final = filtered[:10]
|
||||
final.sort(key=lambda x: x["start"])
|
||||
|
||||
print(f"\nClips finales: {len(final)}")
|
||||
total_dur = sum(c["end"] - c["start"] for c in final)
|
||||
print(f"Duración total: {total_dur}s ({total_dur // 60}m {total_dur % 60}s)")
|
||||
|
||||
print("\nTimeline:")
|
||||
for i, c in enumerate(final, 1):
|
||||
mins, secs = divmod(c["start"], 60)
|
||||
dur = c["end"] - c["start"]
|
||||
print(f"{i:2d}. {mins:02d}:{secs:02d} - {dur}s [{'/'.join(c['reasons'])}]")
|
||||
|
||||
# Guardar
|
||||
highlights = [[c["start"], c["end"]] for c in final]
|
||||
with open("highlights_gameplay_rage.json", "w") as f:
|
||||
json.dump(highlights, f)
|
||||
|
||||
print(f"\nGuardado en highlights_gameplay_rage.json")
|
||||
return highlights
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
find_rage_in_gameplay()
|
||||
Reference in New Issue
Block a user