diff options
| author | Dhravya <[email protected]> | 2024-04-13 11:29:02 -0700 |
|---|---|---|
| committer | Dhravya <[email protected]> | 2024-04-13 11:29:02 -0700 |
| commit | 74206a9cf8dcdc36cf0d016408007a2e7192d4c6 (patch) | |
| tree | db2f91b72a201c17a7c183e0be268cadbea36313 /apps | |
| parent | conflicts (diff) | |
| parent | fix metadata (diff) | |
| download | supermemory-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.ts | 1 | ||||
| -rw-r--r-- | apps/cf-ai-backend/src/routes.ts | 2 | ||||
| -rw-r--r-- | apps/cf-ai-backend/src/routes/getPageContent.ts | 31 | ||||
| -rw-r--r-- | apps/cf-ai-backend/wrangler.toml | 8 | ||||
| -rw-r--r-- | apps/web/src/components/Sidebar/AddMemoryDialog.tsx | 41 | ||||
| -rw-r--r-- | apps/web/src/components/Sidebar/MemoriesBar.tsx | 14 | ||||
| -rw-r--r-- | apps/web/src/server/helpers.ts | 1 | ||||
| -rw-r--r-- | apps/web/wrangler.toml | 5 |
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 |