fixed builds, added friend integration

This commit is contained in:
Dhravya Shah 2024-07-28 19:33:50 -07:00
parent a3f551e557
commit 3e9793436a
10 changed files with 216 additions and 181 deletions

View file

@ -7,7 +7,7 @@ import { memo, useEffect, useState } from "react";
import { Box, TldrawImage } from "tldraw";
const ImageComponent = memo(({ id }: { id: string }) => {
const [snapshot, setSnapshot] = useState({});
const [snapshot, setSnapshot] = useState<any>();
useEffect(() => {
(async () => {
@ -15,7 +15,7 @@ const ImageComponent = memo(({ id }: { id: string }) => {
})();
}, []);
if (snapshot.bounds) {
if (snapshot && snapshot.bounds) {
const pageBounds = new Box(
snapshot.bounds.x,
snapshot.bounds.y,

View file

@ -1,5 +1,5 @@
import { createCanvas } from "@/app/actions/doers";
import { getCanvas, getCanvasData } from "@/app/actions/fetchers";
import { getCanvas } from "@/app/actions/fetchers";
import Link from "next/link";
import React from "react";
import ImageComponent from "./image";

View file

@ -0,0 +1,44 @@
import { type NextRequest } from "next/server";
import { createMemoryFromAPI } from "../helper";
type FriendData = {
id: string;
created_at: string;
transcript: string;
structured: {
title: string;
overview: string;
action_items: [
{
description: string;
},
];
};
};
export async function POST(req: NextRequest) {
const body: FriendData = await req.json();
const userId = new URL(req.url).searchParams.get("uid");
if (!userId) {
return new Response(
JSON.stringify({ status: 400, body: "Missing user ID" }),
);
}
await createMemoryFromAPI({
data: {
title: "Friend: " + body.structured.title,
description: body.structured.overview,
pageContent:
body.transcript + "\n\n" + JSON.stringify(body.structured.action_items),
spaces: [],
type: "note",
url: "https://basedhardware.com",
},
userId: userId,
});
return new Response(JSON.stringify({ status: 200, body: "success" }));
}

View file

@ -0,0 +1,159 @@
import { z } from "zod";
import { db } from "@/server/db";
import { contentToSpace, space, storedContent } from "@/server/db/schema";
import { and, eq, inArray } from "drizzle-orm";
import { LIMITS } from "@/lib/constants";
import { limit } from "@/app/actions/doers";
import { type AddFromAPIType } from "@repo/shared-types";
export const createMemoryFromAPI = async (input: {
data: AddFromAPIType;
userId: string;
}) => {
if (!(await limit(input.userId, input.data.type))) {
return {
success: false,
data: 0,
error: `You have exceeded the limit of ${LIMITS[input.data.type as keyof typeof LIMITS]} ${input.data.type}s.`,
};
}
const vectorSaveResponse = await fetch(
`${process.env.BACKEND_BASE_URL}/api/add`,
{
method: "POST",
body: JSON.stringify({
pageContent: input.data.pageContent,
title: input.data.title,
description: input.data.description,
url: input.data.url,
spaces: input.data.spaces,
user: input.userId,
type: input.data.type,
}),
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + process.env.BACKEND_SECURITY_KEY,
},
},
);
if (!vectorSaveResponse.ok) {
const errorData = await vectorSaveResponse.text();
console.error(errorData);
return {
success: false,
data: 0,
error: `Failed to save to vector store. Backend returned error: ${errorData}`,
};
}
let contentId: number;
const saveToDbUrl =
(input.data.url.split("#supermemory-user-")[0] ?? input.data.url) +
"#supermemory-user-" +
input.userId;
const noteId = new Date().getTime();
// Insert into database
try {
const insertResponse = await db
.insert(storedContent)
.values({
content: input.data.pageContent,
title: input.data.title,
description: input.data.description,
url: saveToDbUrl,
baseUrl: saveToDbUrl,
image: input.data.image,
savedAt: new Date(),
userId: input.userId,
type: input.data.type,
noteId,
})
.returning({ id: storedContent.id });
if (!insertResponse[0]?.id) {
return {
success: false,
data: 0,
error: "Failed to save to database",
};
}
contentId = insertResponse[0].id;
} catch (e) {
const error = e as Error;
console.log("Error: ", error.message);
if (error.message.includes("D1_ERROR: UNIQUE constraint failed:")) {
return {
success: false,
data: 0,
error: "Content already exists",
};
}
return {
success: false,
data: 0,
error: "Failed to save to database with error: " + error.message,
};
}
if (input.data.spaces.length > 0) {
// Adding the many-to-many relationship between content and spaces
const spaceData = await db
.select()
.from(space)
.where(
and(
inArray(
space.id,
input.data.spaces.map((s) => parseInt(s)),
),
eq(space.user, input.userId),
),
)
.all();
await Promise.all(
spaceData.map(async (s) => {
await db
.insert(contentToSpace)
.values({ contentId: contentId, spaceId: s.id });
await db.update(space).set({ numItems: s.numItems + 1 });
}),
);
}
try {
const response = await vectorSaveResponse.json();
const expectedResponse = z.object({ status: z.literal("ok") });
const parsedResponse = expectedResponse.safeParse(response);
if (!parsedResponse.success) {
return {
success: false,
data: 0,
error: `Failed to save to vector store. Backend returned error: ${parsedResponse.error.message}`,
};
}
return {
success: true,
data: 1,
};
} catch (e) {
return {
success: false,
data: 0,
error: `Failed to save to vector store. Backend returned error: ${e as string}`,
};
}
};

View file

@ -1,182 +1,10 @@
import { type NextRequest } from "next/server";
import { addFromAPIType, AddFromAPIType } from "@repo/shared-types";
import { addFromAPIType } from "@repo/shared-types";
import { ensureAuth } from "../ensureAuth";
import { z } from "zod";
import { db } from "@/server/db";
import { contentToSpace, space, storedContent } from "@/server/db/schema";
import { and, eq, gt, inArray, sql } from "drizzle-orm";
import { LIMITS } from "@/lib/constants";
import { limit } from "@/app/actions/doers";
import { createMemoryFromAPI } from "./helper";
export const runtime = "edge";
const createMemoryFromAPI = async (input: {
data: AddFromAPIType;
userId: string;
}) => {
if (!(await limit(input.userId, input.data.type))) {
return {
success: false,
data: 0,
error: `You have exceeded the limit of ${LIMITS[input.data.type as keyof typeof LIMITS]} ${input.data.type}s.`,
};
}
// Get number of items saved in the last 2 hours
const last2Hours = new Date(Date.now() - 2 * 60 * 60 * 1000);
const numberOfItemsSavedInLast2Hours = await db
.select({
count: sql<number>`count(*)`.mapWith(Number),
})
.from(storedContent)
.where(
and(
gt(storedContent.savedAt, last2Hours),
eq(storedContent.userId, input.userId),
),
);
const vectorSaveResponse = await fetch(
`${process.env.BACKEND_BASE_URL}/api/add`,
{
method: "POST",
body: JSON.stringify({
pageContent: input.data.pageContent,
title: input.data.title,
description: input.data.description,
url: input.data.url,
spaces: input.data.spaces,
user: input.userId,
type: input.data.type,
}),
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + process.env.BACKEND_SECURITY_KEY,
},
},
);
if (!vectorSaveResponse.ok) {
const errorData = await vectorSaveResponse.text();
console.error(errorData);
return {
success: false,
data: 0,
error: `Failed to save to vector store. Backend returned error: ${errorData}`,
};
}
let contentId: number;
const saveToDbUrl =
(input.data.url.split("#supermemory-user-")[0] ?? input.data.url) +
"#supermemory-user-" +
input.userId;
const noteId = new Date().getTime();
// Insert into database
try {
const insertResponse = await db
.insert(storedContent)
.values({
content: input.data.pageContent,
title: input.data.title,
description: input.data.description,
url: saveToDbUrl,
baseUrl: saveToDbUrl,
image: input.data.image,
savedAt: new Date(),
userId: input.userId,
type: input.data.type,
noteId,
})
.returning({ id: storedContent.id });
if (!insertResponse[0]?.id) {
return {
success: false,
data: 0,
error: "Failed to save to database",
};
}
contentId = insertResponse[0].id;
} catch (e) {
const error = e as Error;
console.log("Error: ", error.message);
if (error.message.includes("D1_ERROR: UNIQUE constraint failed:")) {
return {
success: false,
data: 0,
error: "Content already exists",
};
}
return {
success: false,
data: 0,
error: "Failed to save to database with error: " + error.message,
};
}
if (input.data.spaces.length > 0) {
// Adding the many-to-many relationship between content and spaces
const spaceData = await db
.select()
.from(space)
.where(
and(
inArray(
space.id,
input.data.spaces.map((s) => parseInt(s)),
),
eq(space.user, input.userId),
),
)
.all();
await Promise.all(
spaceData.map(async (s) => {
await db
.insert(contentToSpace)
.values({ contentId: contentId, spaceId: s.id });
await db.update(space).set({ numItems: s.numItems + 1 });
}),
);
}
try {
const response = await vectorSaveResponse.json();
const expectedResponse = z.object({ status: z.literal("ok") });
const parsedResponse = expectedResponse.safeParse(response);
if (!parsedResponse.success) {
return {
success: false,
data: 0,
error: `Failed to save to vector store. Backend returned error: ${parsedResponse.error.message}`,
};
}
return {
success: true,
data: 1,
};
} catch (e) {
return {
success: false,
data: 0,
error: `Failed to save to vector store. Backend returned error: ${e}`,
};
}
};
export async function POST(req: NextRequest) {
const session = await ensureAuth(req);

View file

@ -9,12 +9,12 @@ import { useRef, useState } from "react";
import { ChevronRight } from "lucide-react";
export default function ResizableLayout({ id }: { id: string }) {
const panelGroupRef = useRef(null);
const panelGroupRef = useRef<any>(null);
const [isLeftPanelCollapsed, setIsLeftPanelCollapsed] = useState(false);
const handleResize = () => {
if (isLeftPanelCollapsed && panelGroupRef.current) {
panelGroupRef.current.setLayout([20, 80]);
panelGroupRef.current?.setLayout([20, 80]);
}
};

View file

@ -55,6 +55,8 @@ function Search({ setContent }: { setContent: (e: any) => void }) {
const sources = await sourcesFetch.json();
console.log(sources);
const sourcesParsed = sourcesZod.safeParse(sources);
if (!sourcesParsed.success) {

View file

@ -21,7 +21,7 @@ export default function Card({
const [isDragging, setIsDragging] = useState(false);
const handleDragStart = (
event: React.DragEvent<HTMLDivElement>,
event: React.DragEvent<HTMLAnchorElement | HTMLDivElement>,
dragSource: "icon" | "link" | "parent",
) => {
setIsDragging(true);

View file

@ -1,3 +1,5 @@
// @ts-nocheck
import cheerio from "cheerio";
export async function unfurl(url: string) {

View file

@ -77,7 +77,7 @@ export function convertChatHistoryList(
}
export const sourcesZod = z.object({
ids: z.array(z.string()),
ids: z.array(z.string().nullable()),
metadata: z.array(z.any()),
normalizedData: z.array(z.any()).optional(),
proModeListedQueries: z.array(z.string()).optional(),