Repository navigation
Voice Input Local STT EN
Speak instead of typing: press Alt+V in the side panel input, watch the draft appear as you talk, and let a local model add punctuation and normalize numbers when you stop. Nothing is sent automatically.
Recognition runs entirely on your machine — no audio ever leaves the device, no cloud ASR service, no extra API key. The price is a one-time setup of two things: optional dependencies and a model pack.
← Back to Wiki Home · Related: Agent Service · Configuration · FAQ
Once enabled, a 🎤 button appears in the input toolbar; while recording, a recorder strip expands above the input:
| Element | Description |
|---|---|
| 24 volume bars | Live waveform that scrolls with your voice |
| Timer |
00:12 style; single take is capped at 5 minutes by default |
| Status text | Listening / Transcribing / Limit reached / Failed |
| Cancel | Discard this take and roll the draft back (Esc does the same) |
| Done | Finish and finalize (Alt+V again does the same) |
Two behaviours differ from typing:
- The draft is provisional. The streaming model writes as you speak. The moment you edit the input by hand, later drafts only append what is genuinely new — and if a new hypothesis is a rewrite rather than an extension, it is skipped entirely instead of overwriting what you already see.
- The result is never sent for you. Finalizing only writes text into the input; sending is still your call.
The 🎤 button only appears when dependencies + models + the switch are all satisfied; otherwise it stays hidden rather than failing after a click.
The Agent needs sherpa-onnx-node plus its platform binary packages. Pick one entry point:
# 1) CLI (recommended: check first, then install)
aha asr detect
aha asr install
# 2) Opt in while installing the Agent (off by default)
bash install.sh --with-asr
# 3) Options → Voice tab → one-click install (progress polled every 2 s)On intranet machines the npm mirror must carry the sherpa-onnx platform packages, otherwise the install stalls at "missing platform binary". The full package list lives in
docs/Voice-Input-Local-STT.md.
Models live in a fixed directory, one sub-directory per pack, each containing a manifest.json:
~/.ai-helper-agent/asr/models/
└── sense-voice-zh-en-ja-ko-yue-2024-07-17/
├── manifest.json
├── model.int8.onnx
└── tokens.txt
Three kinds cooperate; you may install only some of them (offline alone works, you just lose the live draft):
| Kind | Role | If missing |
|---|---|---|
online (streaming) |
Draft as you speak | No draft; one result after you stop |
offline (final pass) |
High-accuracy pass + punctuation | Falls back to streaming draft text |
vad |
Sentence segmentation | Still works, slightly worse punctuation |
Ways to get them:
# Machine can reach the internet or an HF mirror: one-click download
# (writes the manifest and verifies hashes for you)
curl -H "Authorization: Bearer <token>" -X POST \
http://127.0.0.1:18910/api/asr/models/download \
-H 'Content-Type: application/json' \
-d '{"kind":"offline"}'On a fully offline network, download from a connected machine, lay the files out as above with a manifest.json (files plus optional sha256), and copy them over — or import the folder from the Options page.
Options → Voice tab, top toggle. It is off by default: having the dependency and models installed does not enable anything, which avoids the "I installed it, why is nothing happening" confusion.
Once all three are ready the panel re-gates itself (🎤 appears) without reopening the side panel.
In side panel or popup form, Chromium cannot show the microphone prompt. Allow it once in the Options page (tab form) — Voice tab → "Grant permission". After that the side panel records without prompting.
- Put the caret in the input (or anywhere) and press
Alt+V(Option+V); - Speak — the draft appears in the input and you can keep editing it by hand;
- Finish any way you like:
- press
Alt+Vagain, - click Done in the recorder strip,
- or just press Enter to send (recording stops and finalizes first);
- press
- To abandon: press
Escor click Cancel — the draft rolls back.
Shortcuts come in two tiers:
-
Alt+V(default, not remappable) — its point is that it also fires while the focus is on the web page (the extension forwards the key to the panel). -
Right Alt / Right Ctrl (optional, both off by default) — tick them separately under Options → Voice → Quick trigger; ticking both means either one fires.
- Semantics are "press, then release" = one action. Pressing any other key while it is held voids that press — right Alt is a modifier in AltGr layouts, so this neither starts a stray recording nor swallows AltGr character input.
- The config lives in
chrome.storage.localand takes effect immediately in both the side panel and the page — no extension reload, no panel reopen. - It only responds when voice input is ready (dependency × model × switch).
| Item | Description |
|---|---|
| Enable voice input | Master switch; turning it off disables 🎤 and Alt+V
|
| Quick trigger | Right Alt / Right Ctrl single-key toggles, both off by default; Alt+V always works and is unaffected |
| Language |
auto / Chinese / English / Japanese / Korean / Cantonese |
| Streaming model | Pick one of the scanned online packs (first usable by default) |
| Final-pass model | Same, for offline packs |
| Dependency status / install |
sherpa-onnx detection result and install progress |
| Scan / import models | Re-scan the model directory or import a pack from anywhere |
~/.ai-helper-agent/asr/asr-config.json (written by the extension; normally not hand-edited):
{
"enabled": true,
"language": "auto",
"streamingModelId": "sense-voice-streaming-zh-en",
"offlineModelId": "sense-voice-zh-en-ja-ko-yue-2024-07-17",
"idleUnloadMs": 600000
}| Field | Default | Description |
|---|---|---|
enabled |
false |
Master switch |
language |
auto |
Expected language; auto lets the model decide |
streamingModelId / offlineModelId
|
null |
null = first usable pack by capability |
idleUnloadMs |
600000 |
Unload engines after this much idle time (0 = never) |
| Variable | Default | Description |
|---|---|---|
AI_HELPER_ASR_ROOT |
~/.ai-helper-agent/asr |
Root for models and config |
AI_HELPER_ASR_MAX_RECORDING_MS |
300000 |
Max length of one take |
AI_HELPER_ASR_SESSION_IDLE_MS |
30000 |
Idle session reclamation |
AI_HELPER_ASR_MAX_SESSIONS |
1 |
Concurrent sessions |
AI_HELPER_ASR_RSS_LIMIT |
~1.5 GB | Above this RSS, skip the offline final pass |
AI_HELPER_ASR_OFFLINE_TIMEOUT_MS |
180000 |
Per-task inference timeout |
ws://127.0.0.1:18910/ws/asr/<sessionId>?token=<token>&language=auto
| Dir | Frame | Meaning |
|---|---|---|
| → | {type:'start'} |
Open the session |
| → | binary | 16 kHz / 16-bit / mono PCM |
| → | {type:'stop'} |
Finish and finalize (async; final follows) |
| → | {type:'cancel'} |
Abandon, no final
|
| ← | {type:'ready', draft} |
Ready; draft:false means no streaming model |
| ← | {type:'partial', text} |
Draft, roughly every 150 ms |
| ← | {type:'final', text, fallback} |
Final text; fallback:true = streaming draft |
| ← | {type:'error', code} |
busy / model_missing / max_duration / rss_pressure / internal
|
On
stopthe session frees its concurrency slot immediately; the final pass runs on a background worker thread and deliversfinallater, so the next take can start right away.
| Method | Path | Description |
|---|---|---|
| GET | /api/asr/status |
Dependency / model / switch / loaded engine state |
| POST | /api/asr/config |
Update config (switch, language, model ids, idle unload) |
| GET | /api/asr/models |
Scanned packs (invalid ones include a reason) |
| POST | /api/asr/models/scan |
Re-scan the model directory |
| POST | /api/asr/models/pick |
Import a pack from a directory |
| GET | /api/asr/models/catalog |
Downloadable model catalog |
| POST | /api/asr/models/download |
Download (resumable + hash verified) |
| GET | /api/asr/models/download/status |
Download progress |
| POST | /api/asr/models/download/cancel |
Cancel a download |
| POST | /api/asr/transcribe |
One-shot recognition of a WAV buffer |
| POST | /api/asr/warmup |
Warm the engines (also runs at startup) |
| POST | /api/asr/deps/detect |
Detect the sherpa-onnx dependency |
| POST | /api/asr/deps/install |
Install it (allow-listed command) |
| GET | /api/asr/deps/install/status |
Install progress |
All endpoints require a Bearer token, like the rest of the API.
- Audio never leaves the machine — no cloud ASR, nothing written to disk.
- Never auto-sent — finalizing only fills the input.
- Idle unload — engines are released after 10 minutes of disuse, returning a few hundred MB of native memory.
-
Non-blocking — the final pass runs on a worker thread, so
/health, chat streaming and tool execution stay responsive during long transcriptions. -
Memory guard — when process RSS nears the threshold the offline pass is skipped and the streaming draft is used instead (
rss_pressure), so the Agent never gets taken down by one long recording.
Rough sizes: streaming (zh/en, int8) ≈ 100 MB, SenseVoice final pass (zh/en/ja/ko/yue, int8) ≈ 230 MB, VAD ≈ 1 MB.
The 🎤 button never appears. One of the three requirements is missing. Open Options → Voice and read whether it is "dependency not ready" or "models not ready", then use the matching install / scan button; also confirm the switch is on.
Clicking 🎤 says there is no microphone permission. The side panel cannot show the prompt. Go to Options → Voice → "Grant permission" and allow it in the tab page.
I copied a model folder but it says the pack is invalid.
The Options page now shows the concrete reason (missing manifest.json, missing fields, missing files, sha256_mismatch, …). Fix the manifest and hit "Scan" again.
Recognition feels slow / takes seconds after I stop. That is the offline final pass doing a full recomputation for better quality. Install only the streaming model if you prefer speed over punctuation and number normalization.
Long takes get cut off. Default cap is 5 minutes. At the limit the Agent stops recording and finalizes with the full audio — nothing you already said is lost, and the strip shows "recording limit reached, transcribing…".
Can I add a sentence while the AI is generating? Yes. Once the text lands in the input, the send button switches to Send instead of Stop.
Can two recordings run at once?
Default concurrency is 1 (single-user desktop). A second one receives busy and the UI says it is still processing the previous take.
- Full install and model-pack authoring (intranet package list, offline packaging) →
docs/Voice-Input-Local-STT.md - Other Agent capabilities → Agent Service
- Every setting → Configuration
🌐 English Wiki: Home · Quick Start · Showcase · Core Features · Built-in Tools · Architecture · Agent Service · Configuration · FAQ
© AI Helper · GitHub · Discussions · Issues · MIT License
- 🏠 首页 Home
- 🚀 快速开始 Quick Start
- 🎬 实战案例 Showcase
- ✨ 核心功能 Core Features
- 🎙️ 语音输入 Voice Input
- 🧰 内建工具 Built-in Tools
- 🏗️ 架构与技术栈 Architecture
- 🤖 代理服务 Agent Service
- ⚙️ 配置参考 Configuration
- ❓ 常见问题 FAQ
English Wiki: Home · Quick Start · Showcase · Core Features · Voice Input · Built-in Tools · Architecture · Agent Service · Configuration · FAQ