grigio / sonia-assistant
git clone https://github.com/grigio/sonia-assistant.git
v0.3.4 · 2d ago
Sonia - Local Voice Assistant in less than 13GB of RAM, TTS/STT, No Dedicated GPU required, Skills supported
—
stars, 24h
+52
stars, 7 days · #870
+52
stars, 30 days · #5,698
52
★ total · +52% this week
5
forks · 0 open issues
Star history starts 2026-10-20; the chart appears after the second daily snapshot.
LanguageTypeScript
LicenseGPL-3.0
Created2026-10-13 (7d ago)
Last push2d ago
Watchers1
OwnerUser
GitHub topics
Links
- GitHub: github.com/grigio/sonia-assistant
- Homepage: https://github.com/grigio/sonia-assistant
- Releases · Issues · Hacker News mentions
README excerpt
# Sonia Personal Assistant **Sonia** is an LLM + STT + TTS voice assistant that needs **no dedicated GPU** and runs in **less than 15 GB of RAM**, entirely on a local computer. Multilingual and full-duplex: the mic stays open while the assistant talks — interrupt it (barge-in) and it pauses, resumes or cancels accordingly. It mirrors whichever language you speak (English/Italian tested). ▶️ Sonia demo video Everything is local; the only external piece is an **OpenAI-compatible endpoint** (an already-running `llama-server`, managed outside this project). Optionally and experimentally, an existing `pi` executable can replace it — see AI models used. **Contents** — Features · Architecture · Models · Installation · Security · Inspiration · License --- ## Main features - **True full-duplex listening** — the mic never closes; answers can be interrupted mid-sentence. Barge-in is echo-aware: backchannels and Sonia's own voice resume it, real speech cancels the reply and keeps what was already said. - **Streaming ASR + layered turn detection** — partial transcripts drive the live `🎤 …` line; a turn ends on Silero VAD + silence gaps + the Smart Turn classifier, with a 4-token `LISTEN`/`REPLY` prompt only when the pause is ambiguous. - **Bilingual IT/EN** — the model mirrors your language per turn; `LOCALE=it|en` localizes UI, spoken sentences and tool results, and a timer rings in the language of the request that set it. - **Function-calling tools** — datetime, timers, watches, notes, skills, shell (6 tool rounds per turn), gated by a **tool gate** that re-checks each call against your words (so a 4B model can't fire spurious tools) and by `CMD_MODE=off|ask|auto` for risky shell. The read-only skill tools (`read_skill`, `list_skills`) are exempt from the gate — they load context and act on nothing, while the `run_command` that uses them is still judged. - **Externally managed skills** — `SKILL.md` packages are *not* owned by this project: point `SKILLS_DIR` at the directory you already use (`pi`'s, **opencode**'s, any other harness's) and activate each per-turn from the UI settings drawer. - **Two interchangeable LLM legs** — the endpoint (default) or, optionally, an existing `pi` executable (`LLM_VIA_PI=1`, toggled at runtime) — plus a browser app-window UI and `--cli`/`--text` terminal modes. - **A task banner over the chat** — every pending timer, running command and active watch, with its countdown and a ✕ that stops *that* task alone. Watches repeat a read-only command at an interval (≥ 5 s), optionally staying quiet until the output matches some text. - **⟲ rewind + persistent chat** — everything after the clicked line goes (later turns *and* their context, in transcript and model history alike, on both legs); the line itself and pending tasks stay. 🧹 erases the whole chat, this only the part you regret. State lives in `data/chat.json`, so a restart resumes where you left off (`CHAT_PERSIST=0` disables). --- ## Architecture One TypeScript hub proce