Claude Sonnet 4.6
Final hackathon submission: README, Field Notes, UI overhaul, fine-tuned model
9ee7168 Download content/loader.py from build-small-hackathon/sofia-educational-companion: direct link, hf CLI and curl.
- Browser
- Download file 2.28 kB
-
https://huggingface.co/spaces/build-small-hackathon/sofia-educational-companion/resolve/main/content/loader.py
- Command line
-
hf download hf://spaces/build-small-hackathon/sofia-educational-companion/content/loader.py
-
curl -L -o loader.py https://huggingface.co/spaces/build-small-hackathon/sofia-educational-companion/resolve/main/content/loader.py
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 | |