调整气泡累积逻辑
parent
b9fa3e4d5c
commit
fb710fadff
|
|
@ -2021,14 +2021,23 @@ class Qwen3ASRService:
|
|||
self,
|
||||
ctx: ConnectionContext,
|
||||
text: str,
|
||||
*,
|
||||
native_stream_snapshot: bool = False,
|
||||
) -> str:
|
||||
"""Expose only newly stabilized prefixes; the final event carries revisions."""
|
||||
"""Publish a growing preview while leaving Qwen's revisable tail for finalization."""
|
||||
if native_stream_snapshot:
|
||||
# Native Qwen text is a rolling snapshot. Exposing its unstable tail
|
||||
# can make the next correction fail the append-only check and freeze
|
||||
# the bubble at its first preview. Only publish the confirmed prefix.
|
||||
candidate = ctx.stable_partial_prefix.strip()
|
||||
else:
|
||||
candidate = self._partial_display_text(ctx, text)
|
||||
|
||||
previous = ctx.partial_preview_text
|
||||
if not previous or candidate.startswith(previous):
|
||||
if candidate and (not previous or candidate.startswith(previous)):
|
||||
ctx.partial_preview_text = candidate
|
||||
# Qwen may rewrite its rolling snapshot. Keep the already shown prefix
|
||||
# fixed until finalization so the browser never retracts earlier words.
|
||||
# If Qwen revises already published text, keep the preview fixed. The
|
||||
# final segment event will replace it with the model's finalized result.
|
||||
return ctx.partial_preview_text
|
||||
|
||||
def _is_suspicious_segment_text(
|
||||
|
|
@ -3150,6 +3159,7 @@ class Qwen3ASRService:
|
|||
partial_display = self._append_only_partial_preview(
|
||||
ctx,
|
||||
visible_observed,
|
||||
native_stream_snapshot=has_native_stream_snapshot,
|
||||
)
|
||||
partial_display = self._clip_partial_text(partial_display, ctx)
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -4211,24 +4211,34 @@ ${transcript}
|
|||
) {
|
||||
const safeText = (text || "").trim();
|
||||
if (!safeText) return;
|
||||
if (partial && state.liveTranscript.length) {
|
||||
const last = state.liveTranscript[state.liveTranscript.length - 1];
|
||||
if (last.partial && (segmentIndex === null || last.segmentIndex === segmentIndex)) {
|
||||
last.label = label;
|
||||
last.text = safeText;
|
||||
last.speaker = speaker;
|
||||
last.speakerPending = speakerPending;
|
||||
last.segmentIndex = segmentIndex;
|
||||
last.speakerKey = speakerKey || last.speakerKey || (segmentIndex === null ? "unknown" : `segment-${segmentIndex}`);
|
||||
last.startTimeMs = startTimeMs;
|
||||
last.endTimeMs = endTimeMs;
|
||||
if (partial) {
|
||||
const existingPartialIndex = state.liveTranscript.findIndex(
|
||||
(item) => item.partial && (segmentIndex === null || item.segmentIndex === segmentIndex),
|
||||
);
|
||||
if (existingPartialIndex >= 0) {
|
||||
const existingPartial = state.liveTranscript[existingPartialIndex];
|
||||
existingPartial.label = label;
|
||||
existingPartial.text = safeText;
|
||||
existingPartial.speaker = speaker;
|
||||
existingPartial.speakerPending = speakerPending;
|
||||
existingPartial.segmentIndex = segmentIndex;
|
||||
existingPartial.speakerKey = speakerKey || existingPartial.speakerKey || (segmentIndex === null ? "unknown" : `segment-${segmentIndex}`);
|
||||
existingPartial.startTimeMs = startTimeMs;
|
||||
existingPartial.endTimeMs = endTimeMs;
|
||||
renderLiveTranscript();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!partial && state.liveTranscript.length) {
|
||||
const last = state.liveTranscript[state.liveTranscript.length - 1];
|
||||
if (last.partial) state.liveTranscript.pop();
|
||||
if (!partial) {
|
||||
// A late speaker update for an older segment must not erase the live preview.
|
||||
const partialIndex = state.liveTranscript.findIndex(
|
||||
(item) => item.partial && (
|
||||
segmentIndex === null
|
||||
? item.segmentIndex === null
|
||||
: item.segmentIndex === segmentIndex
|
||||
),
|
||||
);
|
||||
if (partialIndex >= 0) state.liveTranscript.splice(partialIndex, 1);
|
||||
}
|
||||
|
||||
if (!partial && segmentIndex !== null) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue