File size: 2,849 Bytes
39cfcd1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# 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**.