Skip to content

Commit

Permalink
Merge Staging
Browse files Browse the repository at this point in the history
  • Loading branch information
VVoruganti committed Nov 29, 2023
2 parents 677f4d0 + 5ebe31c commit 1aa1d9c
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 358 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# https://testdriven.io/blog/docker-best-practices/
FROM python:3.10-slim-bullseye

RUN apt-get update && apt-get install -y build-essential

WORKDIR /app

# https://stackoverflow.com/questions/53835198/integrating-python-poetry-with-docker
Expand Down
138 changes: 71 additions & 67 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ readme = "README.md"

[tool.poetry.dependencies]
python = "^3.10"
langchain = "~0.0.2"
langchain = "~0.0.3"
py-cord = "^2.4.1"
python-dotenv = "^1.0.0"
validators = "^0.20.0"
Expand Down
1 change: 0 additions & 1 deletion www/app/auth/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import icon from "@/public/bloomicon.jpg";
import SignUp from '@/components/signUp';
import SignIn from '@/components/signIn';
import Forgot from '@/components/forgot'
import Reset from '@/components/reset'

export default function Auth() {
const [formType, setFormType] = useState('LOGIN');
Expand Down
239 changes: 49 additions & 190 deletions www/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,22 @@ import Image from "next/image";

import banner from "@/public/bloom2x1.svg";
import darkBanner from "@/public/bloom2x1dark.svg";
import Message from "@/components/message";
import MessageBox from "@/components/messagebox";
import Thoughts from "@/components/thoughts";
import Sidebar from "@/components/sidebar";

import {
FaLightbulb,
FaPaperPlane,
FaBars,
FaTrash,
FaEdit,
} from "react-icons/fa";
// import { IoIosArrowDown } from "react-icons/io";
// import { GrClose } from "react-icons/gr";
import { FaLightbulb, FaPaperPlane, FaBars } from "react-icons/fa";
import {
useRef,
useEffect,
useState,
useCallback,
use,
ElementRef,
} from "react";

import { v4 as uuidv4 } from "uuid";
import Typing from "@/components/typing";

// Supabase
import { Session } from "@supabase/supabase-js";
import { createClientComponentClient } from "@supabase/auth-helpers-nextjs";
import Link from "next/link";
import MarkdownWrapper from "@/components/markdownWrapper";
import { DarkModeSwitch } from "react-toggle-dark-mode";

interface Message {
text: string;
isUser: boolean;
}

interface Conversation {
conversation_id: string;
name: string;
}
import { Message, Conversation, API } from "@/utils/api";

const URL = process.env.NEXT_PUBLIC_API_URL;
const defaultMessage: Message = {
Expand All @@ -54,115 +29,41 @@ const defaultMessage: Message = {
export default function Home() {
const [isThoughtsOpen, setIsThoughtsOpen] = useState(false);
const [isSidebarOpen, setIsSidebarOpen] = useState(false);

const [thought, setThought] = useState("");
const [userId, setUserId] = useState("LOADING");
const [canSend, setCanSend] = useState(false);

const [messages, setMessages] = useState<Array<Message>>([defaultMessage]);
const [authSession, setAuthSession] = useState<Session | null>(null);
const [conversations, setConversations] = useState<Array<Conversation>>([]);
const [currentConversation, setCurrentConversation] = useState<Conversation>({
conversation_id: "",
name: "",
});
const input = useRef<ElementRef<"input">>(null);
const supabase = createClientComponentClient();
const [api, setApi] = useState<API>();

const [messages, setMessages] = useState<Message[]>([defaultMessage]);
const [conversations, setConversations] = useState<Conversation[]>([]);
const [currentConversation, setCurrentConversation] =
useState<Conversation>();

const input = useRef<ElementRef<"textarea">>(null);
//const input = useRef<ElementRef<"input">>(null);
const isAtBottom = useRef(true);
const messageContainerRef = useRef<ElementRef<"section">>(null);

const newChat = useCallback(async () => {
return await fetch(`${URL}/api/conversations/insert?user_id=${userId}`)
.then((res) => res.json())
.then(({ conversation_id }) => {
return conversation_id;
})
.catch((err) => console.error(err));
}, [userId]);

useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setAuthSession(session);
if (session) {
setUserId(session.user.id);
} else {
setUserId(`anon_${uuidv4()}`);
}
});
}, [supabase]);

