File size: 2,278 Bytes
6879860 9ee7168 6879860 4dba873 6879860 4dba873 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | """
Biblioteca de contenido CURADO (la fuente de la verdad, no el LLM).
Cargás JSON validado por ustedes. El motor pide content.pick(intent, edad)
y recibe un 'script' que el LLM presenta con calidez, sin inventar.
"""
import json
import os
import random
class ContentLibrary:
def __init__(self, content_dir: str):
self.items = {} # intent -> list[dict]
self.titles = {} # content_id -> title (para armar bloques de contexto/memoria)
for name in ("activities", "stories", "songs", "learning"):
path = os.path.join(content_dir, f"{name}.json")
if os.path.exists(path):
with open(path, encoding="utf-8") as f:
for item in json.load(f):
self.items.setdefault(item["intent"], []).append(item)
self.titles[item["id"]] = item["title"]
self.colors = [] # paletas para "Sofía, cambiate a <color>" (ver colors.json)
colors_path = os.path.join(content_dir, "colors.json")
if os.path.exists(colors_path):
with open(colors_path, encoding="utf-8") as f:
self.colors = json.load(f)
def pick(self, intent: str, child_age: int, exclude_ids: set | None = None):
"""Elige un ítem curado para la edad. Si hay `exclude_ids` (contenido ya visto
recientemente, ver ParentalStore.seen_ids), preferimos algo nuevo; si ya vio
todo lo disponible, repetimos antes que no ofrecer nada."""
candidates = [
it for it in self.items.get(intent, [])
if it.get("min_age", 0) <= child_age <= it.get("max_age", 99)
]
if not candidates:
return None
if exclude_ids:
fresh = [it for it in candidates if it["id"] not in exclude_ids]
if fresh:
candidates = fresh
return random.choice(candidates)
def match_color(self, message_lower: str) -> dict | None:
"""Si el mensaje menciona uno de los colores simples de colors.json,
devuelve su entrada (script + palette curados). None si no hay match."""
for color in self.colors:
if any(word in message_lower for word in color["match"]):
return color
return None
|