On-device speech-to-text with speaker diarization, powered by Apple Intelligence & CAM++
δΈζη | English
ohr-speaker is an enhanced fork of ohr that integrates three speaker diarization engines β including CAM++ (ιΏιθΎΎζ©ι’) and FluidAudio β on top of the original Apple SpeechAnalyzer transcription engine.
100% on-device. No cloud. No API keys. Your data never leaves your machine.
- π€ Apple Intelligence Transcription β Powered by macOS SpeechAnalyzer, millisecond latency
- π£οΈ Three Diarization Engines β CAM++, Offline VBx (WeSpeaker), or Sortformer (
--engineflag) - π¨π³ Chinese-Optimized β CAM++ model trained on 200k Chinese speakers, ~15MB model
- π Multiple Output Formats β Plain text, JSON, SRT subtitles, VTT subtitles with speaker labels
- ποΈ Live Microphone Transcription β Real-time
--listenmode - π₯οΈ OpenAI-Compatible Server β
--servemode, compatible with OpenAI Whisper API - π¦ Multi-format Support β m4a, wav, mp3, mp4, caf, aiff, flac
- π Privacy First β All processing is local, no data uploaded
Download a pre-built binary from Releases:
| Binary | Default Engine | Model Size |
|---|---|---|
ohr-cam |
CAM++ (default) | ~15 MB |
ohr-speaker |
Offline VBx (WeSpeaker) | ~700 MB |
# CAM++ engine (~15 MB model, auto-downloaded on first use)
ohr-cam --speakers meeting.wav
# Or offline VBx engine (legacy, ~700 MB model)
ohr-speaker --speakers meeting.wavgit clone https://github.com/yanhuicsdn/ohr-speaker.git
cd ohr-speaker
# Using Xcode-beta toolchain (macOS 27+)
DEVELOPER_DIR="/Applications/Xcode-beta.app/Contents/Developer" swift build -c release
# Using Xcode stable (macOS 26+)
swift build -c release
# Copy the binary to your PATH
cp .build/release/ohr /usr/local/bin/ohr-speaker- macOS 26+ (Apple Silicon)
- Xcode 26.6+ or Xcode-beta 27+
ohr-speaker audio.wavohr-speaker --speakers audio.wavSample output:
γS1γ
There is usually a platform management layer with a user center...
γS2γ
Give them the full version so they can use it...
γS1γ
Yes, provincial business layers have isolation requirements for permissions...
# CAM++ (default) β ιΏιθΎΎζ©ι’, 200k Chinese speakers, ~15MB model
ohr-speaker --speakers --engine campplus audio.wav
# Offline VBx (WeSpeaker) β ~700MB model, PLDA scoring
ohr-speaker --speakers --engine offlineVbx audio.wav
# Sortformer β ~200MB model, β€4 speakers, CoreML ANE accelerated
ohr-speaker --speakers --engine sortformer audio.wavohr-speaker --speakers -o srt audio.wav > subtitles.srtohr-speaker --speakers -o json audio.wavohr-speaker --listen --speakersohr-speaker --serve --port 11434Then call from any OpenAI Whisper client:
curl http://localhost:11434/v1/audio/transcriptions \
-F "file=@audio.wav" \
-F "model=whisper-1" \
-F "diarize=true"USAGE:
ohr <file> Transcribe an audio file
ohr -o srt <file> Transcribe to SRT subtitles
ohr -o vtt <file> Transcribe to VTT subtitles
ohr -o json <file> Transcribe to JSON with segments
ohr --listen Live microphone transcription
ohr --serve Start OpenAI-compatible HTTP server
cat audio.wav | ohr Transcribe from stdin
OPTIONS:
-o, --output <format> Output: plain (default), json, srt, vtt
--json Shorthand for -o json
--srt Shorthand for -o srt
--vtt Shorthand for -o vtt
--timestamps Show timestamps in plain text output
--speakers Enable speaker diarization
--engine <name> Diarization engine: campplus, offlineVbx, sortformer
-l, --language <code> Language code (e.g. en-US, de-DE)
-q, --quiet Suppress headers and chrome
--no-color Disable ANSI colors
SERVER OPTIONS:
--serve Start HTTP server
--port <n> Server port (default: 11434, env: OHR_PORT)
--host <addr> Bind address (default: 127.0.0.1, env: OHR_HOST)
--cors Enable CORS headers
--allowed-origins <list> Comma-separated allowed origins
--no-origin-check Disable origin validation
--token <secret> Require Bearer token (env: OHR_TOKEN)
--token-auto Generate random token on startup
--public-health /health without auth on non-loopback
--footgun Disable all protections (DANGEROUS)
--max-concurrent <n> Max concurrent requests (default: 5)
--debug Enable /v1/logs endpoints
INFO:
-h, --help Show this help
-v, --version Show version
--release Show detailed build info
--model-info Show model capabilities
| Engine | Model | Parameters | Size | Speakers | M4 Accel. | Language Bias |
|---|---|---|---|---|---|---|
| CAM++ β | ιΏιθΎΎζ©ι’ CAM++ | 7.2M | ~15 MB | unlimited | GPU | Chinese β |
| Offline VBx | WeSpeaker + PLDA | ~25M | ~700 MB | unlimited | ANE β | Multi |
| Sortformer | FluidAudio Sortformer | β | ~200 MB | β€4 | ANE β | Multi |
| LSβEEND β | dihard3 EEND | β | ~44 MB | unlimited | CoreML | English only |
Benchmark (2-speaker Chinese podcast, 17 min):
| Engine | Segments | S1 | S2 | First-run download |
|---|---|---|---|---|
| CAM++ β | 22 | 11 | 11 | ~5 sec |
| Offline VBx | 26 | 13 | 13 | ~2 min |
| Sortformer | 26 | 13 | 13 | ~1 min |
CAM++ is the recommended engine for Chinese audio β smallest model, fastest download, specifically trained on 200k Chinese speakers by Alibaba DAMO Academy.
| Audio Duration | Transcription Only | Additional Diarization |
|---|---|---|
| 1 min | ~1s | ~1s |
| 10 min | ~3s | ~2s |
| 31 min | ~10s | ~5s |
| 1 hour | ~20s | ~10s |
- Transcription: Uses Apple's
SpeechAnalyzer+SpeechTranscriberframework to convert audio into timestamped text segments - Diarization: One of three engines:
- CAM++: FluidAudio segmentation β independent CAM++ embedding extractor (192-d) β cosine agglomerative clustering
- Offline VBx: FluidAudio's full pipeline (Seg-3 + WeSpeaker + PLDA + VBx)
- Sortformer: FluidAudio's end-to-end Sortformer (β€4 speakers, CoreML ANE)
- Alignment: Uses a time-overlap-maximization algorithm to align transcription segments with speaker segments
| Variable | Description |
|---|---|
OHR_PORT |
Server port (default: 11434) |
OHR_HOST |
Server bind address (default: 127.0.0.1) |
OHR_TOKEN |
Bearer token for server auth |
OHR_LANGUAGE |
Default language code |
REGISTRY_URL |
Model download mirror (e.g. https://hf-mirror.com) |
NO_COLOR |
Disable ANSI colors |
| Feature | ohr | ohr-speaker |
|---|---|---|
| Speaker Diarization | β | β
--speakers |
| Transcription Engine | Apple SpeechAnalyzer | Apple SpeechAnalyzer |
| Diarization Engine | β | CAM++ (default) / Offline VBx / Sortformer |
| Model Download | 0 MB | ~15 MB (CAM++) or ~700 MB (VBx) |
| Engine Selection | β | --engine flag |
| Output Formats | plain/json/srt/vtt | plain/json/srt/vtt + speaker labels |
| Server Mode | β | β
(supports diarize parameter) |
| Engine | Cache Path | Size |
|---|---|---|
| CAM++ | ~/Library/Application Support/ohr-campplus/ |
~15 MB |
| FluidAudio | ~/Library/Application Support/FluidAudio/Models/ |
~700 MB |
- Arthur-Ficial/ohr β The original ohr project
- FluidInference/FluidAudio β FluidAudio diarization engine
- 3D-Speaker / FunASR β CAM++ speaker embedding by Alibaba DAMO Academy
- Apple Speech Framework β macOS built-in speech recognition capabilities