feat: 底部控制栏添加摄像头/麦克风开关,说话时麦克风脉冲动画

- useVisionSession 新增 isCameraOn/isMicOn 状态 + toggleCamera/toggleMic
- 底部控制栏添加 📷🎤 图标按钮,开启绿色/关闭红色
- 说话时麦克风按钮绿色脉冲缩放动画(micPulse)
- 按钮样式优化:nowrap 防换行,flex-wrap 自适应

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-13 20:01:37 +08:00
parent 188782fa66
commit 00f10088d0
3 changed files with 92 additions and 16 deletions

View File

@@ -36,6 +36,8 @@ export function useVisionSession() {
const [config, setConfig] = useState<SessionConfig>(loadConfig);
const [stats, setStats] = useState<SessionStats>({ queryCount: 0, totalTokens: 0 });
const [mode, setMode] = useState<SessionMode>("dialogue");
const [isCameraOn, setIsCameraOn] = useState(false);
const [isMicOn, setIsMicOn] = useState(false);
// 上一帧采样数据(用于关键帧检测)
const prevFrameRef = useRef<Uint8ClampedArray | null>(null);
@@ -280,11 +282,13 @@ export function useVisionSession() {
const startSession = useCallback(async () => {
// 1. 获取摄像头和麦克风
await startCamera();
setIsCameraOn(true);
const micStream = await startMic();
if (!micStream) {
showToast("无法获取麦克风权限", "error");
return;
}
setIsMicOn(true);
// 2. 连接 WebSocket
connect();
@@ -310,8 +314,32 @@ export function useVisionSession() {
setStats({ queryCount: 0, totalTokens: 0 });
historyRef.current = [];
prevFrameRef.current = null;
setIsCameraOn(false);
setIsMicOn(false);
}, [stopObserving, stopVAD, stopMic, stopCamera, disconnect]);
/** 摄像头开关 */
const toggleCamera = useCallback(async () => {
if (isCameraOn) {
stopCamera();
setIsCameraOn(false);
} else {
await startCamera();
setIsCameraOn(true);
}
}, [isCameraOn, startCamera, stopCamera]);
/** 麦克风开关 */
const toggleMic = useCallback(async () => {
if (isMicOn) {
stopMic();
setIsMicOn(false);
} else {
const micStream = await startMic();
setIsMicOn(!!micStream);
}
}, [isMicOn, startMic, stopMic]);
/** 打断当前回复 */
const interrupt = useCallback(() => {
send({ type: "interrupt" });
@@ -351,5 +379,9 @@ export function useVisionSession() {
startSession,
stopSession,
interrupt,
isCameraOn,
isMicOn,
toggleCamera,
toggleMic,
};
}