"use client"; // Core React and AI chat hooks import { useState, useRef, useEffect } from "react"; import { useChat } from "ai/react"; // UI Icons for example prompts import { AcademicCapIcon, ClockIcon, BookOpenIcon, LightBulbIcon, BriefcaseIcon, } from "@heroicons/react/24/outline"; // Extends the basic message type to include streaming state type MessageWithLoading = { content: string; role: string; isStreaming?: boolean; }; // Predefined example prompts for users to quickly start conversations const EXAMPLE_PROMPTS = [ { title: "教案規劃", // Lesson Planning prompt: "我想規劃一堂關於數學的課程", icon: AcademicCapIcon, }, { title: "英語對話", prompt: "我想練習英語對話", icon: ClockIcon, }, { title: "作業批改", prompt: "我想批改學生的作文作業", icon: BookOpenIcon, }, { title: "數學解題", prompt: "我想解數學題目", icon: LightBulbIcon, }, { title: "我想學程式", prompt: "我想學習如何寫程式", icon: BriefcaseIcon, }, ]; export default function LandingPageChatBot() { // Initialize chat functionality with error handling and streaming support const { messages: rawMessages, input, handleInputChange, handleSubmit, isLoading, append, } = useChat({ api: "/api/landing_page_chat", streamProtocol: "data", onError: (error) => { console.error("Chat error:", error); }, onFinish: (message) => { console.log("Chat finished:", message); // Reset streaming state when message is complete setMessages((prev) => prev.map((msg) => ({ ...msg, isStreaming: false })), ); }, keepLastMessageOnError: true, }); // Refs and state management const chatContainerRef = useRef(null); const [hasInteracted, setHasInteracted] = useState(false); const [messages, setMessages] = useState([]); // Update messages with streaming state when new messages arrive useEffect(() => { setMessages( rawMessages.map((msg, index) => ({ ...msg, isStreaming: isLoading && index === rawMessages.length - 1 && msg.role === "assistant", })), ); }, [rawMessages, isLoading]); // Auto-scroll chat to bottom when new messages arrive const scrollToBottom = () => { if (chatContainerRef.current) { const { scrollHeight, clientHeight } = chatContainerRef.current; chatContainerRef.current.scrollTop = scrollHeight - clientHeight; } }; useEffect(() => { scrollToBottom(); }, [messages]); // Message handling functions const sendMessage = async (text: string) => { setHasInteracted(true); await append({ content: text, role: "user", }); }; const onSubmit = async (e: React.FormEvent) => { setHasInteracted(true); handleSubmit(e); }; return (
{/* Initial landing view with example prompts */} {!hasInteracted && messages.length === 0 ? (
{/* Hero section with title and input */}

今天你想學什麼?

探索新主題、獲得教學協助,或發現學習資源

{/* Message input form */}
{/* Example prompts grid */}
{EXAMPLE_PROMPTS.map((prompt, index) => ( ))}
) : ( /* Chat interface after interaction */
{/* Chat header */}

PlayGO 導覽員

{/* Messages container with auto-scroll */}
{/* Message bubbles with different styles for user/assistant */} {messages.map((message, index) => (
{message.content} {message.isStreaming && ( )}
))}
{/* Input form at bottom of chat */}
)}
); }