const { useState, useEffect, useRef, useMemo } = React; /** * Recipe Renderer for the AI Chat section - Text-only version */ const AiRecipeRenderer = ({ recipe, onAdd }) => { return (
{recipe.cuisine}

{recipe.name}

{recipe.time} {recipe.difficulty}
); }; const CentralAIChat = ({ onNewRecipe }) => { const [messages, setMessages] = useState([ { role: 'assistant', content: "I'm QTCook AI. Tell me what you're craving and I'll generate a recipe with ingredients and cooking instructions!", id: 'init' } ]); const [input, setInput] = useState(''); const [isLoading, setIsLoading] = useState(false); const chatEndRef = useRef(null); const aiClient = useRef(new QTwareAI({ systemPrompt: `You are QTCook AI. When providing recipes, ALWAYS include a JSON block at the end. \n JSON SCHEMA: { \n "type": "recipe", \n "name": "Name", \n "cuisine": "Cuisine", \n "time": "Time", \n "difficulty": "Difficulty", \n "ingredients": ["item 1"], \n "instructions": ["step 1", "step 2"]\n }.\n Do NOT provide any text outside the JSON block.`, model: 'gpt-4o' })); useEffect(() => { chatEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [messages]); const handleSend = async (e) => { e.preventDefault(); if (!input.trim() || isLoading) return; const userMsg = input; setMessages(prev => [...prev, { role: 'user', content: userMsg, id: Date.now() }]); setInput(''); setIsLoading(true); try { const response = await aiClient.current.chat(userMsg); setMessages(prev => [...prev, { role: 'assistant', content: response, id: Date.now() + 1 }]); } catch (error) { setMessages(prev => [...prev, { role: 'assistant', content: "The kitchen is a bit busy. Please try again!", id: Date.now() + 2 }]); } finally { setIsLoading(false); } }; const parseResponse = (content, msgId) => { const jsonRegex = /```json([\\s\\S]*?)```|\\{([\\s\\S]*?)"type":\\s*"recipe"([\\s\\S]*?)\\}/; const match = content.match(jsonRegex); if (match) { try { let jsonStr = match[0]; if (jsonStr.startsWith('```json')) { jsonStr = match[1]; } const data = JSON.parse(jsonStr.trim()); return { text: '', data }; } catch (e) { return { text: content, data: null }; } } return { text: content, data: null }; }; return (
AI CULINARY HUB

QTCook Intelligence

{messages.map((msg) => { const parsed = parseResponse(msg.content, msg.id); return (
{parsed.text &&
{parsed.text}
} {parsed.data && parsed.data.type === 'recipe' && ( )}
); })} {isLoading &&
Cooking up a recipe...
}
setInput(e.target.value)} />
); }; const App = () => { const [recipes, setRecipes] = useState([]); const [filter, setFilter] = useState("All"); const [selectedRecipe, setSelectedRecipe] = useState(null); const cuisines = ["All", "Turkish", "Italian", "Japanese", "Mexican", "French"]; const addNewRecipe = (recipe) => { const newRecipe = { ...recipe, id: Date.now() }; setRecipes(prev => [newRecipe, ...prev]); }; const filtered = recipes.filter(r => filter === "All" || r.cuisine === filter); return (

Culinary Collection

{cuisines.map(c => ( ))}
{filtered.length === 0 && (

No recipes yet. Ask the AI to create one!

)} {filtered.map(r => (
setSelectedRecipe(r)}>
{r.cuisine}

{r.name}

{r.time} {r.difficulty}
))}
{selectedRecipe && (
setSelectedRecipe(null)}>
e.stopPropagation()}>

{selectedRecipe.name}

{selectedRecipe.cuisine} {selectedRecipe.time} {selectedRecipe.difficulty}
Ingredients
{selectedRecipe.ingredients && selectedRecipe.ingredients.map((ing, i) => (
{ing}
))}
{selectedRecipe.instructions && (
How to Cook
{selectedRecipe.instructions.map((step, i) => (
{i + 1}

{step}

))}
)}
)}

© 2026 QTware | Powered by QTware Database 2026

); }; const root = ReactDOM.createRoot(document.getElementById('root')); root.render();