// ============================================================ // CamTalk — 主应用组件 // ============================================================ import { useState } from "react"; import { useVisionSession } from "./hooks/useVisionSession"; import { VideoPreview } from "./components/VideoPreview"; import { ChatPanel } from "./components/ChatPanel"; import { ConfigPanel } from "./components/ConfigPanel"; import { ToastContainer } from "./components/Toast"; import "./App.css"; function App() { const [showConfig, setShowConfig] = useState(false); const { messages, currentReply, isProcessing, isAudioPlaying, isSpeaking, isVADReady, vadError, connectionStatus, videoRef, stream, config, updateConfig, stats, mode, isObserving, toggleMode, startSession, stopSession, interrupt, } = useVisionSession(); const isConnected = connectionStatus === "connected"; return (

CamTalk

{isConnected ? "已连接" : connectionStatus === "connecting" ? "连接中..." : "未连接"} {isConnected && ( )}
{showConfig && ( setShowConfig(false)} /> )}
{config.detailLevel === "high" && (
HD
)} {isObserving && (
👁️ 观察中
)} {isSpeaking &&
🎤 正在聆听...
} {isAudioPlaying && config.ttsEnabled && (
🔊 正在播放...
)} {isConnected && !isVADReady && !vadError && (
正在初始化语音检测...
)} {vadError && (
⚠️ {vadError}
)} {isProcessing && (
)}
{connectionStatus === "disconnected" && messages.length > 0 && (
连接已断开,正在重连...
)}
{isConnected && (stats.queryCount > 0 || stats.totalTokens > 0) && (
{stats.queryCount > 0 && {stats.queryCount} 次请求} {stats.totalTokens > 0 && · {stats.totalTokens} tokens}
)}
{!isConnected ? ( ) : ( <> {isProcessing && ( )} )}
); } export default App;