Hand-built hardware
The chassis is cardboard and tape — but inside it's a real ESP32 with INMP441 I2S microphone and MAX98357A I2S amplifier. Soldering, wiring, GPIO mapping, dual-core RTOS task pinning — all of it done from scratch.
Jack is a real robot — custom ESP32 firmware streaming live audio over WebSocket to a Hostinger-hosted C# relay, feeding into OpenAI Whisper for Arabic speech-to-text, GPT-4o for the response, and TTS for the spoken answer played back through the robot's speaker.
The chassis is cardboard and tape — but inside it's a real ESP32 with INMP441 I2S microphone and MAX98357A I2S amplifier. Soldering, wiring, GPIO mapping, dual-core RTOS task pinning — all of it done from scratch.
Bidirectional streaming: the robot's microphone uploads audio continuously while the speaker simultaneously plays back TTS chunks as they arrive. Mic auto-pauses during TTS playback to prevent self-recording.
The wake word is Arabic ("مصطفى"). The Whisper STT call is locked to language="ar". The GPT-4o-mini system prompt is in Arabic Fusha. The TTS voice ("onyx") handles Arabic phonemes. Not a translation layer — Arabic end-to-end.
Five photos of the actual hardware — not a render, not a stock photo. Cardboard chassis, hand-wired ESP32, real working prototype.
After the build, Jack went from a project on my desk to a presentation in front of the entire school — and a teaching opportunity with other students.
The project was chosen for the إذاعة (the school's morning assembly broadcast) — a presentation slot typically reserved for top student work. I stood in front of the entire student body and teaching staff to walk them through what Jack does and how it was built.
It was recognized as the first project of its kind to be presented at the assembly — combining custom hardware (ESP32, I2S audio), cloud infrastructure (WebSocket relay, OpenAI APIs), and Arabic-language voice AI in a single end-to-end build.
Following the presentation, I led informal teaching sessions with classmates on how the system actually works — from soldering and GPIO mapping on the ESP32 side, to WebSocket streaming and OpenAI API integration on the server side.
The INMP441 microphone captures your voice, the ESP32 batches 1500 samples at a time, base64-encodes them, and streams them via WebSocket to a Hostinger VPS that relays the audio to a PC.
The PC runs auto-calibrating voice-activity detection, slices out the utterance, sends it to Whisper for Arabic transcription, checks for the wake word, and sends the rest to GPT-4o-mini with an Arabic system prompt.
GPT's reply goes to OpenAI TTS, converts to 16 kHz PCM via FFmpeg, streams back to the ESP32 in 4 KB chunks. The robot pauses its mic during playback to avoid recording its own voice, and resumes listening after the last chunk.
TL;DR: You speak Arabic. The cardboard robot streams your voice to OpenAI, gets back a smart Arabic reply, and speaks it through its own speaker. End-to-end in one device.
Three machines in the pipeline: the ESP32 on the robot, the Hostinger VPS as a WebSocket relay, and the PC doing the heavy lifting (VAD + STT + LLM + TTS). The VPS is intentionally dumb — it just routes JSON messages with target: "pc" or target: "esp32" between the two endpoints.
This three-tier design means the robot itself can run on a cheap ESP32 (no on-device ML), and the PC backend is replaceable — I could swap GPT-4o for a local LLM, or Whisper for an on-device STT model, without touching the firmware.
Dual-core 240 MHz Xtensa, built-in WiFi. Runs the C++ firmware on FreeRTOS with separate tasks pinned to each core: microphone-send on core 0, speaker-playback on core 0 (priority 2), main loop + WiFi on core 1.
MEMS digital microphone with I2S output. 24-bit, configurable sample rate. Wired to ESP32 GPIO 25 (BCK), 27 (WS), 18 (DATA). 1.5× gain multiplier applied in software.
Class-D mono I2S amplifier, up to 3.2 W. Wired to ESP32 GPIO 12 (BCK), 14 (WS), 13 (DATA). 3× volume gain in software with clipping protection.
Hand-cut, painted, taped. Functional and durable enough for the prototype phase. A 3D-printed enclosure is on the roadmap; cardboard is fine for now.
The ESP32 firmware is ~700 lines of C++ targeting the Arduino-ESP32 framework with the WebSocketsClient library. The interesting parts:
micEnabled = false) when TTS playback startsThe backend is a C# console app (ConsoleApp4) running on a Hostinger VPS. It connects to the relay as the "pc" endpoint and does everything that needs real compute:
System.Threading.Channelswhisper-1 model, language="ar"type: "wake_beep")gpt-4o-mini{target, type:"tts", chunk, total, data}The project taught me a stack I'd never touched in one piece before. Some of the things that turned out harder than they looked:
Jack is paused while I focus on Desertflow, but it's not abandoned. The planned next steps when I come back to it:
The Pi would have been easier — could run Whisper locally, no WebSocket relay needed. But the ESP32 is <$10, runs for hours on a USB battery, and the constraint of "no on-device ML" forced a clean separation between hardware (the robot) and brain (the cloud backend). That separation makes it easier to swap pieces later — different LLM, different STT, different TTS — without re-flashing firmware.
The VPS is the only piece with a stable public IP. The ESP32 is behind a home router; the PC is behind the same router. Having both endpoints reach out to a VPS over WebSocket sidesteps NAT entirely. Same pattern any chat app uses.
The key never touches the ESP32 or the VPS. It lives in an environment variable (OPENAI_API_KEY) on the PC backend only. The robot sends audio bytes; the PC makes the API calls; the robot receives audio bytes back. The key never crosses the WebSocket.
Most voice assistants treat Arabic as an afterthought — Alexa, Siri, and Google Assistant all support it, but their Arabic is noticeably worse than their English. Building one Arabic-first meant choosing the wake word, system prompt, TTS voice, and language flags for that target instead of bolting it on. The same code base trivially supports English by changing config; it just wasn't the priority.
End-of-utterance to first-audio-chunk back is typically 2–4 seconds on a good connection. Most of that is the OpenAI API call sequence (Whisper transcription → GPT response → TTS generation). The audio streaming itself adds <200 ms each way. Could be cut to ~1 s with a faster LLM or by running everything locally.
Yes — the firmware (ESP32 C++) and the server (C# console app) will both go on GitHub once the project resumes after Desertflow. For now, the headline code snippets are on this page; full source is in private repos.
Questions about the hardware, the architecture, or replicating the design — (click to copy)
Code: github.com/mohtheghost
← Back to all projects