import { useState } from 'react' import { createFileRoute } from '@tanstack/react-router' import { ChefHat, Clock, Users, Gauge } from 'lucide-react' import { Streamdown } from 'streamdown' import type { Recipe } from './api.ai.structured' type Mode = 'structured' | 'oneshot' const SAMPLE_RECIPES = [ 'Homemade Margherita Pizza', 'Thai Green Curry', 'Classic Beef Bourguignon', 'Chocolate Lava Cake', 'Crispy Korean Fried Chicken', 'Fresh Spring Rolls with Peanut Sauce', 'Creamy Mushroom Risotto', 'Authentic Pad Thai', ] function RecipeCard({ recipe }: { recipe: Recipe }) { const difficultyColors = { easy: 'demo-pill', medium: 'demo-pill', hard: 'demo-pill', } return (
{/* Header */}

{recipe.name}

{recipe.description}

{/* Meta info */}
Prep: {recipe.prepTime}
Cook: {recipe.cookTime}
{recipe.servings} servings
{recipe.difficulty}
{/* Ingredients */}

Ingredients

{/* Instructions */}

Instructions

    {recipe.instructions.map((step, idx) => (
  1. {idx + 1} {step}
  2. ))}
{/* Tips */} {recipe.tips && recipe.tips.length > 0 && (

Tips

)} {/* Nutrition */} {recipe.nutritionPerServing && (

Nutrition (per serving)

{recipe.nutritionPerServing.calories && ( {recipe.nutritionPerServing.calories} cal )} {recipe.nutritionPerServing.protein && ( Protein: {recipe.nutritionPerServing.protein} )} {recipe.nutritionPerServing.carbs && ( Carbs: {recipe.nutritionPerServing.carbs} )} {recipe.nutritionPerServing.fat && ( Fat: {recipe.nutritionPerServing.fat} )}
)}
) } function StructuredPage() { const [recipeName, setRecipeName] = useState('') const [result, setResult] = useState<{ mode: Mode recipe?: Recipe markdown?: string provider: string model: string } | null>(null) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const handleGenerate = async (mode: Mode) => { if (!recipeName.trim()) return setIsLoading(true) setError(null) setResult(null) try { const response = await fetch('/demo/api/ai/structured', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ recipeName, mode }), }) const data = await response.json() if (!response.ok) { throw new Error(data.error || 'Failed to generate recipe') } setResult(data) } catch (err: any) { setError(err.message) } finally { setIsLoading(false) } } const canExecute = !!(!isLoading && recipeName.trim() && !error) return (

One-Shot & Structured Output

Compare two output modes:{' '} One-Shot returns freeform markdown, while{' '} Structured returns validated JSON conforming to a Zod schema.

setRecipeName(e.target.value)} disabled={isLoading} placeholder="e.g., Chocolate Chip Cookies" className="demo-input text-sm" />
{SAMPLE_RECIPES.map((name) => ( ))}

Generated Recipe

{result && ( {result.mode === 'structured' ? 'Structured JSON' : 'Markdown'} )}
{error && (
{error}
)} {result ? (
{result.mode === 'structured' && result.recipe ? ( ) : result.markdown ? (
{result.markdown}
) : null}
) : !error && !isLoading ? (

Enter a recipe name and click "Generate Recipe" to get started.

) : null}
) } export const Route = createFileRoute('/demo/ai-structured')({ component: StructuredPage, })