|
"use client"; |
|
|
|
import styles from './page.module.css'; |
|
import { useEffect, useRef, useState } from 'react'; |
|
import { useChat } from 'ai/react'; |
|
import { Message } from 'ai'; |
|
import ReactMarkdown from "react-markdown"; |
|
import { functionCallHandler } from './hooks/useFunctions'; |
|
import Input from './input'; |
|
|
|
const Page: React.FC = () => { |
|
|
|
const messagesRef = useRef<HTMLDivElement>(null); |
|
const [keyboardHeight, setKeyboardHeight] = useState(0); |
|
const [isKeyboardVisible, setIsKeyboardVisible] = useState(false); |
|
|
|
const { messages, input, setInput, handleSubmit, isLoading } = useChat({ |
|
experimental_onFunctionCall: functionCallHandler, |
|
onError: (error: any) => { |
|
console.log(error); |
|
}, |
|
}); |
|
|
|
const inputRef = useRef(null); |
|
|
|
useEffect(() => { |
|
if (messagesRef.current) { |
|
messagesRef.current.scrollTop = messagesRef.current.scrollHeight; |
|
} |
|
}, [messages]); |
|
|
|
const [isExpanded, setIsExpanded] = useState(false); |
|
const toggleExpand = () => { |
|
setIsExpanded(!isExpanded); |
|
}; |
|
|
|
const roleUIConfig: { |
|
[key: string]: { |
|
bgColor: string; |
|
avatarColor: string; |
|
|
|
dialogComponent: (message: Message) => JSX.Element; |
|
}; |
|
} = { |
|
user: { |
|
bgColor: "bg-white", |
|
avatarColor: "bg-black", |
|
dialogComponent: (message: Message) => ( |
|
<div className="message-content-container"> |
|
<ReactMarkdown |
|
className="" |
|
components={{ |
|
a: (props) => ( |
|
<a {...props} target="_blank" rel="noopener noreferrer" /> |
|
), |
|
}} |
|
> |
|
{message.content} |
|
</ReactMarkdown> |
|
</div> |
|
), |
|
}, |
|
assistant: { |
|
bgColor: "bg-gray-100", |
|
avatarColor: "bg-green-500", |
|
dialogComponent: (message: Message) => ( |
|
<div className="message-content-container"> |
|
<ReactMarkdown |
|
className="" |
|
components={{ |
|
a: (props) => ( |
|
<a {...props} target="_blank" rel="noopener noreferrer" /> |
|
), |
|
}} |
|
> |
|
{message.content} |
|
</ReactMarkdown> |
|
</div> |
|
), |
|
}, |
|
function: { |
|
bgColor: "bg-gray-200", |
|
avatarColor: "bg-blue-500", |
|
dialogComponent: (message: Message) => { |
|
return ( |
|
<div className="flex flex-col"> |
|
{isExpanded && ( |
|
<div className="py-1">{message.content}</div> |
|
)} |
|
</div> |
|
); |
|
}, |
|
} |
|
}; |
|
|
|
|
|
return ( |
|
<main className={styles.main}> |
|
<div className={styles.messages} ref={messagesRef}> |
|
{messages.length > 0 ? ( |
|
messages.map((message, i) => { |
|
const messageClass = `${styles.message} ${message.role === 'user' ? styles['message-user'] : ''}`; |
|
return ( |
|
<div key={i} className={messageClass} style={{ display: 'flex', alignItems: 'center' }}> |
|
{message.content === "" && message.function_call != undefined ? ( |
|
typeof message.function_call === "object" ? ( |
|
<div style={{ display: 'flex', flexDirection: 'column' }}> |
|
<div> |
|
Using{" "} |
|
<span className="font-bold"> |
|
{message.function_call.name} |
|
</span>{" "} |
|
... |
|
</div> |
|
<div> |
|
{message.function_call.arguments} |
|
</div> |
|
</div> |
|
) : ( |
|
<div className="function-call">{message.function_call}</div> |
|
) |
|
) : ( |
|
<div className="message-text"> |
|
{roleUIConfig[message.role].dialogComponent(message)} |
|
</div> |
|
)} |
|
</div> |
|
); |
|
}) |
|
) : null} |
|
</div> |
|
<Input inputRef={inputRef} handleSubmit={handleSubmit as any} setInput={setInput} input={input} /> |
|
</main> |
|
); |
|
} |
|
|
|
export default Page; |
|
|