Add handy-computer/moss-transcribe-diarize-gguf to the Local Native ASR catalog. It is the only model in the transcribe.cpp family that adds a capability dimension our ASR roster lacks entirely: speaker diarization.
Surfaced while enumerating the full handy-computer GGUF family (68 models; we currently ship 15).
The honest catch: one catalog row ≠ one feature
Adding the row is trivial. Realising the value is not. MOSS emits the canonical diarized format [start][Sxx]text[end], and per the model card the speaker tags and segment timestamps are generated text, not special tokens.
So there are two distinct pieces of work:
- The catalog row — makes the model run. On its own this only buys us another offline en/zh ASR card at WER 1.93, which is worse than Cohere Transcribe (1.25) and narrower than most of the roster. Not worth doing by itself.
- The diarization plumbing — parse
[Sxx] out of the transcript, carry speaker identity through the translate stage, and surface it in the conversation items / subtitle overlay. This is where all the value is, and none of it exists today.
This issue should not be closed by landing step 1 alone.
Why it is interesting anyway
- Speaker-attributed translation is a real product capability for our core use case (multi-participant meetings: Meet / Teams / Zoom). Today every speaker collapses into one undifferentiated transcript stream.
- It is Apache-2.0 and an official
handy-computer GGUF, i.e. it lands on transcribe_cpp — the backend all 15 of our ASR cards already use. No new runtime, no new dependency, no torch.
- Accuracy is competitive: WER 1.93 on the author's uniform LibriSpeech test-clean benchmark — it would slot between Parakeet TDT 0.6B v3 (1.92) and Whisper large-v3-turbo (2.01).
Model facts (verified 2026-07-16 via HF API + model card)
|
|
| Repo |
handy-computer/moss-transcribe-diarize-gguf |
| Base |
OpenMOSS-Team/MOSS-Transcribe-Diarize |
| License |
Apache-2.0 |
| Architecture |
0.9B audio-LLM — Whisper-Medium encoder (24L, d_model 1024) → 4x temporal merge + VQAdaptor bridge → Qwen3-0.6B decoder (28L), via audio-token injection |
| Languages |
en, zh only |
| Streaming |
No (offline, whole-clip) |
| Timestamps |
segment |
| Output |
[start][Sxx]text[end] — tags/timestamps are generated text |
Quant ladder + WER (LibriSpeech test-clean, author's runner)
| Quant |
Size |
WER |
| F16 |
1,833,665,696 |
2.07 |
| Q8_0 |
986,899,616 |
1.93 ← best |
| Q6_K |
768,151,712 |
1.96 |
| Q5_K_M |
700,313,760 |
1.99 |
| Q4_K_M |
617,345,184 |
2.59 ⚠️ |
Note Q8_0 (1.93) beats BF16 (2.08) — same quirk as Fun-ASR MLT Nano, where q6_k beats bf16. So default = Q8_0.
⚠️ Q4_K_M must not be recommended. Its excess WER is not broad degradation but 4-bit tail failures: 6 empty outputs, 5 English→Chinese language-drift utterances, and 1 timestamp-token repetition loop. The card says "Prefer Q5_K_M or higher". Language drift in a translation app is a user-visible correctness bug.
This collides with _tc_row's hardcoded curated = {"q8_0", "q6_k", "q4_k_m"}, which would give q4_k_m rank 1.0 (a recommendation candidate). Cleanest fix: omit Q4_K_M from the quants dict entirely so it is never offered. Alternative: add a per-row curated= override.
Speed (author-reported)
| Machine |
Tier |
RTF |
| M4 Max |
metal |
28.1 |
| M4 Max |
cpu |
5.8 |
| Ryzen 4750U |
vulkan |
3.0 |
| Ryzen 4750U |
cpu |
1.6 |
Real-time on a modest CPU, comfortable on GPU.
Proposed catalog row
In sidecar/sokuji_sidecar/catalog.py, ASR_MODELS (sort_order 85 = between parakeet 80 and turbo 90):
# WER 1.93 (q8_0 beats bf16 2.08) — en/zh + speaker diarization.
# Q4_K_M deliberately omitted: 4-bit tail failures incl. en->zh language drift.
_tc_row("moss-transcribe-diarize", "MOSS Transcribe-Diarize", ("en", "zh"),
"handy-computer/moss-transcribe-diarize-gguf", "MOSS-Transcribe-Diarize",
85, {"F16": 1833665696, "Q8_0": 986899616, "Q6_K": 768151712,
"Q5_K_M": 700313760}, default="Q8_0"),
Open questions
- Pipeline shape: our ASR stage returns plain text. Where do the
[Sxx] tags get parsed — sidecar-side (return structured segments) or renderer-side? Sidecar-side is probably right, but it changes the ASR result contract, which every other card shares.
- Downstream: how does speaker identity survive the translate stage and reach conversation items + the subtitle overlay? Does the subtitle wire format need a speaker field? (Careful: see the heavy-field lesson from the subtitle port.)
- Is diarization even useful without streaming? This is an offline whole-clip model. It fits our existing non-streaming ASR flow, but a diarized live transcript may be what users actually want.
multitalker-parakeet-streaming-0.6b-v1-gguf is the streaming alternative in the same family — worth comparing before committing.
- UI: how are speakers labelled to the user?
S01/S02 are meaningless; are they mappable to real participants?
- en/zh only — is that enough coverage to justify the feature work?
References
Add
handy-computer/moss-transcribe-diarize-ggufto the Local Native ASR catalog. It is the only model in the transcribe.cpp family that adds a capability dimension our ASR roster lacks entirely: speaker diarization.Surfaced while enumerating the full
handy-computerGGUF family (68 models; we currently ship 15).The honest catch: one catalog row ≠ one feature
Adding the row is trivial. Realising the value is not. MOSS emits the canonical diarized format
[start][Sxx]text[end], and per the model card the speaker tags and segment timestamps are generated text, not special tokens.So there are two distinct pieces of work:
[Sxx]out of the transcript, carry speaker identity through the translate stage, and surface it in the conversation items / subtitle overlay. This is where all the value is, and none of it exists today.This issue should not be closed by landing step 1 alone.
Why it is interesting anyway
handy-computerGGUF, i.e. it lands ontranscribe_cpp— the backend all 15 of our ASR cards already use. No new runtime, no new dependency, no torch.Model facts (verified 2026-07-16 via HF API + model card)
handy-computer/moss-transcribe-diarize-ggufOpenMOSS-Team/MOSS-Transcribe-Diarize[start][Sxx]text[end]— tags/timestamps are generated textQuant ladder + WER (LibriSpeech test-clean, author's runner)
Note Q8_0 (1.93) beats BF16 (2.08) — same quirk as Fun-ASR MLT Nano, where q6_k beats bf16. So default = Q8_0.
This collides with
_tc_row's hardcodedcurated = {"q8_0", "q6_k", "q4_k_m"}, which would give q4_k_m rank 1.0 (a recommendation candidate). Cleanest fix: omit Q4_K_M from thequantsdict entirely so it is never offered. Alternative: add a per-rowcurated=override.Speed (author-reported)
Real-time on a modest CPU, comfortable on GPU.
Proposed catalog row
In
sidecar/sokuji_sidecar/catalog.py,ASR_MODELS(sort_order 85 = between parakeet 80 and turbo 90):Open questions
[Sxx]tags get parsed — sidecar-side (return structured segments) or renderer-side? Sidecar-side is probably right, but it changes the ASR result contract, which every other card shares.multitalker-parakeet-streaming-0.6b-v1-ggufis the streaming alternative in the same family — worth comparing before committing.S01/S02are meaningless; are they mappable to real participants?References
sidecar/sokuji_sidecar/catalog.py(_tc_row,ASR_MODELS)