From 976198605349f73798939321a71b943658074b71 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste THERY Date: Thu, 16 Jul 2026 14:20:58 +0700 Subject: [PATCH] docs(addons): document TTS languages and Chat profiles --- README.md | 2 ++ context7.json | 3 +- docs/api-reference.md | 8 ++++++ docs/cli-reference.md | 7 +++++ docs/offline-chat-preload.md | 20 +++++++------ docs/offline-tts-preload.md | 23 ++++++++++++--- llms.txt | 9 +++--- packages/ragmir-chat/README.md | 18 ++++++------ packages/ragmir-core/src/cli.ts | 9 ++++-- packages/ragmir-core/src/mcp.test.ts | 2 +- packages/ragmir-core/src/setup.test.ts | 2 +- packages/ragmir-landing/public/ai.txt | 6 ++-- packages/ragmir-landing/public/llms.txt | 8 ++++-- packages/ragmir-tts/README.md | 17 +++++++++++- packages/ragmir-tts/src/cli.ts | 4 +-- scripts/smoke.mjs | 37 +++++++++++++++++++++++++ 16 files changed, 137 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index f4be083..891070f 100644 --- a/README.md +++ b/README.md @@ -272,6 +272,8 @@ Redaction reduces accidental exposure but is not a compliance certification. Rev | [`@jcode.labs/ragmir-tts`](./packages/ragmir-tts/README.md) | Optional local audio or explicit online voice rendering | Installing Core does not install Chat or TTS. Add only the optional package needed by the workflow. +Choose Chat with `--profile lite`, `fast`, or `quality`; choose offline TTS with `--lang en`, `fr`, +or `es`. The package guides explain the model sizes, preload step, and online boundaries. ## Runnable examples diff --git a/context7.json b/context7.json index 99094cc..c56f520 100644 --- a/context7.json +++ b/context7.json @@ -24,7 +24,8 @@ "Use one `createRagmirClient()` per project root for repeated work in a stateful Node.js process; close it during shutdown and use the top-level functions for one-shot scripts.", "Ragmir does not open an HTTP port; a network-facing host owns its transport, authentication, authorization, and rate limits.", "`rgr chat` is optional add-on generation via @jcode.labs/ragmir-chat; the core remains retrieval-only.", - "Qwen and Gemma are optional Ragmir Chat profiles, never requirements of Core, the CLI, the TypeScript API, or MCP.", + "@jcode.labs/ragmir-chat exposes lite (Qwen2.5 0.5B), default fast (Gemma 4 E2B), and explicit quality (Gemma 4 E4B) profiles; setup, doctor, and generation should use the same profile, and none is required by Core or MCP.", + "@jcode.labs/ragmir-tts selects a language-specific offline MMS model for en, fr, or es; explicit online Edge mode also supports ja, th, and zh, and its default voice follows the selected language.", "The `local-hash` embedding provider (default) is a lexical sha256 embedding, not semantic; use `transformers` for semantic retrieval.", "Switching `embeddingProvider` requires `rgr ingest --rebuild`, since the two providers produce incompatible vectors.", "Ingestion commits resumable file batches under ignored `.ragmir/storage/` state; use `rgr status --json` for progress, and expect `--rebuild` to preserve the active index until a staged generation is validated.", diff --git a/docs/api-reference.md b/docs/api-reference.md index c4e28b1..130f407 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -256,6 +256,10 @@ const result = await generateChatAnswer({ console.log(result.answer, result.citationStatus) ``` +`profile` accepts `lite` (Qwen2.5 0.5B, ~0.49 GB, thinking off), `fast` (default Gemma 4 E2B, +~3.35 GB), or `quality` (Gemma 4 E4B, ~5.15 GB). Setup, doctor, and generation should use the same +profile. + ### Recommended Chat exports | Export | Purpose | @@ -338,6 +342,10 @@ first call explicitly preloads the local model from non-sensitive text. Later ca `allowRemoteModels: false` for confidential content. The Edge path is explicit and sends narration text to the external service. +The local Transformers.js path supports `language: "en"`, `"fr"`, and `"es"`, each with its own +automatically selected MMS model. Edge additionally supports `"ja"`, `"th"`, and `"zh"`. French is +the default when no language is provided. + `RenderSpeechOptions.signal` stops before subsequent render or write phases. The Edge CLI is also terminated when cancelled and defaults to a 120-second bound; override it with `edgeTimeoutMs` when the host needs a shorter deadline. diff --git a/docs/cli-reference.md b/docs/cli-reference.md index 3fa265a..76d25a9 100644 --- a/docs/cli-reference.md +++ b/docs/cli-reference.md @@ -98,6 +98,12 @@ rgr audio /tmp/ragmir-tts-preload.txt --lang en --allow-remote-models --out .rag rgr audio ./brief.md --lang en --offline --out .ragmir/audio/brief.wav ``` +Keep the same Chat profile across `setup`, `doctor`, and answers: `lite` is the ~0.49 GB Qwen option, +`fast` is the default ~3.35 GB Gemma option, and `quality` is the explicit ~5.15 GB Gemma option. +For offline TTS, keep the same `--lang` across preload and render: `en`, `fr`, and `es` select their +own local model automatically. Edge additionally supports `ja`, `th`, and `zh` when explicitly +selected. + | Command | Purpose | | --- | --- | | `models pull [--enable]` | Preload the configured embedding model and optionally enable semantic retrieval. | @@ -109,6 +115,7 @@ OCR runs only for PDF pages without embedded text. The strict privacy profile di extractors. The first audio command above explicitly downloads the model from non-sensitive text; the second uses the prepared cache and does not download anything. See the [offline TTS guide](./offline-tts-preload.md) for model paths and verification. +See [offline Chat](./offline-chat-preload.md) for profile selection and air-gapped preparation. ## Agents, maintenance, and JSON diff --git a/docs/offline-chat-preload.md b/docs/offline-chat-preload.md index 3e74059..40ae3e5 100644 --- a/docs/offline-chat-preload.md +++ b/docs/offline-chat-preload.md @@ -12,23 +12,27 @@ rgr chat doctor --profile fast --verify rgr chat "What evidence supports this decision?" --profile fast --offline ``` -| Profile | Use | -| --- | --- | -| `lite` | Smaller Qwen2.5 profile for lower-memory machines. | -| `fast` | Default Gemma 4 profile for a stronger local answer. | -| `quality` | Larger Gemma 4 profile, explicit opt-in. | +| Profile | Pinned model | Download | Thinking | Use | +| --- | --- | --- | --- | --- | +| `lite` | Qwen2.5 0.5B Q4_K_M | ~0.49 GB | Off | Lower-memory machines and short answers. | +| `fast` | Gemma 4 E2B Q4_0 | ~3.35 GB | Standard or deep | Balanced default. | +| `quality` | Gemma 4 E4B Q4_0 | ~5.15 GB | Standard or deep | Larger explicit quality option. | -Setup downloads and verifies the selected GGUF under `.ragmir/models/chat/`. Normal answers use that local file and do not download or build a runtime. +Use the same profile in all three commands. Setup downloads and verifies the selected GGUF under +`.ragmir/models/chat/`. Normal answers use that local file and do not download or build a +runtime. `lite` forces `--thinking off`; `fast` is the default when no profile is provided. These are Chat implementation profiles, not Ragmir Core requirements. You can use Core with your preferred AI, a local model runner, a deterministic application, or no generative model at all. ## Air-gapped use -Prepare and verify the profile on a connected machine, copy the complete profile directory into the same ignored local path, then rerun `rgr chat doctor --verify` before using `--offline`. +Prepare and verify the profile on a connected machine, copy the complete profile directory into the +same ignored local path, then rerun `rgr chat doctor --profile --verify` before using +`--offline`. ## Operational rules -- The runtime selects its packaged acceleration backend automatically. +- The runtime selects Metal, CUDA, Vulkan, or CPU from its packaged backends automatically. - Visible answers retain citations; raw model thought is never shown, logged, or stored. - Use an external agent only when sending retrieved passages to that agent is acceptable for the corpus. diff --git a/docs/offline-tts-preload.md b/docs/offline-tts-preload.md index ade9066..7c2fd1c 100644 --- a/docs/offline-tts-preload.md +++ b/docs/offline-tts-preload.md @@ -1,6 +1,7 @@ # Offline TTS -Ragmir renders local WAV audio through Transformers.js. Download the model once with non-sensitive text, then render confidential content offline. +Ragmir renders local WAV audio through Transformers.js. Download the language model once with +non-sensitive text, then render confidential content offline. ```bash printf '%s\n' "Non-sensitive model preload text." > /tmp/ragmir-tts-preload.txt @@ -8,12 +9,26 @@ rgr audio /tmp/ragmir-tts-preload.txt --lang en --allow-remote-models --out .rag rgr audio ./brief.md --lang en --offline --out .ragmir/audio/brief.wav ``` -The first command warms `.ragmir/models/tts`. The second command requires the local model and does not download anything. Generated files stay in ignored `.ragmir/audio/` state. +The first command warms `.ragmir/models/tts`. The second command requires the local model and does +not download anything. Generated files stay in ignored `.ragmir/audio/` state. + +Use the same language code for both commands: + +| `--lang` | Language | Offline model | +| --- | --- | --- | +| `en` | English | `Xenova/mms-tts-eng` | +| `fr` | French | `Xenova/mms-tts-fra` | +| `es` | Spanish | `Xenova/mms-tts-spa` | + +French is the default when `--lang` is omitted. Run `rgr audio --doctor --json` to inspect the +supported offline and Edge language lists. For an online MP3 voice, choose Edge explicitly: ```bash -rgr audio ./brief.md --engine edge --out .ragmir/audio/brief.mp3 +rgr audio ./brief.md --engine edge --lang ja --out .ragmir/audio/brief.mp3 ``` -Use that path only when sending the narration text to the external service is acceptable. +Edge also supports `en`, `fr`, `es`, `ja`, `th`, and `zh`; its default voice follows `--lang` unless +`--voice` overrides it. Use that path only when sending the narration text to the external service +is acceptable. diff --git a/llms.txt b/llms.txt index 7299682..c0a6ced 100644 --- a/llms.txt +++ b/llms.txt @@ -26,10 +26,11 @@ Public subtagline: **Stop sending confidential documents directly to the cloud.* authorization belong to the embedding application. - Default retrieval: local-hash, with no model download. Semantic embeddings and local GGUF chat are explicit opt-ins. -- Optional packages: `@jcode.labs/ragmir-chat` for local cited GGUF synthesis and - `@jcode.labs/ragmir-tts` for local audio or explicitly selected online speech. -- Model boundary: Qwen and Gemma are optional Chat profile choices. Ragmir Core, its CLI, API, and - MCP server do not depend on either family or on any generative model. +- Optional packages: `@jcode.labs/ragmir-chat` offers `lite` Qwen, default `fast` Gemma, and explicit + `quality` Gemma profiles; `@jcode.labs/ragmir-tts` supports offline `en`, `fr`, and `es`, plus + explicit online Edge voices for `ja`, `th`, and `zh`. +- Model boundary: Chat profiles and TTS language models are optional. Ragmir Core, its CLI, API, and + MCP server do not depend on any generative model. - Privacy boundary: the corpus and index stay local. A cloud agent receives retrieved passages only when the user chooses that workflow, under that provider's data policy. - OCR boundary: embedded PDF text comes first; a configured local executable runs only for blank diff --git a/packages/ragmir-chat/README.md b/packages/ragmir-chat/README.md index dd7d222..9e951a8 100644 --- a/packages/ragmir-chat/README.md +++ b/packages/ragmir-chat/README.md @@ -32,14 +32,16 @@ npx rgr chat "What evidence supports this decision?" --profile fast --offline `rgr chat setup` downloads and verifies one model under `.ragmir/models/chat/`. Normal generation uses that local file and rejects remote model resolution. -| Profile | Intended use | -| --- | --- | -| `lite` | Smaller Qwen2.5 profile for lower-memory machines | -| `fast` | Default Gemma 4 profile for balanced local use | -| `quality` | Larger Gemma 4 profile, enabled explicitly | - -These are Chat profiles, not requirements of Ragmir Core, the CLI, API, or MCP server. Verify a -prepared profile with `npx rgr chat doctor --profile fast --verify` before offline use. +| Profile | Pinned model | Download | Thinking | Choose it when | +| --- | --- | --- | --- | --- | +| `lite` | Qwen2.5 0.5B Q4_K_M | ~0.49 GB | Off | Memory and startup time matter most | +| `fast` | Gemma 4 E2B Q4_0 | ~3.35 GB | Standard or deep | You want the balanced default | +| `quality` | Gemma 4 E4B Q4_0 | ~5.15 GB | Standard or deep | You accept a larger model for stronger answers | + +Use the same profile for `setup`, `doctor`, and each answer. The `fast` profile is the default; +`lite` always disables thinking. These are Chat profiles, not requirements of Ragmir Core, the CLI, +API, or MCP server. Verify a prepared profile with +`npx rgr chat doctor --profile fast --verify` before offline use. ## TypeScript API diff --git a/packages/ragmir-core/src/cli.ts b/packages/ragmir-core/src/cli.ts index 144d66f..662e12a 100644 --- a/packages/ragmir-core/src/cli.ts +++ b/packages/ragmir-core/src/cli.ts @@ -1209,16 +1209,19 @@ program program .command("audio") - .description("Render a narration text file to local speech audio with Ragmir TTS.") + .description("Render narration as offline WAV or explicitly selected online Edge MP3.") .argument("[text-file]", "Narration text file to render.") .option("-o, --out ", "Output MP3 or WAV path.") .option("--engine ", "TTS engine: auto, edge, or transformers.") - .option("--lang ", "TTS language: en, es, fr, ja, th, or zh.") + .option( + "--lang ", + "TTS language. Offline: en, es, fr. Edge also: ja, th, zh. Default: fr.", + ) .option("--model ", "Transformers.js TTS model ID.") .option("--model-path ", "Local model/cache path.") .option("--offline", "Force the Transformers.js local/offline WAV path.") .option("--allow-remote-models", "Explicitly allow remote model downloads.") - .option("--voice ", "Edge voice. Defaults to fr-FR-DeniseNeural.") + .option("--voice ", "Edge voice override. Default matches --lang.") .option("--rate ", "Edge rate. Defaults to +0%.") .option("--speaker-embeddings ", "Optional model-specific speaker embedding path or URL.") .option("--speed ", "Optional model-specific speech speed.", parseNumber) diff --git a/packages/ragmir-core/src/mcp.test.ts b/packages/ragmir-core/src/mcp.test.ts index b39a531..21c453c 100644 --- a/packages/ragmir-core/src/mcp.test.ts +++ b/packages/ragmir-core/src/mcp.test.ts @@ -321,7 +321,7 @@ describe("MCP protocol contract", () => { const usage = await jsonToolResult(client, "ragmir_usage_report", { days: 1 }) expect(usage).toMatchObject({ totalEvents: expect.any(Number) }) - }) + }, 15_000) it("should bound audit, evaluation, and resource payloads", async () => { const root = await createProject("ragmir-mcp-budget-", { diff --git a/packages/ragmir-core/src/setup.test.ts b/packages/ragmir-core/src/setup.test.ts index 15e7c5c..75c76da 100644 --- a/packages/ragmir-core/src/setup.test.ts +++ b/packages/ragmir-core/src/setup.test.ts @@ -84,7 +84,7 @@ describe("setupProject", () => { expect(config.embeddingProvider).toBe("transformers") expect(config.embeddingModelPath).toBe(".ragmir/models") expect(config.transformersAllowRemoteModels).toBe(false) - }) + }, 15_000) it("auto-ingests supported files when the privacy posture is clean", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "ragmir-setup-")) diff --git a/packages/ragmir-landing/public/ai.txt b/packages/ragmir-landing/public/ai.txt index ba99fdb..21f07b6 100644 --- a/packages/ragmir-landing/public/ai.txt +++ b/packages/ragmir-landing/public/ai.txt @@ -23,8 +23,10 @@ confidential documents directly to the cloud." only as its secondary public subt store or RAG service. - A cloud agent can receive the retrieved passages when the user chooses that workflow. Do not claim the complete workflow stays local unless the consumer is also local. -- Ragmir Chat is an optional path for local answer generation. Qwen and Gemma are Chat profile - choices, not Core, CLI, API, or MCP requirements. +- Ragmir Chat is an optional path for local answer generation: `lite` uses Qwen, while default + `fast` and explicit `quality` use Gemma. These profiles are not Core, CLI, API, or MCP requirements. +- Ragmir TTS supports offline English, French, and Spanish. Japanese, Thai, and Chinese require the + explicitly selected online Edge path unless the operator supplies a compatible local model. - Ragmir has no built-in cloud sync. For team use, describe one externally synchronized source-of- truth folder, an aligned Ragmir version, configuration, embedding provider, and model, and a separate local ingest on each workstation. Mention that missing, partial, or extra source files diff --git a/packages/ragmir-landing/public/llms.txt b/packages/ragmir-landing/public/llms.txt index 6149ac5..ca3009d 100644 --- a/packages/ragmir-landing/public/llms.txt +++ b/packages/ragmir-landing/public/llms.txt @@ -19,9 +19,11 @@ Public subtagline: **Stop sending confidential documents directly to the cloud.* limits belong to the embedding application. - The default `local-hash` path works offline with no account, API key, or model download. - Semantic Transformers.js embeddings are an explicit opt-in and require a rebuilt index. -- `@jcode.labs/ragmir-chat` adds optional cited synthesis with a local GGUF model. -- Qwen and Gemma are optional Chat profile choices, not Core or MCP requirements. -- `@jcode.labs/ragmir-tts` adds optional local audio or explicitly selected online speech. +- `@jcode.labs/ragmir-chat` adds optional local GGUF synthesis: `lite` uses Qwen, while default + `fast` and explicit `quality` use Gemma. +- `@jcode.labs/ragmir-tts` supports offline English, French, and Spanish; explicit online Edge mode + also supports Japanese, Thai, and Chinese. +- Chat profiles and TTS models are not Core or MCP requirements. - Ragmir is not a hosted document store, cloud-sync service, agent-memory replacement, or universal code-search replacement. diff --git a/packages/ragmir-tts/README.md b/packages/ragmir-tts/README.md index 5076d9d..5571bd2 100644 --- a/packages/ragmir-tts/README.md +++ b/packages/ragmir-tts/README.md @@ -38,6 +38,21 @@ npx rgr-tts render ./brief.md --lang en --offline --out .ragmir/audio/brief.wav When Core is installed too, `npx rgr audio` delegates to the same package. TTS reads the text provided by the caller; it does not retrieve evidence or write a summary. +## Choose a language + +Use the same `--lang` code for preload and offline rendering. Ragmir selects the matching model; +French is the default only when `--lang` is omitted. + +| Code | Language | Offline model selected automatically | +| --- | --- | --- | +| `en` | English | `Xenova/mms-tts-eng` | +| `fr` | French | `Xenova/mms-tts-fra` | +| `es` | Spanish | `Xenova/mms-tts-spa` | + +Run `npx rgr-tts doctor --json` to inspect `offlineLanguages` and `edgeLanguages`. Japanese (`ja`), +Thai (`th`), and Chinese (`zh`) are available only through the explicitly selected online Edge +engine unless you supply a compatible Transformers.js model yourself. + ## TypeScript API ```ts @@ -76,7 +91,7 @@ npx rgr-tts render ./public-announcement.md \ | Path | Output | Languages | Network boundary | | --- | --- | --- | --- | -| Transformers.js | WAV | English, Spanish, French | Model preload is explicit; rendering can then stay offline | +| Transformers.js | WAV | English, French, Spanish | Model preload is explicit; rendering can then stay offline | | Edge | MP3 | English, Spanish, French, Japanese, Thai, Chinese | Narration text is sent to the external service | There is no silent fallback from local rendering to Edge. Keep model state and generated audio diff --git a/packages/ragmir-tts/src/cli.ts b/packages/ragmir-tts/src/cli.ts index 0f54670..06d5626 100644 --- a/packages/ragmir-tts/src/cli.ts +++ b/packages/ragmir-tts/src/cli.ts @@ -231,12 +231,12 @@ Usage: Options: --engine transformers, edge, or auto. Default is transformers. - --lang en, es, fr, ja, th, or zh. Selects the language. Default fr. + --lang Offline: en, es, fr. Edge also: ja, th, zh. Default fr. --model Transformers.js TTS model ID. --model-path Local model/cache path. Defaults to .ragmir/models/tts. --offline Force the Transformers.js local/offline WAV path. --allow-remote-models Explicitly allow remote model downloads. - --voice Edge voice. Defaults to fr-FR-DeniseNeural. + --voice Edge voice override. Default matches --lang. --rate Edge rate. Defaults to +0%. --speaker-embeddings Optional model-specific speaker embedding path or URL. --speed Optional model-specific speech speed. diff --git a/scripts/smoke.mjs b/scripts/smoke.mjs index 34423fd..4217fa6 100644 --- a/scripts/smoke.mjs +++ b/scripts/smoke.mjs @@ -76,6 +76,28 @@ try { "ragmir-tts", "TTS help should not advertise the previous command alias", ) + assertIncludes( + ttsHelp.stdout, + "Offline: en, es, fr. Edge also: ja, th, zh.", + "TTS help should distinguish offline and Edge language support", + ) + assertIncludes( + ttsHelp.stdout, + "Default matches --lang.", + "TTS help should explain automatic Edge voice selection", + ) + + const audioHelp = await runKb(["audio", "--help"], tempRoot) + assertIncludes( + audioHelp.stdout, + "Offline: en, es, fr.", + "Core audio help should list offline language support", + ) + assertIncludes( + audioHelp.stdout, + "th, zh. Default: fr.", + "Core audio help should list the remaining Edge languages and default", + ) const deprecatedTtsCliPath = path.join(tempRoot, "ragmir-tts") await symlink(ttsCliPath, deprecatedTtsCliPath) @@ -102,6 +124,21 @@ try { "ragmir-chat", "chat help should not advertise the previous command alias", ) + assertIncludes( + chatHelp.stdout, + "lite (Qwen2.5 0.5B)", + "chat help should identify the lightweight Qwen profile", + ) + assertIncludes( + chatHelp.stdout, + "fast (Gemma 4 E2B, default)", + "chat help should identify the default Gemma profile", + ) + assertIncludes( + chatHelp.stdout, + "Lite always uses off.", + "chat help should explain the lite thinking boundary", + ) const deprecatedChatCliPath = path.join(tempRoot, "ragmir-chat") await symlink(chatCliPath, deprecatedChatCliPath)