Real-time speech-to-text with automatic Bible verse detection and EasyWorship integration.
Built for church AV operators: listen to a sermon in real time, instantly detect any Bible verse reference spoken aloud, and send it directly to EasyWorship with one click (or a hotkey).
- 🎙 Real-time audio capture via JACK (primary) or sounddevice (fallback)
- 〰️ Live audio waveform monitor so you can verify the mic is flowing before text appears
- 🧠 Speech-to-text backends using OpenAI Realtime, faster-whisper, or Vosk
- 📖 Bible verse detection – all 66 books, dozens of abbreviations, natural-language patterns
"Genesis 5:2","Gen 5 v 2","chapter 8 verse 28","Romans 8:28 through 30"
- ⭐ Verse queue with timestamps, confidence scores, and editable references
- 🪟 Local verse preview card above the queue, powered by offline canon files in
canons/<EDITION>/verses.json - 🧭 Likely passage suggestions from a rolling sermon context window, even when no explicit verse reference is spoken
- ⛪ EasyWorship automation via PyAutoGUI – clicks the search box, types the reference, presses Enter
- 🌗 Dark and light themes, church-friendly design
- ⌨ Hotkey:
Ctrl+Shift+Ssends the top queued verse to EasyWorship
- Python 3.10 or newer
- Linux (JACK/ALSA/PulseAudio) – primary platform
- Windows/macOS: supported via sounddevice + PyAutoGUI (JACK not required)
git clone https://github.com/anclatechs/verse-listener.git
cd verse-listenerpython3 -m venv .venv
source .venv/bin/activatepip install -r requirements.txtWindows note:
- use the repo's checked-in
requirements.txt - do not use a Linux-generated
pip freezefile for Windows installs - Linux-only CUDA packages such as
nvidia-cufileare not needed for this app on Windows
The project includes a ready-to-edit .env file.
Set at least:
OPENAI_API_KEY=your_key_here
VERSE_LISTENER_STT_BACKEND=openai_realtimeFor the queue preview card, place canon files like this:
canons/
└── KJV/
└── verses.json
The file should map references to verse text, for example:
{
"John 3:16": "For God so loved the world...",
"John 3:17": "For God sent not his Son..."
}sudo apt install python3-xlib wmctrl jackd2 qjackctl libportaudio2 portaudio19-devOptional Python backends for Linux window focus:
pip install PyWinCtl python-xlibIf you prefer Vosk over faster-whisper:
mkdir -p ~/.vosk
cd ~/.vosk
# Download model from https://alphacephei.com/vosk/models
# Example: English small model
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
unzip vosk-model-small-en-us-0.15.zip
mv vosk-model-small-en-us-0.15 model-en-usStart JACK with QJackCtl or via command line:
jackd -d alsa -r 44100 &Or use QJackCtl (GUI) to configure and start JACK.
VerseListener will auto-connect to the first available physical capture port.
You can also set the exact JACK port name in Settings → Audio.
If JACK is not running, VerseListener automatically falls back to sounddevice (PulseAudio/ALSA).
python main.pyOn first launch, VerseListener now opens a welcome screen with these paths:
Quick Setup→ OpenAI-first setup with API key entryInstall Offline→ in-app add-on manager for optional offline packagesDeveloper Mode→ advanced-friendly startup pathSkip for now
For this project, the best default setup is:
- Audio backend:
sounddeviceon Windows,autoorjackon Linux - STT backend:
openai_realtime - OpenAI model:
gpt-4o-transcribe
Why this is the best starting point:
- you get streaming partial transcripts instead of waiting on local chunked inference
- the
.envprompt can bias the model toward Bible book names and verse notation - you avoid CPU-heavy local Whisper inference
If you need a fully offline fallback:
- use backend
whisperwith modelsmall.enorbase.en
The app can read these values from .env, but the API key can also be entered directly in Settings → Speech Model:
OPENAI_API_KEY=your_key_here
VERSE_LISTENER_STT_BACKEND=openai_realtime
OPENAI_REALTIME_TRANSCRIBE_MODEL=gpt-4o-transcribe
OPENAI_REALTIME_LANGUAGE=en
OPENAI_REALTIME_PROMPT=...Notes:
OPENAI_API_KEYis required for the OpenAI backend- the Settings dialog stores the key locally on the machine and applies it to the running app
OPENAI_REALTIME_PROMPTis a good place to bias scripture names, sermon terms, and punctuation style- OpenAI Realtime transcription expects 24 kHz PCM; the app handles resampling before streaming audio
VerseListener keeps the bundled app lean and lets users install heavier offline tools later from Settings → Add-ons.
Optional in-app installs:
Voskfor offline STTfaster-whisperfor offline Whisper fallbacksentence-transformersfor stronger semantic passage matching
Notes:
- estimated sizes are shown in the add-ons manager before install
- installs go into the user's VerseListener add-ons folder, not into the bundled executable itself
- restart after install is recommended for the cleanest reload
- Windows
onedirbuilds can bundle a helper Python runtime so in-app installs work even when the target PC does not have Python installed
For a lean Windows bundle with OpenAI as the default path:
build_windows.batWhat this does:
- installs the lean Windows runtime dependencies from
requirements-windows-openai.txt - builds
VerseListener.exewithPyInstallerusingVerseListener.spec - prepares and bundles a helper Python runtime under
dist\VerseListener\runtime\python
Why the helper runtime matters:
- the shipped app stays lean and OpenAI-first by default
- optional add-ons still install later from Settings → Add-ons
- the target PC does not need a separate Python install for those add-ons
The helper runtime is prepared by:
powershell -ExecutionPolicy Bypass -File .\scripts\prepare_windows_runtime.ps1 -PythonVersion 3.12.3 -ForceUse the same Python major/minor version that you build the app with on Windows. build_windows.bat will auto-prepare this runtime for you when possible.
The right-hand queue panel includes a compact preview card above the detected verses list.
- Click a queued verse to load its text from
canons/<EDITION>/verses.json - Range references like
Romans 8:28-30are combined into one preview - Chapter-only references show the first few verses as a compact preview
- In Settings → Interface, you can adjust:
- preview canon edition
- preview max height
- gradient start and end colors
VerseListener can also infer a likely Bible passage from what is being preached, even if the speaker does not explicitly say the reference.
- It keeps a rolling context window from the last few transcript segments
- Exact verse detection still wins first
- If no explicit reference is found, the app searches the local canon for the closest passage match
- Suggestions appear as a separate Likely Passage card and can be queued manually
Default behavior:
- context window:
8s - matcher: local keyword retrieval
- optional upgrade: install
sentence-transformersfor semantic reranking
Enable and adjust it in Settings → Speech Model.
VerseListener reads VERSE_LISTENER_EW_WINDOW_BACKEND at startup.
export VERSE_LISTENER_EW_WINDOW_BACKEND=auto
python main.pySupported values:
auto→ Linux triespywinctl, thenwmctrl, thenxlib, thenpygetwindowpywinctlwmctrlxlibpygetwindow
Examples:
export VERSE_LISTENER_EW_WINDOW_BACKEND=pywinctl
export VERSE_LISTENER_EW_WINDOW_BACKEND=xlib- Open EasyWorship on the same machine.
- Click "Calibrate EW" in the VerseListener toolbar.
- You have 3 seconds to move your mouse cursor to the Bible search field in EasyWorship.
- VerseListener saves those coordinates.
- From now on, clicking "Send to EasyWorship" will:
- Focus the EasyWorship window
- Click the search field
- Type the verse reference (e.g.
Romans 8:28) - Press Enter
If EasyWorship is slow to respond, open Settings → EasyWorship and increase the delay values.
| Shortcut | Action |
|---|---|
Ctrl+R |
Start / stop listening |
Ctrl+Shift+S |
Send top queued verse to EasyWorship |
VerseListener detects all of these (and more):
Genesis 5:2
Gen 5:2
Genesis chapter 5 verse 2
Gen ch 5 v 2
Romans 8:28-30
book of Romans chapter 8 verses 28 through 30
Psalm 23
1 Corinthians 13:4
First Corinthians 13:4
Full list of supported books and abbreviations: see core/bible_detector.py.
verse_listener/
├── main.py # Entry point
├── requirements.txt
├── README.md
├── core/
│ ├── bible_detector.py # Verse pattern matching
│ ├── bible_preview.py # Local canon loading for verse preview
│ ├── transcription.py # Audio capture + STT threads
│ ├── easyworship.py # PyAutoGUI EasyWorship controller
│ └── settings.py # Persistent settings
└── ui/
├── main_window.py # Main application window
├── transcript_panel.py # Live transcription display
├── queue_panel.py # Detected verses queue
├── settings_dialog.py # Settings UI
└── styles.py # Dark/light QSS stylesheets
| Problem | Solution |
|---|---|
| No audio captured | Check JACK is running; or set backend to sounddevice in Settings |
| OpenAI realtime does not start | Check OPENAI_API_KEY in .env and confirm websocket-client is installed |
PortAudio library not found |
Install libportaudio2 (and, if needed, portaudio19-dev) then restart the app |
| Model takes long to load | First run downloads faster-whisper model; subsequent runs are fast |
| EasyWorship not focused | Re-run calibration; increase Focus Delay in Settings |
| Verse preview is blank | Check that the selected edition exists under canons/<EDITION>/verses.json |
PyGetWindow currently does not support Linux |
Set VERSE_LISTENER_EW_WINDOW_BACKEND=pywinctl, wmctrl, or xlib |
| PyAutoGUI fails on Linux | Install python3-xlib: sudo apt install python3-xlib |
| JACK auto-connect fails | Manually connect ports in QJackCtl |
GNU GPL v3.0 only (GPL-3.0-only) – see LICENSE.md.
