diff --git a/src/app/ai/page.tsx b/src/app/ai/page.tsx index 3148830..8f616d5 100644 --- a/src/app/ai/page.tsx +++ b/src/app/ai/page.tsx @@ -70,25 +70,53 @@ export default function AIChatPage() { const currentSession = sessions.find(s => s.id === currentSessionId); const handleSend = async () => { - if (!input.trim() || loading || !currentSession) return; + if (!input.trim() || loading) return; setLoading(true); const userContent = input.trim(); setInput(""); + // Auto-create session if none selected + let sessionId = currentSessionId; + if (!sessionId && childId) { + try { + const res = await fetch("/api/chat", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ childId, title: userContent.slice(0, 30) }), + }); + const data = await res.json(); + if (data.session) { + sessionId = data.session.id; + const newSession = { ...data.session, messages: [] }; + setSessions([newSession, ...sessions]); + setCurrentSessionId(sessionId); + } + } catch (err) { + console.error("Failed to create session:", err); + setLoading(false); + return; + } + } + + if (!sessionId) { + setLoading(false); + return; + } + try { // Save user message await fetch("/api/chat", { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionId: currentSessionId, role: "user", content: userContent }), + body: JSON.stringify({ sessionId, role: "user", content: userContent }), }); // Get AI response const aiRes = await fetch("/api/ai", { method: "POST", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ messages: currentSession.messages.concat({ id: "", role: "user", content: userContent, createdAt: "" }) }), + body: JSON.stringify({ messages: [{ role: "user", content: userContent }] }), }); const aiData = await aiRes.json(); @@ -97,7 +125,7 @@ export default function AIChatPage() { await fetch("/api/chat", { method: "PATCH", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ sessionId: currentSessionId, role: "assistant", content: aiData.reply }), + body: JSON.stringify({ sessionId, role: "assistant", content: aiData.reply }), }); } @@ -173,7 +201,7 @@ export default function AIChatPage() { className="flex-1 p-3 border rounded-lg" disabled={loading} /> - diff --git a/src/app/api/chat/route.ts b/src/app/api/chat/route.ts index 9d49cad..5e40b5c 100644 --- a/src/app/api/chat/route.ts +++ b/src/app/api/chat/route.ts @@ -7,28 +7,24 @@ export async function GET(request: Request) { const childId = searchParams.get("childId") || "default"; try { - // Fetch sessions - const sessions = await sql` - SELECT id, title, created_at as "createdAt", updated_at as "updatedAt" - FROM chat_sessions - WHERE child_id = ${childId} - ORDER BY updated_at DESC - `; + // Single query with JOIN for better performance + const sessions = await sql.unsafe(` + SELECT + cs.id, cs.title, cs.created_at as "createdAt", cs.updated_at as "updatedAt", + COALESCE( + json_agg( + json_build_object('id', cm.id, 'role', cm.role, 'content', cm.content, 'createdAt', cm.created_at ORDER BY cm.created_at) + ) FILTER (WHERE cm.id IS NOT NULL), + '[]'::json + ) as messages + FROM chat_sessions cs + LEFT JOIN chat_messages cm ON cm.session_id = cs.id + WHERE cs.child_id = $1 + GROUP BY cs.id + ORDER BY cs.updated_at DESC + `, [childId]); - // Fetch messages for each session - const sessionsWithMessages = await Promise.all( - (sessions || []).map(async (session: any) => { - const messages = await sql` - SELECT id, role, content, created_at as "createdAt" - FROM chat_messages - WHERE session_id = ${session.id} - ORDER BY created_at - `; - return { ...session, messages: messages || [] }; - }) - ); - - return NextResponse.json({ sessions: sessionsWithMessages || [] }); + return NextResponse.json({ sessions: sessions || [] }); } catch (error) { console.error(error); return NextResponse.json({ error: String(error) }, { status: 500 });