1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170 | # Setup โ jarvis-voice
This is a single Python script (`neo-voice-assistant.py`) that listens for a
wake word on your Mac's microphone, sends what you say to a Telegram bot, waits
for that bot's agent to reply, and speaks the reply out loud.
Read this top to bottom before you run anything โ the script deliberately
refuses to start if any of four required values are missing, so there is
nothing to half-configure.
## What you need
| Requirement | Why | Have it already? |
|---|---|---|
| macOS | The script shells out to `afplay` and `say`, both macOS-only binaries. It will not run on Windows or Linux as-is. | Check: you're on a Mac. |
| Python 3 (any recent version) | Runs the script. No version-specific syntax is used. | Check: `python3 --version` |
| Homebrew | Used to install `portaudio`, a system library `PyAudio` needs to compile. | Check: `brew --version` |
| A working microphone | `speech_recognition` records from it to detect the wake word and your speech. | Built into every Mac; external mic works too. |
| Internet connection | Speech-to-text calls Google's free Web Speech API; replies go through Telegram's API; voice synthesis calls ElevenLabs' API. | โ |
| ElevenLabs account + API key | The script calls ElevenLabs for cloned/branded text-to-speech. **The script exits immediately at startup if this key is missing** โ it is not truly optional in the current code, even though `say` can produce speech if the ElevenLabs *call* itself fails at runtime. | Sign up free at elevenlabs.io, grab an API key. |
| An ElevenLabs voice ID | Which voice ElevenLabs speaks in. Use your own cloned voice or any library voice. | From your ElevenLabs dashboard. |
| A Telegram bot (via @BotFather) + its chat ID | This script does not contain any AI itself โ it POSTs what you say to a Telegram chat and polls for a reply. You need a bot token, and a separate agent (yours โ a Claude Code agent, an n8n flow, anything) that actually reads that chat and replies. | Create via https://t.me/BotFather; get the chat ID from the chat you'll use. |
| **NOT needed:** Docker | Nothing in this repo runs in a container. | โ |
| **NOT needed:** GPU | All processing here is either a network call (ElevenLabs, Telegram, Google STT) or macOS's own `say`. | โ |
| **NOT needed:** any local AI model | The "brain" is external โ whatever agent answers your Telegram bot. This repo has no model code. | โ |
Note: the README's "Make it your own" section describes an optional local-TTS
upgrade path (Chatterbox via mlx-audio, Apple Silicon only) as something you
could wire in yourself. **The code as shipped does not call Chatterbox or
mlx-audio at all** โ today it's a two-tier voice path (ElevenLabs, falling
back to `say` only if the ElevenLabs *request* fails), and ElevenLabs is a
hard requirement to start the script at all. If you want the "runs on any Mac
with zero paid keys" version, you'd need to make `ELEVENLABS_API_KEY` truly
optional in the code and default straight to `say` โ see Troubleshooting.
## Install, step by step
1. **Install Homebrew** (skip if `brew --version` already prints something):
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
What it does: installs the Homebrew package manager, used below for `portaudio`.
Check it worked: `brew --version` โ prints `Homebrew x.y.z`.
2. **Install Python 3** (skip if `python3 --version` already prints 3.x):
```bash
brew install python3
```
Check it worked: `python3 --version` โ prints `Python 3.x.x`.
3. **Install portaudio** (system library `PyAudio` needs to build/run):
```bash
brew install portaudio
```
What it does: installs the audio I/O library `PyAudio` links against for
microphone access.
Check it worked: `brew list portaudio` โ lists installed files, no error.
4. **Clone this repo and enter it:**
```bash
git clone <this-repo-url> jarvis-voice
cd jarvis-voice
```
Check it worked: `ls` โ shows `neo-voice-assistant.py`, `requirements.txt`, `env.example`.
5. **Create and activate a virtual environment:**
```bash
python3 -m venv .venv
source .venv/bin/activate
```
What it does: isolates this project's Python packages from the rest of your system.
Check it worked: your shell prompt now starts with `(.venv)`.
6. **Install the Python packages:**
```bash
pip install -r requirements.txt
```
What it does: installs `SpeechRecognition`, `httpx`, and `PyAudio` (the
three, and only three, imports this script needs beyond the Python
standard library).
Check it worked: `python3 -c "import speech_recognition, httpx, pyaudio; print('ok')"` โ prints `ok`.
If `PyAudio` fails to build here, re-run step 3 first โ this is almost
always a missing `portaudio`.
## Configure
Every value below is read from either a real environment variable or a
`.env` file placed next to the script (the script checks the real
environment first, then falls back to reading `.env` itself โ no
`python-dotenv` package involved, it parses the file by hand).
1. Copy the example file:
```bash
cp env.example .env
```
2. Edit `.env` and fill in real values in place of these placeholders:
```
ELEVENLABS_API_KEY=YOUR_KEY_HERE # keyzhub-allow
ELEVENLABS_VOICE_ID=YOUR_VOICE_ID_HERE # keyzhub-allow
NEO_TELEGRAM_BOT_TOKEN=YOUR_TELEGRAM_BOT_TOKEN_HERE # keyzhub-allow
NEO_TELEGRAM_CHAT_ID=YOUR_TELEGRAM_CHAT_ID_HERE # keyzhub-allow
```
- `ELEVENLABS_API_KEY` โ from your ElevenLabs account dashboard.
- `ELEVENLABS_VOICE_ID` โ the ID of the voice you want to speak with
(clone your own, or copy an ID from ElevenLabs' voice library).
- `NEO_TELEGRAM_BOT_TOKEN` โ the token @BotFather gives you when you
create a bot.
- `NEO_TELEGRAM_CHAT_ID` โ the numeric ID of the chat between you and
that bot (or a private group containing the bot) โ this is where the
script posts what you say and where it expects the agent's reply.
`.env` is already listed in `.gitignore` โ it will not be committed.
All four values are required. The script calls `sys.exit()` with an error
message immediately on startup if any one of them is missing.
## Run it
```bash
source .venv/bin/activate # if not already active
python3 neo-voice-assistant.py
```
Success looks like:
```
[Using mic: <your microphone name>]
[Calibrating...]
==================================================
โก NEO VOICE ASSISTANT โก
Powered by OpenClaw Agent (full Neo brain)
Say 'Hey Neo' to activate
Continuous conversation until 'Peace God'
==================================================
๐ [Waiting for 'Hey Neo'...]
```
Say "Hey Neo" out loud. It should print `โก [ACTIVATED]` and speak "Peace
god. What's on your mind?" out loud through your speakers. Anything you say
after that gets sent to your Telegram bot, and whatever replies in that chat
gets spoken back. Say "peace god," "goodbye," "shut down," or "go to sleep"
to end the conversation and return to wake-word listening. Ctrl-C to quit
entirely.
## Troubleshooting
1. **`ERROR: missing ELEVENLABS_API_KEY / NEO_TELEGRAM_BOT_TOKEN / NEO_TELEGRAM_CHAT_ID` at startup.**
One of the four required values in `.env` (or your real environment) is
empty or the file wasn't copied. Fix: `cp env.example .env`, fill in all
four values, confirm the file is actually named `.env` (not `env` or
`.env.txt`) and sits next to `neo-voice-assistant.py`.
2. **`PyAudio` fails to install, or `python3 neo-voice-assistant.py` errors on `import pyaudio` / can't open the microphone.**
`PyAudio` needs the system `portaudio` library, which is not a Python
package. Fix: `brew install portaudio`, then `pip install -r requirements.txt` again inside the activated venv.
3. **It never hears "Hey Neo," or hears you but nothing ever gets a reply.**
Two separate causes, both external to this script:
- No transcription happening at all โ check your internet connection;
`recognize_google()` requires a live connection to Google's free Web
Speech API (no key needed, but no connection means no transcription).
- Transcribes fine but always says "I'm still processing that... check
Telegram" โ the bot token/chat ID are valid but nothing is actually
listening to that Telegram chat and replying. This script only relays
messages; you must have a separate agent (your own bot logic) watching
`NEO_TELEGRAM_CHAT_ID` and posting a reply within ~40 seconds, or you'll
always get the fallback message.
|