Speak your language. Be heard in theirs.
Real-time voice translation for Google Meet — in your own cloned voice.
Spokked sits between your microphone and Google Meet. You speak Turkish; about a second after you finish a sentence, the other side hears it in English in your own voice. When they answer in English, you hear their original voice and read live Turkish subtitles on top of the call. When the meeting ends, a summary and a full bilingual transcript are saved for you.
It runs locally on your Mac as a small Python service plus a Chrome extension. Your own (untranslated) voice never reaches the call.
Turkish ⇄ English is the default pair. Both directions are configurable with ISO language codes.
Outgoing — you speak, they hear your voice in their language
- Streaming speech recognition (ElevenLabs Scribe v2 Realtime) → translation (Claude) → speech in your cloned voice (ElevenLabs Eleven v4 Turbo).
- ~1–1.5 s from the end of your sentence to the first translated audio.
- Tone follows you: the translator tags each sentence (excited, calm, curious, apologetic…) and the voice delivers it that way.
- Pace matching: if the translation is longer than what you said, it is sped up slightly (pitch-preserving, max 1.2×).
- Language-aware early end-of-sentence detection and speculative translation that starts before the recognizer commits.
- Safety nets: the translator never answers or comments instead of translating, output is checked to be in the right language, echo of your own translated voice is filtered, silence "hallucinations" are dropped.
- Muting your mic in Meet pauses Spokked too, and drops anything still in flight.
Incoming — they speak, you read live subtitles
- Their original voice plays normally; a draggable subtitle box shows English on top and Turkish below.
- Finished sentences are locked in white while the speaker is still talking; only the unfinished tail is shown as a grey draft. Previous lines stay visible.
- Subtitle-specific translation (concise, readable, fillers removed).
- Optional automatic language detection for the other side.
Meeting helpers
- 📋 Catch me up (Alt+S): Turkish summary of the last 5 minutes, any question you were asked, and a suggested short answer.
- Automatic meeting notes: when you press Stop or leave the Meet call, a summary (topics, decisions, action items, open questions) and the full bilingual transcript are saved to a folder (default
~/Desktop/Meet Özetleri). - Personal glossary (
sozluk.txt): names and term pairs applied to recognition and both translation directions. - Optional camera beauty filter (brightness, smoothing, warmth) applied inside Chrome.
- Local dashboard at
http://127.0.0.1:8765/with latency, counts and quota.
OUTGOING
Your mic ─► Scribe v2 Realtime (tr) ─► Claude Haiku (tr→en) ─► ElevenLabs v4 Turbo (your voice) ─► BlackHole 2ch ─► Meet "Microphone"
INCOMING
Meet "Speaker" ─► BlackHole 16ch ─► Scribe v2 Realtime (en) ─► Claude Haiku (en→tr) ─► subtitle overlay in Meet
└─► original audio ─► your headphones
- BlackHole provides two virtual audio cables: Meet's microphone only ever receives the translated voice, and Meet's speaker output is captured for subtitles before being passed on to your headphones.
- The Chrome extension draws the subtitle overlay, adds Start/Stop and mute controls, syncs with Meet's mute button and detects when you leave a call.
- The local service (
translator.py) runs as a macOS LaunchAgent in standby mode; it only opens the microphone and spends API credits after you press Start.
- macOS (Apple Silicon or Intel) and Google Chrome
- Homebrew
- An ElevenLabs account with a cloned voice. A paid plan is recommended (Creator is enough); real-time translation uses roughly 800–1,000 characters per minute of your speech. Subtitles cost no ElevenLabs characters.
- An Anthropic API key (translation costs a few cents per meeting)
git clone https://github.com/Bihruze/spokked.git
cd spokked
./setup.shsetup.sh installs the BlackHole virtual audio devices, creates a Python virtual environment, installs the dependencies and creates your .env from .env.example.
If the BlackHole devices don't show up yet, restart Core Audio (or your Mac):
sudo killall coreaudiod- Go to ElevenLabs → Voices → Add a new voice → Instant Voice Clone.
- Record 2–3 minutes of natural speech in a quiet room, in your own language. (Short samples make the clone sound generic; reading English text in a strong accent carries that accent over.)
- Enable "Remove background noise", save, and copy the voice ID.
Edit .env (open -e .env) and fill in the first three lines:
ELEVENLABS_API_KEY=...
ANTHROPIC_API_KEY=...
ELEVENLABS_VOICE_ID=....env is ignored by git and created with owner-only permissions. Then verify the whole setup:
./run.sh checkEvery line should show ✓ (keys, audio devices, quota, and the latency of each cloud service).
- Open
chrome://extensionsand enable Developer mode. - Click Load unpacked and select the
extensionfolder inside this repo. - Pin Spokked from the puzzle-piece menu.
./autostart.sh # install as a LaunchAgent (starts in standby at login)
./autostart.sh remove # uninstallFrom now on you never need the terminal: the extension's ▶ START / ■ STOP button controls everything. Logs go to logs/service.log.
Prefer running it by hand? Use ./run.sh (active immediately, Ctrl+C to quit).
- In Google Meet open ⋮ → Settings → Audio:
- Microphone:
BlackHole 2ch - Speaker:
BlackHole 16ch - Noise cancellation: off (it can clip synthetic speech)
- Microphone:
- Click the Spokked extension → ▶ START.
- Speak normally and pause briefly at the end of sentences.
- Leave the call or press ■ STOP — your notes are saved automatically.
Use headphones for the best result: on built-in speakers Spokked mutes your microphone while a translation is playing to avoid echo; with headphones you can talk over the other side freely. Switching to AirPods mid-call is detected within ~2 seconds.
| Shortcut | Action |
|---|---|
Alt+M |
Mute / unmute your translated voice |
Alt+S |
Catch me up (summary + question + suggested answer) |
Alt+E |
Show / hide the English line in subtitles |
Alt + / Alt - |
Subtitle size |
| Double-click the box header | Reset subtitle position |
./run.sh # run in the foreground
./run.sh check # readiness check: keys, devices, quota, latency
./run.sh devices # list audio devices
./run.sh voices # list your ElevenLabs voices and IDs
./run.sh translate "..." # test translation only
./run.sh say "..." # speak a test sentence in your cloned voice into BlackHole 2ch
./run.sh summary # Turkish notes for the most recent transcriptAll settings live in .env (see .env.example for the full, commented list). The most useful ones:
| Setting | Default | What it does |
|---|---|---|
SOURCE_LANG / TARGET_LANG |
tr / en |
Your language and the other side's language |
INCOMING_STT_LANG |
(target) | auto detects the other side's language; if they speak yours, subtitles show it untranslated |
INCOMING_MODE |
subtitles |
voice reads the other side to you in a translated voice instead |
TTS_MODEL |
eleven_v4_turbo |
Voice model; v4 supports delivery tags like [excited] |
VOICE_ACCENT |
American accent |
Accent tag sent with every sentence |
VAD_SILENCE_SECS |
0.45 |
Silence that ends a sentence (lower = faster, more splits) |
PACE_MATCH / PACE_MAX |
1 / 1.2 |
Match the translation to your speaking pace |
PREBUFFER_MS |
600 |
Upper bound of the adaptive jitter buffer |
KEYTERMS |
Comma-separated names/terms to protect | |
MEETING_CONTEXT |
One line about the meeting; helps resolve ambiguity | |
MEET_NOTES_DIR |
~/Desktop/Meet Özetleri |
Where meeting notes are saved |
TRANSLATE_MODEL |
claude-haiku-5-5 |
Fastest; any Claude model works |
After changing .env or sozluk.txt, restart the service: ./autostart.sh (or restart ./run.sh).
Measured end to end on a home connection (speech end → first translated audio in Meet):
| Stage | Time |
|---|---|
| End-of-sentence detection | ~0.25–0.45 s |
| Translation, first sentence (Claude Haiku, partly hidden by speculative translation) | ~0.6–1.0 s |
| First audio (Eleven v4 Turbo, HTTP streaming) | ~0.2 s |
| Total | ~1.0–1.5 s |
Incoming subtitles: the recognizer delivers its first partial ~1–2 s into a sentence; a Turkish draft follows ~1 s later, and the final line ~1.5–2 s after the speaker stops. Turkish is verb-final, so drafts necessarily change at the end of a sentence — that tail is shown in grey.
- The control server listens on
127.0.0.1only, checks theHostheader (DNS-rebinding protection), only answers the extension, the Meet page and its own dashboard, and requires a custom header plusPOSTfor every state change. .env, transcripts and logs are created with owner-only permissions and are git-ignored.- In standby the microphone is not opened and nothing is sent anywhere.
- Audio and text are processed by ElevenLabs and Anthropic according to their API terms. Meeting notes are written to
MEET_NOTES_DIR; if that folder is inside iCloud Desktop & Documents, they will sync to iCloud. - Let the people you talk to know that you use AI translation and a cloned voice.
| Problem | Fix |
|---|---|
| Extension says the service isn't running | ./autostart.sh or ./run.sh |
| The other side can't hear you | Meet microphone must be BlackHole 2ch, and Spokked must be started |
| No subtitles / you can't hear them | Meet speaker must be BlackHole 16ch (not 2ch) |
| BlackHole not listed | sudo killall coreaudiod or restart your Mac |
| Microphone not detected | System Settings → Privacy & Security → Microphone → allow Terminal/Python |
| Your clone sounds generic or deep | Re-clone with 2–3 minutes of clean speech in your own language |
| Anything else | ./run.sh check, then logs/service.log |
translator.py the local service: audio I/O, STT, translation, TTS, subtitles, control server, notes
extension/ Chrome extension (popup, Meet overlay, camera filter)
setup.sh one-time installer
autostart.sh install/remove the macOS LaunchAgent
run.sh run any command inside the virtual environment
sozluk.txt personal glossary
.env.example every setting, documented
The user-facing strings in the overlay and logs are in Turkish; the code is a single, heavily commented Python file.
