Skip to content

fix(grpc): forward word-level timestamps in AudioTranscription wrapper - #10402

Merged
mudler merged 1 commit into
mudler:masterfrom
fqscfqj:fix/grpc-forward-words
Jun 19, 2026
Merged

fix(grpc): forward word-level timestamps in AudioTranscription wrapper#10402
mudler merged 1 commit into
mudler:masterfrom
fqscfqj:fix/grpc-forward-words

Conversation

@fqscfqj

@fqscfqj fqscfqj commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Problem

The gRPC server wrapper in pkg/grpc/server.go reconstructs TranscriptSegment messages when relaying AudioTranscription results from backends to the HTTP layer. The Words field was not being copied, causing all word-level timestamps to be silently dropped — regardless of which backend produced them.

This explains why:

  • Issue [whisper] word timings in verbose_json #9306 reports words is always None in verbose_json output
  • Backends like faster-whisper, crispasr, qwen-asr, and nemo that populate word-level timestamps never actually surface them through the API

Root Cause

PR #9621 added the TranscriptWord proto message and transcriptResultFromProto (which reads s.Words on the server/HTTP side), but did not update the gRPC server wrapper (pkg/grpc/server.go) to forward the Words field when relaying results from the backend process.

Fix

Copy Words from the backend result into the gRPC response TranscriptSegment, converting each schema.TranscriptionWord to *proto.TranscriptWord.

Testing

Verified on a real deployment (LocalAI v4.4.3, Docker, RTX 3090) with the crispasr backend (parakeet-tdt-0.6b-v3):

Before (no words):

{"segments": [{"id": 0, "start": 0.16, "end": 10.48, "text": "Been playing lots of Nordic Souls recently."}]}

After (21 words):

{"segments": [{"id": 0, "start": 0.16, "end": 10.48, "text": "...", "words": [
  {"start": 0.16, "end": 0.4, "text": "Been"},
  {"start": 0.4, "end": 0.72, "text": "playing"},
  ...
]}]}

Fixes #9306

The gRPC server wrapper in pkg/grpc/server.go reconstructs
TranscriptSegment messages when relaying AudioTranscription results
from backends. The Words field was not being copied, causing all
word-level timestamps to be silently dropped regardless of backend
support.

This was introduced when PR mudler#9621 added the TranscriptWord proto
message and transcriptResultFromProto (server-side), but did not
update the server-side gRPC relay to forward the new field.

Fixes mudler#9306

Signed-off-by: fqscfqj <fqscfqj@outlook.com>
@fqscfqj
fqscfqj force-pushed the fix/grpc-forward-words branch from b4b0eba to 8d992b2 Compare June 19, 2026 10:44
fqscfqj added a commit to fqscfqj/LocalAI that referenced this pull request Jun 19, 2026
Add word-level timestamp extraction to the crispasr backend by calling
the CrispASR C library's word accessor functions that are already
exported by libgocraspasr but were not previously bound by the Go
wrapper.

Two families of word functions are supported:

1. Session-based (get_word_count/text/t0/t1) — works per-segment for
   whisper-like backends.
2. Parakeet-specific (get_parakeet_word_count/text/t0/t1) — returns a
   global word list for TDT/CTC/RNNT parakeet models where the session
   API does not expose per-segment word data.

The Go code tries session-based first and falls back to parakeet-specific
when the session word count is zero.

Depends on mudler#10402 (grpc server Words forwarding) for the words to reach
the HTTP response.

Signed-off-by: fqscfqj <fqscfqj@outlook.com>
@mudler
mudler merged commit 78d6822 into mudler:master Jun 19, 2026
1 check passed
mudler pushed a commit that referenced this pull request Jun 19, 2026
* feat(crispasr): add word-level timestamp support

Add word-level timestamp extraction to the crispasr backend by calling
the CrispASR C library's word accessor functions that are already
exported by libgocraspasr but were not previously bound by the Go
wrapper.

Two families of word functions are supported:

1. Session-based (get_word_count/text/t0/t1) — works per-segment for
   whisper-like backends.
2. Parakeet-specific (get_parakeet_word_count/text/t0/t1) — returns a
   global word list for TDT/CTC/RNNT parakeet models where the session
   API does not expose per-segment word data.

The Go code tries session-based first and falls back to parakeet-specific
when the session word count is zero.

Depends on #10402 (grpc server Words forwarding) for the words to reach
the HTTP response.

Signed-off-by: fqscfqj <fqscfqj@outlook.com>

* fix(crispasr): use portable sed -i.bak for macOS compatibility

BSD sed requires -i '' for in-place editing while GNU sed uses -i.
Replace with -i.bak which works on both platforms, then remove the
backup file.

Signed-off-by: fqscfqj <fqscfqj@outlook.com>

---------

Signed-off-by: fqscfqj <fqscfqj@outlook.com>
@localai-bot localai-bot added the bug Something isn't working label Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[whisper] word timings in verbose_json

3 participants