A fully local, open-source alternative to Google NotebookLM. Chat with your documents, generate mind maps, and get AI-powered insights — all running on your own hardware with no data leaving your machine.
| 📓 Notebooks | Organise sources into separate notebooks |
| 📄 Multi-format sources | PDF, TXT, MD, CSV, JSON, audio (MP3/WAV/OGG/FLAC), URLs |
| 💬 Streaming chat | Real-time streamed answers with source citations |
| 🗺️ Mind maps | LLM-generated interactive mind maps from your sources |
| 🔍 Semantic search | ChromaDB vector store with local embeddings |
| 🤖 LM Studio | Works with any model loaded in LM Studio |
| 🔒 100% local | No internet required after first setup |
- Click any node to focus it and see the most relevant source passages
- Save as PNG
- Auto-saves and reloads without regenerating
- Source checklist — include or exclude individual sources
- Token streaming with a live cursor
- Full markdown rendering (code blocks, tables, lists, headers)
- Stop button to cancel mid-generation
- Model uses both your documents and its own knowledge
| Dependency | Version | Download |
|---|---|---|
| Python | 3.10 + | https://www.python.org/ |
| Node.js | 18 + | https://nodejs.org/ |
| LM Studio | latest | https://lmstudio.ai/ |
LM Studio is the only non-Python/Node requirement. It handles model loading and provides a local OpenAI-compatible API. CompositionLM never calls any cloud service.
git clone https://github.com/your-username/compositionlm.git
cd compositionlm
start.batstart.bat will:
- Check Python and Node.js are installed
- Create
.envfrom.env.example(first run only) - Create a Python virtual environment (first run only)
- Install all Python and Node dependencies (first run only)
- Start the backend on port 8000 and frontend on port 3000
- Open
http://localhost:3000in your browser
Subsequent launches skip the install steps and start in seconds.
- Download and open LM Studio
- Search for and download a model (see recommendations below)
- Go to the Developer tab (icon looks like
</>) - Click Start Server — leave it running
- In CompositionLM, select your model from the dropdown and click to load it
| Model | VRAM | Best for |
|---|---|---|
| Mistral 7B Instruct | ~6 GB | Chat + mind maps, great JSON compliance |
| Qwen2.5 7B Instruct | ~6 GB | Strong structured output, excellent for mind maps |
| Llama 3.1 8B Instruct | ~6 GB | Reliable all-rounder |
| Qwen2.5 14B Instruct | ~10 GB | Best quality if you have the VRAM |
| Mixtral 8x7B Instruct | ~26 GB | Near-GPT-4 quality |
Avoid base (non-instruct) models — they ignore instructions and produce poor results.
# Clone
git clone https://github.com/your-username/compositionlm.git
cd compositionlm
# Backend
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Copy and edit config
cp .env.example .env
# Frontend
cd frontend && npm install && cd ..
# Start backend
HF_HUB_OFFLINE=1 TRANSFORMERS_OFFLINE=1 \
uvicorn backend.main:app --host 127.0.0.1 --port 8000
# In a second terminal — start frontend
cd frontend && npm run devThen open http://localhost:3000.
First run note: the embedding model (
all-MiniLM-L6-v2, ~23 MB) downloads from HuggingFace automatically. After that,HF_HUB_OFFLINE=1keeps it fully offline.
Copy .env.example to .env and edit as needed:
# LM Studio server (change port if you moved it)
LM_STUDIO_URL=http://127.0.0.1:1234
LM_STUDIO_API_BASE=http://127.0.0.1:1234/v1
# Embedding model (downloaded once, then cached)
EMBEDDING_MODEL=all-MiniLM-L6-v2
# How many source chunks to retrieve per chat message
TOP_K=5compositionlm/
├── backend/
│ ├── main.py # FastAPI app — all API endpoints
│ ├── config.py # Settings loaded from .env
│ ├── llm/
│ │ └── llm_client.py # LM Studio OpenAI-compatible client
│ ├── notebooks/
│ │ └── notebook_manager.py # SQLite CRUD for notebooks + messages
│ ├── retrieval/
│ │ └── vector_store.py # ChromaDB semantic search wrapper
│ ├── embedding/
│ │ └── embedder.py # Local sentence-transformers embedder
│ └── ingestion/
│ ├── pdf_parser.py # PDF → text chunks
│ ├── web_parser.py # URL → text chunks
│ └── audio_parser.py # Audio → Whisper transcript → chunks
├── frontend/
│ └── src/
│ ├── app/
│ │ └── page.tsx # Main UI shell
│ └── components/
│ ├── Sidebar.tsx # Notebook + source list
│ ├── ChatPanel.tsx # Streaming chat with markdown
│ ├── MindMapPanel.tsx# React Flow mind map
│ ├── SourceViewer.tsx# Document chunk preview
│ └── UploadPanel.tsx # File / URL upload
├── .env.example # Configuration template
├── requirements.txt # Python dependencies
├── start.bat # One-click launcher (Windows)
└── README.md
Interactive docs available at http://127.0.0.1:8000/docs while the backend is running.
| Method | Path | Description |
|---|---|---|
| GET | /api/health |
Health check |
| GET | /api/config |
LM Studio status + available models |
| POST | /api/v1/models/load?model_id= |
Load a model in LM Studio |
| POST | /api/v1/models/unload |
Unload current model |
| POST | /api/notebooks |
Create notebook |
| GET | /api/notebooks |
List notebooks |
| DELETE | /api/notebooks/{id} |
Delete notebook |
| POST | /api/notebooks/{id}/sources/upload |
Upload file source |
| POST | /api/notebooks/{id}/sources/url |
Add URL source |
| POST | /api/notebooks/{id}/chat/stream |
Streaming chat (SSE) |
| GET | /api/notebooks/{id}/chat/history |
Chat history |
| POST | /api/notebooks/{id}/mindmap |
Generate mind map |
| GET | /api/notebooks/{id}/mindmap |
Load saved mind map |
| GET | /api/notebooks/{id}/search?q= |
Semantic search |
LM Studio shows "Offline"
- Open LM Studio → Developer tab → Start Server
- Make sure it's on port 1234 (or update
LM_STUDIO_URLin.env)
Embedding model fails to download
- Run once with internet access (remove
HF_HUB_OFFLINE=1from the backend start command) - Or set
HF_MIRROR=https://hf-mirror.comfor Asia/China mirrors
Port already in use
- Change
FASTAPI_PORTorFRONTEND_PORTin.env - Update
frontend/next.config.jsdestination URL to match
Mind map fails with "not a valid structure"
- Use a larger/instruct model (7B+)
- Devstral-small (2B) works but struggles with the JSON schema on long sources
PRs welcome. Please open an issue first for large changes.
MIT