update:前端增加可配置的本地唤醒词运行时

This commit is contained in:
3030332422
2026-04-14 16:54:37 +08:00
parent 705b5732a6
commit d5b883817c
18 changed files with 1037 additions and 150 deletions
+145 -34
View File
@@ -2,7 +2,9 @@
import { loadConfig, saveConfig } from '../config/manager.js?v=0205';
import { getAudioPlayer } from '../core/audio/player.js?v=0205';
import { getAudioRecorder } from '../core/audio/recorder.js?v=0205';
import { requestWakewordBridge } from '../core/network/wakeword-bridge.js?v=0205';
import { getWebSocketHandler } from '../core/network/websocket.js?v=0205';
import { log } from '../utils/logger.js?v=0205';
// UI controller class
class UIController {
@@ -14,6 +16,8 @@ class UIController {
this.currentBackgroundIndex = localStorage.getItem('backgroundIndex') ? parseInt(localStorage.getItem('backgroundIndex')) : 0;
this.backgroundImages = ['1.png', '2.png', '3.png'];
this.dialBtnDisabled = false;
this.isConnecting = false;
this.lastWakewordDialTime = 0;
// Bind methods
this.init = this.init.bind(this);
@@ -25,6 +29,9 @@ class UIController {
this.showModal = this.showModal.bind(this);
this.hideModal = this.hideModal.bind(this);
this.switchTab = this.switchTab.bind(this);
this.applyWakewordConfig = this.applyWakewordConfig.bind(this);
this.handleApplyWakeword = this.handleApplyWakeword.bind(this);
this.triggerWakewordDial = this.triggerWakewordDial.bind(this);
}
// Initialize
@@ -262,6 +269,11 @@ class UIController {
});
});
const applyWakewordBtn = document.getElementById('applyWakewordBtn');
if (applyWakewordBtn) {
applyWakewordBtn.addEventListener('click', this.handleApplyWakeword);
}
// 点击模态框背景关闭(仅对特定模态框禁用此功能)
const modals = document.querySelectorAll('.modal');
modals.forEach(modal => {
@@ -512,6 +524,74 @@ class UIController {
}
}
applyWakewordConfig(config = {}) {
const wakewordEnabledInput = document.getElementById('wakewordEnabled');
const wakewordListInput = document.getElementById('wakewordList');
if (!wakewordEnabledInput || !wakewordListInput) {
return;
}
const wakeWords = Array.isArray(config.wakeWords)
? config.wakeWords.filter(item => typeof item === 'string' && item.trim())
: [];
wakewordEnabledInput.value = config.enabled === false ? 'false' : 'true';
wakewordListInput.value = wakeWords.join('\n');
saveConfig();
}
async handleApplyWakeword() {
const wakewordEnabledInput = document.getElementById('wakewordEnabled');
const wakewordListInput = document.getElementById('wakewordList');
if (!wakewordEnabledInput || !wakewordListInput) {
return;
}
const wakeWords = wakewordListInput.value
.split(/\r?\n/u)
.map(item => item.trim())
.filter(Boolean)
.filter((item, index, items) => items.indexOf(item) === index);
const payload = {
enabled: wakewordEnabledInput.value !== 'false',
wakeWords,
};
if (payload.enabled && payload.wakeWords.length === 0) {
this.addChatMessage('启用唤醒词时,至少需要填写一个唤醒词。', false);
return;
}
const applyWakewordBtn = document.getElementById('applyWakewordBtn');
if (applyWakewordBtn) {
applyWakewordBtn.disabled = true;
applyWakewordBtn.textContent = '应用中...';
}
try {
const response = await requestWakewordBridge('set_wakeword_config', payload);
this.applyWakewordConfig(response.payload || payload);
const shouldRestart = window.confirm('唤醒词已保存。是否现在重启唤醒词服务以立即生效?');
if (!shouldRestart) {
this.addChatMessage('唤醒词配置已保存,可稍后手动重启服务后生效。', false);
return;
}
await requestWakewordBridge('restart_wakeword_service');
this.addChatMessage('唤醒词配置已保存,唤醒词服务正在重启。', false);
} catch (error) {
this.addChatMessage(`应用唤醒词失败: ${error.message}`, false);
} finally {
if (applyWakewordBtn) {
applyWakewordBtn.disabled = false;
applyWakewordBtn.textContent = '应用唤醒词';
}
}
}
// Start AI chat session after connection
startAIChatSession() {
this.addChatMessage('连接成功,开始聊天吧~😊', false);
@@ -550,47 +630,51 @@ class UIController {
// Handle connect button click
async handleConnect() {
console.log('handleConnect called');
// Switch to device settings tab
this.switchTab('device');
// Wait for DOM update
await new Promise(resolve => setTimeout(resolve, 50));
const otaUrlInput = document.getElementById('otaUrl');
console.log('otaUrl element:', otaUrlInput);
if (!otaUrlInput || !otaUrlInput.value) {
this.addChatMessage('请输入OTA服务器地址', false);
const wsHandler = getWebSocketHandler();
if (this.isConnecting || (wsHandler && wsHandler.isConnected())) {
log('连接已存在或正在进行,忽略本次拨号请求', 'info');
return;
}
const otaUrl = otaUrlInput.value;
console.log('otaUrl value:', otaUrl);
// Update dial button state to connecting
const dialBtn = document.getElementById('dialBtn');
if (dialBtn) {
dialBtn.classList.add('dial-active');
dialBtn.querySelector('.btn-text').textContent = '连接中...';
dialBtn.disabled = true;
}
// Show connecting message
this.addChatMessage('正在连接服务器...', false);
const chatIpt = document.getElementById('chatIpt');
if (chatIpt) {
chatIpt.style.display = 'flex';
}
this.isConnecting = true;
console.log('handleConnect called');
try {
// Switch to device settings tab
this.switchTab('device');
// Wait for DOM update
await new Promise(resolve => setTimeout(resolve, 50));
const otaUrlInput = document.getElementById('otaUrl');
console.log('otaUrl element:', otaUrlInput);
if (!otaUrlInput || !otaUrlInput.value) {
this.addChatMessage('请输入OTA服务器地址', false);
return;
}
const otaUrl = otaUrlInput.value;
console.log('otaUrl value:', otaUrl);
// Update dial button state to connecting
const dialBtn = document.getElementById('dialBtn');
if (dialBtn) {
dialBtn.classList.add('dial-active');
dialBtn.querySelector('.btn-text').textContent = '连接中...';
dialBtn.disabled = true;
}
// Show connecting message
this.addChatMessage('正在连接服务器...', false);
const chatIpt = document.getElementById('chatIpt');
if (chatIpt) {
chatIpt.style.display = 'flex';
}
// Get WebSocket handler instance
const wsHandler = getWebSocketHandler();
// Register connection state callback BEFORE connecting
wsHandler.onConnectionStateChange = (isConnected) => {
this.updateConnectionUI(isConnected);
@@ -670,9 +754,36 @@ class UIController {
dialBtn.classList.remove('dial-active');
console.log('Dial button state restored successfully');
}
} finally {
this.isConnecting = false;
}
}
async triggerWakewordDial(wakeWord = '唤醒词') {
const wsHandler = getWebSocketHandler();
const now = Date.now();
if (wsHandler && wsHandler.isConnected()) {
log('页面已连接,忽略自动拨号', 'info');
return false;
}
if (this.isConnecting || this.dialBtnDisabled) {
log('页面正在连接中,忽略重复唤醒', 'info');
return false;
}
if (now - this.lastWakewordDialTime < 3000) {
log('唤醒触发过于频繁,忽略本次自动拨号', 'warning');
return false;
}
this.lastWakewordDialTime = now;
this.addChatMessage(`检测到唤醒词“${wakeWord}”,准备连接服务器...`, false);
await this.handleConnect();
return true;
}
// Add MCP tool
addMCPTool() {
const mcpToolsList = document.getElementById('mcpToolsList');