加载中...
👤 个人资料 💰 订阅管理 🚪 退出账号
// 简单的语音识别类(已禁用,使用纯净版语音按钮) // class InlineVoiceSystem { constructor() { this.isRecording = false; this.recognition = null; this.init(); } init() { console.log('🎤 初始化内联语音系统...'); // 使用修复后的语音识别实例 if (window.ServiceNotAllowedFix) { this.recognition = window.ServiceNotAllowedFix.createFixedSpeechRecognition(); } else { // 回退到标准实现 if ('webkitSpeechRecognition' in window) { this.recognition = new webkitSpeechRecognition(); } else if ('SpeechRecognition' in window) { this.recognition = new SpeechRecognition(); } else { console.warn('❌ 浏览器不支持语音识别API'); return; } } if (!this.recognition) { console.error('❌ 无法创建语音识别实例'); return; } // 配置语音识别 this.recognition.continuous = false; this.recognition.interimResults = false; this.recognition.lang = 'zh-CN'; this.recognition.maxAlternatives = 1; // 事件监听 this.recognition.onstart = () => { console.log('🎤 语音识别开始'); this.isRecording = true; this.onRecordingStart?.(); }; this.recognition.onresult = (event) => { const transcript = event.results[0][0].transcript; console.log('📝 识别结果:', transcript); this.onSpeechRecognized?.(transcript); }; this.recognition.onerror = (event) => { console.error('❌ 语音识别错误:', event.error); // 特殊处理service-not-allowed错误 if (event.error === 'service-not-allowed') { console.log('🔄 检测到service-not-allowed错误'); this.showServiceNotAllowedError(); } this.onRecordingError?.(event.error); }; this.recognition.onend = () => { console.log('🛑 语音识别结束'); this.isRecording = false; this.onRecordingEnd?.(); }; console.log('✅ 内联语音系统初始化完成'); } showServiceNotAllowedError() { // 显示详细的错误信息 const errorDiv = document.createElement('div'); errorDiv.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: rgba(231, 76, 60, 0.95); color: white; padding: 25px; border-radius: 12px; z-index: 10001; max-width: 450px; text-align: center; box-shadow: 0 8px 30px rgba(0,0,0,0.4); `; errorDiv.innerHTML = `
🔒
语音识别服务被阻止
错误代码: service-not-allowed
语音识别需要HTTPS安全连接和浏览器权限
解决方案:
  1. 确保使用 https://z3.xblog.pro 访问
  2. 允许浏览器使用麦克风(点击地址栏的锁图标)
  3. 使用Chrome或Edge浏览器(支持最好)
  4. 禁用可能阻止语音识别的浏览器扩展
  5. 清除浏览器缓存后重试
