1import { RECIPES } from './dataset.js'; 2 3export function initAiMood() { 4 const inputEl = document.getElementById('ai-prompt-input'); 5 const sendBtn = document.getElementById('ai-prompt-btn'); 6 const chatContainer = document.getElementById('ai-chat-thread'); 7 8 if (!inputEl || !sendBtn || !chatContainer) return; 9 10 sendBtn.addEventListener('click', handleUserPrompt); 11 inputEl.addEventListener('keypress', (e) => { 12 if (e.key === 'Enter') handleUserPrompt(); 13 }); 14 15 function handleUserPrompt() { 16 const text = inputEl.value.trim(); 17 if (!text) return; 18 19 appendBubble(text, 'user'); 20 inputEl.value = ''; 21 22 setTimeout(() => { 23 processAiResponse(text); 24 }, 400); 25 } 26 27 function appendBubble(text, type) { 28 const bubble = document.createElement('div'); 29 bubble.className = `ai-bubble ${type}`; 30 bubble.innerHTML = text; 31 chatContainer.appendChild(bubble); 32 chatContainer.scrollTop = chatContainer.scrollHeight; 33 } 34 35 function processAiResponse(prompt) { 36 const lower = prompt.toLowerCase(); 37 let matches = []; 38 39 if (lower.includes('quick') || lower.includes('fast') || lower.includes('minute') || lower.includes('20')) { 40 matches = RECIPES.filter(r => (r.tags || r.recommendation_tags || []).includes('Quick & Easy') || (r.prepTimeMinutes && r.prepTimeMinutes <= 25)); 41 } else if (lower.includes('protein') || lower.includes('gym') || lower.includes('muscle') || lower.includes('chicken')) { 42 matches = RECIPES.filter(r => (r.tags || r.recommendation_tags || []).includes('High-Protein') || (r.proteinG && r.proteinG >= 30)); 43 } else if (lower.includes('comfort') || lower.includes('rainy') || lower.includes('cozy') || lower.includes('pasta')) { 44 matches = RECIPES.filter(r => (r.tags || r.recommendation_tags || []).includes('Comfort') || (r.tags || r.recommendation_tags || []).includes('Italian')); 45 } else if (lower.includes('spicy') || lower.includes('hot') || lower.includes('curry') || lower.includes('mexican')) { 46 matches = RECIPES.filter(r => (r.tags || r.recommendation_tags || []).includes('Spicy') || (r.tags || r.recommendation_tags || []).includes('Mexican')); 47 } else { 48 matches = RECIPES.slice(0, 3); 49 } 50 51 const topDish = matches[Math.floor(Math.random() * Math.min(matches.length, 5))] || RECIPES[0]; 52 const topTag = (topDish.tags || topDish.recommendation_tags || ['Chef Pick'])[0]; 53 const prep = topDish.prepTimeMinutes ? `${topDish.prepTimeMinutes} mins` : (topDish.prep_time || '25 mins'); 54 55 const reply = ` 56 ⨠Boosted <strong>${topTag}</strong> & dialed in your craving!<br/> 57 Tonight's top match: <strong style="color: var(--salmon);">${topDish.title}</strong> (${prep} ⢠${topDish.calories} kcal).<br/> 58 <span style="font-size: 0.8rem; color: var(--ink-secondary); font-family: var(--font-mono);">Calibrated with 98.4% taste alignment.</span> 59 `; 60 61 appendBubble(reply, 'assistant'); 62 } 63}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.