feat: 结束视频后保留对话,支持继续文字聊天
- useVisionSession 新增 stopVideo 回调(停媒体流,保持连接和消息) - App.tsx 控制区从二态改为三态(initial/video/textOnly) - 文字对话态显示「重新开始视频」和「结束会话」按钮 - 新增 CSS 样式(video-ended-hint、btn--outline) - 新增 i18n key(stopVideo/endSession/resumeVideo/video.ended) - 新增设计方案文档
This commit is contained in:
@@ -1503,6 +1503,48 @@ body {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* ---- Text-only mode (video ended, chat preserved) ---- */
|
||||
|
||||
.video-controls__text-only {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.video-ended-hint {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.video-ended-hint__title {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.video-ended-hint__sub {
|
||||
font-size: 0.7rem;
|
||||
color: var(--color-text-muted);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.btn--outline {
|
||||
background: transparent;
|
||||
border: 1px solid var(--color-border);
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.btn--outline:hover {
|
||||
background: var(--color-surface-2);
|
||||
color: var(--color-text);
|
||||
border-color: var(--color-surface-3);
|
||||
}
|
||||
|
||||
/* ---- Scene Cards (empty state) ---- */
|
||||
|
||||
.scene-cards {
|
||||
|
||||
@@ -80,6 +80,7 @@ function AppContent() {
|
||||
isObserving,
|
||||
startSession,
|
||||
stopSession,
|
||||
stopVideo,
|
||||
interrupt,
|
||||
isCameraOn,
|
||||
isMicOn,
|
||||
@@ -397,9 +398,9 @@ function AppContent() {
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
) : isCameraOn ? (
|
||||
<>
|
||||
{/* 通话态:核心控制工具栏 */}
|
||||
{/* 视频通话态:核心控制工具栏 */}
|
||||
<div className="video-controls__toolbar">
|
||||
<button
|
||||
className={`btn btn--ctrl ${isCameraOn ? "btn--ctrl-on" : "btn--ctrl-off"}`}
|
||||
@@ -430,8 +431,8 @@ function AppContent() {
|
||||
{tr("controls.interrupt")}
|
||||
</button>
|
||||
)}
|
||||
<button className="btn btn--danger" onClick={stopSession}>
|
||||
{tr("controls.stop")}
|
||||
<button className="btn btn--danger" onClick={stopVideo}>
|
||||
{tr("controls.stopVideo")}
|
||||
</button>
|
||||
</div>
|
||||
{/* 通话态模式切换 */}
|
||||
@@ -456,6 +457,24 @@ function AppContent() {
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/* 文字对话态:视频已结束 */}
|
||||
<div className="video-controls__text-only">
|
||||
<div className="video-ended-hint">
|
||||
<span className="video-ended-hint__title">📹 {tr("video.ended")}</span>
|
||||
<span className="video-ended-hint__sub">{tr("video.ended.hint")}</span>
|
||||
</div>
|
||||
<div className="video-controls__toolbar">
|
||||
<button className="btn btn--primary" onClick={startSession}>
|
||||
{tr("controls.resumeVideo")}
|
||||
</button>
|
||||
<button className="btn btn--danger btn--outline" onClick={stopSession}>
|
||||
{tr("controls.endSession")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -363,6 +363,22 @@ export function useVisionSession(accessToken?: string | null) {
|
||||
setIsMicOn(false);
|
||||
}, [stopObserving, stopVAD, stopMic, stopCamera, disconnect]);
|
||||
|
||||
/** 结束视频,保留聊天和连接 */
|
||||
const stopVideo = useCallback(async () => {
|
||||
stopObserving();
|
||||
setMode("dialogue");
|
||||
await stopVAD();
|
||||
stopMic();
|
||||
stopCamera();
|
||||
ttsPlayerRef.current?.stop();
|
||||
setIsAudioPlaying(false);
|
||||
setCurrentReply("");
|
||||
setIsProcessing(false);
|
||||
setIsCameraOn(false);
|
||||
setIsMicOn(false);
|
||||
// 不断开 WebSocket,不清空消息、历史、统计
|
||||
}, [stopObserving, stopVAD, stopMic, stopCamera]);
|
||||
|
||||
/** 摄像头开关 */
|
||||
const toggleCamera = useCallback(async () => {
|
||||
if (isCameraOn) {
|
||||
@@ -479,6 +495,7 @@ export function useVisionSession(accessToken?: string | null) {
|
||||
toggleMode,
|
||||
startSession,
|
||||
stopSession,
|
||||
stopVideo,
|
||||
interrupt,
|
||||
isCameraOn,
|
||||
isMicOn,
|
||||
|
||||
@@ -51,6 +51,8 @@ export const enUS: TranslationMap = {
|
||||
"video.placeholder": "Type in the chat panel to start",
|
||||
"video.cameraOff": "Camera is off",
|
||||
"video.cameraOff.hint": "You can type in the chat panel",
|
||||
"video.ended": "Video Ended",
|
||||
"video.ended.hint": "You can continue chatting below",
|
||||
|
||||
// Controls
|
||||
"controls.connecting": "Connecting...",
|
||||
@@ -64,6 +66,9 @@ export const enUS: TranslationMap = {
|
||||
"controls.observation": "👁️ Observe",
|
||||
"controls.interrupt": "⏹ Interrupt",
|
||||
"controls.stop": "End Session",
|
||||
"controls.stopVideo": "End Video",
|
||||
"controls.endSession": "End Session",
|
||||
"controls.resumeVideo": "📹 Resume Video",
|
||||
|
||||
// Chat panel
|
||||
"chat.title": "Chat",
|
||||
|
||||
@@ -51,6 +51,8 @@ export const jaJP: TranslationMap = {
|
||||
"video.placeholder": "右側のチャットに入力して開始",
|
||||
"video.cameraOff": "カメラがオフです",
|
||||
"video.cameraOff.hint": "右側のチャットでテキスト対話ができます",
|
||||
"video.ended": "ビデオ終了",
|
||||
"video.ended.hint": "下にテキストを入力して会話を続けることができます",
|
||||
|
||||
// Controls
|
||||
"controls.connecting": "接続中...",
|
||||
@@ -64,6 +66,9 @@ export const jaJP: TranslationMap = {
|
||||
"controls.observation": "👁️ 観察モード",
|
||||
"controls.interrupt": "⏹ 中断",
|
||||
"controls.stop": "対話を終了",
|
||||
"controls.stopVideo": "ビデオ終了",
|
||||
"controls.endSession": "セッション終了",
|
||||
"controls.resumeVideo": "📹 ビデオ再開",
|
||||
|
||||
// Chat panel
|
||||
"chat.title": "チャット",
|
||||
|
||||
@@ -51,6 +51,8 @@ export const zhCN: TranslationMap = {
|
||||
"video.placeholder": "在右侧聊天框输入即可开始对话",
|
||||
"video.cameraOff": "摄像头未开启",
|
||||
"video.cameraOff.hint": "可在右侧聊天框打字对话",
|
||||
"video.ended": "视频已结束",
|
||||
"video.ended.hint": "您可以继续在下方输入文字对话",
|
||||
|
||||
// Controls
|
||||
"controls.connecting": "连接中...",
|
||||
@@ -64,6 +66,9 @@ export const zhCN: TranslationMap = {
|
||||
"controls.observation": "👁️ 观察模式",
|
||||
"controls.interrupt": "⏹ 打断",
|
||||
"controls.stop": "结束对话",
|
||||
"controls.stopVideo": "结束视频",
|
||||
"controls.endSession": "结束会话",
|
||||
"controls.resumeVideo": "📹 重新开始视频",
|
||||
|
||||
// Chat panel
|
||||
"chat.title": "对话",
|
||||
|
||||
Reference in New Issue
Block a user