Add AI chat feature
This commit is contained in:
parent
80056b3728
commit
6a5041be43
15 changed files with 1259 additions and 2 deletions
34
components/chat/chat-form.tsx
Normal file
34
components/chat/chat-form.tsx
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { useState, type SubmitEvent } from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { ArrowUpIcon, SendIcon } from "lucide-react";
|
||||
|
||||
interface ChatFormProps {
|
||||
onMessage: (message: { text: string }) => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function ChatForm({ onMessage, disabled }: ChatFormProps) {
|
||||
const [text, setText] = useState("");
|
||||
|
||||
function handleSubmit(e: SubmitEvent<HTMLFormElement>) {
|
||||
e.preventDefault();
|
||||
if (!text.trim()) return;
|
||||
setText("");
|
||||
onMessage({ text });
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="flex gap-2">
|
||||
<Textarea
|
||||
name="text"
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
className="min-h-18"
|
||||
/>
|
||||
<Button type="submit" disabled={disabled} size="icon-lg">
|
||||
<ArrowUpIcon />
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
32
components/chat/chat-messages.tsx
Normal file
32
components/chat/chat-messages.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { cn } from "@/lib/utils";
|
||||
import { UIMessage } from "ai";
|
||||
|
||||
interface ChatMessagesProps {
|
||||
messages: UIMessage[];
|
||||
}
|
||||
|
||||
export function ChatMessages({ messages }: ChatMessagesProps) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
{messages.map((message, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cn(
|
||||
"bg-primary text-primary-foreground px-3 py-2 rounded-lg whitespace-pre-wrap wrap-break-word break-all",
|
||||
message.role === "user"
|
||||
? "self-end bg-primary text-primary-foreground"
|
||||
: "self-start bg-accent text-accent-foreground",
|
||||
)}
|
||||
>
|
||||
{message.parts.map((part, index) => {
|
||||
if (part.type === "text") {
|
||||
return <span key={index}>{part.text}</span>;
|
||||
}
|
||||
|
||||
return null;
|
||||
})}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
24
components/chat/index.tsx
Normal file
24
components/chat/index.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
"use client";
|
||||
|
||||
import { ChatMessages } from "./chat-messages";
|
||||
import { ChatForm } from "./chat-form";
|
||||
import { DefaultChatTransport } from "ai";
|
||||
import { useChat } from "@ai-sdk/react";
|
||||
|
||||
export function Chat() {
|
||||
const { messages, sendMessage, status, error } = useChat({
|
||||
transport: new DefaultChatTransport({
|
||||
api: "http://localhost:3000/api/chat",
|
||||
}),
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl flex flex-col gap-2">
|
||||
<ChatMessages messages={messages} />
|
||||
<ChatForm
|
||||
onMessage={sendMessage}
|
||||
disabled={status === "submitted" || status === "streaming"}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue