This repo was built with the assistance of Google Antigravity and includes code to run an on-device, fully offline voice translator powered by Gemma 4 and LiteRT-LM. This project features a web frontend optimized for small handheld displays (e.g., 480x320) and a Python API server (http.server) that communicates with Gemma. Text-to-speech is powered by Moonshine.
https://github.com/user-attachments/assets/343072ce-dc78-44a7-a783-99312845cabe
gemma4-e2b model entirely locally. No internet required after setup.deploy-pi.sh on Raspberry Pi OS / Debian
Make Scripts Executable Ensure the setup, download, start, and deployment scripts have execute permissions:
chmod +x setup.sh download_model.sh start.sh deploy-pi.sh
Install Dependencies
Run the setup script to create a Python virtual environment (venv) and install all required packages:
./setup.sh
Download the Model
Run the model downloader script to fetch the gemma4-e2b model from Hugging Face and import it into LiteRT-LM:
./download_model.sh
Start all services (LiteRT-LM, the Python API server, and the Vite Web UI) in development mode:
./start.sh
To run in production mode (skipping Vite dev server and serving compiled UI assets from frontend/dist/ via backend/server.py on port 3000):
./start.sh --prod
The application will be accessible at:
http://localhost:5173http://localhost:3000http://localhost:9379To deploy as a permanent systemd kiosk service on a Raspberry Pi 5 (8GB):
./deploy-pi.sh
This automated script installs Debian audio/venv packages, sets up the Python environment, builds production UI assets, downloads the LiteRT model, registers the systemd unit from deploy/gemma-translator.service, and configures LXDE GUI autostart (~/.config/lxsession/rpd-x/autostart) to launch Chromium in kiosk mode pointing to http://localhost:3000.
frontend/ - React (Vite) web frontend (index.html, src/, styles, and Vite configuration).backend/ - Python API server (server.py and requirements.txt) for Moonshine STT, moonshine-voice TTS, and model proxying.deploy/ - Parameterizable systemd service unit template (gemma-translator.service).stl/ - STL files for 3D printing the hardware case.setup.sh - Automates Python virtual environment creation and dependency installation.download_model.sh - Fetches the required LiteRT model.start.sh - Multi-process launcher supporting --prod and development modes.deploy-pi.sh - One-command Raspberry Pi automated deployment script.The Gemma Translator supports two keyboard modes. Switch between them anytime from the Settings panel → "Keyboard Mode" dropdown. The choice is remembered across restarts (stored in the browser's localStorage under the key keyboardMode).
The app has two lanes (two people facing each other on the kiosk):
Each lane has a rotating language "revolver" and records speech, which is transcribed (Moonshine STT), translated (Gemma), and spoken back in the other lane's language (moonshine-voice TTS).
One lane is the active person at a time. The active lane is framed with corner brackets on all four corners. You drive everything from a single set of keys and switch focus with Space.
| Key | Action | Description |
|---|---|---|
| Spacebar | Switch active person | Toggles the active lane (Person 1 ⇄ Person 2). Disabled while recording. |
| Z | Record (push-to-talk) | Hold to record the active person; release to transcribe & translate. |
| ← Left Arrow | Previous language | Rotates the active person's language backward. |
| → Right Arrow | Next language | Rotates the active person's language forward. |
Notes:
Each lane has its own dedicated keys — there is no active-person concept and no bracket highlight. Both people can be controlled independently.
| Key | Action | Description |
|---|---|---|
| Z | Record — Person 1 (push-to-talk) | Hold to record Lane 1; release to transcribe & translate. |
| X | Record — Person 2 (push-to-talk) | Hold to record Lane 2; release to transcribe & translate. |
| ← Left Arrow | Previous language — Person 1 | Rotates Lane 1's language backward. |
| → Right Arrow | Next language — Person 1 | Rotates Lane 1's language forward. |
− Minus (_) | Previous language — Person 2 | Rotates Lane 2's language backward. |
+ Plus (=) | Next language — Person 2 | Rotates Lane 2's language forward. |
Notes:
<input>, <textarea>, or <select>) — e.g. when editing the API endpoint or settings.Open Settings (⚙) → Keyboard Mode → choose Landscape or Vertical. The change takes effect immediately and persists on the device.
| Setting value | Mode |
|---|---|
landscape | Active-person scheme (Space / Z / ← →) — default |
vertical | Two-hand scheme (Z / X / ← → / − +) |
Made by a small team at Google Creative Lab:
This is not an officially supported Google product. This project is not eligible for the Google Open Source Software Vulnerability Rewards Program.
1,108 followers · starred Aug 2026
579 followers · starred Sep 2026
207 followers · starred Aug 2026
496 followers · starred Aug 2026
This repo was built with the assistance of Google Antigravity and includes code to run an on-device, fully offline voice translator powered by Gemma 4 and LiteRT-LM. This project features a web frontend optimized for small handheld displays (e.g., 480x320) and a Python API server (http.server) that communicates with Gemma. Text-to-speech is powered by Moonshine.
https://github.com/user-attachments/assets/343072ce-dc78-44a7-a783-99312845cabe
gemma4-e2b model entirely locally. No internet required after setup.deploy-pi.sh on Raspberry Pi OS / Debian
Make Scripts Executable Ensure the setup, download, start, and deployment scripts have execute permissions:
chmod +x setup.sh download_model.sh start.sh deploy-pi.sh
Install Dependencies
Run the setup script to create a Python virtual environment (venv) and install all required packages:
./setup.sh
Download the Model
Run the model downloader script to fetch the gemma4-e2b model from Hugging Face and import it into LiteRT-LM:
./download_model.sh
Start all services (LiteRT-LM, the Python API server, and the Vite Web UI) in development mode:
./start.sh
To run in production mode (skipping Vite dev server and serving compiled UI assets from frontend/dist/ via backend/server.py on port 3000):
./start.sh --prod
The application will be accessible at:
http://localhost:5173http://localhost:3000http://localhost:9379To deploy as a permanent systemd kiosk service on a Raspberry Pi 5 (8GB):
./deploy-pi.sh
This automated script installs Debian audio/venv packages, sets up the Python environment, builds production UI assets, downloads the LiteRT model, registers the systemd unit from deploy/gemma-translator.service, and configures LXDE GUI autostart (~/.config/lxsession/rpd-x/autostart) to launch Chromium in kiosk mode pointing to http://localhost:3000.
frontend/ - React (Vite) web frontend (index.html, src/, styles, and Vite configuration).backend/ - Python API server (server.py and requirements.txt) for Moonshine STT, moonshine-voice TTS, and model proxying.deploy/ - Parameterizable systemd service unit template (gemma-translator.service).stl/ - STL files for 3D printing the hardware case.setup.sh - Automates Python virtual environment creation and dependency installation.download_model.sh - Fetches the required LiteRT model.start.sh - Multi-process launcher supporting --prod and development modes.deploy-pi.sh - One-command Raspberry Pi automated deployment script.The Gemma Translator supports two keyboard modes. Switch between them anytime from the Settings panel → "Keyboard Mode" dropdown. The choice is remembered across restarts (stored in the browser's localStorage under the key keyboardMode).
The app has two lanes (two people facing each other on the kiosk):
Each lane has a rotating language "revolver" and records speech, which is transcribed (Moonshine STT), translated (Gemma), and spoken back in the other lane's language (moonshine-voice TTS).
One lane is the active person at a time. The active lane is framed with corner brackets on all four corners. You drive everything from a single set of keys and switch focus with Space.
| Key | Action | Description |
|---|---|---|
| Spacebar | Switch active person | Toggles the active lane (Person 1 ⇄ Person 2). Disabled while recording. |
| Z | Record (push-to-talk) | Hold to record the active person; release to transcribe & translate. |
| ← Left Arrow | Previous language | Rotates the active person's language backward. |
| → Right Arrow | Next language | Rotates the active person's language forward. |
Notes:
Each lane has its own dedicated keys — there is no active-person concept and no bracket highlight. Both people can be controlled independently.
| Key | Action | Description |
|---|---|---|
| Z | Record — Person 1 (push-to-talk) | Hold to record Lane 1; release to transcribe & translate. |
| X | Record — Person 2 (push-to-talk) | Hold to record Lane 2; release to transcribe & translate. |
| ← Left Arrow | Previous language — Person 1 | Rotates Lane 1's language backward. |
| → Right Arrow | Next language — Person 1 | Rotates Lane 1's language forward. |
− Minus (_) | Previous language — Person 2 | Rotates Lane 2's language backward. |
+ Plus (=) | Next language — Person 2 | Rotates Lane 2's language forward. |
Notes:
<input>, <textarea>, or <select>) — e.g. when editing the API endpoint or settings.Open Settings (⚙) → Keyboard Mode → choose Landscape or Vertical. The change takes effect immediately and persists on the device.
| Setting value | Mode |
|---|---|
landscape | Active-person scheme (Space / Z / ← →) — default |
vertical | Two-hand scheme (Z / X / ← → / − +) |
Made by a small team at Google Creative Lab:
This is not an officially supported Google product. This project is not eligible for the Google Open Source Software Vulnerability Rewards Program.
1,108 followers · starred Aug 2026
579 followers · starred Sep 2026
207 followers · starred Aug 2026
496 followers · starred Aug 2026