austinbv
Get ready to deploy
7f0439e
import React, {useState} from 'react';
import './App.css';
import {fetchEventSource} from "@microsoft/fetch-event-source";
interface Message {
message: string;
isUser: boolean;
sources?: string[];
}
function App() {
const [inputValue, setInputValue] = useState("")
const [messages, setMessages] = useState<Message[]>([]);
const setPartialMessage = (chunk: string, sources: string[] = []) => {
setMessages(prevMessages => {
let lastMessage = prevMessages[prevMessages.length - 1];
if (prevMessages.length === 0 || !lastMessage.isUser) {
return [...prevMessages.slice(0, -1), {
message: lastMessage.message + chunk,
isUser: false,
sources: lastMessage.sources ? [...lastMessage.sources, ...sources] : sources
}];
}
return [...prevMessages, {message: chunk, isUser: false, sources}];
})
}
function handleReceiveMessage(data: string) {
let parsedData = JSON.parse(data);
if (parsedData.answer) {
setPartialMessage(parsedData.answer.content)
}
if (parsedData.docs) {
setPartialMessage("", parsedData.docs.map((doc: any) => doc.metadata.source))
}
}
const handleSendMessage = async (message: string) => {
setInputValue("")
setMessages(prevMessages => [...prevMessages, {message, isUser: true}]);
await fetchEventSource(`${process.env.REACT_APP_BACKEND_URL}/rag/stream`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
input: {
question: message,
}
}),
onmessage(event) {
if (event.event === "data") {
handleReceiveMessage(event.data);
}
},
})
}
const handleKeyPress = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (event.key === "Enter" && !event.shiftKey) {
handleSendMessage(inputValue.trim())
}
}
function formatSource(source: string) {
return source.split("/").pop() || "";
}
return (
<div className="min-h-screen bg-gray-900 flex flex-col">
<header className="bg-gray-800 text-white text-center p-4">
Epic v. Apple Legal Assistant
</header>
<main className="flex-grow container mx-auto p-4 flex-col">
<div className="flex-grow bg-gray-700 shadow overflow-hidden sm:rounded-lg">
<div className="border-b border-gray-600 p-4">
{messages.map((msg, index) => (
<div key={index}
className={`p-3 my-3 rounded-lg text-white ml-auto ${msg.isUser ? "bg-gray-800" : "bg-gray-900"}`}>
{msg.message}
{/* Source */}
{!msg.isUser && (
<div className={"text-xs"}>
<hr className="border-b mt-5 mb-5"></hr>
{msg.sources?.map((source, index) => (
<div>
<a
target="_blank"
download
href={`${"http://localhost:8000"}/rag/static/${encodeURI(formatSource(source))}`}
rel="noreferrer"
>{formatSource(source)}</a>
</div>
))}
</div>
)}
</div>
))}
</div>
<div className="p-4 bg-gray-800">
<textarea
className="form-textarea w-full p-2 border rounded text-white bg-gray-900 border-gray-600 resize-none h-auto"
placeholder="Enter your message here..."
onKeyUp={handleKeyPress}
onChange={(e) => setInputValue(e.target.value)}
value={inputValue}
></textarea>
<button
className="mt-2 bg-green-600 hover:bg-green-700 text-white font-bold py-2 px-4 rounded"
onClick={() => handleSendMessage(inputValue.trim())}
>
Send
</button>
</div>
</div>
</main>
<footer className="bg-gray-800 text-white text-center p-4 text-xs">
*AI Agents can make mistakes. Consider checking important information.
<br/>
All training data derived from public records
<br/>
<br/>
© 2024 Focused Labs
</footer>
</div>
);
}
export default App;