feat: add TTS buttons to user messages and fix delete persistence bug
This commit is contained in:
parent
ba76f1dbcd
commit
ae6e3baa35
1 changed files with 168 additions and 3 deletions
171
src/ui.js
171
src/ui.js
|
|
@ -1205,6 +1205,90 @@ async function openUncloseaiEmbeddedModalNew() {
|
|||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
const userTtsBtn = document.createElement("button");
|
||||
userTtsBtn.textContent = "🔊";
|
||||
userTtsBtn.title = "Read aloud";
|
||||
userTtsBtn.style.cssText = `
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
userTtsBtn.onmouseenter = () => {
|
||||
userTtsBtn.style.background = 'rgba(255, 255, 255, 0.3)';
|
||||
};
|
||||
userTtsBtn.onmouseleave = () => {
|
||||
userTtsBtn.style.background = 'rgba(255, 255, 255, 0.2)';
|
||||
};
|
||||
|
||||
// Store audio for pause/resume functionality
|
||||
let userAudio = null;
|
||||
let isPlaying = false;
|
||||
|
||||
userTtsBtn.onclick = async () => {
|
||||
const modalVoiceSelect = document.getElementById('hermes-voice-select');
|
||||
const selectedVoice = modalVoiceSelect?.value || 'alloy';
|
||||
|
||||
// If audio is already playing, pause it
|
||||
if (userAudio && !userAudio.paused) {
|
||||
userAudio.pause();
|
||||
userTtsBtn.textContent = "🔊";
|
||||
isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// If audio exists and is paused, resume it
|
||||
if (userAudio && userAudio.paused && userAudio.currentTime > 0) {
|
||||
userAudio.play();
|
||||
userTtsBtn.textContent = "⏸️";
|
||||
isPlaying = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate new audio
|
||||
const originalText = userTtsBtn.textContent;
|
||||
userTtsBtn.textContent = "⏳";
|
||||
userTtsBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const result = await speakChatText(message, selectedVoice, 1.0);
|
||||
userAudio = result.audio;
|
||||
|
||||
// Set up audio event handlers
|
||||
userAudio.onplay = () => {
|
||||
userTtsBtn.textContent = "⏸️";
|
||||
isPlaying = true;
|
||||
};
|
||||
|
||||
userAudio.onpause = () => {
|
||||
userTtsBtn.textContent = "🔊";
|
||||
isPlaying = false;
|
||||
};
|
||||
|
||||
userAudio.onended = () => {
|
||||
userTtsBtn.textContent = "🔊";
|
||||
isPlaying = false;
|
||||
userAudio = null;
|
||||
};
|
||||
|
||||
// Auto-play the generated audio
|
||||
try {
|
||||
await userAudio.play();
|
||||
} catch (playError) {
|
||||
userTtsBtn.textContent = "🔊";
|
||||
}
|
||||
} catch (error) {
|
||||
alert("User TTS failed: " + error.message);
|
||||
userTtsBtn.textContent = originalText;
|
||||
} finally {
|
||||
userTtsBtn.disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
const userDeleteBtn = document.createElement("button");
|
||||
userDeleteBtn.textContent = "🗑️";
|
||||
userDeleteBtn.title = "Delete message";
|
||||
|
|
@ -1234,6 +1318,7 @@ async function openUncloseaiEmbeddedModalNew() {
|
|||
userMsg.remove();
|
||||
};
|
||||
|
||||
userMessageActions.appendChild(userTtsBtn);
|
||||
userMessageActions.appendChild(userDeleteBtn);
|
||||
userMsg.appendChild(messageText);
|
||||
userMsg.appendChild(userMessageActions);
|
||||
|
|
@ -1542,6 +1627,84 @@ You have complete knowledge of this page content and can reference any details,
|
|||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
const userTtsBtn = document.createElement("button");
|
||||
userTtsBtn.textContent = "🔊";
|
||||
userTtsBtn.title = "Read aloud";
|
||||
userTtsBtn.style.cssText = `
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
color: white;
|
||||
transition: all 0.2s;
|
||||
`;
|
||||
userTtsBtn.onmouseenter = () => {
|
||||
userTtsBtn.style.background = 'rgba(255, 255, 255, 0.3)';
|
||||
};
|
||||
userTtsBtn.onmouseleave = () => {
|
||||
userTtsBtn.style.background = 'rgba(255, 255, 255, 0.2)';
|
||||
};
|
||||
|
||||
// Store audio for pause/resume functionality
|
||||
let historicalUserAudio = null;
|
||||
|
||||
userTtsBtn.onclick = async () => {
|
||||
const modalVoiceSelect = document.getElementById('hermes-voice-select');
|
||||
const selectedVoice = modalVoiceSelect?.value || 'alloy';
|
||||
|
||||
// If audio is already playing, pause it
|
||||
if (historicalUserAudio && !historicalUserAudio.paused) {
|
||||
historicalUserAudio.pause();
|
||||
userTtsBtn.textContent = "🔊";
|
||||
return;
|
||||
}
|
||||
|
||||
// If audio exists and is paused, resume it
|
||||
if (historicalUserAudio && historicalUserAudio.paused && historicalUserAudio.currentTime > 0) {
|
||||
historicalUserAudio.play();
|
||||
userTtsBtn.textContent = "⏸️";
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate new audio
|
||||
const originalText = userTtsBtn.textContent;
|
||||
userTtsBtn.textContent = "⏳";
|
||||
userTtsBtn.disabled = true;
|
||||
|
||||
try {
|
||||
const result = await speakChatText(msg.content, selectedVoice, 1.0);
|
||||
historicalUserAudio = result.audio;
|
||||
|
||||
// Set up audio event handlers
|
||||
historicalUserAudio.onplay = () => {
|
||||
userTtsBtn.textContent = "⏸️";
|
||||
};
|
||||
|
||||
historicalUserAudio.onpause = () => {
|
||||
userTtsBtn.textContent = "🔊";
|
||||
};
|
||||
|
||||
historicalUserAudio.onended = () => {
|
||||
userTtsBtn.textContent = "🔊";
|
||||
historicalUserAudio = null;
|
||||
};
|
||||
|
||||
// Auto-play the generated audio
|
||||
try {
|
||||
await historicalUserAudio.play();
|
||||
} catch (playError) {
|
||||
userTtsBtn.textContent = "🔊";
|
||||
}
|
||||
} catch (error) {
|
||||
alert("User TTS failed: " + error.message);
|
||||
userTtsBtn.textContent = originalText;
|
||||
} finally {
|
||||
userTtsBtn.disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
const userDeleteBtn = document.createElement("button");
|
||||
userDeleteBtn.textContent = "🗑️";
|
||||
userDeleteBtn.title = "Delete message";
|
||||
|
|
@ -1561,15 +1724,16 @@ You have complete knowledge of this page content and can reference any details,
|
|||
userDeleteBtn.onmouseleave = () => {
|
||||
userDeleteBtn.style.background = 'rgba(255, 255, 255, 0.2)';
|
||||
};
|
||||
userDeleteBtn.onclick = () => {
|
||||
userDeleteBtn.onclick = async () => {
|
||||
// Remove from chat history by index
|
||||
const currentHistory = loadConversationHistory();
|
||||
if (index >= 0 && index < currentHistory.length) {
|
||||
currentHistory.splice(index, 1);
|
||||
saveConversationHistory(currentHistory);
|
||||
|
||||
// Update the chat.js module history
|
||||
const systemMsg = currentHistory.find(msg => msg.role === 'system');
|
||||
// Update the chat.js module history to match localStorage
|
||||
const { updateChatHistory } = await import('./chat.js');
|
||||
const { getSystemMessage } = await import('./config.js');
|
||||
const newHistory = [
|
||||
{ role: 'system', content: getSystemMessage() },
|
||||
...currentHistory
|
||||
|
|
@ -1580,6 +1744,7 @@ You have complete knowledge of this page content and can reference any details,
|
|||
userMsg.remove();
|
||||
};
|
||||
|
||||
userMessageActions.appendChild(userTtsBtn);
|
||||
userMessageActions.appendChild(userDeleteBtn);
|
||||
userMsg.appendChild(messageText);
|
||||
userMsg.appendChild(userMessageActions);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue