From 85a83727fdde56b4daed545e8847ac06edf8f837 Mon Sep 17 00:00:00 2001 From: rainv123 <2148537152@qq.com> Date: Tue, 3 Feb 2026 11:52:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=91=84=E5=83=8F=E5=A4=B4=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81=E7=BB=91=E5=AE=9A=E6=A3=80=E6=9F=A5=20&&=20?= =?UTF-8?q?=E8=A7=86=E8=A7=89=E5=88=86=E6=9E=90URL=E5=8A=A8=E6=80=81?= =?UTF-8?q?=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/xiaozhi-server/test/js/app.js | 10 ++++- .../test/js/core/network/websocket.js | 27 ++++++++++++ main/xiaozhi-server/test/js/ui/controller.js | 44 ++++++++++--------- main/xiaozhi-server/test/test_page.html | 4 ++ 4 files changed, 64 insertions(+), 21 deletions(-) diff --git a/main/xiaozhi-server/test/js/app.js b/main/xiaozhi-server/test/js/app.js index 5555213e..2fe309db 100644 --- a/main/xiaozhi-server/test/js/app.js +++ b/main/xiaozhi-server/test/js/app.js @@ -44,6 +44,8 @@ class App { initMcpTools(); // 检查麦克风可用性 await this.checkMicrophoneAvailability(); + // 检查摄像头可用性 + this.checkCameraAvailability(); // 初始化Live2D await this.initLive2D(); // 初始化摄像头 @@ -115,6 +117,12 @@ class App { } } + // 检查摄像头可用性 + checkCameraAvailability() { + window.cameraAvailable = true; + log('摄像头可用性检查完成: 默认已绑定验证码', 'success'); + } + // 初始化摄像头 async initCamera() { const cameraContainer = document.getElementById('cameraContainer'); @@ -232,7 +240,7 @@ class App { log(`拍照成功,图像数据长度: ${photoData.length}`, 'success'); try { - const visionApiUrl = 'http://localhost:8003/mcp/vision/explain'; + const visionApiUrl = window.visionApiUrl || 'http://localhost:8003/mcp/vision/explain'; log(`正在发送图片到视觉分析接口: ${visionApiUrl}`, 'info'); const deviceId = document.getElementById('deviceMac')?.value || ''; diff --git a/main/xiaozhi-server/test/js/core/network/websocket.js b/main/xiaozhi-server/test/js/core/network/websocket.js index e3a9fcc8..90fc7fee 100644 --- a/main/xiaozhi-server/test/js/core/network/websocket.js +++ b/main/xiaozhi-server/test/js/core/network/websocket.js @@ -81,6 +81,23 @@ export class WebSocketHandler { log(`收到音频控制消息: ${JSON.stringify(message)}`, 'info'); } else if (message.type === 'stt') { log(`识别结果: ${message.text}`, 'info'); + // 检查是否需要绑定设备 + if (message.text && (message.text.includes('绑定') || message.text.includes('bind'))) { + log('收到设备绑定提示,更新摄像头状态', 'warning'); + window.cameraAvailable = false; + // 关闭摄像头 + if (typeof window.stopCamera === 'function') { + window.stopCamera(); + } + // 更新摄像头按钮状态 + const cameraBtn = document.getElementById('cameraBtn'); + if (cameraBtn) { + cameraBtn.classList.remove('camera-active'); + cameraBtn.querySelector('.btn-text').textContent = '摄像头'; + cameraBtn.disabled = true; + cameraBtn.title = '请先绑定验证码'; + } + } // 使用新的聊天消息回调显示STT消息 if (this.onChatMessage && message.text) { this.onChatMessage(message.text, true); @@ -288,6 +305,16 @@ export class WebSocketHandler { }); } else if (payload.method === 'initialize') { log(`收到工具初始化请求: ${JSON.stringify(payload.params)}`, 'info'); + // 保存视觉分析接口地址 + if (payload.params?.capabilities?.vision?.url) { + window.visionApiUrl = payload.params.capabilities.vision.url; + log(`视觉分析接口地址: ${window.visionApiUrl}`, 'success'); + // 更新输入框显示 + const visionUrlInput = document.getElementById('visionUrl'); + if (visionUrlInput) { + visionUrlInput.value = window.visionApiUrl; + } + } const replyMessage = JSON.stringify({ "session_id": message.session_id || "", "type": "mcp", diff --git a/main/xiaozhi-server/test/js/ui/controller.js b/main/xiaozhi-server/test/js/ui/controller.js index 682933ae..731f7bf4 100644 --- a/main/xiaozhi-server/test/js/ui/controller.js +++ b/main/xiaozhi-server/test/js/ui/controller.js @@ -311,10 +311,15 @@ class UIController { } } - // Update camera button state - enable when connected + // Update camera button state - enable when connected and camera is available if (cameraBtn && isConnected) { - cameraBtn.disabled = false; - cameraBtn.title = '打开/关闭摄像头'; + if (window.cameraAvailable) { + cameraBtn.disabled = false; + cameraBtn.title = '打开/关闭摄像头'; + } else { + cameraBtn.disabled = true; + cameraBtn.title = '请先绑定验证码'; + } } // Update record button state @@ -487,6 +492,22 @@ class UIController { recordBtn.click(); } } + // Start camera only if camera is available (bound with verification code) + if (window.cameraAvailable && typeof window.startCamera === 'function') { + window.startCamera().then(success => { + if (success) { + const cameraBtn = document.getElementById('cameraBtn'); + if (cameraBtn) { + cameraBtn.classList.add('camera-active'); + cameraBtn.querySelector('.btn-text').textContent = '关闭'; + } + } else { + this.addChatMessage('⚠️ 摄像头启动失败,可能被浏览器拒绝', false); + } + }).catch(error => { + log(`启动摄像头异常: ${error.message}`, 'error'); + }); + } } // Handle connect button click @@ -582,23 +603,6 @@ class UIController { } this.hideModal('settingsModal'); - - // 启动摄像头 - if (typeof window.startCamera === 'function') { - window.startCamera().then(success => { - if (success) { - const cameraBtn = document.getElementById('cameraBtn'); - if (cameraBtn) { - cameraBtn.classList.add('camera-active'); - cameraBtn.querySelector('.btn-text').textContent = '关闭'; - } - } else { - this.addChatMessage('⚠️ 摄像头启动失败,可能被浏览器拒绝', false); - } - }).catch(error => { - log(`启动摄像头异常: ${error.message}`, 'error'); - }); - } } else { throw new Error('OTA连接失败'); } diff --git a/main/xiaozhi-server/test/test_page.html b/main/xiaozhi-server/test/test_page.html index 31791609..9801f3d3 100644 --- a/main/xiaozhi-server/test/test_page.html +++ b/main/xiaozhi-server/test/test_page.html @@ -168,6 +168,10 @@ +