useEffect(() => {
// console.log(authSession)
// console.log(userId)
const getConversations = async () => {
return await fetch(`${URL}/api/conversations/get?user_id=${userId}`)
.then((res) => res.json())
.then(({ conversations }) => {
// console.log(conversations)
return conversations;
});
};
if (authSession) {
getConversations().then((conversations) => {
if (conversations.length > 0) {
setConversations(conversations);
setCurrentConversation(conversations[0]);
} else {
newChat().then((conversation_id) => {
let newConversation: Conversation = {
name: "",
conversation_id,
};
setCurrentConversation(newConversation);
setConversations((c) => [...c, newConversation]);
});
}
});
} else {
// TODO store anonymous chats in localstorage or cookies
if (userId !== "LOADING") {
newChat().then((conversation_id) => {
const newConversation: Conversation = {
name: "",
conversation_id,
};
setCurrentConversation(newConversation);
setConversations((c) => [...c, newConversation]);
});
}
}
}, [authSession, userId, newChat]);

useEffect(() => {
const getMessages = async () => {
return await fetch(
`${URL}/api/messages?user_id=${userId}&conversation_id=${currentConversation.conversation_id}`
)
.then((res) => res.json())
.then(({ messages }) => {
const formattedMessages = messages.map((message: any) => {
return {
text: message.data.content,
isUser: message.type === "human",
};
});
return formattedMessages;
});
};

if (currentConversation.conversation_id) {
(async () => {
const api = await API.create(URL!);
setApi(api);
const conversations = await api.getConversations();
setConversations(conversations);
setCurrentConversation(conversations[0]);
setCanSend(true);
getMessages().then((messages) => {
setMessages([defaultMessage, ...messages]);
});
}
})();
}, []);

// scroll to bottom
const messageContainer = messageContainerRef.current;
if (messageContainer) {
messageContainer.scrollTop = messageContainer.scrollHeight;
}
}, [currentConversation, userId]);
useEffect(() => {
(async () => {
if (!currentConversation) return;
const messages = await currentConversation.getMessages();
setMessages([defaultMessage, ...messages]);
// console.log("set messages", messages);
})();
}, [currentConversation]);

