From c0cc4b1c27dca16ab22c61160f15508b82748a4f Mon Sep 17 00:00:00 2001 From: chenhao Date: Fri, 26 Jun 2026 14:22:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=B8=8A=E6=B8=B8?= =?UTF-8?q?=E6=96=AD=E5=BC=80=E6=97=B6=E7=9A=84=E4=BC=9A=E8=AE=AE=E6=9A=82?= =?UTF-8?q?=E5=81=9C=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AE=9E=E6=97=B6=E8=BD=AC=E5=BD=95=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 `RealtimeAsrSession` 组件中添加 `handleUpstreamPauseError` 方法,处理上游断开时的会议暂停 - 更新 `LocalRealtimeAsrChannel` 类,移除不必要的回调调用 - 优化 `RealtimeMeetingTranscriptCacheServiceImpl` 中的说话人解析逻辑 - 移除 `RealtimeAsrSession` 组件中部分未使用的实时转录显示字段 --- .../impl/LocalRealtimeAsrChannel.java | 2 +- ...timeMeetingTranscriptCacheServiceImpl.java | 2 +- .../src/pages/business/RealtimeAsrSession.tsx | 52 ++++++++++++++----- 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/com/imeeting/service/realtime/impl/LocalRealtimeAsrChannel.java b/backend/src/main/java/com/imeeting/service/realtime/impl/LocalRealtimeAsrChannel.java index 5b03acc..cddc277 100644 --- a/backend/src/main/java/com/imeeting/service/realtime/impl/LocalRealtimeAsrChannel.java +++ b/backend/src/main/java/com/imeeting/service/realtime/impl/LocalRealtimeAsrChannel.java @@ -513,7 +513,6 @@ public class LocalRealtimeAsrChannel implements RealtimeAsrChannel { log.info("上游 ASR websocket 已关闭:meetingId={}, sessionId={}, code={}, reason={}", context.getMeetingId(), currentConnectionId(context), statusCode, reason); context.getChannelState().remove(STATE_UPSTREAM_SOCKET); - context.getCallback().removeMeetingSession(context.getMeetingId()); context.getCallback().sendFrontendError(context.getMeetingId(), "REALTIME_UPSTREAM_CLOSED", reason == null || reason.isBlank() ? "上游 ASR WebSocket 已断开" : "上游 ASR WebSocket 已断开: " + reason); @@ -533,6 +532,7 @@ public class LocalRealtimeAsrChannel implements RealtimeAsrChannel { ? "上游 ASR WebSocket 连接异常" : "上游 ASR WebSocket 连接异常: " + error.getMessage()); context.getCallback().closeFrontend(context.getMeetingId(), CloseStatus.SERVER_ERROR); + context.getCallback().removeMeetingSession(context.getMeetingId()); } } } diff --git a/backend/src/main/java/com/imeeting/service/realtime/impl/RealtimeMeetingTranscriptCacheServiceImpl.java b/backend/src/main/java/com/imeeting/service/realtime/impl/RealtimeMeetingTranscriptCacheServiceImpl.java index 235b14a..9ca0098 100644 --- a/backend/src/main/java/com/imeeting/service/realtime/impl/RealtimeMeetingTranscriptCacheServiceImpl.java +++ b/backend/src/main/java/com/imeeting/service/realtime/impl/RealtimeMeetingTranscriptCacheServiceImpl.java @@ -206,7 +206,7 @@ public class RealtimeMeetingTranscriptCacheServiceImpl implements RealtimeMeetin return item.getSpeakerName().trim(); } String speakerId = resolveSpeakerId(item); - return speakerId == null || speakerId.isBlank() ? null : speakerId; + return speakerId == null || speakerId.isBlank() ? null : "未知说话人" + speakerId; } private String resolveSpeakerId(JsonNode sentence) { diff --git a/frontend/src/pages/business/RealtimeAsrSession.tsx b/frontend/src/pages/business/RealtimeAsrSession.tsx index e7a6cc4..2dbd793 100644 --- a/frontend/src/pages/business/RealtimeAsrSession.tsx +++ b/frontend/src/pages/business/RealtimeAsrSession.tsx @@ -442,6 +442,30 @@ export function RealtimeAsrSession() { message.error(errorMessage); }; + const handleUpstreamPauseError = async (errorMessage: string) => { + if (recording && startedAtRef.current) { + elapsedOffsetRef.current += Math.floor((Date.now() - startedAtRef.current) / 1000); + } + setConnecting(false); + setRecording(false); + setStatusText("上游识别已断开,正在暂停会议..."); + sessionStartedRef.current = false; + wsRef.current?.close(); + wsRef.current = null; + await shutdownAudioPipeline(); + startedAtRef.current = null; + try { + const pauseRes = await pauseRealtimeMeeting(meetingId); + setSessionStatus(pauseRes.data.data); + setElapsedSeconds(elapsedOffsetRef.current); + setStatusText("已暂停,可继续会议"); + message.error(errorMessage); + } catch { + setStatusText("识别已断开"); + message.error(errorMessage); + } + }; + const startAudioPipeline = async () => { if (!window.isSecureContext || !navigator.mediaDevices?.getUserMedia) { throw new Error("当前浏览器环境不支持麦克风访问。请使用 localhost 或 HTTPS 域名访问系统。"); @@ -585,7 +609,11 @@ export function RealtimeAsrSession() { if ((payload.code || payload.type === "error") && payload.message) { setStatusText(payload.message); - void handleFatalRealtimeError(payload.message); + if (payload.code === "REALTIME_UPSTREAM_CLOSED" || payload.code === "REALTIME_UPSTREAM_ERROR") { + void handleUpstreamPauseError(payload.message); + } else { + void handleFatalRealtimeError(payload.message); + } return; } @@ -804,17 +832,17 @@ export function RealtimeAsrSession() { 字数 {totalTranscriptChars} - - 模型 {sessionDraft.asrModelName} - - - 模式 {sessionDraft.mode} - - {sessionDraft.hotwords && sessionDraft.hotwords.length > 0 && ( - - 热词 {sessionDraft.hotwords.length} - - )} + {/**/} + {/* 模型 {sessionDraft.asrModelName}*/} + {/**/} + {/**/} + {/* 模式 {sessionDraft.mode}*/} + {/**/} + {/*{sessionDraft.hotwords && sessionDraft.hotwords.length > 0 && (*/} + {/* */} + {/* 热词 {sessionDraft.hotwords.length}*/} + {/* */} + {/*)}*/} )}