Skip to content

Commit

Permalink
addeed chathistory functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
Dhravya committed Jun 22, 2024
1 parent 074ea24 commit a2f8a27
Show file tree
Hide file tree
Showing 15 changed files with 522 additions and 118 deletions.
35 changes: 35 additions & 0 deletions apps/web/app/(dash)/chat/[chatid]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { getFullChatThread } from "@/app/actions/fetchers";
import { chatSearchParamsCache } from "@/lib/searchParams";
import ChatWindow from "../chatWindow";

async function Page({
params,
searchParams,
}: {
params: { chatid: string };
searchParams: Record<string, string | string[] | undefined>;
}) {
const { firstTime, q, spaces } = chatSearchParamsCache.parse(searchParams);

const chat = await getFullChatThread(params.chatid);

console.log(chat);

if (!chat.success || !chat.data) {
// TODO: handle this error
return <div>Chat not found</div>;
}

console.log(chat.data);

return (
<ChatWindow
q={q}
spaces={spaces}
initialChat={chat.data.length > 0 ? chat.data : undefined}
threadId={params.chatid}
/>
);
}

export default Page;
Empty file.
169 changes: 105 additions & 64 deletions apps/web/app/(dash)/chat/chatWindow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,31 @@ import { codeLanguageSubset } from "@/lib/constants";
import { z } from "zod";
import { toast } from "sonner";
import Link from "next/link";
import { createChatObject } from "@/app/actions/doers";

