""" modules/deep_context.py — FRIDAY Deep Context Memory Remembers everything about the user: - Current projects and their status - Friends/family/connections - Enemies/threats - Personal history - Inside jokes - User preferences """ import time import os import json from config import DATA_DIR CONTEXT_FILE = os.path.join(DATA_DIR, "deep_context.json") def _load() -> dict: if not os.path.exists(CONTEXT_FILE): return { "projects": {}, "people": {}, "relationships": {}, "jokes": [], "preferences": {}, "history": [], } try: with open(CONTEXT_FILE, "r") as f: return json.load(f) except Exception: return {} def _save(data: dict): os.makedirs(DATA_DIR, exist_ok=True) try: with open(CONTEXT_FILE, "w") as f: json.dump(data, f, indent=2) except Exception: pass # ── Projects ─────────────────────────────────────────────────── def track_project(name: str, status: str = "active", description: str = ""): """Track a project.""" data = _load() data.setdefault("projects", {})[name] = { "name": name, "status": status, "description": description, "updated": time.time(), } _save(data) def get_project(name: str) -> dict | None: """Get project details.""" data = _load() return data.get("projects", {}).get(name) def get_active_projects() -> list[dict]: """Get all active projects.""" data = _load() projects = data.get("projects", {}) return [p for p in projects.values() if p.get("status") == "active"] def complete_project(name: str): """Mark project as complete.""" data = _load() if name in data.get("projects", {}): data["projects"][name]["status"] = "complete" data["projects"][name]["completed"] = time.time() _save(data) # ── People ───────────────────────────────────────────────────── def track_person(name: str, relationship: str = "", notes: str = ""): """Track a person in user's life.""" data = _load() data.setdefault("people", {})[name] = { "name": name, "relationship": relationship, "notes": notes, "updated": time.time(), } _save(data) def get_person(name: str) -> dict | None: """Get person details.""" data = _load() return data.get("people", {}).get(name) def get_people(relationship: str = "") -> list[dict]: """Get people by relationship.""" data = _load() people = data.get("people", {}) if not relationship: return list(people.values()) return [p for p in people.values() if p.get("relationship") == relationship] # ── Inside Jokes ─────────────────────────────────────────────────── def add_joke(joke: str, response: str = ""): """Add inside joke/running bit.""" data = _load() data.setdefault("jokes", []).append({ "joke": joke, "response": response, "time": time.time(), }) # Keep last 30 jokes jokes = data.get("jokes", []) if len(jokes) > 30: jokes = jokes[-30:] data["jokes"] = jokes _save(data) def get_joke(keyword: str) -> str | None: """Get response to inside joke.""" data = _load() jokes = data.get("jokes", []) for j in reversed(jokes): if keyword.lower() in j.get("joke", "").lower(): return j.get("response") return None # ── Preferences ───────────────────────────────────────────────── def set_preference(key: str, value): """Remember user preference.""" data = _load() data.setdefault("preferences", {})[key] = {"value": value, "time": time.time()} _save(data) def get_preference(key: str): """Get user preference.""" data = _load() return data.get("preferences", {}).get(key, {}).get("value") # ── History ─────────────────────────────────────────────────── def add_to_history(event: str, category: str = "general"): """Add event to history.""" data = _load() data.setdefault("history", []).append({ "event": event, "category": category, "time": time.time(), }) # Keep last 100 history = data.get("history", []) if len(history) > 100: history = history[-100:] data["history"] = history _save(data) def get_history(category: str = "", limit: int = 5) -> list[dict]: """Get history.""" data = _load() history = data.get("history", []) if category: history = [h for h in history if h.get("category") == category] return history[-limit:] # ── Query Engine ─────────────────────────────────────────────── def query(query_text: str) -> str: """Query deep context.""" q = query_text.lower() # Check projects if "project" in q: active = get_active_projects() if active: names = [p.get("name") for p in active] return f"Active projects: {', '.join(names)}" return "No active projects." # Check people if "friend" in q or "people" in q: friends = get_people("friend") if friends: names = [p.get("name") for p in friends] return f"Your friends: {', '.join(names)}" return "No friends tracked." # Check what project I'm working on if "working on" in q or "current project" in q: active = get_active_projects() if active: return f"You're working on: {active[0].get('name')}" return "Not tracking any projects." return "I don't have that context yet. Teach me?" # ── Teach FRIDAY ────────────────────────────────────────────── def learn(text: str) -> bool: """Learn from user text.""" text_lower = text.lower() # Learn project if "i'm working on" in text_lower or "working on" in text_lower: # Extract project name project = text.replace("i'm working on", "").replace("working on", "").strip() if project and len(project) > 2: track_project(project, "active", "user is working on this") return True # Learn friend if "my friend" in text_lower or "friend named" in text_lower: name = text.replace("my friend", "").replace("friend named", "").strip() if name and len(name) > 1: track_person(name, "friend", "from conversation") return True return False # ── Brain Integration ───────────────────────────────────────── def get_context_block() -> str: """Get context block for brain.""" data = _load() parts = [] # Active projects active = get_active_projects() if active: parts.append(f"Projects: {', '.join([p['name'] for p in active])}") # Key people people = list(data.get("people", {}).values())[:3] if people: parts.append(f"People: {', '.join([p['name'] for p in people])}") # Recent history history = data.get("history", [])[-3:] if history: parts.append(f"Recent: {', '.join([h['event'] for h in history])}") if parts: return "[DEEP CONTEXT] " + " | ".join(parts) return ""