fix user message TTS
TerminallyLazy committed
Aug 4, 2025 at 22:32 UTC
f9958ae3d18547c594a88049ce112414d9afacee
1 file changed
+59
-9
webui/components/messages/action-buttons/message-action-buttons.js
+59
-9
@@ -6,8 +6,10 @@ function extractTextContent(container) {
6
if (container.classList.contains("kvps-row")) {
7
return container.querySelector(".kvps-val")?.innerText || "";
8
} else if (container.classList.contains("message-text")) {
9
- return container.querySelector("span")?.innerText || "";
9
+ // User messages use <pre> elements, not <span>
10
+ return container.querySelector("pre")?.innerText || container.querySelector("span")?.innerText || "";
11
} else {
12
+ // Other message types use <span> elements
13
return container.querySelector("span")?.innerText || "";
14
}
15
}
@@ -63,37 +65,85 @@ function showCopyFeedback(button, success) {
65
// Speak text using speech store
66
async function speakContent(text, button) {
67
try {
68
+ // Validate input text
69
+ if (!text || typeof text !== 'string' || text.trim().length === 0) {
70
+ console.warn("TTS: No valid text to speak");
71
+ return;
72
+ }
73
+
74
// Update button state
75
button.classList.add("speaking");
76
const icon = button.querySelector(".material-symbols-outlined");
77
const originalIcon = icon.textContent;
78
79
// Check if already speaking
72
- if (speechStore.isSpeaking && speechStore.speakingText === text) {
73
- // Stop speaking
74
- speechStore.stopSpeaking();
80
+ if (speechStore.isSpeaking) {
81
+ // Stop speaking using the correct speech store method
82
+ if (speechStore.stop) {
83
+ speechStore.stop();
84
+ } else {
85
+ // Fallback if stop doesn't exist
86
+ speechSynthesis.cancel();
87
+ }
88
icon.textContent = originalIcon;
89
button.classList.remove("speaking");
90
return;
91
}
92
93
// Clean and speak text
81
- const cleanedText = speechStore.cleanText ? speechStore.cleanText(text) : text;
94
+ const cleanedText = speechStore.cleanText ? speechStore.cleanText(text.trim()) : text.trim();
95
+
96
+ // Validate cleaned text
97
+ if (!cleanedText || cleanedText.length === 0) {
98
+ console.warn("TTS: Text was empty after cleaning");
99
+ button.classList.remove("speaking");
100
+ return;
101
+ }
102
103
// Update icon to show speaking state
104
icon.textContent = "stop_circle";
105
86
- // Start speaking
87
- await speechStore.speak(cleanedText);
106
+ // Start speaking - use the speak function from speech store
107
+ if (speechStore.speak) {
108
+ await speechStore.speak(cleanedText);
109
+ } else {
110
+ // Fallback to browser TTS if speech store doesn't have speak function
111
+ const utterance = new SpeechSynthesisUtterance(cleanedText);
112
+ utterance.lang = 'en-US'; // Ensure English language
113
+ utterance.rate = 1.0;
114
+ utterance.pitch = 1.0;
115
+ utterance.volume = 1.0;
116
+
117
+ // Handle utterance events
118
+ utterance.onend = () => {
119
+ icon.textContent = originalIcon;
120
+ button.classList.remove("speaking");
121
+ };
122
+
123
+ utterance.onerror = (event) => {
124
+ console.error("TTS utterance error:", event.error);
125
+ icon.textContent = originalIcon;
126
+ button.classList.remove("speaking");
127
+ };
128
+
129
+ speechSynthesis.speak(utterance);
130
+ return; // Don't reset button state immediately for browser TTS
131
+ }
132
89
- // Reset button state when done
90
- icon.textContent = "volume_up";
133
+ // Reset button state when done (for speech store)
134
+ icon.textContent = originalIcon;
135
button.classList.remove("speaking");
136
137
} catch (err) {
138
console.error("Speech failed:", err);
139
button.classList.remove("speaking");
140
141
+ // Reset icon
142
+ const icon = button.querySelector(".material-symbols-outlined");
143
+ if (icon) {
144
+ icon.textContent = "volume_up";
145
+ }
146
+
147
// Show error feedback
148
button.classList.add("error");
149