EstebanBarac's picture
Final hackathon submission: README, Field Notes, UI overhaul, fine-tuned model
9ee7168
Raw
History Blame Contribute Delete
2.28 kB
"""
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