Files
LocalAI/backend/python/qwen-asr
番茄摔成番茄酱 4e5ec6f67b fix(qwen-asr): enable timestamp output when forced_aligner is configured (#10013)
* fix(qwen-asr): enable timestamp output when forced_aligner is configured

Two bugs prevented timestamps from working in the qwen-asr backend:

1. transcribe() was called without return_time_stamps=True, so the
   forced aligner was loaded but never invoked. Now we pass
   return_time_stamps=True when a forced_aligner is present.

2. The timestamp parsing code expected (list, tuple) items, but the
   qwen_asr library returns ForcedAlignItem dataclass instances with
   .text, .start_time, .end_time attributes. Added hasattr() check
   to handle this correctly, falling back to tuple parsing for
   backward compatibility.

* refactor: address Copilot review for qwen-asr timestamps

- Wrap return_time_stamps kwarg in try/except TypeError for safety
- Add defensive float() normalization for timestamp times
- Use str() for text extraction to ensure string type

* fix(qwen-asr): convert seconds to nanoseconds for Go time.Duration

The Go server reads TranscriptSegment.start/end via time.Duration,
which is in nanoseconds. Previously the backend sent milliseconds
(* 1000), causing timestamps to be 1000x too small (e.g. 8e-8
instead of 0.08). Convert seconds → nanoseconds (* 1e9) instead.

Also applies to the legacy tuple path for consistency.

* feat(qwen-asr): respect timestamp_granularities (segment vs word)

Read request.timestamp_granularities from the gRPC request.
- 'word': return one segment per aligned item (character / word)
- 'segment' (default): merge consecutive items at sentence boundaries

Sentence boundaries detected via CJK punctuation (。!?;…)
and Latin endings (. ! ? ;). This matches the OpenAI Whisper API
contract where omitting the parameter defaults to segment-level.

* fix(qwen-asr): escape smart quotes in punctuation set

Unicode curly quotes (U+2018/2019) were being interpreted as Python
string delimiters, causing SyntaxError. Use explicit unicode escapes.

* fix(qwen-asr): use time-gap threshold for segment boundaries

The forced aligner strips punctuation from its output, so text-based
sentence detection doesn't work. Instead, detect segment boundaries
by measuring time gaps between consecutive aligned items.

Threshold = max(median_gap * 4, 0.3s). This cleanly separates
intra-sentence gaps (< 0.24s) from inter-sentence gaps (> 0.3s)
across Chinese, English, and other languages.

* fix(qwen-asr): smart join with spaces for non-CJK tokens

The forced aligner strips whitespace from tokenized text, so English
words like ['hello', 'world'] were joined as 'helloworld'. Add
_smart_join() that inserts spaces between non-CJK tokens while
keeping CJK characters and punctuation unspaced. Works for Chinese,
English, Korean, Japanese, and mixed-language text.

---------

Co-authored-by: fqscfqj <fqsfqj@outlook.com>
2026-05-26 20:34:21 +00:00
..