From 1fc91d1192780d46e508d9dc06fb7b516d13515f Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Tue, 27 Oct 2026 16:06:50 +0700 Subject: [PATCH] fix(sasquatch): reply in all 24 locales; record translation/Basque state - Sasquatch UI/guide/FAQ were already 100% in all 24 locales; the AI reply language directive only covered es/th/ja. SASQUATCH_LANGUAGES now maps all 24 app languages (trick names/core vocabulary stay English). - Document the Sasquatch privacy difference: its AI calls the CVM/AI proxy (OpenRouter), unlike the on-device translation. - Record the Basque status: IR 9->8 and target-side tokenizer fixed; model now emits Basque but loops on EOS/generation; remaining gap before 1.7.2. --- AGENTS.md | 24 +++++++++++---- src/components/SasquatchGuide.tsx | 51 ++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fc83e18..e14613d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2455,9 +2455,10 @@ Rules: `handle_path /models/*` → `/srv/models`, CORS `*`; backup `/etc/caddy/Caddyfile.bak-…`). - **Verified from the host:** en↔es, ca↔gl, hi↔en. The Basque packs are - converted and hosted (ONNX q8 + generated `tokenizer.json`), but the final - in-browser MarianTokenizer/ONNX runtime verification is **still pending** - (a Marian/ONNX runtime error in the standalone check). + converted and hosted (ONNX q8). Fixed: the ONNX **IR 9→8** mismatch and the + Marian tokenizer's **target-side** `tokenizer.json`. The decoder now emits + Basque, but it **loops** (EOS/generation config), so Basque is still **not + usable**. Next: the `eos_token_id`/generation loop. - Runtime: **`@xenova/transformers` 2.17.2** + ONNX Runtime **1.14** WASM self-hosted in `public/ort/` (37 MB, copied from `onnxruntime-web`), loaded from `../ort/`; worker `src/workers/translate.worker.ts`. M2M100 is used @@ -2480,15 +2481,26 @@ Rules: - **Conversion:** Docker Python 3.11 + torch 2.4.1 + transformers 4.46.3 + optimum 1.24; dynamic q8; `tokenizer.json` generated from the SentencePiece models (needs protobuf + `sentencepiece_model_pb2.py`). -- **Still to do:** finish the Basque tokenizer/ONNX runtime fix, verify all 24 - pairs in the browser/APK, measure speed/memory, and ship **1.7.2** (the phone - is on 1.7.1). No SpotChat. +- **Still to do:** fix the Basque EOS/generation loop, verify all 24 pairs in + the browser/APK, measure speed/memory, and ship **1.7.2** (the phone is on + 1.7.1). No SpotChat. - **Keyboard caveat:** a malicious OS keyboard or rooted device is outside the app’s control. Warn/recommend a trusted offline keyboard, and avoid the OS keyboard for **secrets** (custom secure input / QR / bunker/Amber, `FLAG_SECURE`, no autofill/suggestions). Translation’s guarantee is app-level: no plaintext egress. +### Sasquatch translation + privacy (2026-10-27) +- The Sasquatch **UI, guide and FAQ** strings (`sasquatchUi`/`sasquatchChat`/ + `sasquatchGuide`) are translated in all 24 locales (i18n 100%). +- The **AI reply language** directive was only `es`/`th`/`ja`; + `SasquatchGuide.tsx` now has `SASQUATCH_LANGUAGES` for all 24 (skate trick + names and core vocabulary stay in English), so replies follow the app + language for every locale. +- **Privacy differs:** the Sasquatch AI is **not on-device** — it calls the CVM/ + AI proxy (OpenRouter). Its questions/replies leave the device. Only the + **translation** is local/no-egress; do not conflate the two. + ### Community relay — self-hosted Newlay (2026-10-12) The community relay moved off the hosted relay.tools instance diff --git a/src/components/SasquatchGuide.tsx b/src/components/SasquatchGuide.tsx index 979124b..b9f30c7 100644 --- a/src/components/SasquatchGuide.tsx +++ b/src/components/SasquatchGuide.tsx @@ -24,12 +24,55 @@ import { PLATFORM_OWNER_PUBKEYS } from '@/hooks/useListingRestrictions'; import { SasquatchProDialog } from '@/components/SasquatchProDialog'; import { useSasquatchActions, type SasquatchDraft } from '@/hooks/useSasquatchActions'; import { useTranslation } from '@/contexts/language'; +import type { Language } from '@/contexts/language'; import { SasquatchActionCard } from '@/components/SasquatchActionCard'; import { callSasquatchAI, streamSasquatchAI } from '@/lib/sasquatchBrain'; import { buildProAuthHeaders } from '@/lib/proAuth'; import { answerFromGlossary } from '@/lib/glossary'; import { TripItineraryCard } from '@/components/TripItineraryCard'; import { buildItinerary, type Itinerary, type PlannerSpot, type PlannerEvent, type PlannerCoach, type PlannerCrew, type WeatherLite } from '@/lib/tripPlanner'; + +/** Native language names for the Sasquatch reply-language directive. */ +const SASQUATCH_LANGUAGES: Record = { + en: 'English', + es: 'Spanish (Castellano)', + ca: 'Catalan (Català)', + eu: 'Basque (Euskara)', + gl: 'Galician (Galego)', + hi: 'Hindi (हिन्दी)', + th: 'Thai (ไทย)', + ja: 'Japanese (日本語)', + pt: 'Portuguese', + 'pt-PT': 'European Portuguese', + fr: 'French', + de: 'German', + it: 'Italian', + nl: 'Dutch', + pl: 'Polish', + ru: 'Russian', + ko: 'Korean', + 'ko-KP': 'North Korean', + 'zh-CN': 'Simplified Chinese', + 'zh-TW': 'Traditional Chinese', + uk: 'Ukrainian', + tr: 'Turkish', + vi: 'Vietnamese', + id: 'Indonesian', + sv: 'Swedish', + cs: 'Czech', + ro: 'Romanian', + el: 'Greek', +}; + +/** + * The Sasquatch answers in the app's current language for every locale (not + * just es/th/ja). Skate trick names and core vocabulary stay in English. + */ +function sasquatchLanguageDirective(language: Language): string { + if (language === 'en') return ''; + return `\n\nAlways reply in ${SASQUATCH_LANGUAGES[language]} with a friendly, casual skate tone. Keep skateboarding trick names in English (kickflip, ollie, nollie, heelflip, etc.) and core skate vocabulary (spot, park, bowl, DIY, vert, crew, line) in English — never translate those.`; +} + import { cn } from '@/lib/utils'; import { fetchWeather, calculateSkateability } from '@/lib/weather'; import { getCurrentPosition } from '@/lib/geolocation'; @@ -1117,13 +1160,7 @@ export function SasquatchGuide({ message, onDismiss }: SasquatchGuideProps) { // content. Personal tools are only offered to logged-in Pro supporters. // The reply-language directive is appended so The Sasquatch answers in // the app's current language, keeping skate trick names in English. - const languageDirective = language === 'es' - ? '\n\nAlways reply in Spanish (Castellano). Keep skateboarding trick names in English (kickflip, ollie, nollie, heelflip, etc.) and never translate them.' - : language === 'th' - ? '\n\nAlways reply in Thai (ไทย) with a friendly, casual skate tone. Keep skateboarding trick names in English (kickflip, ollie, nollie, heelflip, etc.) and core skate vocabulary (spot, park, bowl, DIY, vert, crew, line) in English — never translate those.' - : language === 'ja' - ? '\n\nAlways reply in Japanese (日本語) with a friendly, casual skate tone. Keep skateboarding trick names in English (kickflip, ollie, nollie, heelflip, etc.) and core skate vocabulary in English or katakana (spot, park, bowl, DIY, vert, crew, line) — never translate the trick names.' - : ''; + const languageDirective = sasquatchLanguageDirective(language); const systemPrompt = (personal.available && isPro ? `${SYSTEM_PROMPT}${PERSONAL_TOOLS_PROMPT}` : SYSTEM_PROMPT) + languageDirective;