Local NotebookLM Alternative: PDF to a 2-Host Podcast
Want to go deeper than this article?
Free account unlocks the first chapter of all 25 courses — RAG, agents, MCP, voice AI, MLOps, real GitHub repos.
Go from reading about AI to building with AI 20 structured courses. Hands-on projects. Runs on your machine. Start free.
Short answer: run Open Notebook for the notebook, Ollama for the script, and a local OpenAI-compatible TTS server for the voices — then set Open Notebook's TTS provider to openai_compatible with a base URL of http://host.docker.internal:8969/v1 instead of an OpenAI key. That one field is the difference between a "local" notebook that quietly ships your dialogue to a cloud TTS vendor and one where a confidential PDF becomes a two-host audio episode without a packet leaving the box.
If you have already installed Open Notebook, got Ollama answering questions about your documents, and then found the podcast button demanding an ElevenLabs or OpenAI key — skip to Step 2. That is the exact wall this page exists to get you over.
The Wall Everyone Hits
The language model and the voice model are two different providers in Open Notebook, and only the first one has a native Ollama option.
Open Notebook (lfnovo/open-notebook) is the closest open-source thing to NotebookLM that actually ships the Audio Overview, not just the chat. As of our GitHub API check on 18 August 2026 it sits at 37,003 stars, MIT-licensed, created 21 October 2024, last pushed 16 August 2026, with v1.14.0 as the latest tagged release (21 July 2026). It is genuinely maintained, which is more than can be said for some of the alternatives.
Its podcast pipeline is real and well-built: episode profiles, speaker profiles, an outline stage, a dialogue-writing stage, per-speaker synthesis, then mixing. But the provider model splits into services — language, embedding, text-to-speech, speech-to-text — and the setup guides all cover the first two. So people wire up Ollama, watch chat work beautifully, hit Generate Podcast, and get told to add an API key.
The instinct at that point is to look for an "Ollama TTS" option. There isn't one, and there never will be: Ollama has no /v1/audio/speech endpoint. It serves language models and embeddings. Text-to-speech is a different piece of software entirely.
What Open Notebook does have is an openai_compatible provider with its own per-service base URLs. That provider does not care whether OpenAI is on the other end. Anything that speaks /v1/audio/speech will do — including a container running on your own laptop.
Reading articles is good. Building is better.
Free account = the first chapter of all 25 courses, with a per-chapter AI tutor. No card.
The Stack
Three containers, three ports, zero API keys.
| Piece | What it does | Port | Provider setting in Open Notebook |
|---|---|---|---|
| Open Notebook (v1.14.0) | Notebook, RAG, podcast pipeline | 8502 / 5055 | — |
| Ollama | Writes the outline and dialogue; embeds your sources | 11434 | ollama (native) |
| Speaches or Kokoro-FastAPI | Speaks each line | 8969 / 8880 | openai_compatible |
Speaches is the one Open Notebook's own docs use, so it is the path of least resistance. Kokoro-FastAPI is the alternative if you already run one — same Kokoro-82M model underneath, same OpenAI surface, different port and a different model name string. Either works; the config differs by two fields.
Step 1: The Local Brain
Pull one chat model and one embedding model, then add Ollama as a credential — Open Notebook needs both, and the embedding model is the one people forget.
ollama pull qwen3 # the script writer
ollama pull mxbai-embed-large # source search / RAG
Those two are the models Open Notebook's Ollama documentation recommends by name (it also lists gemma3, phi4 and deepseek-r1 as alternatives for the language slot, and nomic-embed-text as a lighter embedding option). Then in Settings → API Keys, add an Ollama credential pointing at http://host.docker.internal:11434 if Open Notebook is in Docker, or http://localhost:11434 if you run it from source.
Two gotchas worth knowing before they cost you an hour:
- The model name must match
ollama listexactly. Open Notebook's docs call this out specifically —qwen3:32bworks,qwen3-32bdoes not. - Turn the worker down to one task. Open Notebook runs background jobs with a default concurrency of 5. On a single-GPU or CPU-only box that means five requests fighting over one model. Set
OPEN_NOTEBOOK_WORKER_MAX_TASKS=1in theenvironment:block of your compose file — the variable is read at worker launch, not by the app, so putting it in.envalone may not take effect.
New to Ollama itself? Our complete Ollama guide covers the model-tag and memory basics this step assumes.
Step 2: The Local Voice
This is the load-bearing step: run a container that implements /v1/audio/speech, and Open Notebook will treat it as if it were OpenAI.
Open Notebook's own docs/5-CONFIGURATION/local-tts.md documents this route — it is supported, not a workaround. The compose file from those docs:
services:
speaches:
image: ghcr.io/speaches-ai/speaches:latest-cpu
container_name: speaches
ports:
- "8969:8000"
volumes:
- hf-hub-cache:/home/ubuntu/.cache/huggingface/hub
restart: unless-stopped
volumes:
hf-hub-cache:
Start it and pull the voice model (~500MB):
docker compose up -d
docker compose exec speaches uv tool run speaches-cli model download speaches-ai/Kokoro-82M-v1.0-ONNX
Prove it works before you touch Open Notebook. If this curl produces a playable file, the hard part is done:
curl "http://localhost:8969/v1/audio/speech" -s \
-H "Content-Type: application/json" \
--output test.mp3 \
--data '{
"input": "Hello! Local TTS is working.",
"model": "speaches-ai/Kokoro-82M-v1.0-ONNX",
"voice": "af_bella"
}'
Note the :latest-cpu tag. This stage does not need a GPU. Kokoro-82M is an 82-million-parameter model; Open Notebook's docs put the recommended spec for the TTS container at 4+ CPU cores and 4GB of RAM. There is a :latest-cuda image if you want it faster, and Kokoro on a GPU runs many times realtime — but a two-host episode is a batch job you walk away from, not a live conversation, so CPU is a perfectly reasonable default. If you want the deeper comparison of what these servers cost in memory, our Kokoro-FastAPI walkthrough has the verified figures for both images.
Using Kokoro-FastAPI instead? Two fields change: the base URL becomes http://host.docker.internal:8880/v1 and the model name becomes the literal string kokoro. Voice IDs (af_bella, am_adam, bf_emma…) are the same Kokoro set either way. Our Kokoro TTS setup guide covers the voice list.
Run this on your own machine and stop paying every month
Pay once and keep it. No renewal, no per-token bill, and nothing you feed it ever leaves your hardware.
Step 3: Wire It Up
Add an OpenAI-Compatible credential whose TTS URL points at your container, then register a TTS model with provider openai_compatible. Both halves are required — the credential alone does nothing until a model uses it.
Credential — Settings → API Keys → Add Credential → OpenAI-Compatible:
| Field | Speaches | Kokoro-FastAPI |
|---|---|---|
| TTS base URL (Docker, macOS/Windows) | http://host.docker.internal:8969/v1 | http://host.docker.internal:8880/v1 |
| TTS base URL (Docker, Linux) | http://172.17.0.1:8969/v1 | http://172.17.0.1:8880/v1 |
| TTS base URL (from source) | http://localhost:8969/v1 | http://localhost:8880/v1 |
| API key | leave blank, or any placeholder | not-needed |
Then hit Test Connection. The credential dialog lets you set per-service URLs — LLM, embedding, TTS, STT — so you can leave the LLM slot empty and only fill TTS, which is exactly what you want here since Ollama handles the language side natively.
Model — Settings → Models → Add Model, in the Text-to-Speech section:
| Field | Speaches | Kokoro-FastAPI |
|---|---|---|
| Provider | openai_compatible | openai_compatible |
| Model Name | speaches-ai/Kokoro-82M-v1.0-ONNX | kokoro |
| Display Name | Local TTS | Local TTS |
The model name is the single most common failure. Open Notebook passes it straight through to the server, and the server rejects anything it does not recognise. If you get "model not found," run curl http://localhost:8969/v1/models and copy the string it returns, character for character.
There is also a deprecated environment-variable route — OPENAI_COMPATIBLE_BASE_URL_TTS=http://host.docker.internal:8969/v1 in your compose environment: block. It still functions, and Open Notebook's docs still show it, but they mark it deprecated in favour of the Settings UI. Use the UI unless you are scripting a deployment.
Step 4: Generate the Episode
Upload the PDF as a source, pick a two-speaker episode profile, assign one voice per speaker, generate. The pipeline from here is Open Notebook's, and it is worth understanding because it explains the quality ceiling.
The project ships preset episode profiles. For the NotebookLM-style two-host feel, the closest presets are:
| Profile | Speakers | Feel |
|---|---|---|
| Expert Interview | 2 | Host asks, expert answers — closest to NotebookLM |
| Debate Format | 2 | Two positions, deliberate disagreement |
| Panel Discussion | 3-4 | Multiple perspectives |
| Solo Explanation | 1 | One friendly narrator |
| Academic Presentation | 1 | One expert, lecture tone |
Each speaker profile gets a TTS model and a voice. Give speaker 1 af_bella and speaker 2 am_adam and you have a woman-and-man pair; bf_emma and bm_george gives you the British version. Per-speaker model overrides are supported, so nothing stops you mixing servers.
Open Notebook's docs also give the pipeline and its own time budget: content analysis (~1 min) → outline (2-3 min) → dialogue writing (2-3 min) → audio synthesis, 3-5 min per speaker → mixing (1-2 min), for a stated total of 10-20 minutes for a typical episode. Two caveats we want to be straight about: those are the project's figures, and they describe a cloud-model configuration. Swapping in a local Ollama model makes the three text stages track your own hardware, and swapping in a CPU TTS container changes the synthesis stage. We have not run this end to end on a single 12GB card, so we are not going to quote you a wall-clock number or a peak-VRAM figure we did not measure. What we can tell you is where the time goes and what to watch: docker stats on the TTS container during the synthesis stage, and ollama ps during the outline and dialogue stages.
On source volume, the docs' own advice is 3-5 sources per podcast, and it is good advice. A 30-page PDF plus your own notes produces a focused episode. Twelve sources produces a rambling one.
The Better-Voices Route
If per-line Kokoro is not conversational enough for you, use Open Notebook to write the script and VibeVoice to perform it — one pass, both hosts, still offline.
The structural limit of the in-app route is that each speaker turn is synthesised in isolation and the results are stitched. That gives you two clean voices alternating. It does not give you the overlap, interruption and reaction that make NotebookLM's hosts sound like people rather than a table read.
VibeVoice is the only open-weights model we know of that generates multi-speaker conversation in a single pass, holding voice identity across a long runtime. So:
- Generate the episode in Open Notebook with a two-speaker profile.
- Use Export Transcript to get the script out.
- Reformat as
Speaker 1:/Speaker 2:lines and run it through VibeVoice.
The trade-off is honest and it is not small. VibeVoice-1.5B runs on an 8GB card; the better-sounding 7B "Large" needs roughly 20GB, and Microsoft pulled its weights from Hugging Face in September 2025, so the 7B now comes from community mirrors. Microsoft's own model card also asks people not to use it commercially without further testing, and its outputs carry an audible AI disclaimer plus a watermark. Everything is MIT-licensed — Microsoft withdrew distribution, not permission — but you should know all of that before you build a workflow on it. Our VibeVoice setup guide covers the mirror situation and VRAM tiers in detail.
You lose the one-click convenience. You gain a conversation that sounds like one.
What This Setup Cannot Do
Four things worth knowing before you commit an evening.
- The voices will not match NotebookLM. Open Notebook's own local-vs-cloud table in
local-tts.mdrates local TTS quality "Good" against cloud's "Excellent", and local voices as "Limited" against cloud's "Many options" — the project is not overselling this, and neither will we. In our reading the line-by-line synthesis architecture caps the realism more than the model does. Either way: set expectations at "two clear narrators," not "two friends riffing." - Three services means three failure modes. When generation fails, the useful first move is to check each layer independently:
curl http://localhost:11434/api/tagsfor Ollama,curl http://localhost:8969/v1/modelsfor the TTS server, thendocker compose logsfor Open Notebook itself. From inside the Open Notebook container,docker exec -it open-notebook curl http://host.docker.internal:8969/v1/modelstells you whether the problem is the server or the Docker networking between them. - Linux Docker networking is the usual culprit.
host.docker.internalis a macOS and Windows convenience. On Linux use the bridge IP172.17.0.1, or run with--network hostand uselocalhost. - "Offline" needs one online session first. The Docker images, the Ollama models and the Kokoro ONNX weights all have to be downloaded once. After that the stack genuinely runs with the network unplugged — which is the entire point if your PDFs are client, legal or medical documents.
For the document-Q&A half of the workflow without the audio, chat with your PDFs locally covers the lighter-weight tools, and private AI knowledge base covers the same idea at team scale. If you are producing an actual show rather than research briefings, local AI podcast production is the editing-side companion, and best local TTS models compares the voice engines head to head.
Sources
- lfnovo/open-notebook — repository metadata (37,003 stars, MIT, pushed 16 Aug 2026) and release v1.14.0, both read from the GitHub API on 18 August 2026
- Open Notebook documentation —
docs/5-CONFIGURATION/local-tts.md(Speaches compose file, port 8969, model download, credential fields),docs/5-CONFIGURATION/openai-compatible.md(per-service base URLs, deprecated env vars, model-name rules),docs/5-CONFIGURATION/ollama.md(recommended models, tag-format gotcha),docs/3-USER-GUIDE/creating-podcasts.md(episode profiles, pipeline stages and time budget, source-count advice) - Speaches — OpenAI-compatible TTS/STT server used in Open Notebook's documented local route
- remsky/Kokoro-FastAPI — the alternative OpenAI-compatible TTS server (Apache 2.0)
- Microsoft VibeVoice model card and repository — licence, weights availability and safety notes, as documented in our own VibeVoice setup guide
FAQ
Go from reading about AI to building with AI
20 structured courses. Hands-on projects. Runs on your machine. Start free.
Liked this? 25 full AI courses are waiting.
From fundamentals to RAG, agents, MCP servers, voice AI, and production deployment with real GitHub repos. First chapter free, every course.
Build Real AI on Your Machine
RAG, agents, NLP, vision, and MLOps - chapters across 25 courses that take you from reading about AI to building AI.
Want structured AI education?
25 courses, 519+ chapters, from $9. Understand AI, don't just use it.
Continue Your Local AI Journey
Comments (0)
No comments yet. Be the first to share your thoughts!