merge
|
|
@ -5,7 +5,8 @@
|
|||
"scripts": {
|
||||
"deploy": "wrangler deploy",
|
||||
"dev": "wrangler dev",
|
||||
"start": "wrangler dev"
|
||||
"start": "wrangler dev",
|
||||
"unsafe-reset-vector-db": "wrangler vectorize delete supermem-vector && wrangler vectorize create --dimensions=1536 supermem-vector-1 --metric=cosine"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/workers-types": "^4.20240222.0",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import * as apiAsk from './routes/ask';
|
|||
import * as apiChat from './routes/chat';
|
||||
import * as apiBatchUploadTweets from './routes/batchUploadTweets';
|
||||
import * as apiGetPageContent from './routes/getPageContent';
|
||||
import * as apiDelete from './routes/delete';
|
||||
import * as apiEdit from './routes/edit';
|
||||
import * as apiWipeData from './routes/wipedata';
|
||||
import { OpenAIEmbeddings } from './OpenAIEmbedder';
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { Request } from '@cloudflare/workers-types';
|
||||
|
|
@ -30,7 +33,10 @@ routeMap.set('/chat', apiChat);
|
|||
|
||||
routeMap.set('/batchUploadTweets', apiBatchUploadTweets);
|
||||
routeMap.set('/getPageContent', apiGetPageContent);
|
||||
routeMap.set('/delete', apiDelete);
|
||||
routeMap.set('/edit', apiEdit);
|
||||
|
||||
routeMap.set('/wipedata', apiWipeData);
|
||||
// Add more route mappings as needed
|
||||
// routeMap.set('/api/otherRoute', { ... });
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ export async function POST(request: Request, store: CloudflareVectorizeStore, _:
|
|||
if (!body.pageContent || !body.url) {
|
||||
return new Response(JSON.stringify({ message: 'Invalid Page Content' }), { status: 400 });
|
||||
}
|
||||
|
||||
// TODO: FIX THIS,BUT TEMPERORILY TRIM page content to 1000 words
|
||||
body.pageContent = body.pageContent.split(' ').slice(0, 1000).join(' ');
|
||||
|
||||
const newPageContent = `Title: ${body.title}\nDescription: ${body.description}\nURL: ${body.url}\nContent: ${body.pageContent}`;
|
||||
|
||||
const ourID = `${body.url}-${body.user}`;
|
||||
|
|
@ -31,7 +35,7 @@ export async function POST(request: Request, store: CloudflareVectorizeStore, _:
|
|||
{
|
||||
pageContent: newPageContent,
|
||||
metadata: {
|
||||
title: body.title ?? '',
|
||||
title: body.title?.slice(0, 50) ?? '',
|
||||
description: body.description ?? '',
|
||||
space: body.space ?? '',
|
||||
url: body.url,
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ export async function POST(request: Request, _: CloudflareVectorizeStore, embedd
|
|||
const ai = new Ai(env?.AI);
|
||||
// @ts-ignore
|
||||
const output: AiTextGenerationOutput = (await ai.run('@hf/mistralai/mistral-7b-instruct-v0.2', {
|
||||
prompt,
|
||||
prompt: prompt.slice(0, 6144),
|
||||
stream: true,
|
||||
})) as ReadableStream;
|
||||
|
||||
|
|
|
|||
27
apps/cf-ai-backend/src/routes/delete.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { Request } from '@cloudflare/workers-types';
|
||||
import { type CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { OpenAIEmbeddings } from '../OpenAIEmbedder';
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { seededRandom } from '../util';
|
||||
|
||||
export async function DELETE(request: Request, store: CloudflareVectorizeStore, _: OpenAIEmbeddings, m: GenerativeModel, env: Env) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const websiteUrl = searchParams.get('websiteUrl');
|
||||
const user = searchParams.get('user');
|
||||
|
||||
if (!websiteUrl || !user) {
|
||||
return new Response(JSON.stringify({ message: 'Invalid Request, need websiteUrl and user' }), { status: 400 });
|
||||
}
|
||||
|
||||
const ourID = `${websiteUrl}-${user}`;
|
||||
|
||||
const uuid = await env.KV.get(ourID);
|
||||
|
||||
if (!uuid) {
|
||||
return new Response(JSON.stringify({ message: 'Document not found' }), { status: 404 });
|
||||
}
|
||||
|
||||
await store.delete({ ids: [uuid] });
|
||||
|
||||
return new Response(JSON.stringify({ message: 'Document deleted' }), { status: 200 });
|
||||
}
|
||||
61
apps/cf-ai-backend/src/routes/edit.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { Request } from '@cloudflare/workers-types';
|
||||
import { type CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { OpenAIEmbeddings } from '../OpenAIEmbedder';
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { seededRandom } from '../util';
|
||||
|
||||
export async function POST(request: Request, store: CloudflareVectorizeStore, _: OpenAIEmbeddings, m: GenerativeModel, env: Env) {
|
||||
const body = (await request.json()) as {
|
||||
pageContent: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
space?: string;
|
||||
url: string;
|
||||
user: string;
|
||||
};
|
||||
|
||||
if (!body.pageContent || !body.url) {
|
||||
return new Response(JSON.stringify({ message: 'Invalid Page Content' }), { status: 400 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(request.url);
|
||||
const uniqueUrl = searchParams.get('uniqueUrl');
|
||||
|
||||
const toBeDeleted = `${uniqueUrl}-${body.user}`;
|
||||
const tbduuid = await env.KV.get(toBeDeleted);
|
||||
if (tbduuid) {
|
||||
await store.delete({ ids: [tbduuid] });
|
||||
}
|
||||
|
||||
// TODO: FIX THIS,BUT TEMPERORILY TRIM page content to 1000 words
|
||||
body.pageContent = body.pageContent.split(' ').slice(0, 1000).join(' ');
|
||||
|
||||
const newPageContent = `Title: ${body.title}\nDescription: ${body.description}\nURL: ${body.url}\nContent: ${body.pageContent}`;
|
||||
|
||||
const ourID = `${body.url}-${body.user}`;
|
||||
|
||||
const random = seededRandom(ourID);
|
||||
const uuid = random().toString(36).substring(2, 15) + random().toString(36).substring(2, 15);
|
||||
|
||||
await env.KV.put(uuid, ourID);
|
||||
|
||||
await store.addDocuments(
|
||||
[
|
||||
{
|
||||
pageContent: newPageContent,
|
||||
metadata: {
|
||||
title: body.title?.slice(0, 50) ?? '',
|
||||
description: body.description ?? '',
|
||||
space: body.space ?? '',
|
||||
url: body.url,
|
||||
user: body.user,
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
ids: [uuid],
|
||||
},
|
||||
);
|
||||
|
||||
return new Response(JSON.stringify({ message: 'Document Added' }), { status: 200 });
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ export const queue = async (batch: MessageBatch, env: Env): Promise<void> => {
|
|||
const collectedDocsUUIDs: {
|
||||
document: {
|
||||
pageContent: string;
|
||||
metadata: { title: string; description: string; space: string; url: string; user: string };
|
||||
metadata: { title: string; description: string; space?: string; url: string; user: string };
|
||||
id: string;
|
||||
};
|
||||
}[] = [];
|
||||
|
|
@ -57,7 +57,6 @@ export const queue = async (batch: MessageBatch, env: Env): Promise<void> => {
|
|||
metadata: {
|
||||
title: 'Twitter Bookmark',
|
||||
description: '',
|
||||
space: 'Bookmarked Tweets',
|
||||
url: message.postUrl,
|
||||
user: limits.user,
|
||||
},
|
||||
|
|
|
|||
19
apps/cf-ai-backend/src/routes/wipedata.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { Request } from '@cloudflare/workers-types';
|
||||
import { type CloudflareVectorizeStore } from '@langchain/cloudflare';
|
||||
import { OpenAIEmbeddings } from '../OpenAIEmbedder';
|
||||
import { GenerativeModel } from '@google/generative-ai';
|
||||
import { seededRandom } from '../util';
|
||||
|
||||
// TODO: Waiting for cloudflare to implement tojson so i can get all IDS for that user and delete them
|
||||
export async function DELETE(request: Request, store: CloudflareVectorizeStore, _: OpenAIEmbeddings, m: GenerativeModel, env: Env) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const user = searchParams.get('user');
|
||||
|
||||
console.log(store.toJSONNotImplemented());
|
||||
|
||||
// for (const match of matches.matches) {
|
||||
// await store.delete({ ids: [match.id] });
|
||||
// }
|
||||
|
||||
return new Response(JSON.stringify({ message: 'Document deleted' }), { status: 200 });
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ compatibility_flags = ['nodejs_compat']
|
|||
|
||||
[[vectorize]]
|
||||
binding = "VECTORIZE_INDEX"
|
||||
index_name = "supermem-vector"
|
||||
index_name = "supermem-vector-1"
|
||||
|
||||
[ai]
|
||||
binding = "AI"
|
||||
|
|
|
|||
|
|
@ -13,15 +13,15 @@ CREATE TABLE `account` (
|
|||
`session_state` text(255),
|
||||
`oauth_token_secret` text,
|
||||
`oauth_token` text,
|
||||
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
|
||||
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `contentToSpace` (
|
||||
`contentId` integer NOT NULL,
|
||||
`spaceId` integer NOT NULL,
|
||||
PRIMARY KEY(`contentId`, `spaceId`),
|
||||
FOREIGN KEY (`contentId`) REFERENCES `storedContent`(`id`) ON UPDATE no action ON DELETE no action,
|
||||
FOREIGN KEY (`spaceId`) REFERENCES `space`(`id`) ON UPDATE no action ON DELETE no action
|
||||
FOREIGN KEY (`contentId`) REFERENCES `storedContent`(`id`) ON UPDATE no action ON DELETE cascade,
|
||||
FOREIGN KEY (`spaceId`) REFERENCES `space`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `session` (
|
||||
|
|
@ -29,14 +29,14 @@ CREATE TABLE `session` (
|
|||
`sessionToken` text(255) NOT NULL,
|
||||
`userId` text(255) NOT NULL,
|
||||
`expires` integer NOT NULL,
|
||||
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
|
||||
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `space` (
|
||||
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
`name` text DEFAULT 'none' NOT NULL,
|
||||
`user` text(255),
|
||||
FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
|
||||
FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `storedContent` (
|
||||
|
|
@ -50,7 +50,7 @@ CREATE TABLE `storedContent` (
|
|||
`type` text DEFAULT 'page',
|
||||
`image` text(255),
|
||||
`user` text(255),
|
||||
FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
|
||||
FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE `user` (
|
||||
|
|
|
|||
7
apps/web/db/wipe.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
DELETE FROM `account`;
|
||||
DELETE FROM `contentToSpace`;
|
||||
DELETE FROM `session`;
|
||||
DELETE FROM `space`;
|
||||
DELETE FROM `storedContent`;
|
||||
DELETE FROM `user`;
|
||||
DELETE FROM `verificationToken`;
|
||||
BIN
apps/web/public/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
apps/web/public/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
apps/web/public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
apps/web/public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 689 B |
BIN
apps/web/public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
apps/web/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
apps/web/public/og-image.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
19
apps/web/public/site.webmanifest
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "Supermemory - Your second brain",
|
||||
"short_name": "Save your memories forever, build your own second brain.",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 25 KiB |
|
|
@ -6,8 +6,33 @@ const roboto = Roboto({ weight: ["300", "400", "500"], subsets: ["latin"] });
|
|||
const inter = Inter({ weight: ["300", "400", "500"], subsets: ["latin"] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title: "Supermemory - Your second brain",
|
||||
description: "Save your memories forever, build your own second brain.",
|
||||
openGraph: {
|
||||
images: [
|
||||
{
|
||||
url: "https://supermemory.dhr.wtf/og-image.png",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
},
|
||||
],
|
||||
siteName: "Supermemory",
|
||||
title: "Supermemory - Your second brain",
|
||||
description: "Save your memories forever, build your own second brain.",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
site: "https://supermemory.dhr.wtf",
|
||||
creator: "@dhravyashah",
|
||||
description: "Save your memories forever, build your own second brain.",
|
||||
images: [
|
||||
{
|
||||
url: "https://supermemory.dhr.wtf/og-image.png",
|
||||
width: 1200,
|
||||
height: 630,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
|
|
|||