// DOM元素获取 const apiKeyInput = document.getElementById('apiKey'); const apiBaseInput = document.getElementById('apiBase'); const textInput = document.getElementById('textInput'); const charCount = document.getElementById('charCount'); const modelSelect = document.getElementById('model'); const voiceSelect = document.getElementById('voice'); const generateBtn = document.getElementById('generateBtn'); const playBtn = document.getElementById('playBtn'); const downloadBtn = document.getElementById('downloadBtn'); const statusDiv = document.getElementById('status'); const audioPlayer = document.getElementById('audioPlayer'); // 当前生成的音频URL let currentAudioURL = null; // 初始化函数 function init() { // 加载本地存储的配置 loadConfig(); // 绑定事件监听器 bindEventListeners(); // 初始状态更新 updateCharCount(); } // 加载本地存储的配置 function loadConfig() { const savedAPIKey = localStorage.getItem('openai_api_key'); const savedAPIBase = localStorage.getItem('openai_api_base'); if (savedAPIKey) { apiKeyInput.value = savedAPIKey; } if (savedAPIBase) { apiBaseInput.value = savedAPIBase; } } // 保存配置到本地存储 function saveConfig() { localStorage.setItem('openai_api_key', apiKeyInput.value); localStorage.setItem('openai_api_base', apiBaseInput.value); } // 绑定事件监听器 function bindEventListeners() { // 文本输入事件 - 更新字符计数 textInput.addEventListener('input', updateCharCount); // API配置输入事件 - 保存到本地存储 apiKeyInput.addEventListener('input', saveConfig); apiBaseInput.addEventListener('input', saveConfig); // 生成语音按钮点击事件 generateBtn.addEventListener('click', generateSpeech); // 播放按钮点击事件 playBtn.addEventListener('click', togglePlay); // 下载按钮点击事件 downloadBtn.addEventListener('click', downloadAudio); // 音频播放结束事件 audioPlayer.addEventListener('ended', onAudioEnded); } // 更新字符计数 function updateCharCount() { const count = textInput.value.length; charCount.textContent = count; } // 生成语音 async function generateSpeech() { // 验证输入 if (!validateInput()) { return; } // 保存配置 saveConfig(); // 更新状态 setStatus('loading', '正在生成语音...'); disableControls(); try { // 构建请求数据 const requestData = { api_key: apiKeyInput.value, text: textInput.value, voice: voiceSelect.value, model: modelSelect.value, api_base: apiBaseInput.value }; // 发送请求到后端API const response = await fetch('/api/tts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(requestData) }); if (!response.ok) { const errorData = await response.json().catch(() => ({ error: `HTTP错误: ${response.status} ${response.statusText}` })); throw new Error(errorData.error || '生成语音失败'); } // 获取音频Blob const audioBlob = await response.blob(); // 创建音频URL if (currentAudioURL) { URL.revokeObjectURL(currentAudioURL); } currentAudioURL = URL.createObjectURL(audioBlob); // 更新音频播放器 audioPlayer.src = currentAudioURL; // 更新状态 setStatus('success', '语音生成成功!'); enableControls(); } catch (error) { // 处理错误 setStatus('error', `生成失败: ${error.message}`); disableControls(); } } // 验证输入 function validateInput() { if (!apiKeyInput.value.trim()) { setStatus('error', '请输入API Key'); apiKeyInput.focus(); return false; } if (!textInput.value.trim()) { setStatus('error', '请输入要转换的文本'); textInput.focus(); return false; } return true; } // 切换播放状态 function togglePlay() { if (audioPlayer.paused) { audioPlayer.play(); playBtn.textContent = '暂停'; } else { audioPlayer.pause(); playBtn.textContent = '播放'; } } // 音频播放结束 function onAudioEnded() { playBtn.textContent = '播放'; } // 下载音频 function downloadAudio() { if (!currentAudioURL) { return; } // 创建下载链接 const link = document.createElement('a'); link.href = currentAudioURL; link.download = 'speech.mp3'; // 触发下载 document.body.appendChild(link); link.click(); document.body.removeChild(link); } // 设置状态 function setStatus(type, message) { statusDiv.className = `status ${type}`; statusDiv.textContent = message; // 清除成功状态 if (type === 'success') { setTimeout(() => { statusDiv.className = 'status'; statusDiv.textContent = ''; }, 3000); } } // 禁用控件 function disableControls() { generateBtn.disabled = true; playBtn.disabled = true; downloadBtn.disabled = true; generateBtn.classList.add('loading'); } // 启用控件 function enableControls() { generateBtn.disabled = false; playBtn.disabled = false; downloadBtn.disabled = false; generateBtn.classList.remove('loading'); } // 页面加载完成后初始化 document.addEventListener('DOMContentLoaded', init);