# --------------------------------------------------------------------------- # Freezmo - Ollama configuration # Copy this file to `.env.local` and adjust if needed. # --------------------------------------------------------------------------- # WHO PROVIDES THE API KEY ----------------------------------------------------- # user-key (default) Every browser supplies its own key. The key is typed # into the settings dialog, kept in that browser's local # storage and sent with each request in the # `x-ollama-key` header. The server never stores it. # Point OLLAMA_BASE_URL at https://ollama.com. # server One key for everyone, read from OLLAMA_API_KEY below # (single-user installs). Nothing is sent from the client. # local No key at all: a local daemon signed in with # `ollama signin` proxies the cloud models. OLLAMA_AUTH=user-key # Ollama endpoint. https://ollama.com for cloud, http://localhost:11434 for a # local daemon. In user-key mode this is the endpoint the browser's key is sent # to; in server/local mode it is used directly. OLLAMA_BASE_URL=https://ollama.com # Only used when OLLAMA_AUTH=server. Never commit a real key. OLLAMA_API_KEY= # Model used for the vision/transcription step (reads photos of notes). # Must be multimodal — gpt-oss and other text-only models cannot be used here. # Free-tier friendly: gemma4:31b-cloud, kimi-k3:cloud (paid), mistral-large-3 (paid). VISION_MODEL=gemma4:31b-cloud # Model used to generate activities, grade short answers and restore the # language if a transcription came back translated. gpt-oss:120b is free-tier # friendly, very good at strict JSON and the strongest multilingual model in the # free plan. NOTE: it is text-only, so it can't be used as VISION_MODEL. # Free alternatives: nemotron-3-super:cloud, gpt-oss:20b-cloud. # Paid/credit: glm-5.3-flash:cloud, kimi-k3:cloud. TEXT_MODEL=gpt-oss:120b-cloud # CHAT MODELS (optional) ------------------------------------------------------- # The allowlist the chat model picker offers, comma-separated. The server never # accepts a model name outside this list. The first entry is the default. # When unset, the configured TEXT_MODEL and VISION_MODEL are used. # Example: CHAT_MODELS=gemma4:31b-cloud,gpt-oss:120b-cloud # CHAT_MODELS= # RATE LIMITS (per client IP, sliding window, in-memory) ---------------------- # Generation decks are expensive, so they are limited tightly by default. # RATE_LIMIT_WINDOW_MS=300000 # RATE_LIMIT_GENERATE=12 # RATE_LIMIT_GRADE=40 # RATE_LIMIT_HOMEWORK=12 # Homework follow-ups (short rewrites). # RATE_LIMIT_REFINE=30 # RATE_LIMIT_HEALTH=90 # Encrypted sync (no model calls, but shouldn't be hammered). # RATE_LIMIT_SYNC=60 # Push subscription changes and test sends. # RATE_LIMIT_PUSH=30 # Chat turns (one model call each; users send them in bursts). # RATE_LIMIT_CHAT=60 # PUSH REMINDERS (optional) ---------------------------------------------------- # Web Push reminders only appear in the UI when BOTH VAPID keys are set. # Generate them once with: npx web-push generate-vapid-keys # VAPID_PUBLIC_KEY= # VAPID_PRIVATE_KEY= # VAPID_SUBJECT=mailto:you@example.com # Where subscriptions are stored (endpoint, keys, and the reminder text the # browser composed for that device — it may name one of its decks). # PUSH_DIR=.freezmo/push # The daily sender is a script you schedule yourself — cron, or the shipped # systemd timer (deploy/freezmo-reminders.timer): # node scripts/send-reminders.mjs # A device's own reminder text wins; these generic lines are the fallback for # subscriptions that never synced one (same words the app uses without notes). # PUSH_REMINDER_TITLE=Time to review # PUSH_REMINDER_BODY=Your decks are waiting — a few due cards keep the streak alive. # ENCRYPTED SYNC STORAGE ------------------------------------------------------- # Opt-in sync uploads an opaque AES-GCM blob; the server can't read it and # never sees the passphrase or the API key. One small JSON file per sync ID. # SYNC_DIR=.freezmo/sync # Per-blob cap in bytes (larger uploads are refused with HTTP 413). # SYNC_MAX_BYTES=12582912 # Total cap for the directory in bytes (new blobs refused with HTTP 507). # SYNC_TOTAL_BYTES=1073741824 # Optional tuning ------------------------------------------------------------ # OLLAMA_TIMEOUT_MS=300000 # OLLAMA_HEALTH_TIMEOUT_MS=8000 # Send `think: false` to thinking models for faster JSON output. # OLLAMA_THINK=false # FREEZMO_DEFAULT_ACTIVITY_COUNT=10