HTTP 200 is not a usable transcript: a meeting-audio acceptance checklist
A transcription request returned text. Is it ready for meeting notes, subtitles or speaker-based editing? Treat transport, words, speakers and timing as separate acceptance questions. This article uses a FunASR MOSS result and a small standard-library Python checker to show what can be automated, and what still needs listening.

Four questions, four kinds of evidence
| Layer | Question | Not a substitute |
|---|---|---|
| Request and structure | Did the request complete with the expected fields, units and ordering? | HTTP 200 and nonempty JSON do not establish correctness. |
| Words | Are names, numbers, negations and decisions transcribed correctly? | Fluent text can still omit or invent speech. |
| Speakers | Are turns and overlapping speech assigned consistently? | Two output labels do not prove correct separation of two people. |
| Timing and coverage | Do subtitles locate the right sound? Are the beginning, middle and end covered? | An end timestamp near the recording duration does not prove complete transcription. |
VAD detects regions that may contain speech; ASR transcribes words; speaker diarization assigns anonymous speakers to speech regions. They answer different evaluation questions. A label such as S01 is local to a recording, not a name, an enrolled voiceprint or a cross-recording identity.
Choose the output contract for the application
MOSS-Transcribe-Diarize is a third-party model maintained by OpenMOSS. FunASR normalizes its output into text and timed segments with anonymous speaker labels. This path does not require an additional external VAD or speaker model. Do not arbitrarily split a meeting into independent requests and then assume that every chunk's S01 identifies the same person.
- Sentence subtitles or speaker clips: segment timestamps are an appropriate interface, but boundaries and speaker turns still need listening checks.
- Word highlighting or arbitrary text-based precision edits: segment timing is insufficient. Choose a path with the required character/word alignment, checking capabilities and supported languages, for example Paraformer. Dividing a sentence duration evenly does not create accurate word timing.
- Meeting notes: retain traceable transcript text, anonymous labels and time ranges before summarization. A summarizer cannot be assumed to repair incorrect names, numbers or decisions.
Version-specific installation belongs in the maintained MOSS deployment page and integration guide, not a second recipe that drifts independently. See the speaker-clipping walkthrough for FunClip boundaries and the model catalogue for selection.
A structural checker, not a quality evaluator
Download transcript-audit.py or read its source. It reads one file, makes no network requests and does not modify results. The input is one MOSS result object from FunASR AutoModel.generate(...)[0], also written as .moss-vllm.json by the repository's offline example. It is not raw vLLM diarized_json, SRT or the Qwen3 example's segments schema.
This deliberately constructed result represents a hypothetical 12-second recording. It is not model output and carries no accuracy claim:
{
"text": "Let's start. Agreed.",
"sentence_info": [
{"start": 1000, "end": 3500, "spk": "S01", "text": "Let's start."},
{"start": 6000, "end": 8000, "spk": "S02", "text": "Agreed."}
]
}
Use the example JSON as result.json. Units are milliseconds: pass 12000 for 12 seconds, not 12.
python3 transcript-audit.py result.json --duration-ms 12000
The report has segment_count=2, last_end_ms=8000 and tail_not_covered_ms=4000. It always returns quality_verified=false: it has neither heard the audio nor received human reference annotations. Synthetic cases, invalid fields and CLI behavior are regression-tested on Python 3.12. Those tests validate the checker, not the model. Rejecting zero-length segments is an additional acceptance policy here, not a guarantee that the model adapter always emits positive-length intervals.
- Missing
sentence_info, nonnumeric or infinite timing, reversed or zero-length intervals and intervals outside the recording produce an error and nonzero exit status. - Empty text, nonchronological starts and overlapping intervals are listed by zero-based index without rewriting the data. Overlap may be real simultaneous speech; do not delete it automatically. The checker sorts by start time, marking the original indices of segments that intersect an earlier-starting interval. Touching boundaries do not count as overlap.
- An empty result explicitly reports zero segments and the full uncovered tail. That may be reasonable for silence, but requires investigation for a meeting recording.
- The tail is only the distance from the last output interval to the recording end, not a duration of missed speech or a speech-recall metric. A missing sentence in the middle can coexist with a zero tail.
Move from structural checks to acceptance
- Freeze input and configuration. Retain the audio hash, duration, sample rate/channels, model revision, server version, response format and generation limit. Record resampling, channel mixing and trimming. Removing silence requires an offset map if timestamps must locate the original video.
- Listen at high-risk positions. Check the start and end, both sides of long silence, speaker changes, interruptions, quiet speech and critical numbers. Sampling can reveal problems; a successful sample is not proof of whole-recording accuracy.
- Evaluate text and speakers separately. With a human reference transcript, measure CER/WER under consistent punctuation, case and tokenization rules. With human speaker/time annotations, evaluate diarization. The number of distinct output labels is not a diarization acceptance test.
- Freeze the diarization scoring policy. pyannote.metrics provides speaker metrics. Boundary collars and whether overlapping speech is scored affect results. Compare systems on the same reference and configuration, not detached numbers.
- Diagnose incomplete output before tuning. Inspect termination due to generation limits, structural completeness and whether the client consumed the whole response. Raising a token limit may address some truncations, but cannot guarantee recall. A successful request is not grounds to close an unresolved user issue.
What should travel with the result?
Follow consent and retention requirements, store only necessary data, and restrict access to audio and speaker annotations. Retain the source-audio identifier, fixed configuration, original output, structural report and human acceptance notes. Link summaries back to transcript passages. Check subtitle readability, positioning and privacy. Replay edited clips instead of only checking interval lengths. Known-person identification needs a separate consent, enrollment and verification design; renaming anonymous cluster labels does not provide it.
This checker is an entry point into acceptance, not a leaderboard or a substitute for listening and annotation. Start a real workload through the deployment centre, then use the FunASR repository for implementation details or a minimal reproducible issue.
Sources and reproduction
- OpenMOSS project: ownership and task definition; the fixed-revision model card explains anonymous labels.
- Offline result-file contract inspected here: fixed repository commit; the MOSS branch writes one result object.
- Official pyannote.metrics implementation: diarization metrics and configuration. This article does not run or report DER, CER or WER.