Skip to content

Repository files navigation

Jarvis — Assistente de Voz Local (Wake Word + Transcrição + Injeção de Texto + Claude Code por voz)

Assistente de voz desktop, em background, que transcreve sua fala localmente (sem enviar áudio para a nuvem) e injeta o texto no campo que estiver focado em qualquer aplicativo — VSCode, terminal, navegador, editores, etc. Também pode conversar diretamente com o Claude Code CLI por voz, com as respostas lidas em voz alta por um motor de TTS local.

Status: v2 funcional (dictado + modo Claude Code). Testado em Windows. Veja prompt-jarvis-voice-assistant.md para o histórico da v1 e planejamento-v2-integracao-claude-code.md para as decisões de arquitetura da v2.

Electron React TypeScript Vite Python FastAPI WebGL openWakeWord faster--whisper webrtcvad Piper TTS Claude Code

Funcionalidades

v1 — Ditado por voz

  • Escuta contínua e leve em background com wake word "Hey Jarvis".
  • Ao detectar o wake word, grava o áudio, detecta o fim da fala automaticamente (VAD) e transcreve localmente.
  • Injeta o texto transcrito no campo focado via clipboard + paste simulado (não precisa clicar em lugar nenhum antes de falar).
  • Overlay flutuante (animação Strands, WebGL) que reage ao estado (parado / ouvindo / gravando / transcrevendo), arrastável com o mouse para qualquer posição da tela.
  • Painel de configuração (Electric Border) para ajustar a posição do overlay.
  • Tudo roda localmente: wake word e transcrição não saem da máquina.

v2 — Modo Claude Code por voz

  • Segundo modo de operação (alternável pela bandeja do sistema): em vez de ditar texto, o áudio transcrito vira um prompt enviado ao Claude Code CLI (claude -p, modo headless), e a resposta volta para o Jarvis.
  • Respostas lidas em voz alta por um motor de TTS 100% local (Piper) — nenhum texto sai da máquina para virar áudio.
  • Token do Claude Code (ANTHROPIC_API_KEY) armazenado com criptografia via safeStorage do Electron (Credential Vault/Keychain do SO), nunca em texto plano.
  • Gerenciamento de projetos: registra pastas de trabalho, escolhe o projeto ativo (usado como diretório do claude -p) e mantém a sessão/contexto de conversa por projeto entre reinícios do app.
  • Histórico de conversa (pergunta transcrita → resposta do Claude Code), com painel próprio acessível pela bandeja.
  • Suporte alternativo a um servidor LLM local compatível com a API da OpenAI (Ollama, LM Studio, text-generation-webui, ...), como opção ao Claude Code.

Stack técnica

Camada Tecnologia
Shell desktop Electron 33 + electron-vite (build) + electron-builder (empacotamento)
Frontend React 18 + TypeScript + Vite
Animação do overlay Strands (React Bits, WebGL via ogl)
Moldura das janelas (Customizar/Histórico) Electric Border (React Bits, Canvas 2D)
Injeção de texto no SO @nut-tree-fork/nut-js (Windows/macOS, clipboard + paste simulado, Enter opcional); xdotool via subprocess (Linux/X11)
Sidecar local Python 3.13 + FastAPI + Uvicorn (WebSocket + REST)
Wake word openWakeWord — modelo pré-treinado hey_jarvis (ONNX runtime), reaproveitado também como comando de saída da conversa fluida
Transcrição (STT) faster-whisper — modelo small, CPU, int8
VAD (detecção de fim de fala) webrtcvad (via webrtcvad-wheels), com gate de energia (RMS) pra não confundir ruído de fundo com fala
Captura de áudio Web Audio API (getUserMedia + AudioWorklet) direto no renderer, downsample para PCM16 16kHz mono
Claude Code (v2) @anthropic-ai/claude-code — CLI instalado separadamente via npm, chamado em modo headless (claude -p), prompt enviado via stdin
TTS (v2) Piper (piper-tts) — voz pt_BR-faber-medium, síntese local, playback via winsound (Windows)
Armazenamento de credenciais (v2) safeStorage do Electron (Credential Vault/Keychain do SO) — token nunca em texto plano
LLM local alternativo (v2) Qualquer servidor compatível com a API da OpenAI (Ollama, LM Studio, text-generation-webui, ...)

Arquitetura

┌────────────────────────────────────────────────┐
│  Electron — processo principal (Node.js)        │
│  - Tray, overlay, Customizar, Histórico          │
│  - Injeção de texto no SO (clipboard + paste)    │
│  - safeStorage (token), projetos/sessões/config  │
│  - Sobe/gerencia o sidecar Python (subprocess)    │
└───────────────────┬──────────────────────────────┘
                     │ IPC (contextBridge)
┌───────────────────▼──────────────────────────────┐
│  Renderer (React) — janela overlay                │
│  - Captura de áudio (getUserMedia+AudioWorklet)   │
│  - Conecta direto no sidecar via WebSocket         │
│  - Renderiza Strands (cor muda por modo ativo)     │
│  - Chama /claude-code/query e /tts (modo v2)       │
└───────────────────┬──────────────────────────────┘
                     │ WebSocket (áudio PCM16 16kHz + eventos JSON + controle)
                     │ REST (/claude-code/query, /tts)
