Skip to content

Commit b6912b0

Browse files
authored
Merge branch 'main' into develop
2 parents 0bc1441 + c80a067 commit b6912b0

File tree

4 files changed

+456
-246
lines changed

4 files changed

+456
-246
lines changed

ai/chat-part1.js

Lines changed: 90 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,30 @@ document.addEventListener("DOMContentLoaded", () => {
99
const voiceToggleBtn = document.getElementById("voice-toggle");
1010
const modelSelect = document.getElementById("model-select");
1111

12+
// Initialize current session from storage (or create a new one if none exists)
13+
let currentSession = Storage.getCurrentSession();
14+
if (!currentSession) {
15+
currentSession = Storage.createSession("New Chat");
16+
localStorage.setItem("currentSessionId", currentSession.id);
17+
}
18+
1219
const synth = window.speechSynthesis;
1320
let voices = [];
1421
let selectedVoice = null;
1522
let isSpeaking = false;
1623
let autoSpeakEnabled = localStorage.getItem("autoSpeakEnabled") === "true";
1724
let currentlySpeakingMessage = null;
25+
26+
// Combined variable declarations from both branches
1827
let activeUtterance = null;
1928
let recognition = null;
2029
let isListening = false;
2130
let voiceInputBtn = null;
31+
let slideshowInterval = null;
2232

23-
// Voice Chat Modal Elements
24-
const voiceChatModal = document.getElementById("voice-chat-modal") || createVoiceChatModal();
33+
// Voice Chat Modal Elements (from develop branch)
34+
const voiceChatModal =
35+
document.getElementById("voice-chat-modal") || createVoiceChatModal();
2536
const voiceChatBtn = document.getElementById("open-voice-chat-modal");
2637
const voiceChatClose = document.getElementById("voice-chat-modal-close");
2738
const voiceChatListen = document.getElementById("voice-chat-listen");
@@ -66,8 +77,30 @@ document.addEventListener("DOMContentLoaded", () => {
6677
voices = synth.getVoices();
6778
if (voices.length > 0) {
6879
voicesLoaded = true;
80+
// First try to restore a previously selected voice
6981
const savedVoiceIndex = localStorage.getItem("selectedVoiceIndex");
70-
selectedVoice = savedVoiceIndex && voices[savedVoiceIndex] ? voices[savedVoiceIndex] : voices.find(v => v.name.toLowerCase().includes("female")) || voices[0];
82+
if (savedVoiceIndex && voices[savedVoiceIndex]) {
83+
selectedVoice = voices[savedVoiceIndex];
84+
} else {
85+
// Otherwise, use a list of preferred voices
86+
const preferredVoices = [
87+
"Google UK English Female",
88+
"Microsoft Zira",
89+
"Samantha",
90+
"Victoria"
91+
];
92+
for (const name of preferredVoices) {
93+
const voice = voices.find((v) => v.name === name);
94+
if (voice) {
95+
selectedVoice = voice;
96+
break;
97+
}
98+
}
99+
if (!selectedVoice) {
100+
selectedVoice = voices.find((v) => v.name.toLowerCase().includes("female")) || voices[0];
101+
}
102+
}
103+
console.log("Selected voice:", selectedVoice ? selectedVoice.name : "None");
71104
resolve(selectedVoice);
72105
}
73106
}
@@ -78,9 +111,10 @@ document.addEventListener("DOMContentLoaded", () => {
78111
});
79112
}
80113

81-
loadVoices().then(() => updateVoiceToggleUI());
114+
loadVoices().then(() => {
115+
updateVoiceToggleUI();
116+
});
82117

83-
// Toggle auto-speak
84118
function toggleAutoSpeak() {
85119
autoSpeakEnabled = !autoSpeakEnabled;
86120
localStorage.setItem("autoSpeakEnabled", autoSpeakEnabled.toString());
@@ -90,24 +124,41 @@ document.addEventListener("DOMContentLoaded", () => {
90124

91125
function updateVoiceToggleUI() {
92126
if (voiceToggleBtn) {
93-
voiceToggleBtn.innerHTML = autoSpeakEnabled ? '<i class="fas fa-volume-up"></i> Voice On' : '<i class="fas fa-volume-mute"></i> Voice Off';
127+
voiceToggleBtn.innerHTML = autoSpeakEnabled
128+
? '<i class="fas fa-volume-up"></i> Voice On'
129+
: '<i class="fas fa-volume-mute"></i> Voice Off';
94130
voiceToggleBtn.style.backgroundColor = autoSpeakEnabled ? "#4CAF50" : "";
95131
}
96132
}
97133

98-
// Speak message with completion callback
99134
function speakMessage(text, onEnd = null) {
100135
if (!synth || !window.SpeechSynthesisUtterance) {
101136
showToast("Speech synthesis not supported");
102137
return;
103138
}
104-
if (isSpeaking) synth.cancel();
139+
if (isSpeaking) {
140+
synth.cancel();
141+
}
142+
143+
let cleanText = text
144+
.replace(/```[\s\S]*?```/g, "code block omitted.")
145+
.replace(/`[\s\S]*?`/g, "inline code omitted.")
146+
.replace(/https?:\/\/[^\s]+/g, "URL link.");
105147

106-
const cleanText = text.replace(/```[\s\S]*?```/g, "code block omitted.").replace(/`[\s\S]*?`/g, "inline code omitted.");
107148
const utterance = new SpeechSynthesisUtterance(cleanText);
108149
activeUtterance = utterance;
109-
if (selectedVoice) utterance.voice = selectedVoice;
110-
utterance.rate = 0.9;
150+
if (selectedVoice) {
151+
utterance.voice = selectedVoice;
152+
} else {
153+
loadVoices().then((voice) => {
154+
if (voice) {
155+
utterance.voice = voice;
156+
synth.speak(utterance);
157+
}
158+
});
159+
return;
160+
}
161+
utterance.rate = 1.0;
111162
utterance.pitch = 1.0;
112163
utterance.volume = 1.0;
113164

@@ -155,7 +206,6 @@ document.addEventListener("DOMContentLoaded", () => {
155206
}
156207
}
157208

158-
// Initialize speech recognition
159209
function initSpeechRecognition() {
160210
if ("webkitSpeechRecognition" in window) {
161211
recognition = new webkitSpeechRecognition();
@@ -218,36 +268,43 @@ document.addEventListener("DOMContentLoaded", () => {
218268

219269
// Send voice chat message to API and handle response
220270
function sendVoiceChatMessage(message) {
221-
const currentSession = Storage.getCurrentSession();
222-
currentSession.messages.push({ role: "user", content: message });
223-
Storage.updateSessionMessages(currentSession.id, currentSession.messages);
271+
// Use the global currentSession, but refresh it from Storage if needed
272+
const session = Storage.getCurrentSession();
273+
session.messages.push({ role: "user", content: message });
274+
Storage.updateSessionMessages(session.id, session.messages);
224275
window.addNewMessage({ role: "user", content: message }); // Display in chat
225276
statusText.textContent = "Waiting for AI response...";
226277

227278
const messages = [
228279
{ role: "system", content: "You are a helpful AI assistant. Respond concisely." },
229-
...currentSession.messages.slice(-10).map(msg => ({ role: msg.role === "ai" ? "assistant" : "user", content: msg.content }))
280+
...session.messages.slice(-10).map((msg) => ({
281+
role: msg.role === "ai" ? "assistant" : "user",
282+
content: msg.content
283+
}))
230284
];
231285

232-
const safeParam = window._pollinationsAPIConfig ? `safe=${window._pollinationsAPIConfig.safe}` : "safe=false";
286+
const safeParam = window._pollinationsAPIConfig
287+
? `safe=${window._pollinationsAPIConfig.safe}`
288+
: "safe=false";
233289
fetch(`https://text.pollinations.ai/openai?${safeParam}`, {
234290
method: "POST",
235291
headers: { "Content-Type": "application/json" },
236292
body: JSON.stringify({ messages, model: modelSelect.value || "unity", stream: false })
237293
})
238-
.then(res => {
294+
.then((res) => {
239295
if (!res.ok) throw new Error(`Pollinations error: ${res.status}`);
240296
return res.json();
241297
})
242-
.then(data => {
298+
.then((data) => {
243299
let aiContent = data.choices?.[0]?.message?.content || "Error: No response";
244300

245301
// Check for image generation request
246302
const lastUserMsg = message.toLowerCase();
247-
const isImageRequest = lastUserMsg.includes("image") ||
248-
lastUserMsg.includes("picture") ||
249-
lastUserMsg.includes("show me") ||
250-
lastUserMsg.includes("generate an image");
303+
const isImageRequest =
304+
lastUserMsg.includes("image") ||
305+
lastUserMsg.includes("picture") ||
306+
lastUserMsg.includes("show me") ||
307+
lastUserMsg.includes("generate an image");
251308
if (isImageRequest && !aiContent.includes("https://image.pollinations.ai")) {
252309
let imagePrompt = lastUserMsg.replace(/show me|generate|image of|picture of|image|picture/gi, "").trim();
253310
if (imagePrompt.length < 5 && aiContent.toLowerCase().includes("image")) {
@@ -256,20 +313,22 @@ document.addEventListener("DOMContentLoaded", () => {
256313
if (imagePrompt.length > 100) imagePrompt = imagePrompt.substring(0, 100);
257314
imagePrompt += ", photographic";
258315
const seed = Math.floor(Math.random() * 1000000);
259-
const imageUrl = `https://image.pollinations.ai/prompt/${encodeURIComponent(imagePrompt)}?width=512&height=512&seed=${seed}&${safeParam}&nolog=true`;
316+
const imageUrl = `https://image.pollinations.ai/prompt/${encodeURIComponent(
317+
imagePrompt
318+
)}?width=512&height=512&seed=${seed}&${safeParam}&nolog=true`;
260319
aiContent += `\n\n**Generated Image:**\n${imageUrl}`;
261320
}
262321

263-
currentSession.messages.push({ role: "ai", content: aiContent });
264-
Storage.updateSessionMessages(currentSession.id, currentSession.messages);
322+
session.messages.push({ role: "ai", content: aiContent });
323+
Storage.updateSessionMessages(session.id, session.messages);
265324
window.addNewMessage({ role: "ai", content: aiContent }); // Display in chat
266325
voiceChatTranscript.value = aiContent;
267326
statusText.textContent = "Speaking response...";
268327
speakMessage(aiContent, () => {
269328
statusText.textContent = "Press 'Listen' to start";
270329
});
271330
})
272-
.catch(err => {
331+
.catch((err) => {
273332
showToast("Failed to get AI response");
274333
statusText.textContent = "Error: Try again";
275334
});
@@ -328,7 +387,7 @@ document.addEventListener("DOMContentLoaded", () => {
328387
toast.textContent = message;
329388
toast.style.opacity = "1";
330389
clearTimeout(toast.timeout);
331-
toast.timeout = setTimeout(() => toast.style.opacity = "0", duration);
390+
toast.timeout = setTimeout(() => (toast.style.opacity = "0"), duration);
332391
}
333392

334393
window._chatInternals = {
@@ -338,6 +397,7 @@ document.addEventListener("DOMContentLoaded", () => {
338397
clearChatBtn,
339398
voiceToggleBtn,
340399
modelSelect,
400+
currentSession,
341401
synth,
342402
voices,
343403
selectedVoice,
@@ -347,11 +407,12 @@ document.addEventListener("DOMContentLoaded", () => {
347407
recognition,
348408
isListening,
349409
voiceInputBtn,
410+
slideshowInterval,
350411
toggleAutoSpeak,
351412
updateVoiceToggleUI,
352413
speakMessage,
353414
stopSpeaking,
354415
initSpeechRecognition,
355416
showToast
356417
};
357-
});
418+
});

0 commit comments

Comments
 (0)