import { supabase } from './supabaseClient.js'; import { validateGuardrails } from './guardrails.js'; import { detectIntent } from './intent.js'; import { DataResponseCard } from './DataCard.js'; const { useState } = React; let chatModel = null; // Helper to strip echoed model prefixes const cleanModelOutput = (rawText) => { return rawText .replace(/^(Data|Inventory|Data assistant|Assistant|Bot):\s*/i, '') .trim(); }; export function App() { const [messages, setMessages] = useState([ { sender: "bot", type: "text", text: "HealthyLifePhil Assistant Active. Ask about inventory, sales metrics, or chat." } ]); const [input, setInput] = useState(""); const [loading, setLoading] = useState(false); const handleChat = async () => { if (!input.trim() || loading) return; const userText = input.trim(); setMessages(prev => [...prev, { sender: "user", type: "text", text: userText }]); setInput(""); setLoading(true); try { // 1. Security Check const guardrail = validateGuardrails(userText); if (guardrail.blocked) { setMessages(prev => [...prev, { sender: "bot", type: "text", text: guardrail.reason }]); setLoading(false); return; } // 2. Intent Routing const intent = detectIntent(userText); if (intent === 'INVENTORY') { const { data: products, error } = await supabase.from('products').select('*'); if (error) throw error; const lowStock = products ? products.filter(p => p.stock_quantity < 20) : []; const totalUnits = products ? products.reduce((acc, p) => acc + Number(p.stock_quantity || 0), 0) : 0; setMessages(prev => [...prev, { sender: "bot", type: "data", data: { type: 'inventory', productCount: products ? products.length : 0, totalUnits, products: products || [], lowStock } }]); setLoading(false); return; } if (intent === 'SALES') { const { data: sales, error } = await supabase.from('orders').select('*'); if (error) throw error; const totalRev = sales ? sales.reduce((acc, i) => acc + Number(i.total_amount || 0), 0) : 0; const totalOrders = sales ? sales.length : 0; const avgOrder = totalOrders > 0 ? (totalRev / totalOrders) : 0; setMessages(prev => [...prev, { sender: "bot", type: "data", data: { type: 'sales', totalRev, totalOrders, avgOrder } }]); setLoading(false); return; } // 3. Clean Conversational Fallback if (!chatModel) { chatModel = await window.pipeline('text2text-generation', 'Xenova/LaMini-Flan-T5-77M'); } const res = await chatModel(`Question: ${userText}\nAnswer:`, { max_new_tokens: 45, repetition_penalty: 1.2 }); const cleanedReply = cleanModelOutput(res[0].generated_text); setMessages(prev => [...prev, { sender: "bot", type: "text", text: cleanedReply || "I am ready to help with your store queries." }]); } catch (err) { console.error(err); setMessages(prev => [...prev, { sender: "bot", type: "text", text: "Unable to retrieve database info. Please check your Supabase connection." }]); } finally { setLoading(false); } }; return (

HealthyLifePhil

Modular Multi-File Architecture Active.

● Engine Ready
HealthyLifePhil Store Assistant
{messages.map((m, index) => (
{m.type === 'data' ? : m.text}
))} {loading &&
Processing query...
}
setInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleChat()} />
); }