--- license: mit tags: - esp32 - audio - speech-to-text - real-time - deepgram - gemini - fastapi - iot --- # πŸŽ™οΈ ESP32 Real-Time Audio Transcriber A real-time speech-to-text system that captures audio from an **ESP32 + INMP441** microphone, streams it to a cloud-hosted **FastAPI** server, transcribes it via **Deepgram Nova-3**, and generates conversational AI responses using **Google Gemini 2.5 Flash** β€” all viewable in a sleek live web dashboard. --- ## πŸ“Έ Product Images

Product Image 1    Product Image 2

ESP32 + INMP441 assembly housed in a custom 3D printed case

### πŸŽ₯ Demo Video [β–Ά Watch the product demo video](product-media/product-demo.mp4) --- ## ✨ Features - **Real-time transcription** β€” Live interim + final transcripts powered by Deepgram Nova-3 - **AI conversation** β€” Press **Q** or click *Ask Gemini* to get a conversational response from Gemini 2.5 Flash with multi-turn context - **WiFi captive portal** β€” No hardcoded credentials; configure WiFi via phone/laptop on first boot - **One-click deploy** β€” Server deploys to [Railway](https://railway.app) with zero configuration - **Live status dashboard** β€” Monitor WebSocket, Deepgram, ESP32, and Gemini connection states in real time - **Debug panel** β€” Built-in debug log overlay for troubleshooting --- ## πŸ—οΈ Architecture ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” WSS (binary audio) β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” WSS β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ ESP32 + β”‚ ──────────────────────────────▢ β”‚ FastAPI Server β”‚ ──────────────▢ β”‚ Deepgram β”‚ β”‚ INMP441 β”‚ β”‚ (Railway) β”‚ ◀────────────── β”‚ Nova-3 β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ transcripts β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ REST β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” WSS (text events) β”‚ β”‚ ──────────────▢ β”‚ Gemini β”‚ β”‚ Browser β”‚ ◀────────────────────────────── β”‚ β”‚ ◀────────────── β”‚ 2.5 Flashβ”‚ β”‚ Dashboard β”‚ ──────────────────────────────▢ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ AI response β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ "PROCESS" / "CLEAR" ``` --- ## πŸ“ Project Structure ``` audio_transcriber/ β”œβ”€β”€ server.py # FastAPI server (transcription + LLM + web UI) β”œβ”€β”€ esp32_firmware/ β”‚ └── esp32_firmware.ino # Arduino sketch for ESP32 + INMP441 β”œβ”€β”€ requirements.txt # Python dependencies β”œβ”€β”€ Procfile # Railway process definition β”œβ”€β”€ runtime.txt # Python version for Railway β”œβ”€β”€ .gitignore # Ignored files (venv, cache, etc.) └── README.md # This file ``` --- ## πŸ”§ Hardware Requirements | Component | Description | |---|---| | **ESP32 Dev Board** | Any ESP32-WROOM-32 based board | | **INMP441** | I2S MEMS microphone module | | **Jumper wires** | 5 connections (see wiring below) | | **USB cable** | For flashing and serial monitor | ### Wiring Diagram | ESP32 Pin | INMP441 Pin | Function | |---|---|---| | `GPIO 26` | `SCK` | Bit Clock | | `GPIO 32` | `WS` | Word Select (LRCLK) | | `GPIO 33` | `SD` | Serial Data Out | | `3.3V` | `VDD` | Power | | `GND` | `GND` + `L/R` | Ground (L/R β†’ GND for left channel) | --- ## πŸš€ Getting Started ### 1. Deploy the Server to Railway 1. Push this repository to GitHub 2. Go to [railway.app](https://railway.app) β†’ **New Project** β†’ **Deploy from GitHub Repo** 3. Railway auto-detects the `Procfile` and `runtime.txt` β€” no extra config needed 4. Note your deployed URL (e.g. `audio-transcriber.up.railway.app`) ### 2. Flash the ESP32 Firmware 1. Open `esp32_firmware/esp32_firmware.ino` in **Arduino IDE** 2. Install the required libraries via **Library Manager**: - `WiFiManager` by tzapu (β‰₯ 2.0) - `WebSockets` by Markus Sattler (β‰₯ 2.4) 3. Update `SERVER_HOST` in the sketch if your Railway URL differs: ```cpp const char* SERVER_HOST = "your-app-name.up.railway.app"; ``` 4. Select board: **ESP32 Dev Module** 5. Flash and open the Serial Monitor at **115200 baud** ### 3. Connect to WiFi 1. On first boot, the ESP32 creates a WiFi AP named **`Transcriber-Setup`** 2. Connect to it from your phone or laptop 3. Select your home WiFi network and enter the password 4. The ESP32 saves the credentials and auto-connects on subsequent boots > πŸ’‘ **Reset WiFi:** Hold the **BOOT** button (GPIO 0) while powering on to clear saved credentials. ### 4. View the Dashboard Open your Railway URL in a browser: ``` https://audio-transcriber.up.railway.app ``` You'll see live transcription appear as the ESP32 streams audio. --- ## 🧠 Using Gemini AI Once transcription lines appear: 1. Press **Q** on your keyboard or click the **⬑ Ask Gemini** button 2. Gemini reads the buffered transcript and responds in a casual, conversational tone 3. The conversation supports **multi-turn context** β€” keep talking and asking 4. Click **Reset Chat** to clear the conversation history --- ## βš™οΈ Configuration ### Server Environment | Variable | Default | Description | |---|---|---| | `PORT` | `8000` | HTTP port (auto-set by Railway) | ### API Keys API keys are currently embedded in `server.py`. For production, move them to environment variables: ```python DEEPGRAM_API_KEY = os.environ.get("DEEPGRAM_API_KEY") GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY") ``` ### ESP32 Firmware | Constant | Default | Description | |---|---|---| | `SERVER_HOST` | `audio-transcriber.up.railway.app` | Railway domain | | `SERVER_PORT` | `443` | HTTPS/WSS port | | `WS_PATH` | `/ws/audio` | WebSocket endpoint | | `SAMPLE_RATE` | `16000` | Audio sample rate (Hz) | | `I2S_READ_LEN` | `256` | Samples per I2S read cycle | --- ## πŸ› οΈ Local Development ```bash # Clone the repo git clone https://github.com//audio_transcriber.git cd audio_transcriber # Create a virtual environment python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # Install dependencies pip install -r requirements.txt # Run the server locally python server.py # β†’ Server starts at http://localhost:8000 ``` > Update `SERVER_HOST` in the ESP32 sketch to your local IP for local testing. --- ## πŸ“¦ Dependencies ### Python (Server) | Package | Purpose | |---|---| | `fastapi` | Async web framework & WebSocket handling | | `uvicorn` | ASGI server | | `websockets` | Async WebSocket client for Deepgram | | `langchain-google-genai` | LangChain integration for Gemini | ### Arduino (ESP32) | Library | Purpose | |---|---| | `WiFiManager` | Captive portal for WiFi provisioning | | `WebSockets` | WebSocket client with SSL support | --- ## πŸ“ API Endpoints | Endpoint | Type | Description | |---|---|---| | `GET /` | HTTP | Serves the live transcription dashboard | | `WS /ws` | WebSocket | Browser ↔ Server (transcripts + LLM events) | | `WS /ws/audio` | WebSocket | ESP32 β†’ Server (raw 16-bit PCM audio) | ### Browser WebSocket Messages | Direction | Message | Description | |---|---|---| | Browser β†’ Server | `PROCESS` | Trigger Gemini on buffered transcript | | Browser β†’ Server | `CLEAR_HISTORY` | Reset conversation history | | Server β†’ Browser | `__FINAL__:` | Final transcript line | | Server β†’ Browser | `__INTERIM__:` | Interim (partial) transcript | | Server β†’ Browser | `__LLM_START__` | Gemini processing started | | Server β†’ Browser | `__LLM_TOKEN__:` | Gemini response text | | Server β†’ Browser | `__LLM_DONE__` | Gemini processing complete | | Server β†’ Browser | `__LLM_ERROR__:` | Gemini error message | | Server β†’ Browser | `__STATUS__:` | Connection state change | --- ## 🀝 Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request --- ## πŸ“„ License This project is open source and available under the [MIT License](LICENSE). ---

Built with ❀️ using ESP32 · FastAPI · Deepgram · Gemini