如果问题持续,请使用文本输入功能
`; document.body.appendChild(errorDiv); // 点击背景关闭 errorDiv.addEventListener('click', (e) => { if (e.target === errorDiv) { errorDiv.remove(); } }); // 10秒后自动关闭 setTimeout(() => { if (errorDiv.parentElement) { errorDiv.style.opacity = '0'; errorDiv.style.transition = 'opacity 0.5s'; setTimeout(() => { if (errorDiv.parentElement) { errorDiv.remove(); } }, 500); } }, 10000); } startRecording() { if (this.isRecording) { console.warn('⚠️ 已经在录音中'); return; } if (!this.recognition) { console.error('❌ 语音识别未初始化'); this.showError('浏览器不支持语音识别'); return; } // 请求麦克风权限 navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { console.log('✅ 麦克风权限已获取'); this.recognition.start(); }) .catch(error => { console.error('❌ 麦克风权限被拒绝:', error); this.showError('请允许麦克风访问权限'); this.onRecordingError?.(error); }); } stopRecording() { if (!this.isRecording) { console.warn('⚠️ 没有在录音'); return; } if (this.recognition) { this.recognition.stop(); } } showError(message) { // 创建错误提示 const errorDiv = document.createElement('div'); errorDiv.style.cssText = ` position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: #ff4757; color: white; padding: 12px 24px; border-radius: 8px; z-index: 10000; box-shadow: 0 4px 12px rgba(0,0,0,0.2); animation: slideDown 0.3s ease-out; `; errorDiv.textContent = message; document.body.appendChild(errorDiv); // 3秒后移除 setTimeout(() => { errorDiv.style.opacity = '0'; errorDiv.style.transform = 'translateX(-50%) translateY(-20px)'; setTimeout(() => errorDiv.remove(), 300); }, 3000); } // 事件回调 onRecordingStart = null; onRecordingEnd = null; onRecordingError = null; onSpeechRecognized = null; } // 创建全局语音系统实例 window.LotusVoiceSystem = new InlineVoiceSystem(); console.log('✅ 内联语音系统已创建'); // 更新语音按钮函数 function startVoiceRecording() { console.log('🎤 开始语音录音...'); // 检查语音系统是否已加载 if (typeof window.LotusVoiceSystem === 'undefined') { console.error('❌ 语音系统未加载'); showVoiceStatus('语音系统未加载,请刷新页面', 'error'); return; } // 开始录音 try { window.LotusVoiceSystem.startRecording(); // 设置语音识别回调 window.LotusVoiceSystem.onSpeechRecognized = (text) => { console.log('✅ 语音识别成功:', text); showVoiceStatus('识别成功: ' + text.substring(0, 20) + '...', 'success'); // 将识别结果填入输入框 const messageInput = document.getElementById('messageInput'); if (messageInput) { messageInput.value = text; messageInput.style.height = 'auto'; messageInput.style.height = Math.min(messageInput.scrollHeight, 120) + 'px'; // 启用发送按钮 const sendBtn = document.getElementById('sendBtn'); if (sendBtn) { sendBtn.disabled = false; } } }; // 设置录音错误回调 window.LotusVoiceSystem.onRecordingError = (error) => { console.error('❌ 语音识别错误:', error); showVoiceStatus('语音识别失败: ' + error, 'error'); }; // 设置录音开始回调 window.LotusVoiceSystem.onRecordingStart = () => { console.log('✅ 语音识别开始'); showVoiceStatus('正在录音... 请说话', 'recording'); }; // 设置录音结束回调 window.LotusVoiceSystem.onRecordingEnd = () => { console.log('✅ 语音识别结束'); // 状态会在识别结果或错误时更新 }; } catch (error) { console.error('❌ 启动录音失败:', error); showVoiceStatus('启动录音失败: ' + error.message, 'error'); } } function stopVoiceRecording() { console.log('🛑 停止语音录音...'); // 检查语音系统是否已加载 if (typeof window.LotusVoiceSystem === 'undefined') { console.error('❌ 语音系统未加载'); return; } // 停止录音 try { window.LotusVoiceSystem.stopRecording(); console.log('✅ 已停止录音'); } catch (error) { console.error('❌ 停止录音失败:', error); } } function showVoiceStatus(message, type = 'info') { // 移除现有状态 hideVoiceStatus(); const statusDiv = document.createElement('div'); statusDiv.id = 'voiceStatusInline'; statusDiv.style.cssText = ` position: fixed; bottom: 100px; left: 50%; transform: translateX(-50%); background: ${type === 'recording' ? '#ff4757' : type === 'warning' ? '#ffa502' : type === 'success' ? '#2ecc71' : type === 'error' ? '#e74c3c' : 'rgba(0,0,0,0.8)'}; color: white; padding: 12px 24px; border-radius: 25px; z-index: 9999; display: flex; align-items: center; gap: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.2); animation: slideUp 0.3s ease-out; `; const icon = type === 'recording' ? '🎤' : type === 'warning' ? '⚠️' : type === 'success' ? '✅' : type === 'error' ? '❌' : '💬'; statusDiv.innerHTML = `
${icon}
${message}
`; document.body.appendChild(statusDiv); } function hideVoiceStatus() { const statusDiv = document.getElementById('voiceStatusInline'); if (statusDiv) { statusDiv.style.opacity = '0'; statusDiv.style.transform = 'translateX(-50%) translateY(20px)'; setTimeout(() => statusDiv.remove(), 300); } } // 添加slideDown动画 const voiceStyle = document.createElement('style'); voiceStyle.textContent = ` @keyframes slideDown { from { transform: translateX(-50%) translateY(-20px); opacity: 0; } to { transform: translateX(-50%) translateY(0); opacity: 1; } } `; document.head.appendChild(voiceStyle); console.log('✅ 内联语音系统集成完成'); // 语音功能优化器(内联版本) (function() { console.log('🎤 加载内联语音功能优化器...'); class InlineVoiceOptimizer { constructor() { this.isRecording = false; this.recognition = null; this.voiceBtn = null; this.init(); } init() { console.log('🎤 初始化内联语音优化器...'); // 获取语音按钮 this.voiceBtn = document.getElementById('voiceBtn'); if (!this.voiceBtn) { console.error('❌ 找不到语音按钮'); return; } // 添加事件监听器 this.setupEventListeners(); // 初始化语音识别 this.initSpeechRecognition(); // 添加样式 this.addStyles(); console.log('✅ 内联语音优化器初始化完成'); } setupEventListeners() { // 移除所有现有事件监听器 const newVoiceBtn = this.voiceBtn.cloneNode(true); this.voiceBtn.parentNode.replaceChild(newVoiceBtn, this.voiceBtn); this.voiceBtn = newVoiceBtn; // 添加新的事件监听器 this.voiceBtn.addEventListener('mousedown', (e) => this.handleVoiceButtonDown(e)); this.voiceBtn.addEventListener('mouseup', (e) => this.handleVoiceButtonUp(e)); this.voiceBtn.addEventListener('mouseleave', (e) => this.handleVoiceButtonUp(e)); this.voiceBtn.addEventListener('touchstart', (e) => { e.preventDefault(); this.handleVoiceButtonDown(e); }); this.voiceBtn.addEventListener('touchend', (e) => { e.preventDefault(); this.handleVoiceButtonUp(e); }); this.voiceBtn.addEventListener('touchcancel', (e) => { e.preventDefault(); this.handleVoiceButtonUp(e); }); console.log('✅ 语音按钮事件监听器设置完成'); } initSpeechRecognition() { // 检查浏览器支持 if ('webkitSpeechRecognition' in window) { this.recognition = new webkitSpeechRecognition(); } else if ('SpeechRecognition' in window) { this.recognition = new SpeechRecognition(); } else { console.warn('❌ 浏览器不支持语音识别API'); this.showStatus('您的浏览器不支持语音识别', 'error'); return; } // 配置语音识别 this.recognition.lang = 'zh-CN'; this.recognition.interimResults = false; this.recognition.maxAlternatives = 1; this.recognition.continuous = false; // 事件监听 this.recognition.onstart = () => { console.log('🎤 语音识别开始'); this.isRecording = true; this.showStatus('🎤 正在录音...请说话', 'recording'); this.voiceBtn.classList.add('recording'); }; this.recognition.onresult = (event) => { const transcript = event.results[0][0].transcript; console.log('📝 语音识别结果:', transcript); // 直接发送语音消息 this.sendVoiceMessage(transcript); }; this.recognition.onerror = (event) => { console.error('❌ 语音识别错误:', event.error); this.showStatus('语音识别失败: ' + event.error, 'error'); this.voiceBtn.classList.remove('recording'); this.isRecording = false; }; this.recognition.onend = () => { console.log('🛑 语音识别结束'); this.voiceBtn.classList.remove('recording'); this.isRecording = false; }; console.log('✅ 语音识别初始化完成'); } handleVoiceButtonDown(event) { event.preventDefault(); event.stopPropagation(); console.log('🎤 语音按钮按下'); if (this.isRecording) { console.warn('⚠️ 已经在录音中'); return; } if (!this.recognition) { console.error('❌ 语音识别未初始化'); this.showStatus('语音识别未初始化', 'error'); return; } // 检查麦克风权限状态 this.checkMicrophonePermission() .then(hasPermission => { if (hasPermission) { // 已经有权限,直接开始录音 console.log('✅ 已有麦克风权限,开始录音'); this.recognition.start(); } else { // 没有权限,请求权限但不开始录音 console.log('🔒 请求麦克风权限...'); this.requestMicrophonePermission() .then(granted => { if (granted) { console.log('✅ 麦克风权限已授予'); this.showStatus('✅ 权限已授予,请再次长按语音按钮说话', 'success'); } else { console.log('❌ 麦克风权限被拒绝'); this.showStatus('❌ 麦克风权限被拒绝,请在浏览器设置中允许麦克风访问', 'error'); } }) .catch(error => { console.error('❌ 权限请求失败:', error); this.showStatus('权限请求失败', 'error'); }); } }) .catch(error => { console.error('❌ 权限检查失败:', error); this.showStatus('权限检查失败', 'error'); }); } handleVoiceButtonUp(event) { if (event) { event.preventDefault(); event.stopPropagation(); } console.log('🛑 语音按钮松开'); if (!this.isRecording) { return; } if (this.recognition) { this.recognition.stop(); } } async sendVoiceMessage(message) { console.log('📤 发送语音消息:', message); // 获取当前用户ID const currentUserId = await this.getCurrentUserId(); if (!currentUserId) { console.error('❌ 用户未登录,无法发送消息'); this.showStatus('请先登录', 'error'); return; } // 显示用户语音消息 await this.addVoiceMessage('user', message); // 调用AI获取回复 const aiResponse = await this.callAI(message, currentUserId); if (aiResponse) { // 显示心月的文字回复 await this.addVoiceMessage('lotus', aiResponse); // 播放心月的语音回复 this.playLotusVoice(aiResponse); } } async addVoiceMessage(type, text) { return new Promise((resolve) => { // 使用页面现有的addMessage函数 if (typeof window.addMessage === 'function') { window.addMessage(type, text, null).then(resolve); } else { // 如果addMessage不存在,使用简单实现 this.simpleAddMessage(type, text); resolve(); } }); } simpleAddMessage(type, text) { const chatMessages = document.getElementById('chatMessages'); if (!chatMessages) return; const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}-message`; const contentDiv = document.createElement('div'); contentDiv.className = 'message-content'; // 头像 const avatarDiv = document.createElement('div'); avatarDiv.className = 'message-avatar'; if (type === 'user') { avatarDiv.style.backgroundColor = '#95ec69'; avatarDiv.textContent = '你'; } else { avatarDiv.style.backgroundColor = '#D4897B'; avatarDiv.textContent = '莲'; } // 消息气泡 const bubbleContainer = document.createElement('div'); bubbleContainer.className = 'message-bubble-container'; const bubbleDiv = document.createElement('div'); bubbleDiv.className = type === 'user' ? 'user-bubble' : 'ai-bubble'; bubbleDiv.textContent = text; // 如果是语音消息,添加语音图标 if (type === 'user') { const voiceIcon = document.createElement('span'); voiceIcon.textContent = ' 🎤'; voiceIcon.style.marginLeft = '5px'; bubbleDiv.appendChild(voiceIcon); } bubbleContainer.appendChild(bubbleDiv); contentDiv.appendChild(avatarDiv); contentDiv.appendChild(bubbleContainer); messageDiv.appendChild(contentDiv); chatMessages.appendChild(messageDiv); // 滚动到底部 chatMessages.scrollTop = chatMessages.scrollHeight; } async callAI(message, userId) { console.log('🧠 调用AI获取回复:', message.substring(0, 50) + '...'); try { // 尝试使用基于殊师说智慧的API const response = await fetch('/api/chat-with-knowledge.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message, user_id: userId, conversation_id: 'conv_' + Date.now() }) }); const data = await response.json(); if (data.success) { console.log('✅ AI回复成功'); return data.data.response; } else { // 回退到普通AI console.warn('基于殊师说智慧的AI调用失败,回退到普通AI'); return await this.callFallbackAI(message, userId); } } catch (error) { console.error('❌ AI调用失败:', error); return '抱歉,我暂时无法处理您的语音消息。'; } } async callFallbackAI(message, userId) { try { const response = await fetch('/api/chat-with-ai.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: message, user_id: userId, conversation_id: 'conv_' + Date.now() }) }); const data = await response.json(); if (data.success) { return data.data.response; } else { throw new Error(data.message || 'AI调用失败'); } } catch (error) { console.error('❌ 回退AI调用失败:', error); return '我收到了您的语音消息,但暂时无法回复。'; } } // 智能分段函数:将长文本分成适合TTS播放的段落 splitTextForTTS(text, maxLength = 150) { console.log(`📝 智能分段处理: ${text.length}字符 -> 每段最多${maxLength}字符`); const segments = []; let currentSegment = ''; // 按标点符号分割,保持语义完整性 const sentences = text.split(/([。!?;\.\!\?;])/); for (let i = 0; i < sentences.length; i += 2) { const sentence = sentences[i] + (sentences[i + 1] || ''); if ((currentSegment + sentence).length <= maxLength) { currentSegment += sentence; } else { if (currentSegment) segments.push(currentSegment.trim()); if (sentence.length <= maxLength) { currentSegment = sentence; } else { // 句子本身太长,按字数硬分割 const words = sentence.split(''); let chunk = ''; for (const word of words) { if ((chunk + word).length <= maxLength) { chunk += word; } else { if (chunk) segments.push(chunk.trim()); chunk = word; } } if (chunk) segments.push(chunk.trim()); currentSegment = ''; } } } if (currentSegment) segments.push(currentSegment.trim()); // 过滤空段 const filteredSegments = segments.filter(segment => segment.length > 0); console.log(`📊 分段结果: ${filteredSegments.length}段`); filteredSegments.forEach((segment, index) => { console.log(` ${index + 1}. ${segment.length}字符: ${segment.substring(0, 30)}...`); }); return filteredSegments; } // 分段播放函数 async playSegmentedVoice(segments) { console.log(`🎵 开始分段播放: ${segments.length}段`); for (let i = 0; i < segments.length; i++) { try { console.log(`▶️ 播放第${i + 1}/${segments.length}段`); await this.playSingleSegment(segments[i], i + 1, segments.length); } catch (error) { console.error(`❌ 第${i + 1}段播放失败:`, error); // 继续播放下一段 } } console.log('✅ 所有分段播放完成'); } // 播放单个段落 async playSingleSegment(text, current, total) { return new Promise((resolve, reject) => { console.log(`🔊 播放段落 ${current}/${total}: ${text.substring(0, 30)}...`); // 显示播放状态 this.showStatus(`正在播放语音 (${current}/${total})...`, 'playing'); fetch('/api/tencent-tts.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text, voice_type: '502001' // 智小柔音色 }) }) .then(response => response.json()) .then(data => { if (data.success && data.audio_base64) { const audioUrl = 'data:audio/mp3;base64,' + data.audio_base64; const audio = new Audio(audioUrl); audio.onended = () => { console.log(`✅ 段落 ${current}/${total} 播放完成`); resolve(); }; audio.onerror = (error) => { console.error(`❌ 段落 ${current}/${total} 播放错误:`, error); reject(error); }; // 检查是否是微信浏览器 const isWeChat = /MicroMessenger/i.test(navigator.userAgent); if (isWeChat) { console.log(`📱 微信环境检测到,需要用户交互才能播放音频`); // 在微信中,我们可能需要显示一个播放按钮 // 但目前先尝试播放,如果失败就继续下一段 audio.play().catch(error => { console.warn(`⚠️ 微信环境播放被阻止,继续下一段: ${error.message}`); resolve(); // 不reject,继续下一段 }); } else { audio.play().catch(reject); } } else { console.error(`❌ 段落 ${current}/${total} TTS失败:`, data.message); reject(new Error(data.message)); } }) .catch(error => { console.error(`❌ 段落 ${current}/${total} 网络错误:`, error); reject(error); }); }); } playLotusVoice(text) { console.log('🔊 播放心月语音回复:', text.substring(0, 50) + '...'); // 检查文本长度,决定是否分段 const MAX_LENGTH_FOR_SINGLE = 200; // 单次播放的最大长度 if (text.length <= MAX_LENGTH_FOR_SINGLE) { console.log('📏 短文本,直接播放'); this.playSingleVoice(text); } else { console.log('📏 长文本,启用智能分段播放'); const segments = this.splitTextForTTS(text, MAX_LENGTH_FOR_SINGLE); this.playSegmentedVoice(segments); } } // 单次播放函数(用于短文本) playSingleVoice(text) { fetch('/api/tencent-tts.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text, voice_type: '502001' // 智小柔音色 }) }) .then(response => response.json()) .then(data => { if (data.success && data.audio_base64) { console.log(`✅ 腾讯云TTS语音合成成功`); const audioUrl = 'data:audio/mp3;base64,' + data.audio_base64; this.playAudio(audioUrl); } else { console.error('❌ TTS请求失败:', data.message); this.playBrowserVoice(text); } }) .catch(error => { console.error('❌ TTS网络错误:', error); this.playBrowserVoice(text); }); } playAudio(audioUrl) { const audio = new Audio(audioUrl); audio.onplay = () => { console.log('🔊 开始播放心月语音'); this.showStatus('正在播放心月语音...', 'playing'); }; audio.onended = () => { console.log('🛑 心月语音播放结束'); this.showStatus('', 'success'); }; audio.onerror = (error) => { console.error('❌ 音频播放错误:', error); this.showStatus('语音播放失败', 'error'); }; audio.play().catch(error => { console.error('❌ 播放失败:', error); this.showStatus('播放失败: ' + error.message, 'error'); }); } playBrowserVoice(text) { if (!window.speechSynthesis) { console.warn('❌ 浏览器不支持语音合成'); return; } const utterance = new SpeechSynthesisUtterance(text); utterance.lang = 'zh-CN'; utterance.rate = 1.0; utterance.pitch = 1.0; utterance.volume = 1.0; utterance.onstart = () => { console.log('🔊 开始播放浏览器语音'); this.showStatus('正在播放心月语音...', 'playing'); }; utterance.onend = () => { console.log('🛑 浏览器语音播放结束'); this.showStatus('', 'success'); }; utterance.onerror = (event) => { console.error('❌ 语音播放错误:', event.error); this.showStatus('语音播放失败', 'error'); }; window.speechSynthesis.speak(utterance); } async getCurrentUserId() { try { const response = await fetch('/api/check-auth.php', { credentials: 'include' }); const data = await response.json(); if (data.success && data.is_logged_in) { return data.user_info.id; } } catch (error) { console.error('❌ 获取用户ID失败:', error); } return null; } // 检查麦克风权限状态 async checkMicrophonePermission() { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { console.log('ℹ️ 浏览器不支持MediaDevices API'); return false; } try { // 尝试获取权限状态(较新浏览器支持) if (navigator.permissions && navigator.permissions.query) { const permissionStatus = await navigator.permissions.query({ name: 'microphone' }); console.log('🔍 麦克风权限状态:', permissionStatus.state); return permissionStatus.state === 'granted'; } // 回退方案:尝试获取媒体流但不开始录音 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); stream.getTracks().forEach(track => track.stop()); console.log('✅ 麦克风权限检查通过'); return true; } catch (error) { console.log('🔍 麦克风权限检查失败:', error.name); return false; } } // 请求麦克风权限(不开始录音) async requestMicrophonePermission() { if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { console.error('❌ 浏览器不支持MediaDevices API'); return false; } try { // 请求权限但不开始录音 const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); // 立即停止所有音轨,我们只需要权限 stream.getTracks().forEach(track => { track.stop(); stream.removeTrack(track); }); console.log('✅ 麦克风权限请求成功'); return true; } catch (error) { console.error('❌ 麦克风权限请求失败:', error); return false; } } showStatus(message, type = 'info') { // 移除现有状态 this.hideStatus(); if (!message) return; const statusDiv = document.createElement('div'); statusDiv.id = 'voiceStatusInline'; statusDiv.style.cssText = ` position: fixed; bottom: 100px; left: 50%; transform: translateX(-50%); background: ${type === 'recording' ? '#ff4757' : type === 'playing' ? '#3498db' : type === 'success' ? '#2ecc71' : type === 'error' ? '#e74c3c' : 'rgba(0,0,0,0.8)'}; color: white; padding: 12px 24px; border-radius: 25px; z-index: 9999; display: flex; align-items: center; gap: 10px; box-shadow: 0 4px 20px rgba(0,0,0,0.2); animation: slideUp 0.3s ease-out; `; const icon = type === 'recording' ? '🎤' : type === 'playing' ? '🔊' : type === 'success' ? '✅' : type === 'error' ? '❌' : '💬'; statusDiv.innerHTML = `
${icon}
${message}
`; document.body.appendChild(statusDiv); // 自动隐藏 if (type !== 'recording' && type !== 'playing') { setTimeout(() => this.hideStatus(), 3000); } } hideStatus() { const statusDiv = document.getElementById('voiceStatusInline'); if (statusDiv) { statusDiv.remove(); } } addStyles() { const style = document.createElement('style'); style.textContent = ` @keyframes slideUp { from { transform: translateX(-50%) translateY(20px); opacity: 0; } to { transform: translateX(-50%) translateY(0); opacity: 1; } } .voice-btn.recording { background: #ff4757 !important; animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 71, 87, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(255, 71, 87, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 71, 87, 0); } } .message.user-message .user-bubble::after { content: ' 🎤'; font-size: 14px; opacity: 0.7; } `; document.head.appendChild(style); } } // 等待页面加载完成后初始化 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { window.InlineVoiceOptimizer = new InlineVoiceOptimizer(); }); } else { window.InlineVoiceOptimizer = new InlineVoiceOptimizer(); } console.log('✅ 内联语音功能优化器加载完成'); })(); border-radius: 5px; font-size: 11px; line-height: 1.4; "> 等待测试...
🎤 绿色按钮: 等待测试
'; chatMessages.appendChild(msg); console.log('✅ 模拟语音消息添加成功'); } // 步骤2:设置永久标记 console.log('2. 设置永久标记...'); window.permanentVoiceFlag = true; window.voiceMessageTimestamp = Date.now(); console.log('✅ 永久标记设置成功:', window.permanentVoiceFlag); // 步骤3:模拟AI回复 console.log('3. 模拟AI回复...'); const aiResponse = '这是诊断测试的AI回复。如果你听到这句话,说明AI语音回复功能正常。'; // 步骤4:直接调用语音播放 console.log('4. 直接调用语音播放...'); if (typeof window.playLotusVoice === 'function') { console.log('🎤 调用 window.playLotusVoice'); // 优化文本,在换行处添加停顿 const optimizedText = optimizeTextForTTS(aiResponse); window.playLotusVoice(optimizedText); console.log('✅ 语音播放调用完成(已优化停顿)'); return '诊断完成,应该听到测试语音(带适当停顿)'; } else { console.error('❌ 找不到 playLotusVoice 函数'); return '诊断失败:找不到语音函数'; } }; console.log('💡 提示:在控制台输入 testAIVoiceFlow() 进行诊断'); }, 3000); */