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}*/}
+ {/* */}
+ {/*)}*/}
)}