Live sermon translation into 100+ languages, running entirely on one Mac per campus: audio in, voice detection, Whisper on the GPU, NLLB-200 in its own process, and a built-in web server the congregation reads from on their phones. No audio leaves the building. This is the source only. What used to sit beside it — 14 GB of speech and translation models, 8 GB of voice bundles, 6 GB of natural voices, the Electron caches, and the app data holding the operator PIN and every service transcript — is machine state and downloaded assets, and stays in the NAS backup where it belongs. The vendored node, cloudflared and Windows ffmpeg binaries are out too (533 MB, re-fetched for packaging); the browser-side runtime beside them is kept, so a checkout still serves the congregation page. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
3.3 KiB
Stream Deck / Bitfocus Companion
One button starts and stops translation. That is the whole integration.
The button
In Companion:
- Connections → add Generic HTTP. No settings needed.
- Make a button. Add a press action: Generic HTTP → GET.
- Paste the toggle URL from the operator page (Stream Deck / Companion section — there is a Copy button):
http://127.0.0.1:3100/api/control/toggle?key=YOUR_TOKEN
Use 127.0.0.1 when Companion runs on the same Mac as the app, which is the
normal case. If Companion is on a different machine, use that Mac's LAN address
instead — the app shows it under What the congregation opens.
The token is per-campus. Copy it from the operator page → Stream Deck / Companion, which has a copy button for exactly this.
Set the button text to TRANSLATE. Done.
Separate start and stop URLs are on the operator page too if you'd rather have two buttons than one toggle.
The key is a password. Anyone who has it can start and stop translation for the whole congregation. Don't put it on a slide, and don't paste it into a group chat.
Making the button change colour
Worth doing — a volunteer should be able to tell at a glance whether it is running.
The server pushes its state into a Companion custom variable, so the button is always right the moment anything changes, including when translation was started from the operator page or stopped because the Mac engine quit.
First, switch Companion's HTTP API on. It ships disabled — checked on your Companion 5.0.4 and every API endpoint returns 404 until you enable it. In Companion: Settings → HTTP API → enable. (The button itself works without this; only the colour feedback needs it, because that is the server calling into Companion rather than Companion calling out.)
Then: Variables → Custom Variables → create one called translate_state.
On the operator page: set Companion address. When Companion runs on the
same Mac as the app — the normal case — that is http://127.0.0.1:8000.
The variable will then hold one of:
| Value | Meaning | Suggested colour |
|---|---|---|
live |
Translating right now | Red |
ready |
Engine connected, standing by | Green |
offline |
The Mac engine is not running | Dark grey / amber |
Add feedbacks on the button: Internal → Custom variable value — one rule per value, each setting the background colour.
offline is the useful one. It tells the volunteer the Mac app is closed
before the sermon starts, instead of after.
If you'd rather poll
There is also a plain-text endpoint that returns exactly one word:
http://127.0.0.1:3100/api/status.txt?key=YOUR_TOKEN
Returns live, ready, or offline. Use it with any control system that can
fetch a string — it needs no JSON parsing.
Other control systems
Everything is plain HTTP GET, so anything that can fetch a URL can drive this:
a browser bookmark, a shortcut on a phone, an AMX/Crestron panel, a curl in a
script.
curl "http://127.0.0.1:3100/api/control/start?key=YOUR_TOKEN"
curl "http://127.0.0.1:3100/api/control/stop?key=YOUR_TOKEN"
Both return JSON describing the new state, including how many people are listening and in which languages.