aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorDhravya <[email protected]>2024-04-13 11:29:02 -0700
committerDhravya <[email protected]>2024-04-13 11:29:02 -0700
commit74206a9cf8dcdc36cf0d016408007a2e7192d4c6 (patch)
treedb2f91b72a201c17a7c183e0be268cadbea36313 /apps
parentconflicts (diff)
parentfix metadata (diff)
downloadsupermemory-74206a9cf8dcdc36cf0d016408007a2e7192d4c6.tar.xz
supermemory-74206a9cf8dcdc36cf0d016408007a2e7192d4c6.zip
added browser rendering for getting clean page content
Diffstat (limited to 'apps')
-rw-r--r--apps/cf-ai-backend/src/env.d.ts1
-rw-r--r--apps/cf-ai-backend/src/routes.ts2
-rw-r--r--apps/cf-ai-backend/src/routes/getPageContent.ts31
-rw-r--r--apps/cf-ai-backend/wrangler.toml8
-rw-r--r--apps/web/src/components/Sidebar/AddMemoryDialog.tsx41
-rw-r--r--apps/web/src/components/Sidebar/MemoriesBar.tsx14
-rw-r--r--apps/web/src/server/helpers.ts1
-rw-r--r--apps/web/wrangler.toml5
8 files changed, 90 insertions, 13 deletions
diff --git a/apps/cf-ai-backend/src/env.d.ts b/apps/cf-ai-backend/src/env.d.ts
index e760cba3..e4ae9a1b 100644
--- a/apps/cf-ai-backend/src/env.d.ts
+++ b/apps/cf-ai-backend/src/env.d.ts
@@ -6,6 +6,7 @@ interface Env {
GOOGLE_AI_API_KEY: string;
MY_QUEUE: Queue<TweetData[]>;
KV: KVNamespace;
+ MYBROWSER: BrowserWorker;
}
interface TweetData {
diff --git a/apps/cf-ai-backend/src/routes.ts b/apps/cf-ai-backend/src/routes.ts
index 0349c397..ff1218e8 100644
--- a/apps/cf-ai-backend/src/routes.ts
+++ b/apps/cf-ai-backend/src/routes.ts
@@ -4,6 +4,7 @@ import * as apiQuery from './routes/query';
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 { OpenAIEmbeddings } from './OpenAIEmbedder';
import { GenerativeModel } from '@google/generative-ai';
import { Request } from '@cloudflare/workers-types';
@@ -28,6 +29,7 @@ routeMap.set('/ask', apiAsk);
routeMap.set('/chat', apiChat);
routeMap.set('/batchUploadTweets', apiBatchUploadTweets);
+routeMap.set('/getPageContent', apiGetPageContent);
// Add more route mappings as needed
// routeMap.set('/api/otherRoute', { ... });
diff --git a/apps/cf-ai-backend/src/routes/getPageContent.ts b/apps/cf-ai-backend/src/routes/getPageContent.ts
new file mode 100644
index 00000000..d380657e
--- /dev/null
+++ b/apps/cf-ai-backend/src/routes/getPageContent.ts
@@ -0,0 +1,31 @@
+import { GenerativeModel } from '@google/generative-ai';
+import { OpenAIEmbeddings } from '../OpenAIEmbedder';
+import { CloudflareVectorizeStore } from '@langchain/cloudflare';
+import { Request } from '@cloudflare/workers-types';
+import puppeteer from '@cloudflare/puppeteer';
+
+export async function GET(request: Request, _: CloudflareVectorizeStore, embeddings: OpenAIEmbeddings, model: GenerativeModel, env?: Env) {
+ const { searchParams } = new URL(request.url);
+ let url = searchParams.get('url');
+ let img: Buffer;
+ if (url) {
+ url = new URL(url).toString(); // normalize
+ const browser = await puppeteer.launch(env?.MYBROWSER);
+ const page = await browser.newPage();
+ await page.goto(url);
+
+ // Innertext of content
+ const contentElement = await page.$('body');
+ const content = await page.evaluate((element) => element.innerText, contentElement);
+
+ await browser.close();
+
+ return new Response(content, {
+ headers: {
+ 'content-type': 'text/html',
+ },
+ });
+ } else {
+ return new Response('Please add an ?url=https://example.com/ parameter');
+ }
+}
diff --git a/apps/cf-ai-backend/wrangler.toml b/apps/cf-ai-backend/wrangler.toml
index e1fc018a..832d9e0d 100644
--- a/apps/cf-ai-backend/wrangler.toml
+++ b/apps/cf-ai-backend/wrangler.toml
@@ -1,6 +1,7 @@
name = "cf-ai-backend"
main = "src/index.ts"
compatibility_date = "2024-02-23"
+compatibility_flags = ['nodejs_compat']
[[vectorize]]
binding = "VECTORIZE_INDEX"
@@ -19,6 +20,13 @@ binding = "AI"
[[kv_namespaces]]
binding = "KV"
id = "37a90353da63401e84e20e71165531d0"
+preview_id = "c58b6202814f4224acea97627d0c18aa"
+
+[browser]
+binding = "MYBROWSER"
+
+[placement]
+mode = "smart"
# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)
# Note: Use secrets to store sensitive data.
diff --git a/apps/web/src/components/Sidebar/AddMemoryDialog.tsx b/apps/web/src/components/Sidebar/AddMemoryDialog.tsx
index d0523581..3043c972 100644
--- a/apps/web/src/components/Sidebar/AddMemoryDialog.tsx
+++ b/apps/web/src/components/Sidebar/AddMemoryDialog.tsx
@@ -16,10 +16,12 @@ import { Loader, Plus, X } from "lucide-react";
import { StoredContent } from "@/server/db/schema";
import { cleanUrl } from "@/lib/utils";
import { motion } from "framer-motion";
+import { getMetaData } from "@/server/helpers";
-export function AddMemoryPage() {
+export function AddMemoryPage({ closeDialog }: { closeDialog: () => void }) {
const { addMemory } = useMemory();
+ const [loading, setLoading] = useState(false);
const [url, setUrl] = useState("");
const [selectedSpacesId, setSelectedSpacesId] = useState<number[]>([]);
@@ -37,38 +39,59 @@ export function AddMemoryPage() {
placeholder="Enter the URL of the page"
type="url"
data-modal-autofocus
- className="bg-rgray-4 mt-2 w-full"
+ className="bg-rgray-4 mt-2 w-full disabled:cursor-not-allowed disabled:opacity-70"
value={url}
onChange={(e) => setUrl(e.target.value)}
+ disabled={loading}
/>
<DialogFooter>
<FilterSpaces
selectedSpaces={selectedSpacesId}
setSelectedSpaces={setSelectedSpacesId}
- className="hover:bg-rgray-5 mr-auto bg-white/5"
+ className="hover:bg-rgray-5 mr-auto bg-white/5 disabled:cursor-not-allowed disabled:opacity-70"
name={"Spaces"}
+ disabled={loading}
/>
<button
type={"submit"}
+ disabled={loading}
onClick={async () => {
- // @Dhravya this is adding a memory with insufficient information fix pls
+ setLoading(true);
+ const metadata = await getMetaData(url);
await addMemory(
{
- title: url,
+ title: metadata.title,
+ description: metadata.description,
content: "",
type: "page",
url: url,
- image: "/icons/logo_without_bg.png",
+ image: metadata.image,
savedAt: new Date(),
},
selectedSpacesId,
);
+ closeDialog();
}}
- className="bg-rgray-4 hover:bg-rgray-5 focus-visible:bg-rgray-5 focus-visible:ring-rgray-7 rounded-md px-4 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2"
+ className="bg-rgray-4 hover:bg-rgray-5 focus-visible:bg-rgray-5 focus-visible:ring-rgray-7 relative rounded-md px-4 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-70"
>
- Add
+ <motion.div
+ initial={{ x: "-50%", y: "-100%" }}
+ animate={loading && { y: "-50%", x: "-50%", opacity: 1 }}
+ className="absolute left-1/2 top-1/2 -translate-x-1/2 translate-y-[-100%] opacity-0"
+ >
+ <Loader className="text-rgray-11 h-5 w-5 animate-spin" />
+ </motion.div>
+ <motion.div
+ initial={{ y: "0%" }}
+ animate={loading && { opacity: 0, y: "30%" }}
+ >
+ Add
+ </motion.div>
</button>
- <DialogClose className="hover:bg-rgray-4 focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 rounded-md px-3 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2">
+ <DialogClose
+ disabled={loading}
+ className="hover:bg-rgray-4 focus-visible:bg-rgray-4 focus-visible:ring-rgray-7 rounded-md px-3 py-2 ring-transparent transition focus-visible:outline-none focus-visible:ring-2 disabled:cursor-not-allowed disabled:opacity-70"
+ >
Cancel
</DialogClose>
</DialogFooter>
diff --git a/apps/web/src/components/Sidebar/MemoriesBar.tsx b/apps/web/src/components/Sidebar/MemoriesBar.tsx
index 970deb68..0c468475 100644
--- a/apps/web/src/components/Sidebar/MemoriesBar.tsx
+++ b/apps/web/src/components/Sidebar/MemoriesBar.tsx
@@ -210,7 +210,15 @@ export function MemoryItem({ id, title, image, type }: StoredContent) {
<div className="flex h-24 w-24 items-center justify-center">
{type === "page" ? (
- <img className="h-16 w-16" id={id.toString()} src={image!} />
+ <img
+ className="h-16 w-16"
+ id={id.toString()}
+ src={image!}
+ onError={(e) => {
+ (e.target as HTMLImageElement).src =
+ "/icons/white_without_bg.png";
+ }}
+ />
) : type === "note" ? (
<div className="bg-rgray-4 flex items-center justify-center rounded-md p-2 shadow-md">
<Text className="h-10 w-10" />
@@ -406,7 +414,7 @@ export function SpaceMoreButton({
className="focus:bg-red-100 focus:text-red-400 dark:focus:bg-red-100/10"
>
<Trash2 className="mr-2 h-4 w-4" strokeWidth={1.5} />
- Move to Trash
+ Delete
</DropdownMenuItem>
</DialogTrigger>
</DropdownMenuContent>
@@ -471,7 +479,7 @@ export function AddMemoryModal({
className="w-max max-w-[auto]"
>
{type === "page" ? (
- <AddMemoryPage />
+ <AddMemoryPage closeDialog={() => setIsDialogOpen(false)} />
) : type === "note" ? (
<NoteAddPage closeDialog={() => setIsDialogOpen(false)} />
) : type === "space" ? (
diff --git a/apps/web/src/server/helpers.ts b/apps/web/src/server/helpers.ts
index 8538f743..9a9a9607 100644
--- a/apps/web/src/server/helpers.ts
+++ b/apps/web/src/server/helpers.ts
@@ -1,3 +1,4 @@
+"use server";
import * as cheerio from "cheerio";
export async function getMetaData(url: string) {
diff --git a/apps/web/wrangler.toml b/apps/web/wrangler.toml
index 049e482b..2db56e0d 100644
--- a/apps/web/wrangler.toml
+++ b/apps/web/wrangler.toml
@@ -17,4 +17,7 @@ type = "ratelimit"
namespace_id = "1001"
# 25 requests per 10 seconds
-simple = { limit = 25, period = 10 } \ No newline at end of file
+simple = { limit = 25, period = 10 }
+
+[placement]
+mode = "smart" \ No newline at end of file