"use client"; import { Attachment, AttachmentPreview, AttachmentRemove, Attachments, } from "@/components/ai-elements/attachments"; import { ModelSelector, ModelSelectorContent, ModelSelectorEmpty, ModelSelectorGroup, ModelSelectorInput, ModelSelectorItem, ModelSelectorList, ModelSelectorLogo, ModelSelectorLogoGroup, ModelSelectorName, ModelSelectorTrigger, } from "@/components/ai-elements/model-selector"; import type { PromptInputMessage } from "@/components/ai-elements/prompt-input"; import { PromptInput, PromptInputActionAddAttachments, PromptInputActionAddScreenshot, PromptInputActionMenu, PromptInputActionMenuContent, PromptInputActionMenuTrigger, PromptInputBody, PromptInputButton, PromptInputFooter, PromptInputProvider, PromptInputSubmit, PromptInputTextarea, PromptInputTools, usePromptInputAttachments, } from "@/components/ai-elements/prompt-input"; import { CheckIcon, GlobeIcon } from "lucide-react"; import { memo, useCallback, useState } from "react"; const models = [ { chef: "OpenAI", chefSlug: "openai", id: "gpt-4o", name: "GPT-4o", providers: ["openai", "azure"], }, { chef: "OpenAI", chefSlug: "openai", id: "gpt-4o-mini", name: "GPT-4o Mini", providers: ["openai", "azure"], }, { chef: "Anthropic", chefSlug: "anthropic", id: "claude-opus-4-20250514", name: "Claude 4 Opus", providers: ["anthropic", "azure", "google", "amazon-bedrock"], }, { chef: "Anthropic", chefSlug: "anthropic", id: "claude-sonnet-4-20250514", name: "Claude 4 Sonnet", providers: ["anthropic", "azure", "google", "amazon-bedrock"], }, { chef: "Google", chefSlug: "google", id: "gemini-2.0-flash-exp", name: "Gemini 2.0 Flash", providers: ["google"], }, ]; const SUBMITTING_TIMEOUT = 200; const STREAMING_TIMEOUT = 2000; interface AttachmentItemProps { attachment: { id: string; type: "file"; filename?: string; mediaType?: string; url: string; }; onRemove: (id: string) => void; } const AttachmentItem = memo(({ attachment, onRemove }: AttachmentItemProps) => { const handleRemove = useCallback( () => onRemove(attachment.id), [onRemove, attachment.id] ); return ( ); }); AttachmentItem.displayName = "AttachmentItem"; interface ModelItemProps { m: (typeof models)[0]; selectedModel: string; onSelect: (id: string) => void; } const ModelItem = memo(({ m, selectedModel, onSelect }: ModelItemProps) => { const handleSelect = useCallback(() => onSelect(m.id), [onSelect, m.id]); return ( {m.name} {m.providers.map((provider) => ( ))} {selectedModel === m.id ? ( ) : (
)} ); }); ModelItem.displayName = "ModelItem"; const PromptInputAttachmentsDisplay = () => { const attachments = usePromptInputAttachments(); const handleRemove = useCallback( (id: string) => attachments.remove(id), [attachments] ); if (attachments.files.length === 0) { return null; } return ( {attachments.files.map((attachment) => ( ))} ); }; const Example = () => { const [model, setModel] = useState(models[0].id); const [modelSelectorOpen, setModelSelectorOpen] = useState(false); const [status, setStatus] = useState< "submitted" | "streaming" | "ready" | "error" >("ready"); const selectedModelData = models.find((m) => m.id === model); const handleModelSelect = useCallback((id: string) => { setModel(id); setModelSelectorOpen(false); }, []); const handleSubmit = useCallback((message: PromptInputMessage) => { const hasText = Boolean(message.text); const hasAttachments = Boolean(message.files?.length); if (!(hasText || hasAttachments)) { return; } setStatus("submitted"); // eslint-disable-next-line no-console console.log("Submitting message:", message); setTimeout(() => { setStatus("streaming"); }, SUBMITTING_TIMEOUT); setTimeout(() => { setStatus("ready"); }, STREAMING_TIMEOUT); }, []); return (
Search {selectedModelData?.chefSlug && ( )} {selectedModelData?.name && ( {selectedModelData.name} )} No models found. {["OpenAI", "Anthropic", "Google"].map((chef) => ( {models .filter((m) => m.chef === chef) .map((m) => ( ))} ))}
); }; export default Example;