aboutsummaryrefslogtreecommitdiff
path: root/apps/web/src
diff options
context:
space:
mode:
authorYash <[email protected]>2024-04-09 01:16:58 +0000
committerYash <[email protected]>2024-04-09 01:16:58 +0000
commit2e88eee56f77cdcd03c14f694213d999180ead43 (patch)
tree161b1f319f2bad0b417b907b4940b43ec0c703f2 /apps/web/src
parentchat (diff)
parentsetup for multi chat (diff)
downloadsupermemory-2e88eee56f77cdcd03c14f694213d999180ead43.tar.xz
supermemory-2e88eee56f77cdcd03c14f694213d999180ead43.zip
Merge branch 'new-ui' of https://github.com/Dhravya/supermemory into new-ui
Diffstat (limited to 'apps/web/src')
-rw-r--r--apps/web/src/app/api/chat/route.ts62
-rw-r--r--apps/web/src/components/ChatMessage.tsx50
-rw-r--r--apps/web/src/components/Main.tsx41
3 files changed, 152 insertions, 1 deletions
diff --git a/apps/web/src/app/api/chat/route.ts b/apps/web/src/app/api/chat/route.ts
new file mode 100644
index 00000000..2cb03186
--- /dev/null
+++ b/apps/web/src/app/api/chat/route.ts
@@ -0,0 +1,62 @@
+import { db } from "@/server/db";
+import { eq } from "drizzle-orm";
+import { sessions, users } from "@/server/db/schema";
+import { type NextRequest, NextResponse } from "next/server";
+import { env } from "@/env";
+import { ChatHistory } from "../../../../types/memory";
+
+export const runtime = "edge";
+
+export async function POST(req: NextRequest) {
+ const token = req.cookies.get("next-auth.session-token")?.value ?? req.cookies.get("__Secure-authjs.session-token")?.value ?? req.cookies.get("authjs.session-token")?.value ?? req.headers.get("Authorization")?.replace("Bearer ", "");
+
+ const sessionData = await db.select().from(sessions).where(eq(sessions.sessionToken, token!))
+
+ if (!sessionData || sessionData.length === 0) {
+ return new Response(JSON.stringify({ message: "Invalid Key, session not found." }), { status: 404 });
+ }
+
+ const user = await db.select().from(users).where(eq(users.id, sessionData[0].userId)).limit(1)
+
+ if (!user || user.length === 0) {
+ return NextResponse.json({ message: "Invalid Key, session not found." }, { status: 404 });
+ }
+
+ const session = { session: sessionData[0], user: user[0] }
+
+ const query = new URL(req.url).searchParams.get("q");
+ const sourcesOnly = new URL(req.url).searchParams.get("sourcesOnly") ?? "false";
+
+ const chatHistory = await req.json() as {
+ chatHistory: ChatHistory[]
+ };
+
+
+ if (!query) {
+ return new Response(JSON.stringify({ message: "Invalid query" }), { status: 400 });
+ }
+
+ const resp = await fetch(`https://cf-ai-backend.dhravya.workers.dev/chat?q=${query}&user=${session.user.email ?? session.user.name}&sourcesOnly=${sourcesOnly}`, {
+ headers: {
+ "X-Custom-Auth-Key": env.BACKEND_SECURITY_KEY,
+ },
+ method: "POST",
+ body: JSON.stringify({
+ chatHistory
+ })
+ })
+
+ console.log(resp.status)
+
+ if (resp.status !== 200 || !resp.ok) {
+ const errorData = await resp.json();
+ console.log(errorData)
+ return new Response(JSON.stringify({ message: "Error in CF function", error: errorData }), { status: resp.status });
+ }
+
+ // Stream the response back to the client
+ const { readable, writable } = new TransformStream();
+ resp && resp.body!.pipeTo(writable);
+
+ return new Response(readable, { status: 200 });
+} \ No newline at end of file
diff --git a/apps/web/src/components/ChatMessage.tsx b/apps/web/src/components/ChatMessage.tsx
new file mode 100644
index 00000000..a8199758
--- /dev/null
+++ b/apps/web/src/components/ChatMessage.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
+import { User } from 'next-auth';
+import { User2 } from 'lucide-react';
+import Image from 'next/image';
+
+function ChatMessage({
+ message,
+ user,
+}: {
+ message: string;
+ user: User | 'ai';
+}) {
+ return (
+ <div className="flex flex-col gap-4">
+ <div
+ className={`font-bold ${!(user === 'ai') && 'text-xl '} flex flex-col md:flex-row items-center gap-4`}
+ >
+ <Avatar>
+ {user === 'ai' ? (
+ <Image
+ src="/logo.png"
+ width={48}
+ height={48}
+ alt="AI"
+ className="rounded-md w-12 h-12"
+ />
+ ) : user?.image ? (
+ <>
+ <AvatarImage
+ className="h-6 w-6 rounded-lg"
+ src={user?.image}
+ alt="user pfp"
+ />
+ <AvatarFallback>
+ {user?.name?.split(' ').map((n) => n[0])}{' '}
+ </AvatarFallback>
+ </>
+ ) : (
+ <User2 strokeWidth={1.3} className="h-6 w-6" />
+ )}
+ </Avatar>
+ <div className="ml-4">{message}</div>
+ </div>
+ <div className="w-full h-0.5 bg-gray-700 my-2 md:my-0 md:mx-4 mt-8"></div>
+ </div>
+ );
+}
+
+export { ChatMessage };
diff --git a/apps/web/src/components/Main.tsx b/apps/web/src/components/Main.tsx
index b77106a9..3c338526 100644
--- a/apps/web/src/components/Main.tsx
+++ b/apps/web/src/components/Main.tsx
@@ -1,5 +1,5 @@
"use client";
-import { useEffect, useRef, useState } from "react";
+import { useCallback, useEffect, useRef, useState } from "react";
import { FilterCombobox } from "./Sidebar/FilterCombobox";
import { Textarea2 } from "./ui/textarea";
import { ArrowRight } from "lucide-react";
@@ -8,6 +8,9 @@ import useViewport from "@/hooks/useViewport";
import { motion } from "framer-motion";
import { cn } from "@/lib/utils";
import SearchResults from "./SearchResults";
+import { ChatHistory } from "../../types/memory";
+import { ChatMessage } from "./ChatMessage";
+import { useSession } from "next-auth/react";
function supportsDVH() {
try {
@@ -26,7 +29,34 @@ export default function Main({ sidebarOpen }: { sidebarOpen: boolean }) {
const [searchResults, setSearchResults] = useState<string[]>([]);
const [isAiLoading, setIsAiLoading] = useState(false);
+ const { data: session } = useSession();
+
+ // Variable to keep track of the chat history in this session
+ const [chatHistory, setChatHistory] = useState<ChatHistory[]>([]);
+
+ // TEMPORARY solution: Basically this is to just keep track of the sources used for each chat message
+ // Not a great solution
+ const [chatTextSourceDict, setChatTextSourceDict] = useState<
+ Record<string, string>
+ >({});
+
+ // helper function to append a new msg
+ const appendToChatHistory = useCallback(
+ (role: "user" | "model", content: string) => {
+ setChatHistory((prev) => [
+ ...prev,
+ {
+ role,
+ parts: [{ text: content }],
+ },
+ ]);
+ },
+ [],
+ );
+
+ // This is the streamed AI response we get from the server.
const [aiResponse, setAIResponse] = useState("");
+
const [toBeParsed, setToBeParsed] = useState("");
const textArea = useRef<HTMLTextAreaElement>(null);
@@ -155,6 +185,15 @@ export default function Main({ sidebarOpen }: { sidebarOpen: boolean }) {
hide ? "" : "main-hidden",
)}
>
+ <div className="flex w-full flex-col">
+ {chatHistory.map((chat, index) => (
+ <ChatMessage
+ key={index}
+ message={chat.parts[0].text}
+ user={chat.role === "model" ? "ai" : session?.user!}
+ />
+ ))}
+ </div>
<h1 className="text-rgray-11 mt-auto w-full text-center text-3xl md:mt-0">
Ask your Second brain
</h1>