Phase 25. Spanish was never built — the groundwork was all [x] (DreamDict data, the prompt language, the L1 rule gating, TTS env-discovery), which is why the plan read as though it had shipped. shippedPairs was the honest answer: the server had been refusing es on purpose. The langpack is neutral Latin American, chosen with the user: tú, ustedes, no vosotros, and the pan-American half of every vocabulary split. A vitest greps for the peninsular twins the way fr is greped for québécismes — including coger, which is not merely regional but obscene through most of Latin America. The dictionary is the story. Debian's hunspell-es symlinks twenty country codes to one file, which reads as pan-Hispanic; RLA publishes twenty-four builds per release, one per country plus a generic es that is the union, and Debian ships peninsular es_ES. The 58,622-form gap is essentially voseo, so the first version of this commit underlined vení and tenés as misspellings and called it a considered gap. The MUST_ACCEPT list was written to catch exactly that and structurally could not: it asserted the pan-Hispanic vocabulary, and every RLA variant carries the full pan-Hispanic vocabulary — only the paradigms are localised. The REP table cited as the second witness is shared by all builds too. Two independent-looking proofs, neither able to distinguish anything, agreeing with each other. The profile now demands what discriminates, each verified against the build it targets: voseo rejects es_ES and Debian, vosotros rejects es_MX, and arepa/chévere/bacán reject es_AR, which has both paradigms and would otherwise pass. 717,640 forms, 1.74 MB gzipped, 762 ms / 97 MB in a real nspell. fr and pt-PT rebuild byte-identical from their own upstream debs, so the shared script still means what it meant. Shipping the union is fr's call arrived at from the other side: coût and cout are both correct French, tienes and tenés are both correct Spanish. The dictionary holds every variety because underlining is all it can do; the copy picks a register because speaking requires one. Reviewed by four models at the usual >=2-of-4 threshold, 5 of 27 findings applied — one catching the bedtime proverb as fr's Qui dort dîne calqued into Spanish, gloss and all, which is the rule the fr header states. One below-threshold finding (a missing ¡, seen by 1 of 4 because an absent opening mark has no closing ! to look wrong against) was applied and turned into an assertion instead: the suite now rejects any native line that closes ? or ! without opening one. piper-es on es_MX-ald-medium, not the es_ES-davefx-medium the plan named — six of Piper's nine Spanish voices are peninsular, so the obvious pick was the pt-PT trap through a different door. go build/vet/test, tsc, vite, vitest 251/251. Not deployed, not seen in a browser, not read by a native speaker, and no es account exists.
103 lines
5.1 KiB
Bash
103 lines
5.1 KiB
Bash
# Petal — production environment for the parodia.dev VPS.
|
|
# Copy to the stack directory as `.env` (docker-compose.yml reads it via
|
|
# env_file) and fill in the model names. Values the image already fixes
|
|
# (PORT, DATABASE_PATH, IMAGE_DIR, TTS_CACHE_DIR, TTS endpoints) are set in
|
|
# docker-compose.yml, not here.
|
|
|
|
# --- Routing -----------------------------------------------------------------
|
|
# Must match the DNS A record and the Traefik Host() rule.
|
|
PETAL_HOST=petal.parodia.dev
|
|
# Absolute origin the app knows itself by. Phase 16's OIDC redirect URI is
|
|
# built from this, so it has to be the real public HTTPS origin.
|
|
BASE_URL=https://petal.parodia.dev
|
|
|
|
# The companion's bedtime nag and the night theme read the container clock.
|
|
TZ=Europe/Lisbon
|
|
|
|
# The container runs as this uid/gid so it can write the ./data bind mount.
|
|
# Set both to the output of `id -u` / `id -g` for the account owning the stack
|
|
# directory. Wrong values show up as "unable to open database file (14)".
|
|
PETAL_UID=1001
|
|
PETAL_GID=1001
|
|
|
|
# (The interim PETAL_BASIC_AUTH edge gate is gone: Petal authenticates for
|
|
# itself now, and the auth block at the bottom of this file is what holds the
|
|
# door. A second password in front of a real login is one more thing to lose.)
|
|
|
|
# --- LLM (millenia, over headscale) ------------------------------------------
|
|
# The only cross-VPN dependency. Petal degrades warmly when it's unreachable:
|
|
# spell check, gloss, garden, search, export and read-aloud all keep working and
|
|
# the status bar shows 小助手在休息 · Petal's helper is resting.
|
|
#
|
|
# 100.64.0.2 is millenia on the headscale network. vLLM must be bound to that
|
|
# interface (NOT 0.0.0.0 — this host is public); see deploy/README.md.
|
|
LLM_BACKEND=vllm
|
|
LLM_ENDPOINT=http://100.64.0.2:8000
|
|
LLM_MODEL=
|
|
LLM_CHAT_MODEL=
|
|
# 30s is the local-network default. Over WAN + VPN, with the voice and
|
|
# collocation passes sending a whole document, that truncates real work — the
|
|
# request is a hard deadline on Complete, and a timeout surfaces as the same
|
|
# warm 502 as an unreachable model. 90s leaves headroom without letting a
|
|
# genuinely wedged backend hang the pass forever.
|
|
LLM_TIMEOUT=90s
|
|
|
|
# --- Read-aloud (Piper sidecars) ---------------------------------------------
|
|
# Endpoints are wired in docker-compose.yml; these pick the voice each sidecar
|
|
# loads. Changing one means recreating that container so it downloads the model.
|
|
#
|
|
# A language is routable only when both halves are set — a TTS_ENDPOINT_XX with
|
|
# no TTS_VOICE_XX reads as "no voice for this language" and the browser's own
|
|
# synthesizer takes over, rather than as an instance that errors on every
|
|
# request. Adding es is a compose service plus a pair of lines here.
|
|
#
|
|
# pt_PT-tugão-medium is the only European Portuguese voice Piper ships; every
|
|
# other pt model in the catalogue is Brazilian. French has the opposite
|
|
# property — every fr voice in the catalogue is fr_FR — so there is no wrong
|
|
# country to land on and no non-ASCII name to trip the downloader.
|
|
TTS_VOICE_EN=en_US-amy-medium
|
|
TTS_VOICE_ZH=zh_CN-huayan-medium
|
|
TTS_VOICE_PT=pt_PT-tugão-medium
|
|
TTS_VOICE_FR=fr_FR-siwis-medium
|
|
# Mexican, not peninsular — the es pack is written in neutral Latin American
|
|
# Spanish, and es_ES-davefx-medium would read it in the accent it avoids.
|
|
TTS_VOICE_ES=es_MX-ald-medium
|
|
TTS_AUDIO_FORMAT=mp3
|
|
TTS_TIMEOUT=15s
|
|
|
|
# --- Auth (Authentik OIDC) ---------------------------------------------------
|
|
# NOT OPTIONAL HERE. Authentik already runs on this host; set all three and
|
|
# Petal authenticates for itself.
|
|
#
|
|
# Leave any of them unset and Petal REFUSES TO START, because the alternative is
|
|
# worse: it would otherwise fall back to resolving every anonymous request to
|
|
# the single `local` user, handing the open internet full read and write over
|
|
# every document in the database. That fallback is right on a laptop and a
|
|
# catastrophe on this host, so the guard is on for any non-loopback BASE_URL.
|
|
# See PETAL_REQUIRE_AUTH below.
|
|
#
|
|
# AUTHENTIK_URL is the provider's issuer, and the redirect URI to register in
|
|
# Authentik is https://petal.parodia.dev/auth/callback.
|
|
AUTHENTIK_URL=https://auth.parodia.dev/application/o/petal/
|
|
AUTHENTIK_CLIENT_ID=petal
|
|
AUTHENTIK_CLIENT_SECRET=
|
|
|
|
# Who may sign in: comma-separated subject ids and/or emails.
|
|
#
|
|
# SET THIS. Empty means everyone Authentik authenticates, and Authentik on this
|
|
# host fronts half a dozen applications — being a valid user there is not the
|
|
# same as belonging in someone's private journal. An empty value is legal (a
|
|
# single-household instance may genuinely want it) and says so loudly in the
|
|
# startup log every boot.
|
|
#
|
|
# An email is knowable in advance; a subject id is an opaque uuid nobody can
|
|
# know before that person's first login. Use emails to invite, subject ids to
|
|
# pin.
|
|
PETAL_ALLOWED_SUBS=her@example.com,me@example.com
|
|
|
|
# The guard itself. Defaulted from BASE_URL — loopback origins run open, real
|
|
# ones demand a login — so it does not normally need setting. Set it to false
|
|
# only for a deployment genuinely reachable from nowhere but a trusted network,
|
|
# and understand that it means anyone who reaches Petal is the `local` user.
|
|
# PETAL_REQUIRE_AUTH=true
|