# ZuZu Grammar — self-hosted LanguageTool ZuZu Grammar uses **LanguageTool** for full sentence grammar, spelling, and punctuation. If LanguageTool is offline, the API falls back to basic local rules. ## Hugging Face Spaces (recommended) The Docker image **embeds LanguageTool** and starts it with the app (`scripts/start.sh`). 1. Redeploy the Space (rebuild the image). 2. First boot can take **1–3 minutes** while Java + LT warm up. 3. Check `GET /health` → `"languagetool": { "reachable": true }`. 4. Space secrets (optional overrides): ```env LANGUAGE_TOOL_EMBEDDED=true LANGUAGE_TOOL_URL=http://127.0.0.1:8010 LANGUAGE_TOOL_LANGUAGE=en-US LANGUAGE_TOOL_ENABLED=true LANGUAGE_TOOL_TIMEOUT=90 LANGUAGE_TOOL_CHUNK_CHARS=1800 GRAMMAR_MAX_CHARS=12000 LANGUAGETOOL_JAVA_OPTS=-Xms256m -Xmx1024m ``` Needs about **1–2 GB RAM**. If the Space OOMs, raise Space hardware or lower `-Xmx` (Java 21 is used in the image). Long drafts are **split into ~1800-character chunks** so one long paragraph does not OOM LanguageTool. Pastes over `GRAMMAR_MAX_CHARS` (default 12,000) return a clear 413 instead of a raw 500. **Do not** set `LANGUAGE_TOOL_URL` to a host that isn’t running LT (that causes `Connection refused` and the “offline” fallback message). ## Local: LanguageTool only + `python app.py` ```bash docker compose up languagetool -d ``` Wait until healthy, then in `.env`: ```env LANGUAGE_TOOL_URL=http://127.0.0.1:8010 LANGUAGE_TOOL_LANGUAGE=en-US LANGUAGE_TOOL_ENABLED=true ``` `LANGUAGE_TOOL_LANGUAGE` is the server default (en-US). The Grammar UI can override per check (`en-GB`, etc.). ```bash curl -s http://127.0.0.1:8010/v2/languages | head python app.py ``` ## Local: full Compose (app + LT sidecar) ```bash docker compose up --build ``` App: http://127.0.0.1:7860 LanguageTool: http://127.0.0.1:8010 Compose sets `LANGUAGE_TOOL_EMBEDDED=false` and `LANGUAGE_TOOL_URL=http://languagetool:8010`. ## Health ```json "languagetool": { "configured": true, "reachable": true, "default_language": "en-US" } ``` When reachable, grammar responses use `"engine": "languagetool"`. ## Troubleshooting `Connection refused` | Cause | Fix | |--------|-----| | LT container not running | `docker compose up languagetool -d` | | App URL wrong | Local app → `http://127.0.0.1:8010`; Compose app → `http://languagetool:8010`; Space embedded → `http://127.0.0.1:8010` | | Space still on old image | Rebuild/redeploy so embedded LT + `start.sh` are included | | LT still starting | Wait 1–2 min; watch logs for `LanguageTool ready` | | Long text → HTTP 500 | Redeploy latest build (sentence chunking + higher heap). Over `GRAMMAR_MAX_CHARS` now returns a clear 413. | ## Resources LanguageTool needs roughly **1–2 GB RAM**.