diff --git a/packages/web/package.json b/packages/web/package.json index 769b0e91..72dbc8d5 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -12,6 +12,7 @@ "stripe:listen": "stripe listen --forward-to http://localhost:3000/api/stripe" }, "dependencies": { + "@ai-sdk/openai": "^1.3.21", "@auth/prisma-adapter": "^2.7.4", "@codemirror/commands": "^6.6.0", "@codemirror/lang-cpp": "^6.0.2", @@ -83,6 +84,7 @@ "@uiw/react-codemirror": "^4.23.0", "@viz-js/lang-dot": "^1.0.4", "@xiechao/codemirror-lang-handlebars": "^1.0.4", + "ai": "^4.3.14", "ajv": "^8.17.1", "bcryptjs": "^3.0.2", "class-variance-authority": "^0.7.0", diff --git a/packages/web/src/app/[domain]/chat/page.tsx b/packages/web/src/app/[domain]/chat/page.tsx new file mode 100644 index 00000000..9af3fcf6 --- /dev/null +++ b/packages/web/src/app/[domain]/chat/page.tsx @@ -0,0 +1,124 @@ +"use client" + +import type React from "react" +import { useState, useRef, useEffect } from "react" +import { useChat } from "@ai-sdk/react" +import { Button } from "@/components/ui/button" +import { Textarea } from "@/components/ui/textarea" +import { ScrollArea } from "@/components/ui/scroll-area" +import { Separator } from "@/components/ui/separator" +import { Send, Loader2, ChevronDown } from "lucide-react" +import { Avatar } from "@/components/ui/avatar" +import { AvatarFallback, AvatarImage } from "@/components/ui/avatar" + +export default function ChatPage() { + const { messages, input, handleInputChange, handleSubmit, status } = useChat() + const [inputRows, setInputRows] = useState(1) + const messagesEndRef = useRef(null) + + // Auto-scroll to bottom when messages change + useEffect(() => { + messagesEndRef.current?.scrollIntoView({ behavior: "smooth" }) + }, [messages]) + + // Auto-resize textarea based on content + useEffect(() => { + const rows = input.split("\n").length + setInputRows(Math.min(5, Math.max(1, rows))) + }, [input]) + + // Handle form submission + const onSubmit = (e: React.FormEvent) => { + e.preventDefault() + if (input.trim() === "") return + handleSubmit(e) + } + + return ( +
+ {/* Main chat area */} +
+ +
+ {messages.length === 0 ? ( +
+
+

Welcome to AI Chat

+

+ Ask me anything +

+
+
+ ) : ( +
+ {messages.map((message, index) => ( +
+
+ + {message.role === "user" ? "U" : "AI"} + {message.role === "user" ? ( + + ) : ( + + )} + + +
+
+
+ {message.role === "user" ? "You" : "AI Assistant"} +
+ {index === messages.length - 1 && message.role === "assistant" && ( +
+ + Thought for {Math.floor(Math.random() * 10) + 1} seconds +
+ )} +
+ +
{message.content}
+
+
+ + {index < messages.length - 1 && } +
+ ))} +
+
+ )} +
+ +
+ + {/* Input area */} +
+
+
+