voice-copilot 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- voice_copilot-0.0.1/.dockerignore +20 -0
- voice_copilot-0.0.1/.env.example +19 -0
- voice_copilot-0.0.1/.github/ISSUE_TEMPLATE/bug_report.yml +56 -0
- voice_copilot-0.0.1/.github/ISSUE_TEMPLATE/config.yml +5 -0
- voice_copilot-0.0.1/.github/ISSUE_TEMPLATE/feature_request.yml +41 -0
- voice_copilot-0.0.1/.github/pull_request_template.md +14 -0
- voice_copilot-0.0.1/.github/workflows/ci.yml +50 -0
- voice_copilot-0.0.1/.gitignore +27 -0
- voice_copilot-0.0.1/CLAUDE.md +122 -0
- voice_copilot-0.0.1/CODE_OF_CONDUCT.md +30 -0
- voice_copilot-0.0.1/CONTRIBUTING.md +55 -0
- voice_copilot-0.0.1/Dockerfile +52 -0
- voice_copilot-0.0.1/LICENSE +21 -0
- voice_copilot-0.0.1/LICENSING.md +20 -0
- voice_copilot-0.0.1/PKG-INFO +325 -0
- voice_copilot-0.0.1/README.md +250 -0
- voice_copilot-0.0.1/SECURITY.md +25 -0
- voice_copilot-0.0.1/docs/architecture.md +104 -0
- voice_copilot-0.0.1/docs/cli-companion-interface.md +463 -0
- voice_copilot-0.0.1/docs/launch/README.md +21 -0
- voice_copilot-0.0.1/docs/launch/hacker-news.md +44 -0
- voice_copilot-0.0.1/docs/launch/reddit-post.md +38 -0
- voice_copilot-0.0.1/docs/launch/video-pitch.md +55 -0
- voice_copilot-0.0.1/docs/launch/x-posts.md +49 -0
- voice_copilot-0.0.1/docs/providers.md +81 -0
- voice_copilot-0.0.1/docs/schemas/cli-companion-interface.schema.json +514 -0
- voice_copilot-0.0.1/pyproject.toml +106 -0
- voice_copilot-0.0.1/scripts/test_narration_prompt.py +252 -0
- voice_copilot-0.0.1/scripts/voice-copilot.ps1 +26 -0
- voice_copilot-0.0.1/scripts/voice-copilot.sh +23 -0
- voice_copilot-0.0.1/src/voice_copilot/__init__.py +3 -0
- voice_copilot-0.0.1/src/voice_copilot/__main__.py +4 -0
- voice_copilot-0.0.1/src/voice_copilot/adapters/__init__.py +5 -0
- voice_copilot-0.0.1/src/voice_copilot/adapters/base.py +91 -0
- voice_copilot-0.0.1/src/voice_copilot/adapters/claude_code.py +232 -0
- voice_copilot-0.0.1/src/voice_copilot/adapters/codex.py +288 -0
- voice_copilot-0.0.1/src/voice_copilot/audio/__init__.py +5 -0
- voice_copilot-0.0.1/src/voice_copilot/audio/hub.py +63 -0
- voice_copilot-0.0.1/src/voice_copilot/audio/mic.py +98 -0
- voice_copilot-0.0.1/src/voice_copilot/audio/tts_driver.py +295 -0
- voice_copilot-0.0.1/src/voice_copilot/cli.py +423 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/__init__.py +3 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/format.py +212 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/importance.py +90 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/pipeline.py +548 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/__init__.py +55 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/en.cli.md +25 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/en.cli.summary.md +14 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/en.md +23 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/en.summary.md +14 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/es.md +24 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/fr.md +24 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/ru.cli.md +17 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/ru.cli.summary.md +17 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/ru.md +23 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/ru.summary.md +23 -0
- voice_copilot-0.0.1/src/voice_copilot/commentator/prompts/uk.md +23 -0
- voice_copilot-0.0.1/src/voice_copilot/core/__init__.py +4 -0
- voice_copilot-0.0.1/src/voice_copilot/core/bus.py +41 -0
- voice_copilot-0.0.1/src/voice_copilot/core/config.py +176 -0
- voice_copilot-0.0.1/src/voice_copilot/core/events.py +61 -0
- voice_copilot-0.0.1/src/voice_copilot/core/secrets.py +80 -0
- voice_copilot-0.0.1/src/voice_copilot/dialog/__init__.py +3 -0
- voice_copilot-0.0.1/src/voice_copilot/dialog/manager.py +148 -0
- voice_copilot-0.0.1/src/voice_copilot/hotkeys.py +194 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/__init__.py +5 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/__init__.py +11 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/anthropic.py +53 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/base.py +37 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/copilot_cli.py +145 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/github_copilot.py +134 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/openai.py +76 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/llm/openai_compat.py +27 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/registry.py +43 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/stt/__init__.py +6 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/stt/base.py +55 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/stt/deepgram.py +12 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/stt/faster_whisper.py +75 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/stt/whisper_api.py +49 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/__init__.py +8 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/base.py +53 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/edge.py +47 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/elevenlabs.py +58 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/openai.py +50 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/piper.py +12 -0
- voice_copilot-0.0.1/src/voice_copilot/providers/tts/silero.py +16 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/__init__.py +3 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/anthropic.py +152 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/body_sniffer.py +96 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/cli_catalog.py +43 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/cli_catalog.yaml +47 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/cli_shims.py +615 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/ollama_native.py +126 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/openai.py +169 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/server.py +248 -0
- voice_copilot-0.0.1/src/voice_copilot/proxy/session.py +202 -0
- voice_copilot-0.0.1/src/voice_copilot/tray.py +66 -0
- voice_copilot-0.0.1/src/voice_copilot/web/__init__.py +3 -0
- voice_copilot-0.0.1/src/voice_copilot/web/demo.py +34 -0
- voice_copilot-0.0.1/src/voice_copilot/web/server.py +384 -0
- voice_copilot-0.0.1/src/voice_copilot/web/static/app.js +1585 -0
- voice_copilot-0.0.1/src/voice_copilot/web/static/index.html +374 -0
- voice_copilot-0.0.1/src/voice_copilot/web/static/style.css +783 -0
- voice_copilot-0.0.1/src/voice_copilot/web/ws.py +193 -0
- voice_copilot-0.0.1/start.bat +37 -0
- voice_copilot-0.0.1/tests/__init__.py +0 -0
- voice_copilot-0.0.1/tests/unit/__init__.py +0 -0
- voice_copilot-0.0.1/tests/unit/test_bus.py +51 -0
- voice_copilot-0.0.1/tests/unit/test_config.py +56 -0
- voice_copilot-0.0.1/tests/unit/test_secrets.py +40 -0
- voice_copilot-0.0.1/uv.lock +3996 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Copy to .env and fill in the keys you plan to use.
|
|
2
|
+
# Alternatively, store them in the OS keyring through the settings page.
|
|
3
|
+
|
|
4
|
+
# --- Commentator LLM ---
|
|
5
|
+
ANTHROPIC_API_KEY=
|
|
6
|
+
OPENAI_API_KEY=
|
|
7
|
+
# For OpenAI-compatible local servers (Ollama, LM Studio)
|
|
8
|
+
OPENAI_COMPAT_BASE_URL=http://127.0.0.1:11434/v1
|
|
9
|
+
OPENAI_COMPAT_API_KEY=ollama
|
|
10
|
+
|
|
11
|
+
# --- Cloud STT ---
|
|
12
|
+
DEEPGRAM_API_KEY=
|
|
13
|
+
|
|
14
|
+
# --- Cloud TTS ---
|
|
15
|
+
ELEVENLABS_API_KEY=
|
|
16
|
+
|
|
17
|
+
# --- Server ---
|
|
18
|
+
VOICE_COPILOT_HOST=127.0.0.1
|
|
19
|
+
VOICE_COPILOT_PORT=8765
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report something that is not working as expected
|
|
3
|
+
title: "bug: "
|
|
4
|
+
labels: [bug]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for taking the time to report a bug. Please remove any API keys, tokens, and private file paths before submitting.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: summary
|
|
12
|
+
attributes:
|
|
13
|
+
label: Summary
|
|
14
|
+
description: What happened?
|
|
15
|
+
placeholder: Voice Copilot...
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: steps
|
|
20
|
+
attributes:
|
|
21
|
+
label: Reproduction steps
|
|
22
|
+
description: How can we reproduce the issue?
|
|
23
|
+
placeholder: |
|
|
24
|
+
1. Run `voice-copilot ...`
|
|
25
|
+
2. Open ...
|
|
26
|
+
3. See ...
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: textarea
|
|
30
|
+
id: expected
|
|
31
|
+
attributes:
|
|
32
|
+
label: Expected behavior
|
|
33
|
+
description: What did you expect to happen?
|
|
34
|
+
validations:
|
|
35
|
+
required: true
|
|
36
|
+
- type: textarea
|
|
37
|
+
id: environment
|
|
38
|
+
attributes:
|
|
39
|
+
label: Environment
|
|
40
|
+
description: Versions and platform details
|
|
41
|
+
value: |
|
|
42
|
+
- OS:
|
|
43
|
+
- Python:
|
|
44
|
+
- Voice Copilot version or commit:
|
|
45
|
+
- Target CLI and version:
|
|
46
|
+
- TTS provider:
|
|
47
|
+
- STT provider:
|
|
48
|
+
- Commentator provider:
|
|
49
|
+
validations:
|
|
50
|
+
required: true
|
|
51
|
+
- type: textarea
|
|
52
|
+
id: logs
|
|
53
|
+
attributes:
|
|
54
|
+
label: Logs or screenshots
|
|
55
|
+
description: Paste relevant logs. Redact secrets and tokens.
|
|
56
|
+
render: text
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or improvement
|
|
3
|
+
title: "feature: "
|
|
4
|
+
labels: [enhancement]
|
|
5
|
+
body:
|
|
6
|
+
- type: textarea
|
|
7
|
+
id: problem
|
|
8
|
+
attributes:
|
|
9
|
+
label: Problem
|
|
10
|
+
description: What workflow or pain point should this solve?
|
|
11
|
+
placeholder: When using Voice Copilot with...
|
|
12
|
+
validations:
|
|
13
|
+
required: true
|
|
14
|
+
- type: textarea
|
|
15
|
+
id: proposal
|
|
16
|
+
attributes:
|
|
17
|
+
label: Proposed solution
|
|
18
|
+
description: What would you like Voice Copilot to do?
|
|
19
|
+
validations:
|
|
20
|
+
required: true
|
|
21
|
+
- type: dropdown
|
|
22
|
+
id: area
|
|
23
|
+
attributes:
|
|
24
|
+
label: Area
|
|
25
|
+
options:
|
|
26
|
+
- CLI adapter
|
|
27
|
+
- Proxy
|
|
28
|
+
- Commentator / narration
|
|
29
|
+
- TTS provider
|
|
30
|
+
- STT provider
|
|
31
|
+
- Web UI
|
|
32
|
+
- Hotkeys / tray
|
|
33
|
+
- Documentation
|
|
34
|
+
- Other
|
|
35
|
+
validations:
|
|
36
|
+
required: true
|
|
37
|
+
- type: textarea
|
|
38
|
+
id: alternatives
|
|
39
|
+
attributes:
|
|
40
|
+
label: Alternatives considered
|
|
41
|
+
description: Are there other ways to solve this?
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
Describe what changed and why.
|
|
4
|
+
|
|
5
|
+
## Testing
|
|
6
|
+
|
|
7
|
+
- [ ] `uv run ruff format --check .`
|
|
8
|
+
- [ ] `uv run ruff check .`
|
|
9
|
+
- [ ] `uv run mypy src/voice_copilot`
|
|
10
|
+
- [ ] `uv run pytest`
|
|
11
|
+
|
|
12
|
+
## Notes
|
|
13
|
+
|
|
14
|
+
Mention any follow-up work, compatibility concerns, or provider-specific behavior.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
test:
|
|
15
|
+
name: ${{ matrix.os }} / Python ${{ matrix.python-version }}
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
21
|
+
python-version: ["3.11", "3.12"]
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- name: Check out repository
|
|
25
|
+
uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@v5
|
|
29
|
+
with:
|
|
30
|
+
enable-cache: true
|
|
31
|
+
|
|
32
|
+
- name: Set up Python
|
|
33
|
+
uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: ${{ matrix.python-version }}
|
|
36
|
+
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: uv sync --extra dev
|
|
39
|
+
|
|
40
|
+
- name: Check formatting
|
|
41
|
+
run: uv run ruff format --check .
|
|
42
|
+
|
|
43
|
+
- name: Lint
|
|
44
|
+
run: uv run ruff check .
|
|
45
|
+
|
|
46
|
+
- name: Type check
|
|
47
|
+
run: uv run mypy src/voice_copilot
|
|
48
|
+
|
|
49
|
+
- name: Test
|
|
50
|
+
run: uv run pytest
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
.venv/
|
|
5
|
+
.env
|
|
6
|
+
.env.local
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
.mypy_cache/
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
htmlcov/
|
|
14
|
+
*.log
|
|
15
|
+
|
|
16
|
+
# voice-copilot runtime
|
|
17
|
+
~/.voice-copilot/
|
|
18
|
+
logs/
|
|
19
|
+
recordings/
|
|
20
|
+
|
|
21
|
+
# editor
|
|
22
|
+
.vscode/
|
|
23
|
+
.idea/
|
|
24
|
+
|
|
25
|
+
# claude code
|
|
26
|
+
.claude/
|
|
27
|
+
.aider*
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Project: **voice-copilot** — open-source voice pair-programmer for LLM CLIs (Claude Code, Codex CLI, Gemini CLI, Aider, …).
|
|
4
|
+
|
|
5
|
+
## Product idea
|
|
6
|
+
|
|
7
|
+
The tool sits next to an LLM coding agent and narrates what the agent is doing — decisions taken, files changed, reasoning summarised — as a calm human-voice stream. The user can press a push-to-talk hotkey, ask a question or give a correction, and that message gets injected back into the running agent.
|
|
8
|
+
|
|
9
|
+
Think: a programmer on a screen-share, talking through what they're doing while their partner can interrupt at any time.
|
|
10
|
+
|
|
11
|
+
## High-level architecture
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌──────────────────────────────────────────────────────────┐
|
|
15
|
+
│ Browser (popup + settings) ← localhost:PORT │
|
|
16
|
+
│ getUserMedia → WebSocket (mic in) │
|
|
17
|
+
│ <audio> ← WebSocket (TTS out) │
|
|
18
|
+
└──────────────────────────────────────────────────────────┘
|
|
19
|
+
▲ ▲
|
|
20
|
+
│ │ WebSocket (events, audio frames)
|
|
21
|
+
▼ ▼
|
|
22
|
+
┌──────────────────────────────────────────────────────────┐
|
|
23
|
+
│ Python server (FastAPI + uvicorn + asyncio) │
|
|
24
|
+
│ │
|
|
25
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
26
|
+
│ │ CLI adapter │──▶│ Event bus │◀──│ HTTP proxy │ │
|
|
27
|
+
│ │ (stream-json │ │ (asyncio) │ │ (mitmproxy) │ │
|
|
28
|
+
│ │ subprocess) │ └──────┬───────┘ └──────────────┘ │
|
|
29
|
+
│ └──────┬───────┘ │ │
|
|
30
|
+
│ │ ▼ │
|
|
31
|
+
│ stdin │ ┌───────────────┐ │
|
|
32
|
+
│ inject │ │ Commentator │ Haiku/gpt-4o-mini/ │
|
|
33
|
+
│ │ │ (debounce, │ local ollama │
|
|
34
|
+
│ │ │ classify, │ │
|
|
35
|
+
│ │ │ summarize) │ │
|
|
36
|
+
│ │ └──────┬────────┘ │
|
|
37
|
+
│ │ ▼ │
|
|
38
|
+
│ │ ┌───────────────┐ │
|
|
39
|
+
│ │ │ TTS provider │ edge-tts / Silero / │
|
|
40
|
+
│ │ │ │ ElevenLabs / OpenAI │
|
|
41
|
+
│ │ └───────────────┘ │
|
|
42
|
+
│ ▲ │
|
|
43
|
+
│ ┌──────┴───────┐ ┌───────────────┐ ┌───────────────┐ │
|
|
44
|
+
│ │ Dialog mgr │◀─│ STT provider │◀─│ Hotkey / Tray │ │
|
|
45
|
+
│ │ (queue, │ │ (whisper-api/ │ │ (pynput/ │ │
|
|
46
|
+
│ │ /btw, inj.) │ │ f-whisper/ │ │ pystray) │ │
|
|
47
|
+
│ │ │ │ deepgram) │ │ │ │
|
|
48
|
+
│ └──────────────┘ └───────────────┘ └───────────────┘ │
|
|
49
|
+
└──────────────────────────────────────────────────────────┘
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Three interception strategies (A first-class, B first-class, C fallback)
|
|
53
|
+
|
|
54
|
+
- **A. Stream-JSON mode of the target CLI** — e.g. `claude -p --output-format stream-json`, `codex exec --json`. Structured events, reliable, but CLI runs headless (no TUI).
|
|
55
|
+
- **B. HTTP proxy** — mitmproxy sets on `ANTHROPIC_BASE_URL` / `OPENAI_BASE_URL`. Captures the raw SSE including `thinking` blocks. Works alongside interactive TUI.
|
|
56
|
+
- **C. PTY wrapper fallback** — wraps any binary, parses rendered stdout. Low-quality narration but guarantees coverage.
|
|
57
|
+
|
|
58
|
+
### Injecting voice into a running agent — per-adapter capability
|
|
59
|
+
|
|
60
|
+
Adapters declare a `QuickAsideCapability`:
|
|
61
|
+
|
|
62
|
+
1. **native** — CLI supports a built-in "side question" channel (e.g. Claude Code `/btw <q>`). Inject immediately.
|
|
63
|
+
2. **queue** — no native channel; we write the message to subprocess stdin at the next turn boundary (or on hard-interrupt).
|
|
64
|
+
3. **manual** — fully external CLI; we copy the question to the clipboard and show it in the popup so the user pastes it.
|
|
65
|
+
|
|
66
|
+
### Providers are pluggable
|
|
67
|
+
|
|
68
|
+
All of **TTS**, **STT**, **commentator LLM** implement a small interface and are selected via config. Defaults are cloud-light; local backends are optional extras.
|
|
69
|
+
|
|
70
|
+
| | Default (light) | Local (extra `[local]`) | Premium cloud |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| TTS | `edge-tts` | `silero`, `piper` | `elevenlabs`, `openai-tts` |
|
|
73
|
+
| STT | `openai-whisper-api` | `faster-whisper` | `deepgram` |
|
|
74
|
+
| LLM | `anthropic` (Haiku 4.5) | `openai-compat` (Ollama / LM Studio) | `openai` |
|
|
75
|
+
|
|
76
|
+
## Directory layout
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
src/voice_copilot/
|
|
80
|
+
core/ event bus, event types, config
|
|
81
|
+
adapters/ CLI adapters (claude_code, codex, proxy, pty_fallback)
|
|
82
|
+
llm/ commentator LLM providers
|
|
83
|
+
tts/ TTS providers
|
|
84
|
+
stt/ STT providers
|
|
85
|
+
commentator/ debounce + prompt assembly + i18n
|
|
86
|
+
dialog/ queue + quick-aside + interrupt flow
|
|
87
|
+
web/ FastAPI app + static popup/settings UI
|
|
88
|
+
hotkeys.py global hotkey listener (pynput)
|
|
89
|
+
tray.py system tray icon (pystray)
|
|
90
|
+
cli.py `voice-copilot run <target-cli> -- ...`
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Run model
|
|
94
|
+
|
|
95
|
+
`voice-copilot run claude -p "implement feature X"` does:
|
|
96
|
+
|
|
97
|
+
1. Start FastAPI on `127.0.0.1:<port>`, open browser to popup URL.
|
|
98
|
+
2. Spawn the tray icon and register global hotkey.
|
|
99
|
+
3. Optionally start mitmproxy and set `ANTHROPIC_BASE_URL` for the child.
|
|
100
|
+
4. Spawn the child CLI with appropriate JSON-stream flags.
|
|
101
|
+
5. Pipe events into the bus → commentator → TTS.
|
|
102
|
+
6. When user presses push-to-talk → record → STT → dialog manager decides: quick-aside / queue / manual.
|
|
103
|
+
|
|
104
|
+
## Conventions
|
|
105
|
+
|
|
106
|
+
- Python 3.11+. Formatter: **ruff format**. Linter: **ruff**. Type checker: **mypy** (strict on new code).
|
|
107
|
+
- Package manager: **uv** (`uv sync`, `uv run voice-copilot ...`). pipx also supported.
|
|
108
|
+
- Config lives at `~/.voice-copilot/config.yaml`; secrets in OS keyring or `.env`.
|
|
109
|
+
- Prompt files are markdown in `src/voice_copilot/commentator/prompts/<lang>.md` — treat them as product surface.
|
|
110
|
+
- No hidden retries, no silent fallbacks between providers: if configured provider fails, surface the error to the popup and stop narrating. Fail loud.
|
|
111
|
+
|
|
112
|
+
## Non-goals (at least for v1)
|
|
113
|
+
|
|
114
|
+
- We do **not** try to be a TUI replacement. The browser popup is the UI for voice-copilot itself; the underlying CLI's TUI (if any) stays as-is.
|
|
115
|
+
- We do **not** re-implement CLIs. If Claude Code doesn't expose some event, we accept that and narrate what we have.
|
|
116
|
+
- We do **not** train models.
|
|
117
|
+
|
|
118
|
+
## Memory for future Claude sessions
|
|
119
|
+
|
|
120
|
+
Persistent notes about this user and project live in
|
|
121
|
+
`C:\Users\vladi\.claude\projects\f---VOICE-COPILOT\memory\` (indexed by `MEMORY.md`).
|
|
122
|
+
Use them — don't re-derive the project's purpose from scratch each session.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
Voice Copilot follows the Contributor Covenant Code of Conduct.
|
|
4
|
+
|
|
5
|
+
## Our Pledge
|
|
6
|
+
|
|
7
|
+
We pledge to make participation in this project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
8
|
+
|
|
9
|
+
## Our Standards
|
|
10
|
+
|
|
11
|
+
Examples of behavior that contributes to a positive environment include:
|
|
12
|
+
|
|
13
|
+
- using welcoming and inclusive language
|
|
14
|
+
- being respectful of differing viewpoints and experiences
|
|
15
|
+
- giving and gracefully accepting constructive feedback
|
|
16
|
+
- focusing on what is best for the community
|
|
17
|
+
- showing empathy toward other community members
|
|
18
|
+
|
|
19
|
+
Examples of unacceptable behavior include:
|
|
20
|
+
|
|
21
|
+
- harassment, insults, or personal attacks
|
|
22
|
+
- public or private harassment
|
|
23
|
+
- publishing others' private information without explicit permission
|
|
24
|
+
- other conduct which could reasonably be considered inappropriate in a professional setting
|
|
25
|
+
|
|
26
|
+
## Enforcement
|
|
27
|
+
|
|
28
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to info@conus.vision. Project maintainers are responsible for clarifying and enforcing standards of acceptable behavior and may remove, edit, or reject comments, commits, code, issues, and other contributions that are not aligned with this Code of Conduct.
|
|
29
|
+
|
|
30
|
+
This Code of Conduct is adapted from the Contributor Covenant, version 2.1.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Contributing to Voice Copilot
|
|
2
|
+
|
|
3
|
+
Thanks for helping make Voice Copilot better. The project is early, so small focused pull requests are especially valuable: bug fixes, provider improvements, tests, docs, and reports from real CLI workflows.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
Voice Copilot uses Python 3.11+ and `uv`.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/voice-copilot/voice-copilot.git
|
|
11
|
+
cd voice-copilot
|
|
12
|
+
uv sync --extra dev
|
|
13
|
+
uv run voice-copilot serve --demo
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Useful checks before opening a pull request:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uv run ruff format .
|
|
20
|
+
uv run ruff check .
|
|
21
|
+
uv run mypy src/voice_copilot
|
|
22
|
+
uv run pytest
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Pull Requests
|
|
26
|
+
|
|
27
|
+
- Keep changes focused on one problem or feature.
|
|
28
|
+
- Add or update tests for behavioral changes.
|
|
29
|
+
- Update README or docs when user-facing behavior changes.
|
|
30
|
+
- Do not include API keys, tokens, local config files, or generated cache directories.
|
|
31
|
+
- Prefer explicit errors over silent fallbacks. If a provider fails, surface the failure.
|
|
32
|
+
|
|
33
|
+
## Tests
|
|
34
|
+
|
|
35
|
+
Unit tests live under `tests/unit/`. Tests should avoid real network calls and external API providers unless they are explicitly marked as integration tests.
|
|
36
|
+
|
|
37
|
+
## Code Style
|
|
38
|
+
|
|
39
|
+
- Format with `ruff format`.
|
|
40
|
+
- Lint with `ruff check`.
|
|
41
|
+
- Keep new code compatible with strict `mypy`.
|
|
42
|
+
- Use typed interfaces for providers and adapters.
|
|
43
|
+
- Keep secrets in the OS keyring or environment variables, never in config files.
|
|
44
|
+
|
|
45
|
+
## Reporting Issues
|
|
46
|
+
|
|
47
|
+
Please include:
|
|
48
|
+
|
|
49
|
+
- Operating system and Python version
|
|
50
|
+
- Voice Copilot version or commit SHA
|
|
51
|
+
- Target CLI and version, if relevant
|
|
52
|
+
- Provider configuration, without secret values
|
|
53
|
+
- Reproduction steps and expected behavior
|
|
54
|
+
|
|
55
|
+
Security issues should be reported privately. See `SECURITY.md`.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Dockerfile for voice-copilot.
|
|
2
|
+
#
|
|
3
|
+
# CAVEATS — read before running:
|
|
4
|
+
# 1. Microphone: the browser only grants `getUserMedia` on trusted origins.
|
|
5
|
+
# That means `localhost`. Running the server in a container and opening
|
|
6
|
+
# the popup from the host works ONLY if you use `--network host` (Linux)
|
|
7
|
+
# or terminate HTTPS in front of the container. On Docker Desktop for
|
|
8
|
+
# Mac/Windows, the host sees the server as `localhost:8765` via port
|
|
9
|
+
# forwarding — modern Chromium treats that as a secure context, so mic
|
|
10
|
+
# access usually works. Firefox is stricter.
|
|
11
|
+
# 2. Target CLIs: `claude`, `codex`, etc. are NOT installed in this image.
|
|
12
|
+
# You'd typically mount your workspace and install them inside, or run
|
|
13
|
+
# only `voice-copilot serve` and talk to a CLI running on the host.
|
|
14
|
+
# 3. Global hotkeys: `pynput` needs an X server / input device on Linux. In
|
|
15
|
+
# a headless container they silently no-op. Use the in-popup buttons.
|
|
16
|
+
# 4. Tray icon: `pystray` is skipped when `--tray=false` is passed.
|
|
17
|
+
#
|
|
18
|
+
# In short: the container is most useful for `voice-copilot serve --demo` and
|
|
19
|
+
# for the `proxy` mode; for full voice-paired coding, install on the host.
|
|
20
|
+
|
|
21
|
+
FROM python:3.12-slim AS base
|
|
22
|
+
|
|
23
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
24
|
+
PYTHONUNBUFFERED=1 \
|
|
25
|
+
PIP_NO_CACHE_DIR=1 \
|
|
26
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1
|
|
27
|
+
|
|
28
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
29
|
+
build-essential \
|
|
30
|
+
curl \
|
|
31
|
+
ca-certificates \
|
|
32
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
33
|
+
|
|
34
|
+
WORKDIR /app
|
|
35
|
+
COPY pyproject.toml README.md LICENSE ./
|
|
36
|
+
COPY voice_copilot ./voice_copilot
|
|
37
|
+
|
|
38
|
+
RUN pip install --upgrade pip && pip install .
|
|
39
|
+
|
|
40
|
+
# Keyring needs a backend in the container. Fall back to a plaintext file
|
|
41
|
+
# backend — keys still don't leave the container image because nothing is
|
|
42
|
+
# baked in; operators mount /root/.local/share/python_keyring at runtime.
|
|
43
|
+
RUN pip install keyrings.alt
|
|
44
|
+
|
|
45
|
+
EXPOSE 8765 8766
|
|
46
|
+
|
|
47
|
+
ENV VOICE_COPILOT_HOST=0.0.0.0 \
|
|
48
|
+
VOICE_COPILOT_PORT=8765
|
|
49
|
+
|
|
50
|
+
# Default entrypoint — demo mode, no hotkeys, no tray.
|
|
51
|
+
ENTRYPOINT ["voice-copilot"]
|
|
52
|
+
CMD ["serve", "--host", "0.0.0.0", "--no-open", "--no-hotkeys", "--no-tray", "--demo"]
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Volodymyr Moskvin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Licensing Notes
|
|
2
|
+
|
|
3
|
+
Voice Copilot core is open-source under the MIT license.
|
|
4
|
+
|
|
5
|
+
## What this means
|
|
6
|
+
|
|
7
|
+
- You can use, modify, fork, redistribute, and commercialize this repository
|
|
8
|
+
- You can build your own workflows, integrations, and products on top of it
|
|
9
|
+
- Contributions and third-party adoption are intentionally low-friction
|
|
10
|
+
|
|
11
|
+
## Branding
|
|
12
|
+
|
|
13
|
+
The MIT license applies to the code in this repository. It does not grant
|
|
14
|
+
trademark rights to the Voice Copilot or Conus Vision names, logos, or brand
|
|
15
|
+
identity except for fair descriptive reference.
|
|
16
|
+
|
|
17
|
+
## Contact
|
|
18
|
+
|
|
19
|
+
- Email: info@conus.vision
|
|
20
|
+
- Website: https://conus.vision
|