Files
TTSpeiyin/app.js
T
2026-01-03 00:16:36 +08:00

222 lines
5.7 KiB
JavaScript

// 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);