//javascript
// let audioEnabled = false; // audio is ooff
// let audioMuted = true;
let currentAudio = null;
async function playReply(src) {
if (currentAudio) {
currentAudio.pause();
currentAudio = null;
}
currentAudio = new Audio(src);
await currentAudio.play();
}
document.getElementById('toggle-audio').addEventListener('click', () => {
audioEnabled = !audioEnabled;
audioMuted = !audioMuted;
const icon = audioEnabled ? '🔊' : '🔇';
const label = audioEnabled ? 'Audio: On' : 'Audio: Off';
document.getElementById('toggle-audio').textContent = `${icon} ${label}`;
// stop any in-flight audio
if (currentAudio) {
currentAudio.pause();
currentAudio = null;
}
// speechSynthesis.cancel(); // Stop anything currently speaking
console.log('🔇 Audio muted');
});
let audio_instruction; // = 'Speak in a funny middle aged and funny tone, like a sasquatch';
const openingTaglines = [
'Hey there, forest friend—Willy Squatch here! What wild wisdom can I share today?',
'Willy’s in the woods but I heard you—what cryptid conundrum’s on your mind?',
'Sup, woodland wanderer? Willy Squatch at your service—let’s get squatchy!',
'Growl! Willy Squatch reporting—hit me with your best question!',
'You rang? Willy Squatch here—ready to dish out some hairy advice!',
'What’s crackling among the leaves today? Willy Squatch is all ears!',
'Good day, tree trooper—Willy Squatch listening, shoot me your question!',
'Roar! Willy Squatch on the line—what’s got you curious in these woods?',
'Willy Squatch in the underbrush—what’s the scoop from your corner of the forest?',
];
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// pick one at random
const randomTag = openingTaglines[
Math.floor(Math.random() * openingTaglines.length)
];
// you can extract your greeting logic into its own async fn:
async function fireGreeting() {
sendBtn.disabled = true;
const typingEl = showTypingIndicator();
let payload;
audio_instruction = 'Speak in a mean old man and scarey tone, like a sasquatch, end in a GRRRRRRR! HA Ha HA';
try {
payload = await speakWithEleven(randomTag);
} catch (err) {
console.error('TTS error:', err);
removeTypingIndicator(typingEl);
appendMsg('assist', randomTag, true);
return;
}
if (!payload.audio) {
console.error('No audio returned');
removeTypingIndicator(typingEl);
appendMsg('assist', randomTag, true);
return;
}
const audio = new Audio(payload.audio);
audio.addEventListener('play', () => {
removeTypingIndicator(typingEl);
appendMsg('assist', randomTag, true);
}, { once: true });
try {
await audio.play();
} catch (err) {
console.error('Playback failed:', err);
removeTypingIndicator(typingEl);
appendMsg('assist', randomTag, true);
}
/// send an adv
const cpaHtml = `
Top Q to Ask Willy! (click)
-
What’s the ultimate side hustle you’d recommend?
`;
// appendMsg('list', cpaHtml, true);
sendBtn.disabled = false;
inputEl.focus();
}
// --- DOM References ---
const chatEl = document.getElementById('chat');
const inputEl = document.getElementById('input');
const sendBtn = document.getElementById('send');
let userHasInteracted = false;
// delegate all clicks on .ask_q, even if added later
document.addEventListener('click', async (e) => {
const li = e.target.closest('.ask_q');
if (!li) return;
// grab the question
const msg = li.getAttribute('data-message');
inputEl.value = msg;
// fire your send routine
await sendMessage();
});
// --- Typing Indicator ---
function showTypingIndicator() {
const indicator = document.createElement('div');
indicator.className = 'typing-indicator';
indicator.innerHTML = '...';
chatEl.appendChild(indicator);
chatEl.scrollTop = chatEl.scrollHeight;
return indicator;
}
function removeTypingIndicator(ind) {
if (ind && ind.parentNode) ind.parentNode.removeChild(ind);
}
// --- Append Messages ---
function appendMsg(role, content, isHtml = false) {
const wrapper = document.createElement('div');
wrapper.classList.add('msg', role === 'user' ? 'user' : role === 'assist' ? 'assist' : role === 'adv' ? 'adv' : 'assist');
if (role === 'assist') {
const avatar = document.createElement('img');
avatar.src = 'willy_logo.png';
avatar.alt = 'Willy';
avatar.className = 'avatar';
wrapper.appendChild(avatar);
}
// if this is an “adv” message, inject an AdSense block
if (role === 'adv') {
// 1. Create a new, un-marked ins
const adIns = document.createElement('ins');
adIns.className = 'adsbygoogle';
adIns.style.display = 'block';
adIns.style.width = '100%';
adIns.style.maxWidth = '300px';
adIns.setAttribute('data-ad-client', 'ca-pub-2528341625965597');
adIns.setAttribute('data-ad-slot', '4861484366');
// adIns.setAttribute('data-ad-format', 'fluid');
adIns.setAttribute('data-ad-layout-key', '-6t+ed+2i-1n-4w');
adIns.setAttribute('data-ad-format', 'fluid');
adIns.setAttribute('data-full-width-responsive', 'true');
wrapper.appendChild(adIns);
chatEl.appendChild(wrapper);
chatEl.scrollTop = chatEl.scrollHeight;
// 2. Mark it immediately and push only this one
adIns.dataset.adsInitiated = 'true';
setTimeout(() => {
try {
(adsbygoogle = window.adsbygoogle || []).push({});
} catch (e) {
// no-op
}
}, 0);
}
const textEl = document.createElement('div');
if (isHtml) textEl.innerHTML = content;
else textEl.textContent = content;
wrapper.appendChild(textEl);
chatEl.appendChild(wrapper);
chatEl.scrollTop = chatEl.scrollHeight;
}
inputEl.addEventListener('keydown', e => {
if (e.key === 'Enter' && !sendBtn.disabled) {
e.preventDefault(); // prevent a form submit if you have one
sendMessage();
}
});
// --- Send Message ---
async function sendMessage() {
if (sendBtn.disabled) return;
userHasInteracted = true;
const msg = inputEl.value.trim();
if (!msg) return;
appendMsg('user', msg);
inputEl.value = '';
sendBtn.disabled = true;
const typingEl = showTypingIndicator();
try {
const res = await fetch('../../../../scripts/yeti_chat.js.php', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: msg
})
});
const data = await res.json();
/// look for action
if (data.action) { eval(data.action);}
if (data.error) {
appendMsg('assist', `Error: ${data.error}`, true);
} else {
let payload;
try {
audio_instruction = 'Speak in a kind old man and scruffy tone, like a sasquatch, end in a happy Grrrrr and a laugh! Ha Ha HA!';
payload = await speakWithEleven(data.reply);
} catch (err) {
console.error('TTS error:', err);
appendMsg('assist', data.reply, true);
return;
}
if (!payload.audio) {
removeTypingIndicator(typingEl);
console.error('No audio returned');
appendMsg('assist', data.reply, true);
return;
}
const audio = new Audio(payload.audio);
audio.addEventListener('play', () => {
appendMsg('assist', data.reply, true);
}, { once: true });
audio.addEventListener('ended', () => {
console.log('Audio has finished playing');
sendBtn.disabled = false;
}, { once: true });
try {
await audio.play();
} catch (err) {
console.error('Playback failed:', err);
appendMsg('assist', data.reply, true);
}
}
removeTypingIndicator(typingEl);
} catch (err) {
removeTypingIndicator(typingEl);
appendMsg('assist', 'Network error, Service in these woods is sketchy!! try again.', true);
console.error(err);
} finally {
sendBtn.disabled = false;
inputEl.focus();
}
}
// --- Event Listeners ---
sendBtn.addEventListener('click', sendMessage);
inputEl.addEventListener('keydown', e => { if (e.key === 'Enter') sendMessage(); });
function stripTags(str) { return str.replace(/<[^>]*>/g, ''); }
async function speakWithEleven(text) {
if (audioMuted) {return { error: "Audio is muted so no audio" }; }
text = stripTags(text);
try {
const token = 'a4456a6b-128d-4f9c-8dbc-85e8b2584303';
const res = await fetch('../../../../../scripts/chat_voicekiller.js.php', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ instructions: audio_instruction, token, text })
});
const payload = await res.json();
if (!res.ok) throw new Error(payload.error || 'TTS failed');
return payload;
} catch (err) {
console.error(err);
window.speechSynthesis.speak(new SpeechSynthesisUtterance(text));
}
}