Deploy: LanguageTool spell checker in production, with optional n-grams

- docker-compose.yml: a `languagetool` service (erikvl87/languagetool:6.8),
  internal only, 1 GB heap, one CPU, a 28 GB memory limit that is room for the
  n-gram page cache (reclaimable, not memory in use), and a low-priority
  warm-up read of the n-gram files at start so first checks hit RAM even on
  mechanical disks. `init` creates $DATA_ROOT/languagetool-ngrams; the app
  containers get LANGUAGETOOL_URL (empty turns the check off).
- `webmail.sh ngrams [langs]` (default en de fr es): deploy/ngrams.py, run in
  the backend image, downloads LanguageTool's n-gram data with resume, checks
  free space first (unpacked is ~2x the zip: ~26 GB for all four), unpacks into
  a temp folder and moves it into place, then recreates the engine to load it.
  languagetool.org refuses Python's default User-Agent, so it sends its own.
- `doctor` reports whether the spell checker answers and which n-gram
  languages are installed.
- docs/nas-install.md and .env.prod.example describe all of it.

Verified locally: German n-grams (1.58 GB -> 3.06 GB) load, and catch what the
rules alone do not ("liegt ihm Schrank" -> im, "Der Patenten" -> Patienten).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 07:44:36 +02:00
co-authored by Claude Opus 5.5
parent 1f2e539eb2
commit 139fff826e
5 changed files with 279 additions and 1 deletions
+12
View File
@@ -59,6 +59,18 @@ RSPAMD_MEM_LIMIT=256m
RSPAMD_REDIS_MEM_LIMIT=160m
RSPAMD_REDIS_MAXMEMORY=128mb
# --- Spelling and grammar check (LanguageTool) -------------------------------
# The compose window's spell checker. Leave empty to turn it off for everyone;
# unset uses the bundled container (http://languagetool:8010).
#LANGUAGETOOL_URL=
# Java heap. 1g covers a household or small team.
LANGUAGETOOL_HEAP=1g
# Mostly file cache for the optional n-gram data (`webmail.sh ngrams`, ~26 GB
# unpacked for en/de/fr/es), which the kernel gives back under memory pressure.
# Without n-grams it never comes near this. Lower it on a small NAS.
LANGUAGETOOL_MEM_LIMIT=28g
LANGUAGETOOL_CPUS=1.0
# --- Search -----------------------------------------------------------------
# pg = Postgres full-text. No extra container, no extra RAM. Default.
# meili = Meilisearch: typo tolerance, better ranking, faster on large mailboxes.