Spaces:
Running
Running
Download store.py from BonusLockSMith/memory-chatbot: direct link, hf CLI and curl.
- Browser
- Download file 3.58 kB
-
https://huggingface.co/spaces/BonusLockSMith/memory-chatbot/resolve/main/store.py
- Command line
-
hf download hf://spaces/BonusLockSMith/memory-chatbot/store.py
-
curl -L -o store.py https://huggingface.co/spaces/BonusLockSMith/memory-chatbot/resolve/main/store.py
3.58 kB
| #!/usr/bin/env python | |
| """Long-term memory for the Memory Chatbot (#16). | |
| The architecture, in four moves: | |
| 1. EXTRACT — after each exchange, an LLM pulls durable facts about the user (name, prefs, projects). | |
| 2. STORE — facts are written to SQLite, keyed by user, deduped. This is what survives across sessions. | |
| 3. RETRIEVE— on each new turn, the user's stored facts are loaded. | |
| 4. INJECT — they're placed in the system prompt so the bot "remembers you." | |
| This is the distinction the rung teaches: the short-term conversation buffer lives in the request; | |
| long-term memory lives here, in a store that outlives the session. | |
| """ | |
| import os | |
| import sqlite3 | |
| import threading | |
| import llm | |
| DB = os.environ.get("MEMBOT_DB", os.path.join(os.path.dirname(os.path.abspath(__file__)), "memory.db")) | |
| _lock = threading.Lock() | |
| EXTRACT_SYS = ( | |
| "You maintain a chatbot's LONG-TERM memory of a user. From the latest exchange, extract only DURABLE " | |
| "facts worth remembering across future sessions — the user's name, stable preferences, ongoing projects, " | |
| "role, constraints, or personal context they'd expect you to recall later. Do NOT store the assistant's " | |
| "words, one-off questions, greetings, or transient chit-chat. Return a JSON array of short first-person-" | |
| "about-the-user fact strings (e.g. [\"Name is Alex\", \"Prefers Python\", \"Building a bakery website\"]). " | |
| "If nothing durable was shared, return []." | |
| ) | |
| def _conn(): | |
| c = sqlite3.connect(DB) | |
| c.execute("""CREATE TABLE IF NOT EXISTS facts ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, user_id TEXT NOT NULL, fact TEXT NOT NULL, | |
| created_at TEXT DEFAULT (datetime('now')))""") | |
| return c | |
| def get_facts(user_id: str) -> list: | |
| with _lock, _conn() as c: | |
| rows = c.execute("SELECT id, fact FROM facts WHERE user_id=? ORDER BY id", (user_id,)).fetchall() | |
| return [{"id": r[0], "fact": r[1]} for r in rows] | |
| def add_fact(user_id: str, fact: str): | |
| fact = (fact or "").strip() | |
| if not fact: | |
| return | |
| with _lock, _conn() as c: | |
| exists = c.execute("SELECT 1 FROM facts WHERE user_id=? AND lower(fact)=lower(?)", | |
| (user_id, fact)).fetchone() | |
| if not exists: | |
| c.execute("INSERT INTO facts (user_id, fact) VALUES (?, ?)", (user_id, fact)) | |
| def delete_fact(user_id: str, fact_id: int): | |
| with _lock, _conn() as c: | |
| c.execute("DELETE FROM facts WHERE user_id=? AND id=?", (user_id, fact_id)) | |
| def clear(user_id: str): | |
| with _lock, _conn() as c: | |
| c.execute("DELETE FROM facts WHERE user_id=?", (user_id,)) | |
| def remember_from_exchange(user_id: str, user_msg: str, assistant_msg: str) -> list: | |
| """EXTRACT + STORE. Returns the list of newly-added facts (for UI feedback).""" | |
| prompt = f"USER SAID: {user_msg}\nASSISTANT REPLIED: {assistant_msg}\n\nExtract durable facts about the user." | |
| facts = llm.extract_json(EXTRACT_SYS, prompt) | |
| if not isinstance(facts, list): | |
| return [] | |
| before = {f["fact"].lower() for f in get_facts(user_id)} | |
| added = [] | |
| for f in facts: | |
| if isinstance(f, str) and f.strip() and f.strip().lower() not in before: | |
| add_fact(user_id, f.strip()) | |
| added.append(f.strip()) | |
| return added | |
| def memory_block(user_id: str) -> str: | |
| """RETRIEVE + format for INJECTion into the system prompt.""" | |
| facts = get_facts(user_id) | |
| if not facts: | |
| return "" | |
| lines = "\n".join(f"- {f['fact']}" for f in facts) | |
| return f"\n\nWhat you remember about this user from past sessions:\n{lines}\n" | |