#!/usr/bin/env python """Memory Chatbot (#16 of the 30-in-15) — a bot that remembers you across sessions. The lesson is memory architecture: a short-term conversation buffer (this session) vs long-term memory (a store that outlives the session). After each exchange the bot extracts durable facts and saves them; on every turn it injects what it remembers. Close the tab, come back tomorrow — it still knows you. pip install -r requirements.txt python app.py # http://127.0.0.1:7860 (local Ollama by default; ANTHROPIC_API_KEY for Claude) """ import os import uuid from flask import Flask, request, render_template_string, jsonify, make_response import llm import store app = Flask(__name__) BASE_SYSTEM = ("You are a warm, helpful assistant with a long-term memory of the user across sessions. " "Use what you remember naturally — don't recite it back robotically. Be concise.") MAX_BUFFER = 8 # short-term turns folded in per request PAGE = r""" GritAI · Memory Chatbot
GritAI · Memory Chatbot
Remembers you across sessions · close the tab, come back — it still knows you
#16 · 30-in-15
Hi! I'll remember what you tell me — your name, what you're working on, how you like things — and recall it next time you're here. Tell me a bit about yourself.

Backend: {{ backend }} · GritAI Solutions

🧠 Memory

what I remember about you — persists across sessions
nothing yet — tell me something durable
""" def _user(): return request.cookies.get("memuser") or "" @app.route("/") def index(): resp = make_response(render_template_string(PAGE, backend=llm.backend_label())) if not request.cookies.get("memuser"): resp.set_cookie("memuser", uuid.uuid4().hex, max_age=60 * 60 * 24 * 365, samesite="Lax") return resp @app.route("/api/memory") def api_memory(): return jsonify({"facts": store.get_facts(_user())}) @app.route("/api/memory/delete", methods=["POST"]) def api_delete(): d = request.get_json(force=True) store.delete_fact(_user(), int(d.get("id", 0))) return jsonify({"ok": True}) @app.route("/api/memory/clear", methods=["POST"]) def api_clear(): store.clear(_user()) return jsonify({"ok": True}) @app.route("/api/chat", methods=["POST"]) def api_chat(): user_id = _user() d = request.get_json(force=True) message = (d.get("message") or "").strip()[:2000] if not message: return jsonify({"reply": "Say something!", "remembered": []}) history = d.get("history") or [] system = BASE_SYSTEM + store.memory_block(user_id) # long-term memory injected here # short-term buffer: recent turns folded into the prompt recent = history[-MAX_BUFFER * 2:-1] if len(history) > 1 else [] convo = "".join(f"{m['role']}: {m['content']}\n" for m in recent) user_prompt = (f"Recent conversation:\n{convo}\n" if convo else "") + f"User: {message}" try: reply = llm.chat(system, user_prompt, temperature=0.6, max_tokens=600) except Exception as e: print(f"chat error: {type(e).__name__}") return jsonify({"reply": "My brain backend hiccuped — is the model running?", "remembered": []}) remembered = [] try: remembered = store.remember_from_exchange(user_id, message, reply) except Exception as e: print(f"memory error: {type(e).__name__}") return jsonify({"reply": reply, "remembered": remembered}) if __name__ == "__main__": port = int(os.environ.get("PORT", "7860")) app.run(host="0.0.0.0", port=port, debug=False)