Local AI setup
The “Ask AI” panel on each page sends the page’s context to a model and streams the answer back. This guide runs everything on your machine, with the model served locally by Ollama.1. Ollama
- Install Ollama from https://ollama.com
-
Start the server with a larger context window (keep this terminal open):
Ollama defaults to 4096 tokens and silently drops anything past that, so a large page would be cut off with no error. 8192 fits comfortably in 16 GB alongside the 7B model. If you run the Ollama menu-bar app instead of
ollama serve, set it for the app and restart it: -
In a second terminal, pull the models:
Check it works
2. Redis
The rate limiter keeps its counters in Redis. From the repo root:3. The AI worker
The worker is the Python FastAPI service that builds the prompt and talks to the model (POST /chat, GET /health). Run it from services/ai-worker
(also summarized in that folder’s README).
First time only:
.env:
INTERNAL_SECRET must match AI_WORKER_SECRET in apps/web/.env.local
(see step 4).
Every time you work on it (activate the virtualenv first in each new
terminal):
AI_WORKER_URL). Start it
from services/ai-worker so it finds .env.
Check it is up:
python -m pytest.
4. The web app
apps/web/.env.local must already have DATABASE_URL, REDIS_URL and
AUTH_SECRET (see the root README). Add:
AI_RATE_LIMIT_PER_MINUTE=20 (see below). Restart the dev server
after editing .env.local, since Next only reads it at startup.
Then sign in (seeded demo: workspace acme, password acme-demo-password),
open any page and click the sparkle icon beside the copy button. The badge
beside “Ask AI” says whether a local or hosted model answered.
Costs and limits
Local models are free, but a hosted model is billed per token and the chat is reachable by every signed-in user. These guards keep one user, or one large page, from running up cost or exhausting the model’s context window.
Notes:
- The rate limiter fails open. If Redis is unreachable, requests are allowed through and a warning is logged, so a Redis outage doesn’t take chat down. That is why the provider spend limit below matters.
- The context budget is shared. The model’s window holds the system
prompt, page data, history, question and the answer together. The route
budgets them as one: a prompt may total about 21,500 characters (the
8,192-token window minus 1,024 for the answer, at a conservative 3
characters per token), and history gets whatever the page and question
leave. The limits in
limits.tsare derived fromOLLAMA_CONTEXT_LENGTHandmax_tokens, so change them together. - Limits apply to local and hosted alike, so behaviour doesn’t change when you switch providers.
Hosted models: set a spend cap
Before putting a hosted key in.env, set a hard ceiling in the provider’s
own dashboard (for Fireworks, a monthly spend limit or a small prepaid
balance). Application limits can be bypassed by a bug or an outage; the
provider’s limit cannot. Use a key made only for this project so it can be
revoked on its own.
To use a hosted model, switch the worker’s .env to the hosted profile in
.env.example and restart it. No web app change is needed.
Notes
- The first request is slow while the model loads into memory.
- On 16 GB machines, close memory-heavy apps or use the 3b model.
- Never commit
.envfiles..env.exampleis the template.