// Configuration const API_KEY = 'GEMINI_KEY'; const API_URL = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${API_KEY}`; const synth = window.speechSynthesis; let isSpeaking = false; let recognition = null; let isDarkMode = localStorage.getItem('darkMode') === 'enabled';
// Initialize dark mode function initDarkMode() { if (isDarkMode) { body.classList.add('dark-mode'); localStorage.setItem('darkMode', 'enabled'); } else { body.classList.remove('dark-mode'); localStorage.setItem('darkMode', 'disabled'); } }
// Toggle dark mode function toggleDarkMode() { isDarkMode = !isDarkMode; initDarkMode(); }
// Event listeners for dark mode darkModeToggle.addEventListener('click', toggleDarkMode); initDarkMode();
// Speech Recognition Setup function initSpeechRecognition() { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (SpeechRecognition) { recognition = new SpeechRecognition(); recognition.continuous = false; recognition.interimResults = false; recognition.lang = 'en-US';
// Hold-to-speak functionality let isRecording = false;
speakBtn.addEventListener('mousedown', startRecording); speakBtn.addEventListener('touchstart', startRecording);
speakBtn.addEventListener('mouseup', stopRecording); speakBtn.addEventListener('touchend', stopRecording); speakBtn.addEventListener('touchcancel', stopRecording);
function startRecording(e) { e.preventDefault(); if (isRecording) return; isRecording = true; userInput.placeholder = "Listening..."; recognition.start(); }
function stopRecording() { if (!isRecording) return; isRecording = false; recognition.stop(); userInput.placeholder = "Ask me anything..."; }
recognition.onresult = (event) => { const transcript = event.results[0][0].transcript; userInput.value = transcript; handleSend(); };
recognition.onerror = () => { userInput.placeholder = "Ask me anything..."; addMessage("Sorry, I didn't catch that. Please try speaking again."); }; } else { speakBtn.disabled = true; speakBtn.title = "Speech recognition not supported in your browser"; } }
// Handle special queries function handleNameQuery(prompt) { const lowerPrompt = prompt.toLowerCase(); if (lowerPrompt.includes('your name') || lowerPrompt.includes('who are you') || lowerPrompt.includes('what are you')) { return "I'm sOubhIk AI - Your personal artificial intelligence assistant!"; } return null; }
// Get response from Gemini API async function getGeminiResponse(prompt) { const nameResponse = handleNameQuery(prompt); if (nameResponse) return nameResponse;
try { const response = await fetch(API_URL, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({contents: [{parts: [{text: prompt}]}]}) }); const data = await response.json(); return data.candidates?.[0]?.content?.parts?.[0]?.text || "I'm sorry, I didn't understand that. Could you rephrase?"; } catch (error) { console.error('API Error:', error); return "I'm having trouble connecting right now. Please try again later."; } }
// Add message to chat function addMessage(message, isUser = false) { const messageDiv = document.createElement('div'); messageDiv.className = `message ${isUser ? 'user-message' : 'bot-message'}`; messageDiv.textContent = message; chatContainer.appendChild(messageDiv); chatContainer.scrollTop = chatContainer.scrollHeight;
if (!isUser && toggleSpeech.checked) { speakResponse(message); } }
// Speak response function speakResponse(text) { if (isSpeaking || !text) return;
// Cancel any ongoing speech synth.cancel();
const utterance = new SpeechSynthesisUtterance(text);
// Select a voice const voices = synth.getVoices(); const preferredVoice = voices.find(voice => voice.name.includes('Male') || voice.lang === 'en-US' || voice.name.includes('Google') );
if (preferredVoice) { utterance.voice = preferredVoice; }
utterance.rate = 1; utterance.pitch = 1; utterance.volume = 1;
utterance.onstart = () => { isSpeaking = true; botAvatar.parentElement.classList.add('speaking'); speechBubble.textContent = text; speechBubble.classList.add('active'); };
utterance.onend = () => { isSpeaking = false; botAvatar.parentElement.classList.remove('speaking'); speechBubble.classList.remove('active'); };
utterance.onerror = (event) => { console.error('SpeechSynthesis error:', event); isSpeaking = false; botAvatar.parentElement.classList.remove('speaking'); speechBubble.classList.remove('active'); };
synth.speak(utterance); }
// Handle send message async function handleSend() { const prompt = userInput.value.trim(); if (!prompt) return;
addMessage(prompt, true); userInput.value = ''; disableInputs(true);
const thinkingDiv = document.createElement('div'); thinkingDiv.className = 'message bot-message thinking'; thinkingDiv.innerHTML = `
Processing...`; chatContainer.appendChild(thinkingDiv); chatContainer.scrollTop = chatContainer.scrollHeight;
try { const response = await getGeminiResponse(prompt); chatContainer.removeChild(thinkingDiv); addMessage(response); } catch (error) { chatContainer.removeChild(thinkingDiv); addMessage("Sorry, I encountered an error. Please try again."); } disableInputs(false); userInput.focus(); }
// Disable/enable inputs function disableInputs(disabled) { userInput.disabled = disabled; sendBtn.disabled = disabled; speakBtn.disabled = disabled; }
// Initialize the app function init() { // Load voices when they become available synth.onvoiceschanged = () => { console.log('Voices loaded:', synth.getVoices()); };
// Initial bot introduction setTimeout(() => { addMessage("Hello! I'm sOubhIk AI. How can I assist you today?", false); }, 1000);
// Event Listeners sendBtn.addEventListener('click', handleSend); userInput.addEventListener('keypress', (e) => e.key === 'Enter' && handleSend());
// Initialize speech recognition initSpeechRecognition(); }
// Start the app
document.addEventListener('DOMContentLoaded', init);