┌───────────────────▼──────────────────────────────┐
│  Sidecar Python (FastAPI, subprocess local)        │
│  - openWakeWord + webrtcvad + faster-whisper       │
│    (wake word, fim de fala, transcrição — v1)      │
│  - /claude-code/query → subprocess `claude -p`     │
│    (prompt via stdin, --resume por sessão — v2)    │
│  - /tts → Piper (síntese + playback local — v2)    │
└────────────────────────────────────────────────────┘

A captura de áudio roda direto no processo de renderer (Chromium) via getUserMedia/AudioWorklet, conectando via WebSocket diretamente no sidecar — o processo principal do Electron não fica no caminho crítico do áudio, só cuida de tray, janelas, credenciais e da injeção de texto no SO.

Fluxo do modo Claude Code (v2): wake word → grava até detectar silêncio (VAD) → transcreve → renderer chama POST /claude-code/query (sidecar roda claude -p com o texto via stdin, --resume se houver sessão salva pro projeto ativo) → resposta é injetada no campo focado e, se ativado, enviada a POST /tts pra ser falada. Depois de a fala terminar de tocar (nunca antes, pra não se auto-ouvir), o sidecar volta a escutar sem exigir o wake word — só encerra a conversa fluida se o wake word for dito de novo ou após um timeout de inatividade.

Pré-requisitos

  • Node.js 20+ e npm
  • Python 3.11+ (testado com 3.13)
  • Windows ou macOS para o MVP (Linux é stretch goal — veja limitações abaixo)
  • Claude Code CLI instalado e no PATH (npm install -g @anthropic-ai/claude-code), com ANTHROPIC_API_KEY cadastrado pelo app — só necessário se for usar o modo "Claude Code" (o modo Ditado funciona sem isso)

Como rodar (desenvolvimento)

# 1. Dependências do Electron/React
npm install

# 2. Ambiente virtual do sidecar Python
cd sidecar
python -m venv .venv
.venv\Scripts\activate        # Windows
# source .venv/bin/activate   # macOS/Linux
pip install -r requirements.txt
cd ..

# 3. Rodar tudo (Electron sobe o sidecar automaticamente)
npm run dev

Na primeira execução, o sidecar baixa os modelos do openWakeWord e do faster-whisper (precisa de internet nesse primeiro run; depois funciona 100% offline).

Build de produção

npm run build:win    # ou build:mac / build:linux

Limitações conhecidas / riscos documentados

  • Electron pinado em 33.x: a versão 43.2.0 apresentou um crash de inicialização (falha ao carregar o snapshot do V8) neste ambiente de desenvolvimento. Se for atualizar o Electron, valide antes que electron.exe sobe sem crashar.
  • Linux/Wayland: a injeção de texto via xdotool não funciona em Wayland (só X11). Suporte a Linux é stretch goal.
  • Wake word único: por enquanto só "Hey Jarvis" (modelo pronto do openWakeWord). Treinar frases customizadas em português exige um passo de treino adicional — veja o roadmap no .md de especificação.
  • Um único idioma de transcrição por vez: o modelo Whisper detecta o idioma automaticamente por padrão; pode ser fixado via variável de ambiente do sidecar.

Estrutura de pastas

jarvis-two/
├── src/
│   ├── main/            # processo principal do Electron
│   │   ├── claude-cli.ts           # integração com o Claude Code CLI
│   │   ├── claude-token-store.ts   # token criptografado (safeStorage)
│   │   ├── projects-store.ts       # projetos registrados + sessão ativa
│   │   ├── chat-history-store.ts   # histórico de pergunta/resposta
│   │   ├── llm-settings-store.ts   # configurações de LLM/TTS
│   │   ├── local-llm-client.ts     # cliente p/ servidor LLM local (Ollama etc.)
│   │   └── history-window.ts       # janela do painel de histórico
│   ├── preload/          # bridge contextBridge/ipcRenderer
│   ├── renderer/         # app React (overlay, Customizar, Histórico)
│   └── shared/           # tipos compartilhados entre main e renderer
├── sidecar/               # app FastAPI (wakeword, VAD, transcrição)
│   ├── claude_code/       # subprocess `claude -p` (modo headless)
│   └── tts/                # síntese e reprodução de voz (Piper)
├── electron.vite.config.ts
├── electron-builder.yml
├── prompt-jarvis-voice-assistant.md          # spec v1 + histórico de decisões
└── planejamento-v2-integracao-claude-code.md # planejamento v2 (Claude Code + TTS)

Roadmap

Veja a seção "Próximos Passos" em prompt-jarvis-voice-assistant.md.

Licença

MIT.

About

Assistente de voz local com detecção de wake word e transcrição de fala que digita o texto direto no campo focado — sem nuvem, sem atalho de teclado.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages