/** * AI SDK UI - Message Persistence * * Demonstrates: * - Saving chat history to localStorage * - Loading previous conversations * - Multiple chat sessions * - Clear history functionality * * Features: * - Auto-save on message changes * - Persistent chat IDs * - Load on mount * - Clear/delete chats * * Usage: * 1. Copy this component * 2. Customize storage mechanism (localStorage, database, etc.) * 3. Add chat history UI if needed */ 'use client'; import { useChat } from 'ai/react'; import { useState, FormEvent, useEffect } from 'react'; import type { Message } from 'ai'; // Storage key prefix const STORAGE_KEY_PREFIX = 'ai-chat-'; // Helper functions for localStorage const saveMessages = (chatId: string, messages: Message[]) => { try { localStorage.setItem( `${STORAGE_KEY_PREFIX}${chatId}`, JSON.stringify(messages) ); } catch (error) { console.error('Failed to save messages:', error); } }; const loadMessages = (chatId: string): Message[] => { try { const stored = localStorage.getItem(`${STORAGE_KEY_PREFIX}${chatId}`); return stored ? JSON.parse(stored) : []; } catch (error) { console.error('Failed to load messages:', error); return []; } }; const clearMessages = (chatId: string) => { try { localStorage.removeItem(`${STORAGE_KEY_PREFIX}${chatId}`); } catch (error) { console.error('Failed to clear messages:', error); } }; const listChats = (): string[] => { const chats: string[] = []; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key?.startsWith(STORAGE_KEY_PREFIX)) { chats.push(key.replace(STORAGE_KEY_PREFIX, '')); } } return chats; }; export default function PersistentChat() { // Generate or use existing chat ID const [chatId, setChatId] = useState(''); const [isLoaded, setIsLoaded] = useState(false); // Initialize chat ID useEffect(() => { // Try to load from URL params or generate new const params = new URLSearchParams(window.location.search); const urlChatId = params.get('chatId'); if (urlChatId) { setChatId(urlChatId); } else { // Generate new chat ID const newChatId = `chat-${Date.now()}`; setChatId(newChatId); // Update URL const url = new URL(window.location.href); url.searchParams.set('chatId', newChatId); window.history.replaceState({}, '', url.toString()); } setIsLoaded(true); }, []); const { messages, setMessages, sendMessage, isLoading, error } = useChat({ api: '/api/chat', id: chatId, initialMessages: isLoaded ? loadMessages(chatId) : [], }); const [input, setInput] = useState(''); // Save messages whenever they change useEffect(() => { if (chatId && messages.length > 0) { saveMessages(chatId, messages); } }, [messages, chatId]); const handleSubmit = (e: FormEvent) => { e.preventDefault(); if (!input.trim()) return; sendMessage({ content: input }); setInput(''); }; const handleClearChat = () => { if (confirm('Are you sure you want to clear this chat?')) { clearMessages(chatId); setMessages([]); } }; const handleNewChat = () => { const newChatId = `chat-${Date.now()}`; setChatId(newChatId); setMessages([]); // Update URL const url = new URL(window.location.href); url.searchParams.set('chatId', newChatId); window.history.pushState({}, '', url.toString()); }; if (!isLoaded) { return
Loading...
; } return (
{/* Header */}

Persistent Chat

Chat ID: {chatId}

{messages.length > 0 && ( )}
{/* Messages */}
{messages.length === 0 ? (
💾

Your conversation is saved

All messages are automatically saved to localStorage

) : (
{messages.map((message) => (
{message.content}
))} {isLoading && (
)}
)}
{/* Error */} {error && (
Error: {error.message}
)} {/* Input */}
setInput(e.target.value)} placeholder="Type a message..." disabled={isLoading} className="flex-1 p-3 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100" />
{messages.length > 0 && ( <>Last saved: {new Date().toLocaleTimeString()} )}
); } // ============================================================================ // Database Persistence Example (Supabase) // ============================================================================ /* import { createClient } from '@supabase/supabase-js'; const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ); const saveMessagesToDB = async (chatId: string, messages: Message[]) => { const { error } = await supabase .from('chat_messages') .upsert({ chat_id: chatId, messages, updated_at: new Date() }); if (error) console.error('Save error:', error); }; const loadMessagesFromDB = async (chatId: string): Promise => { const { data, error } = await supabase .from('chat_messages') .select('messages') .eq('chat_id', chatId) .single(); if (error) { console.error('Load error:', error); return []; } return data?.messages || []; }; */