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