|
1 | 1 | "use client"; |
2 | 2 | import { useState } from "react"; |
| 3 | +import { |
| 4 | + ChatBubble, |
| 5 | + ChatBubbleAvatar, |
| 6 | + ChatBubbleMessage, |
| 7 | +} from "@shared/components/ui/chat/chat-bubble"; |
| 8 | +import { ChatMessageList } from "@shared/components/ui/chat/chat-message-list"; |
| 9 | +import { ChatInput } from "@shared/components/ui/chat/chat-input"; |
| 10 | +import { Button } from "@/shared/components/ui/button"; |
| 11 | + |
3 | 12 | import { |
4 | 13 | ChatClientWithSession, |
5 | 14 | RagFlowMessage, |
6 | 15 | RagFlowMessages, |
7 | 16 | sendMessage, |
8 | 17 | } from "@shared/lib/ragflow/chat/chat-client"; |
9 | 18 | import { toast } from "@shared/hooks/use-toast"; |
| 19 | +import LogoComponent from "@/shared/components/Logo"; |
| 20 | +import { SendIcon } from "lucide-react"; |
10 | 21 |
|
11 | | -function MessageBox(props: { |
| 22 | +interface MessageBoxProps { |
12 | 23 | chatClient: ChatClientWithSession; |
13 | 24 | messageHistory: RagFlowMessages | null; |
14 | | -}) { |
15 | | - const [value, setValue] = useState(""); |
| 25 | +} |
16 | 26 |
|
17 | | - const [messages, setMessage] = useState<RagFlowMessages>( |
18 | | - props.messageHistory ? props.messageHistory : [] |
| 27 | +export default function MessageBox({ |
| 28 | + chatClient, |
| 29 | + messageHistory, |
| 30 | +}: MessageBoxProps) { |
| 31 | + const [value, setValue] = useState(""); |
| 32 | + const [messages, setMessages] = useState<RagFlowMessages>( |
| 33 | + messageHistory || [] |
19 | 34 | ); |
| 35 | + const [isLoading, setIsLoading] = useState(false); |
20 | 36 |
|
21 | | - async function handle() { |
22 | | - const ownMessage = { role: "user", content: value } as RagFlowMessage; |
23 | | - |
24 | | - setMessage((oldArray) => [...oldArray, ownMessage]); |
| 37 | + async function handleSend() { |
| 38 | + if (!value.trim()) return; |
25 | 39 |
|
| 40 | + const userMessage: RagFlowMessage = { role: "user", content: value }; |
| 41 | + setMessages((prev) => [...prev, userMessage]); |
26 | 42 | setValue(""); |
| 43 | + setIsLoading(true); |
| 44 | + const response = await sendMessage(chatClient, value); |
| 45 | + setIsLoading(false); |
27 | 46 |
|
28 | | - const messageResponse = await sendMessage(props.chatClient, value); |
29 | | - |
30 | | - if (!messageResponse.ragflowCallSuccess) { |
| 47 | + if (!response.ragflowCallSuccess) { |
31 | 48 | toast({ |
32 | 49 | title: "Error sending message", |
33 | | - description: `Please try refreshing the page`, |
| 50 | + description: "Please try refreshing the page", |
34 | 51 | duration: 10000, |
35 | 52 | variant: "destructive", |
36 | 53 | }); |
37 | 54 | return; |
38 | 55 | } |
39 | 56 |
|
40 | | - const messageData = { |
| 57 | + const assistantMessage: RagFlowMessage = { |
41 | 58 | role: "assistant", |
42 | | - content: messageResponse.response, |
43 | | - } as RagFlowMessage; |
44 | | - |
45 | | - setMessage((oldArray) => [...oldArray, messageData]); |
46 | | - // console.log("response thingy2", messages); |
| 59 | + content: response.response, |
| 60 | + }; |
| 61 | + setMessages((prev) => [...prev, assistantMessage]); |
47 | 62 | } |
48 | 63 |
|
49 | 64 | return ( |
50 | | - <div className="min-h-screen w-1/2 flex-col justify-self-center p-4 text-gray-800 dark:text-white"> |
51 | | - <h1 className="mb-4 text-2xl font-bold">Chat:</h1> |
52 | | - |
53 | | - <div className="flex-col rounded-t-lg bg-gray-100 p-3"> |
54 | | - {messages.map((aMessage, idx) => ( |
55 | | - <div |
56 | | - key={idx} |
57 | | - className={`my-2 max-w-md rounded-lg p-3 shadow-md ${ |
58 | | - aMessage.role != "assistant" |
59 | | - ? "justify-self-end bg-green-200 hover:bg-green-300" |
60 | | - : "justify-self-start bg-blue-200 hover:bg-blue-300" |
61 | | - }`} |
62 | | - > |
63 | | - <p className="font-medium text-gray-800">{aMessage.content}</p> |
64 | | - </div> |
65 | | - ))} |
| 65 | + <div className="flex h-[600px] w-11/12 flex-col place-self-center rounded border p-4 text-gray-800 shadow dark:text-white"> |
| 66 | + <LogoComponent |
| 67 | + className={"size-24 place-self-center stroke-black stroke-[10px]"} |
| 68 | + /> |
| 69 | + {/* doesn't seem like 400 px does much */} |
| 70 | + <div className="h-[400px] flex-1 overflow-auto"> |
| 71 | + <ChatMessageList smooth> |
| 72 | + {messages.map((msg, index) => ( |
| 73 | + <ChatBubble |
| 74 | + key={index} |
| 75 | + variant={msg.role === "assistant" ? "received" : "sent"} |
| 76 | + > |
| 77 | + {msg.role === "assistant" ? ( |
| 78 | + <ChatBubbleAvatar fallback="AI" /> |
| 79 | + ) : ( |
| 80 | + <ChatBubbleAvatar fallback="Me" /> |
| 81 | + )} |
| 82 | + <ChatBubbleMessage |
| 83 | + variant={msg.role === "assistant" ? "received" : "sent"} |
| 84 | + className="p-2" |
| 85 | + > |
| 86 | + {msg.content} |
| 87 | + </ChatBubbleMessage> |
| 88 | + </ChatBubble> |
| 89 | + ))} |
| 90 | + {isLoading && ( |
| 91 | + <ChatBubble variant="received"> |
| 92 | + <ChatBubbleAvatar fallback="AI" /> |
| 93 | + <ChatBubbleMessage isLoading variant="received" /> |
| 94 | + </ChatBubble> |
| 95 | + )} |
| 96 | + </ChatMessageList> |
66 | 97 | </div> |
67 | | - {/* <div className="justify-self-end"> */} |
68 | | - <div className="flex items-center rounded-b-lg bg-gray-200 px-4 py-2 dark:bg-gray-700"> |
69 | | - <textarea |
70 | | - id="chat" |
71 | | - rows={1} |
72 | | - className="mx-2 block w-full rounded-lg border border-gray-300 bg-white p-2.5 text-sm text-gray-900 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-800 dark:text-white dark:placeholder-gray-400 dark:focus:border-blue-500 dark:focus:ring-blue-500" |
73 | | - placeholder="Your message..." |
| 98 | + <div className="relative mt-4"> |
| 99 | + <ChatInput |
74 | 100 | value={value} |
75 | | - onChange={(e) => { |
76 | | - setValue(e.target.value); |
77 | | - }} |
78 | | - ></textarea> |
79 | | - <button |
80 | | - onClick={handle} |
81 | | - className="inline-flex cursor-pointer justify-center rounded-full p-2 text-blue-600 hover:bg-blue-100 dark:text-blue-500 dark:hover:bg-gray-600" |
82 | | - > |
83 | | - <svg |
84 | | - className="h-5 w-5 rotate-90 rtl:-rotate-90" |
85 | | - aria-hidden="true" |
86 | | - xmlns="http://www.w3.org/2000/svg" |
87 | | - fill="currentColor" |
88 | | - viewBox="0 0 18 20" |
89 | | - > |
90 | | - <path d="m17.914 18.594-8-18a1 1 0 0 0-1.828 0l-8 18a1 1 0 0 0 1.157 1.376L8 18.281V9a1 1 0 0 1 2 0v9.281l6.758 1.689a1 1 0 0 0 1.156-1.376Z" /> |
91 | | - </svg> |
92 | | - <span className="sr-only">Send message</span> |
93 | | - </button> |
94 | | - |
95 | | - {/* <input |
96 | | - type="text" |
97 | | - placeholder="Type your message here..." |
98 | | - className="w-100 rounded-md border border-gray-300 p-2 dark:bg-gray-700 dark:text-white" |
99 | | - value={value} |
100 | | - onChange={(e) => { |
101 | | - setValue(e.target.value); |
102 | | - }} |
| 101 | + onChange={(e) => setValue(e.target.value)} |
| 102 | + placeholder="Type your message..." |
103 | 103 | /> |
104 | | -
|
105 | | - <button |
106 | | - className="ml-4 mt-2 rounded-md bg-blue-500 px-4 py-2 text-white hover:bg-blue-600" |
107 | | - onClick={handle} |
| 104 | + <Button |
| 105 | + onClick={handleSend} |
| 106 | + size="default" |
| 107 | + className="absolute right-2 top-1/2 -translate-y-1/2" |
108 | 108 | > |
109 | | - Send |
110 | | - </button> */} |
| 109 | + Send <SendIcon /> |
| 110 | + </Button> |
111 | 111 | </div> |
112 | 112 | </div> |
113 | 113 | ); |
114 | 114 | } |
115 | | - |
116 | | -export default MessageBox; |
0 commit comments