feat: 添加自动播放开关和音量调节功能
This commit is contained in:
BIN
audio_cache/8bc65e9ebfc94095a698d1fc1b742428.mp3
Normal file
BIN
audio_cache/8bc65e9ebfc94095a698d1fc1b742428.mp3
Normal file
Binary file not shown.
BIN
logs/server.log
BIN
logs/server.log
Binary file not shown.
143
static/tts.html
143
static/tts.html
@@ -124,6 +124,96 @@
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* TTS 控制选项 */
|
||||
.tts-controls {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 1px solid #eee;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.auto-play-switch {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.switch {
|
||||
position: relative;
|
||||
width: 44px;
|
||||
height: 22px;
|
||||
}
|
||||
|
||||
.switch input {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc;
|
||||
transition: .3s;
|
||||
border-radius: 22px;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
background-color: white;
|
||||
transition: .3s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: #667eea;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(22px);
|
||||
}
|
||||
|
||||
.volume-control {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.volume-control input[type="range"] {
|
||||
width: 80px;
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background: #ddd;
|
||||
outline: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.volume-control input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-radius: 50%;
|
||||
background: #667eea;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.volume-value {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
min-width: 35px;
|
||||
}
|
||||
|
||||
.voice-select {
|
||||
margin-top: 10px;
|
||||
}
|
||||
@@ -388,6 +478,20 @@
|
||||
<option value="zh-CN-XiaoyouNeural">晓悠(女)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="tts-controls" id="ttsControls" style="display: none;">
|
||||
<div class="auto-play-switch">
|
||||
<label class="switch">
|
||||
<input type="checkbox" id="autoPlaySwitch" checked>
|
||||
<span class="slider"></span>
|
||||
</label>
|
||||
<span>自动播放</span>
|
||||
</div>
|
||||
<div class="volume-control">
|
||||
<span>🔊</span>
|
||||
<input type="range" id="volumeSlider" min="0.5" max="2" step="0.1" value="1.5">
|
||||
<span class="volume-value" id="volumeValue">150%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 录音 -->
|
||||
@@ -439,6 +543,8 @@
|
||||
let conversationId = null;
|
||||
let currentTTSProvider = 'none';
|
||||
let currentVoice = 'zh-CN-XiaoxiaoNeural';
|
||||
let autoPlay = true; // 自动播放开关
|
||||
let volumeLevel = 1.5; // 音量倍率
|
||||
|
||||
// 元素
|
||||
const statusDot = document.getElementById('statusDot');
|
||||
@@ -453,6 +559,10 @@
|
||||
const ttsOptions = document.getElementById('ttsOptions');
|
||||
const voiceSelect = document.getElementById('voiceSelect');
|
||||
const voiceDropdown = document.getElementById('voiceDropdown');
|
||||
const ttsControls = document.getElementById('ttsControls');
|
||||
const autoPlaySwitch = document.getElementById('autoPlaySwitch');
|
||||
const volumeSlider = document.getElementById('volumeSlider');
|
||||
const volumeValue = document.getElementById('volumeValue');
|
||||
|
||||
// 初始化
|
||||
async function init() {
|
||||
@@ -531,6 +641,9 @@
|
||||
// 显示/隐藏音色选择
|
||||
voiceSelect.style.display = provider === 'edge' ? 'block' : 'none';
|
||||
|
||||
// 显示/隐藏控制选项(有TTS才显示)
|
||||
ttsControls.style.display = provider !== 'none' ? 'flex' : 'none';
|
||||
|
||||
// 保存设置
|
||||
saveTTSSettings();
|
||||
}
|
||||
@@ -779,8 +892,10 @@
|
||||
`;
|
||||
} else if (role === 'assistant') {
|
||||
let audioHtml = '';
|
||||
let audioBtnId = '';
|
||||
if (audioData) {
|
||||
audioHtml = `<button class="play-btn tts-play-btn" onclick="playAudio('${audioData}', this)">
|
||||
audioBtnId = `audioBtn_${Date.now()}`;
|
||||
audioHtml = `<button class="play-btn tts-play-btn" id="${audioBtnId}" onclick="playAudio('${audioData}', this)">
|
||||
<span class="play-icon">🔊</span>
|
||||
<span>播放回复</span>
|
||||
</button>`;
|
||||
@@ -789,6 +904,16 @@
|
||||
<div class="role">AI</div>
|
||||
<div class="content">${content}${audioHtml}</div>
|
||||
`;
|
||||
|
||||
// 自动播放(如果开启)
|
||||
if (audioData && autoPlay) {
|
||||
setTimeout(() => {
|
||||
const btn = document.getElementById(audioBtnId);
|
||||
if (btn) {
|
||||
playAudio(audioData, btn);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
} else {
|
||||
msg.innerHTML = `<div class="role">我</div><div class="content">${content}</div>`;
|
||||
}
|
||||
@@ -802,13 +927,16 @@
|
||||
const audio = new Audio(url);
|
||||
const icon = btn.querySelector('.play-icon');
|
||||
|
||||
// 应用音量倍率
|
||||
audio.volume = Math.min(volumeLevel, 2); // 最大不超过2
|
||||
|
||||
audio.onplay = () => {
|
||||
icon.textContent = '🔊';
|
||||
btn.classList.add('playing');
|
||||
};
|
||||
|
||||
audio.onended = () => {
|
||||
icon.textContent = url.startsWith('/audio') ? '🔊' : '▶️';
|
||||
icon.textContent = url.startsWith('/audio') || url.startsWith('http') ? '🔊' : '▶️';
|
||||
btn.classList.remove('playing');
|
||||
};
|
||||
|
||||
@@ -862,6 +990,17 @@
|
||||
saveTTSSettings();
|
||||
});
|
||||
|
||||
// 自动播放开关
|
||||
autoPlaySwitch.addEventListener('change', () => {
|
||||
autoPlay = autoPlaySwitch.checked;
|
||||
});
|
||||
|
||||
// 音量控制
|
||||
volumeSlider.addEventListener('input', () => {
|
||||
volumeLevel = parseFloat(volumeSlider.value);
|
||||
volumeValue.textContent = `${Math.round(volumeLevel * 100)}%`;
|
||||
});
|
||||
|
||||
recordBtn.addEventListener('click', () => {
|
||||
isRecording ? stopRecording() : startRecording();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user