function ChatWindow({
q,
spaces,
}: {
q: string;
spaces: { id: string; name: string }[];
}) {
const [layout, setLayout] = useState<"chat" | "initial">("initial");
const [chatHistory, setChatHistory] = useState<ChatHistory[]>([
initialChat = [
{
question: q,
answer: {
parts: [],
sources: [],
},
},
]);
],
threadId,
}: {
q: string;
spaces: { id: string; name: string }[];
initialChat?: ChatHistory[];
threadId: string;
}) {
const [layout, setLayout] = useState<"chat" | "initial">(
initialChat.length > 1 ? "chat" : "initial",
);
const [chatHistory, setChatHistory] = useState<ChatHistory[]>(initialChat);
const [isAutoScroll, setIsAutoScroll] = useState(true);

const removeJustificationFromText = (text: string) => {
Expand All @@ -61,7 +68,7 @@ function ChatWindow({

const getAnswer = async (query: string, spaces: string[]) => {
const sourcesFetch = await fetch(
`/api/chat?q=${query}&spaces=${spaces}&sourcesOnly=true`,
`/api/chat?q=${query}&spaces=${spaces}&sourcesOnly=true&threadId=${threadId}`,
{
method: "POST",
body: JSON.stringify({ chatHistory }),
Expand All @@ -84,74 +91,108 @@ function ChatWindow({
toast.error("Something went wrong while getting the sources");
return;
}

setChatHistory((prevChatHistory) => {
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "smooth",
});
const newChatHistory = [...prevChatHistory];
const lastAnswer = newChatHistory[newChatHistory.length - 1];
if (!lastAnswer) return prevChatHistory;
const filteredSourceUrls = new Set(
sourcesParsed.data.metadata.map((source) => source.url),
);
const uniqueSources = sourcesParsed.data.metadata.filter((source) => {
if (filteredSourceUrls.has(source.url)) {
filteredSourceUrls.delete(source.url);
return true;
}
return false;
});
lastAnswer.answer.sources = uniqueSources.map((source) => ({
title: source.title ?? "Untitled",
type: source.type ?? "page",
source: source.url ?? "https://supermemory.ai",
content: source.description ?? "No content available",
numChunks: sourcesParsed.data.metadata.filter(
(f) => f.url === source.url,
).length,
}));
return newChatHistory;
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "smooth",
});

const resp = await fetch(`/api/chat?q=${query}&spaces=${spaces}`, {
method: "POST",
body: JSON.stringify({ chatHistory }),
});
// Assuming this is part of a larger function within a React component
const updateChatHistoryAndFetch = async () => {
// Step 1: Update chat history with the assistant's response
await new Promise((resolve) => {
setChatHistory((prevChatHistory) => {
const newChatHistory = [...prevChatHistory];
const lastAnswer = newChatHistory[newChatHistory.length - 1];
if (!lastAnswer) {
resolve(undefined);
return prevChatHistory;
}

const reader = resp.body?.getReader();
let done = false;
while (!done && reader) {
const { value, done: d } = await reader.read();
done = d;
const filteredSourceUrls = new Set(
sourcesParsed.data.metadata.map((source) => source.url),
);
const uniqueSources = sourcesParsed.data.metadata.filter((source) => {
if (filteredSourceUrls.has(source.url)) {
filteredSourceUrls.delete(source.url);
return true;
}
return false;
});

setChatHistory((prevChatHistory) => {
const newChatHistory = [...prevChatHistory];
const lastAnswer = newChatHistory[newChatHistory.length - 1];
if (!lastAnswer) return prevChatHistory;
const txt = new TextDecoder().decode(value);
lastAnswer.answer.sources = uniqueSources.map((source) => ({
title: source.title ?? "Untitled",
type: source.type ?? "page",
source: source.url ?? "https://supermemory.ai",
content: source.description ?? "No content available",
numChunks: sourcesParsed.data.metadata.filter(
(f) => f.url === source.url,
).length,
}));

resolve(newChatHistory);
return newChatHistory;
});
});

if (isAutoScroll) {
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "smooth",
// Step 2: Fetch data from the API
const resp = await fetch(
`/api/chat?q=${query}&spaces=${spaces}&threadId=${threadId}`,
{
method: "POST",
body: JSON.stringify({ chatHistory }),
},
);

// Step 3: Read the response stream and update the chat history
const reader = resp.body?.getReader();
let done = false;
while (!done && reader) {
const { value, done: d } = await reader.read();
if (d) {
console.log(chatHistory);
setChatHistory((prevChatHistory) => {
console.log(prevChatHistory);
createChatObject(threadId, prevChatHistory);
return prevChatHistory;
});
}
done = d;

lastAnswer.answer.parts.push({ text: txt });
return newChatHistory;
});
}
const txt = new TextDecoder().decode(value);
setChatHistory((prevChatHistory) => {
const newChatHistory = [...prevChatHistory];
const lastAnswer = newChatHistory[newChatHistory.length - 1];
if (!lastAnswer) return prevChatHistory;

if (isAutoScroll) {
window.scrollTo({
top: document.documentElement.scrollHeight,
behavior: "smooth",
});
}

lastAnswer.answer.parts.push({ text: txt });
return newChatHistory;
});
}
};

updateChatHistoryAndFetch();
};

useEffect(() => {
if (q.trim().length > 0) {
if (q.trim().length > 0 || chatHistory.length > 0) {
setLayout("chat");
getAnswer(
q,
spaces.map((s) => s.id),
);
const lastChat = chatHistory.length > 0 ? chatHistory.length - 1 : 0;
const startGenerating = chatHistory[lastChat]?.answer.parts[0]?.text
? false
: true;
if (startGenerating) {
getAnswer(
q,
spaces.map((s) => `${s}`),
);
}
} else {
router.push("/home");
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/app/(dash)/chat/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function Page({

console.log(spaces);

return <ChatWindow q={q} spaces={[]} />;
return <ChatWindow q={q} spaces={spaces} threadId={""} />;
}

export default Page;
18 changes: 9 additions & 9 deletions apps/web/app/(dash)/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,42 @@ import QueryInput from "./queryinput";
import { homeSearchParamsCache } from "@/lib/searchParams";
import { getSpaces } from "@/app/actions/fetchers";
import { useRouter } from "next/navigation";
import { createChatThread } from "@/app/actions/doers";

function Page({
searchParams,
}: {
searchParams: Record<string, string | string[] | undefined>;
}) {
// TODO: use this to show a welcome page/modal
const { firstTime } = homeSearchParamsCache.parse(searchParams);
// const { firstTime } = homeSearchParamsCache.parse(searchParams);
const { push } = useRouter();

const [spaces, setSpaces] = useState<{ id: number; name: string }[]>([]);

useEffect(() => {
getSpaces().then((res) => {
if (res.success && res.data) {
setSpaces(res.data);
return;
}
// TODO: HANDLE ERROR
});
}, []);

const { push } = useRouter();

return (
<div className="max-w-3xl h-full justify-center flex mx-auto w-full flex-col">
{/* all content goes here */}
{/* <div className="">hi {firstTime ? 'first time' : ''}</div> */}

<div className="w-full h-96">
<QueryInput
handleSubmit={(q, spaces) => {
const newQ =
"/chat?q=" +
encodeURI(q) +
(spaces ? "&spaces=" + JSON.stringify(spaces) : "");
handleSubmit={async (q, spaces) => {
const threadid = await createChatThread(q);

push(newQ);
push(
`/chat/${threadid.data}?spaces=${JSON.stringify(spaces)}&q=${q}`,
);
}}
initialSpaces={spaces}
/>
Expand Down
Loading

0 comments on commit a2f8a27

Please sign in to comment.