An AI study tutor that remembers what you struggle with — across sessions.
🔗 Live demo: memorytutor-8xubbwgxarbmzutwjeger2.streamlit.app
Every chat-based tutor has the same flaw: it forgets you the moment the conversation ends. Ask it to explain backpropagation today, ask again next week, and it starts from zero — no memory of what confused you, what you've already mastered, or what your notes even said. You end up re-explaining your own context to the AI every single session. The tutor never actually gets to know you as a learner.
MemoryTutor is built on Cognee, which turns your course notes into a knowledge graph — concepts as nodes, relationships between them as edges — stored on disk instead of in a chat window that disappears when you close the tab.
On top of that graph, MemoryTutor tracks a second layer of memory: what you personally struggle with. Every question you ask, every follow-up clarification you need, feeds into a WeakArea / MasteredTopic model for each topic. That model is:
- Stored locally in
user_memory.json, so lookups at the start of a session are instant. - Mirrored into the same knowledge graph as short memory statements (e.g. "WeakArea: gradient descent is a topic the learner finds difficult..."), so the tutor's answers can reference your history and the concept graph visualization can highlight what you're struggling with.
The result: close the app, come back tomorrow, and MemoryTutor greets you with "Last session you struggled with gradient descent — want to revisit it?" — because it actually remembers.
┌─────────────────────────┐
│ Streamlit UI (app.py) │
│ ┌────────────┐ ┌──────┐│
│ │ Sidebar │ │ Chat ││
│ │ (uploads, │ │ ││
│ │ weak areas)│ │ ││
│ └────────────┘ └──────┘│
│ ┌──────────────────────┐│
│ │ Concept graph panel ││
│ └──────────────────────┘│
└───────────┬──────────────┘
│
┌────────┴─────────┐
│ │
┌──▼───────┐ ┌──────▼───────┐
│engine.py │ │ tracker.py │
│(cognee │ │(WeakArea / │
│ add/ │◄───┤ MasteredTopic│
│ cognify/ │ │ JSON store │
│ search) │ │ + graph │
└──┬───────┘ │ mirroring) │
│ └──────────────┘
┌──▼─────────────────────────┐
│ Cognee (LiteLLM + Gemini) │
│ knowledge graph, stored │
│ in .cognee_system/ and │
│ .data_storage/ │
└─────────────────────────────┘
engine.py— thin async wrapper aroundcognee.add(),cognee.cognify(), andcognee.search(..., SearchType.GRAPH_COMPLETION). All cognee calls are async; a persistent background event loop bridges them into Streamlit's synchronous script model.tracker.py— the learner-state layer: extracts a topic per question (via a cheap Gemini call), detects follow-ups (keyword heuristics + explicit "Still confused" / "Got it" buttons), and maintains WeakArea/MasteredTopic status both locally and in the graph.viz.py— builds anetworkxgraph from cognee's raw graph data and renders it withmatplotlib, filtering out cognee's internal bookkeeping nodes (chunks, summaries) so only real course concepts show up, colored red (weak) / green (mastered) / blue (neutral).app.py— the Streamlit UI tying it together.
-
Get a Gemini API key at aistudio.google.com/apikey.
-
Create a virtual environment and install dependencies:
python -m venv .venv .venv\Scripts\activate # Windows # source .venv/bin/activate # macOS/Linux pip install -r requirements.txt
-
Configure your API key:
copy .env.example .env # Windows # cp .env.example .env # macOS/Linux
Then edit
.envand setGEMINI_API_KEY.
streamlit run app.pyOpen the URL Streamlit prints (usually http://localhost:8501), upload a PDF or text file of course notes from the sidebar, click Process notes, and start asking questions.
Don't run other cognee scripts (like
scripts/smoke_test.py) while the app is running. Cognee's graph database uses file locking and doesn't support concurrent access from multiple processes — stop the Streamlit app first.
Live demo: memorytutor-8xubbwgxarbmzutwjeger2.streamlit.app
- Go to share.streamlit.io and sign in with GitHub.
- New app → pick this repo, branch
main, main file pathapp.py. - Before clicking Deploy, open Advanced settings → Secrets and paste:
(
GEMINI_API_KEY = "your-key-here"
LLM_MODEL/EMBEDDING_MODELoverrides are optional, same as.env.example.) - Click Deploy.
Two things behave differently on Streamlit Cloud versus running locally:
- Storage is ephemeral. Streamlit Cloud doesn't guarantee a persistent disk across app restarts/redeploys, so the knowledge graph and weak-area memory may reset when the app sleeps from inactivity and wakes back up. Cross-session memory is fully persistent when you run the app locally (that's what
DEMO.mddemonstrates); on the free cloud tier, treat it as persistent within a single "awake" period rather than indefinitely. - Memory footprint. Cognee's local graph/vector stores plus its dependency stack are heavier than a typical Streamlit app. If the free tier's ~1GB RAM limit causes crashes, that's a platform constraint, not an app bug.
- Upload notes →
cognee.add()ingests the file,cognee.cognify()extracts entities and relationships into a knowledge graph, stored in.cognee_system/and.data_storage/in this project directory (not inside the venv, so it survivespip installreruns). - Ask a question → MemoryTutor extracts the topic, checks whether it's a follow-up (either by phrasing like "I don't get it" or because you asked about the same topic recently), and answers using
cognee.search(query_type=SearchType.GRAPH_COMPLETION)— a graph-aware retrieval that reasons over entity relationships, not just vector similarity. - Struggle or succeed → each follow-up (or an explicit "Still confused" click) marks the topic as a
WeakArea; clicking "Got it" marks itMasteredTopic. Both are saved touser_memory.jsonand mirrored into the graph. - Come back later → on a fresh session, MemoryTutor reads your weak areas and greets you with a prompt to revisit them — no re-uploading, no re-explaining.
MemoryTutor/
├── app.py # Streamlit UI
├── memory_tutor/
│ ├── config.py # .env loading, Gemini/LiteLLM env wiring
│ ├── engine.py # async cognee wrapper
│ ├── tracker.py # WeakArea/MasteredTopic tracking
│ └── viz.py # networkx + matplotlib concept graph
├── scripts/
│ └── smoke_test.py # CLI pipeline check (add → cognify → search)
├── sample_data/
│ └── sample_notes.txt # sample notes for a quick demo
├── requirements.txt
├── .env.example
└── DEMO.md
gemini-1.5-flash/text-embedding-004not found (404). Google has retired these models. MemoryTutor defaults togemini/gemini-flash-lite-latest(chat/topic extraction) andgemini/gemini-embedding-001(embeddings) instead — both current and free-tier friendly. If you have a paid key, setLLM_MODEL=gemini/gemini-2.5-flashin.envfor noticeably better answer quality.- Rate limit / 429 errors. Free-tier Gemini keys have low daily quotas per model (as low as ~20 requests/day for
gemini-2.5-flash). Cognee retries automatically with backoff, so slow responses during heavy use are expected; if it hard-fails, wait a bit or switch to a lite model. - First
cognify()on a new file is slow. Entity/relationship extraction runs an LLM call per text chunk. The bundledsample_data/sample_notes.txtis small and ingests in well under a minute; large PDFs will take longer. - "Could not set lock on file" error. Cognee's graph database doesn't support concurrent multi-process access. Make sure only one process (the Streamlit app or a CLI script, not both) is touching
.cognee_system/at a time. - Storage location. By default cognee stores its databases inside its own package folder, which would delete your "persistent" memory every time you reinstall dependencies. MemoryTutor overrides this in
config.pyto store everything under the project root instead (.cognee_system/,.data_storage/), so it survivespip installreruns — just don't delete those folders if you want to keep your memory.