"use client"; import { useCallback, useState } from "react"; import type { ImageMessagePart, MessagePartStatus } from "@assistant-ui/react"; import { Image } from "@/components/assistant-ui/image"; type ImageView = ImageMessagePart & { status: MessagePartStatus }; export default function Home() { const [prompt, setPrompt] = useState("A golden retriever wearing a top hat"); const [activePrompt, setActivePrompt] = useState(""); const [view, setView] = useState(null); const [revisedPrompt, setRevisedPrompt] = useState(null); const [isGenerating, setIsGenerating] = useState(false); const [error, setError] = useState(null); const generate = useCallback(async (p: string) => { setIsGenerating(true); setActivePrompt(p); setError(null); setRevisedPrompt(null); setView({ type: "image", image: "", status: { type: "running" } }); try { const res = await fetch("/api/image", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ prompt: p }), }); if (!res.ok) throw new Error(await res.text()); const result = (await res.json()) as { image: string; metadata?: { revisedPrompt?: string }; }; setView({ type: "image", image: result.image, status: { type: "complete" }, }); if (typeof result.metadata?.revisedPrompt === "string") { setRevisedPrompt(result.metadata.revisedPrompt); } } catch (e) { setError(e instanceof Error ? e.message : String(e)); setView({ type: "image", image: "", status: { type: "incomplete", reason: "error" }, }); } finally { setIsGenerating(false); } }, []); return (

Image Generation

Calls a server route that runs ai.generateImage and renders the result with the @assistant-ui/ui Image component.

{ e.preventDefault(); void generate(prompt); }} className="flex gap-2" > setPrompt(e.target.value)} placeholder="Describe an image…" className="flex-1 rounded border px-3 py-2" />
{error && (

{error}

)} {view && (
{revisedPrompt && (

Revised prompt: {revisedPrompt}

)} {view.status.type === "complete" && view.image && ( generate(activePrompt)} /> )}
)}
); }