Spaces:
Running
Running
"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 = () => { | |
// Ref for the messages container | |
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; | |
// eslint-disable-next-line no-unused-vars | |
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={{ 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; | |