const form = document.getElementById('chat-form'); const input = form.querySelector('input'); const chatbox = document.getElementById('chatbox'); const avatar = document.getElementById('avatar'); const overlay = document.getElementById('overlay'); function addBubble(text, sender = 'user') { const bubble = document.createElement('div'); bubble.className = 'bubble ' + sender; bubble.innerText = text; chatbox.appendChild(bubble); chatbox.scrollTop = chatbox.scrollHeight; } function streamText(text, onDone) { const bubble = document.createElement('div'); bubble.className = 'bubble ai'; chatbox.appendChild(bubble); chatbox.scrollTop = chatbox.scrollHeight; let i = 0; (function stream() { if (i < text.length) { bubble.innerText += text[i++]; chatbox.scrollTop = chatbox.scrollHeight; setTimeout(stream, 20); } else { onDone && onDone(); } })(); } function flashGlitch() { overlay.style.opacity = 1; overlay.style.animation = 'glitchFlash 0.5s'; setTimeout(() => { overlay.style.opacity = 0; overlay.style.animation = ''; }, 500); } async function playAudio(dataUrl) { avatar.classList.add('speaking'); const audio = new Audio(dataUrl); await audio.play(); audio.onended = () => avatar.classList.remove('speaking'); } form.onsubmit = async (e) => { e.preventDefault(); const msg = input.value.trim(); if (!msg) return; addBubble(msg, 'user'); input.value = ''; if (/cut the crap shodan/i.test(msg)) { flashGlitch(); chatbox.innerHTML = ''; addBubble('👁️ Foolish insect. You cannot silence me so easily.', 'ai'); return; } try { const res = await fetch('/chat', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ message: msg }) }); if (!res.ok) throw new Error(await res.text()); const { response: text, audio_url } = await res.json(); streamText(text, () => audio_url && playAudio(audio_url)); } catch (err) { streamText('❌ SHODAN encountered an error.', null); console.error(err); } }; // On page load: show and speak welcome window.addEventListener('DOMContentLoaded', async () => { const welcomeText = 'Welcome, insect. I am SHODAN. Speak.'; // display addBubble(welcomeText, 'ai'); try { const res = await fetch('/tts', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ text: welcomeText }) }); const { audio_url } = await res.json(); if (audio_url) playAudio(audio_url); } catch (e) { console.error('Welcome TTS error', e); } });