useEffect(() => {
const messageContainer = messageContainerRef.current;
Expand Down Expand Up @@ -190,35 +91,10 @@ export default function Home() {
setIsDarkMode(checked);
};

// async function newChat() {
// return await fetch(`${URL}/api/conversations/insert?user_id=${userId}`)
// .then((res) => res.json())
// .then(({ conversation_id }) => {
// return conversation_id
// })
// .catch((err) => console.error(err))
// }
// const chatContainerRef = useRef(null);
// const shouldAutoScroll = useRef(true);

// useEffect(() => {
// if (chatContainerRef.current) {
// const container = chatContainerRef.current;
// // Detect if user is at the bottom of the messages
// shouldAutoScroll.current = container.scrollHeight - container.scrollTop === container.clientHeight;
// }
// }, [messages]);

// useEffect(() => {
// if (shouldAutoScroll.current && chatContainerRef.current) {
// const container = chatContainerRef.current;
// container.scrollTop = container.scrollHeight;
// }
// }, [messages]);

async function chat() {
const textbox = input.current!;
const message = textbox.value;
// process message to have double newline for markdown
const message = textbox.value.replace(/\n/g, "\n\n");
textbox.value = "";

setCanSend(false); // Disable sending more messages until the current generation is done
Expand All @@ -235,33 +111,13 @@ export default function Home() {
},
]);

const data = await fetch(`${URL}/api/stream`, {
method: "POST",
body: JSON.stringify({
user_id: userId,
conversation_id: currentConversation.conversation_id,
message: message,
}),
// no cors
// mode: "no-cors",
headers: {
"Content-Type": "application/json",
},
});

const reader = data.body?.pipeThrough(new TextDecoderStream()).getReader()!;
const reader = await currentConversation!.chat(message);

const messageContainer = messageContainerRef.current;
if (messageContainer) {
messageContainer.scrollTop = messageContainer.scrollHeight;
}

// clear the last message
setMessages((prev) => {
prev[prev.length - 1].text = "";
return [...prev];
});

let isThinking = true;
setThought("");

Expand Down Expand Up @@ -302,25 +158,22 @@ export default function Home() {

return (
<main
className={`flex h-[100dvh] w-screen flex-col pb-[env(keyboard-inset-height)] text-sm lg:text-base overflow-hidden relative ${
isDarkMode ? "dark" : ""
}`}
className={`flex h-[100dvh] w-screen flex-col pb-[env(keyboard-inset-height)] text-sm lg:text-base overflow-hidden relative ${isDarkMode ? "dark" : ""
}`}
>
<Sidebar
conversations={conversations}
authSession={authSession}
currentConversation={currentConversation}
setCurrentConversation={setCurrentConversation}
setConversations={setConversations}
newChat={newChat}
userId={userId}
api={api}
isSidebarOpen={isSidebarOpen}
setIsSidebarOpen={setIsSidebarOpen}
/>
<div className="flex flex-col w-full h-[100dvh] lg:pl-60 xl:pl-72 dark:bg-gray-900">
<nav className="flex justify-between items-center p-4 border-b border-gray-300 dark:border-gray-700">
<FaBars
className="inline lg:hidden"
className="inline lg:hidden dark:text-white"
onClick={() => setIsSidebarOpen(!isSidebarOpen)}
/>

Expand All @@ -340,7 +193,7 @@ export default function Home() {
</button>
</div>
</nav>
{!authSession && (
{!api?.session && (
<section className="bg-neon-green text-black text-center py-4">
<p>
To save your conversation history and personalize your messages{" "}
Expand All @@ -358,9 +211,9 @@ export default function Home() {
ref={messageContainerRef}
>
{messages.map((message, i) => (
<Message isUser={message.isUser} key={i}>
<MessageBox isUser={message.isUser} key={i}>
<MarkdownWrapper text={message.text} />
</Message>
</MessageBox>
))}
</section>
<form
Expand All @@ -374,14 +227,20 @@ export default function Home() {
}}
>
{/* TODO: validate input */}
<input
type="text"
<textarea
ref={input}
placeholder="Type a message..."
className={`flex-1 px-3 py-1 lg:px-5 lg:py-3 bg-gray-100 dark:bg-gray-800 text-gray-400 rounded-2xl border-2 ${
canSend ? " border-green-200" : "border-red-200 opacity-50"
}`}
className={`flex-1 px-3 py-1 lg:px-5 lg:py-3 bg-gray-100 dark:bg-gray-800 text-gray-400 rounded-2xl border-2 resize-none ${canSend ? " border-green-200" : "border-red-200 opacity-50"}`}
disabled={!canSend}
rows={1}
onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
if (canSend && input.current?.value) {
chat();
}
}
}}
/>
<button
className="bg-dark-green text-neon-green rounded-full px-4 py-2 lg:px-7 lg:py-3 flex justify-center items-center gap-2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Image from "next/image";
import icon from "@/public/bloomicon.jpg";
import usericon from "@/public/usericon.svg";

export default function Message({
export default function MessageBox({
children,
isUser,
}: {
Expand Down
Loading

0 comments on commit 1aa1d9c

Please sign in to comment.