feat: 添加上游断开时的会议暂停处理逻辑并优化实时转录显示
- 在 `RealtimeAsrSession` 组件中添加 `handleUpstreamPauseError` 方法,处理上游断开时的会议暂停 - 更新 `LocalRealtimeAsrChannel` 类,移除不必要的回调调用 - 优化 `RealtimeMeetingTranscriptCacheServiceImpl` 中的说话人解析逻辑 - 移除 `RealtimeAsrSession` 组件中部分未使用的实时转录显示字段dev_na
parent
bf40b13383
commit
c0cc4b1c27
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
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() {
|
|||
<Text type="secondary" style={{ fontSize: 13 }}>
|
||||
字数 <strong style={{ color: "#334155" }}>{totalTranscriptChars}</strong>
|
||||
</Text>
|
||||
<Text type="secondary" style={{ fontSize: 13 }}>
|
||||
模型 <strong style={{ color: "#334155" }}>{sessionDraft.asrModelName}</strong>
|
||||
</Text>
|
||||
<Text type="secondary" style={{ fontSize: 13 }}>
|
||||
模式 <strong style={{ color: "#334155" }}>{sessionDraft.mode}</strong>
|
||||
</Text>
|
||||
{sessionDraft.hotwords && sessionDraft.hotwords.length > 0 && (
|
||||
<Text type="secondary" style={{ fontSize: 13 }}>
|
||||
热词 <strong style={{ color: "#334155" }}>{sessionDraft.hotwords.length}</strong>
|
||||
</Text>
|
||||
)}
|
||||
{/*<Text type="secondary" style={{ fontSize: 13 }}>*/}
|
||||
{/* 模型 <strong style={{ color: "#334155" }}>{sessionDraft.asrModelName}</strong>*/}
|
||||
{/*</Text>*/}
|
||||
{/*<Text type="secondary" style={{ fontSize: 13 }}>*/}
|
||||
{/* 模式 <strong style={{ color: "#334155" }}>{sessionDraft.mode}</strong>*/}
|
||||
{/*</Text>*/}
|
||||
{/*{sessionDraft.hotwords && sessionDraft.hotwords.length > 0 && (*/}
|
||||
{/* <Text type="secondary" style={{ fontSize: 13 }}>*/}
|
||||
{/* 热词 <strong style={{ color: "#334155" }}>{sessionDraft.hotwords.length}</strong>*/}
|
||||
{/* </Text>*/}
|
||||
{/*)}*/}
|
||||
</Space>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue