mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-05-19 07:42:43 +00:00
Merge branch 'main' of github.com:supermemoryai/supermemory
This commit is contained in:
commit
8931c43295
6 changed files with 55 additions and 230 deletions
|
|
@ -194,7 +194,7 @@ export function LandingPage() {
|
|||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://discord.gg/supermemory"
|
||||
href="https://discord.gg/b3BgKWpbtR"
|
||||
target="_blank"
|
||||
className="hover:text-white"
|
||||
rel="noreferrer"
|
||||
|
|
|
|||
|
|
@ -131,10 +131,6 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
|
||||
// Pre-compute the vector similarity expression
|
||||
const vectorSimilarity = sql<number>`1 - (embeddings <=> ${JSON.stringify(embedding[0])}::vector)`;
|
||||
const textSearchRank = sql<number>`ts_rank_cd(
|
||||
to_tsvector('english', coalesce(${chunk.textContent}, '')),
|
||||
plainto_tsquery('english', ${queryText})
|
||||
)`;
|
||||
|
||||
// Get matching chunks with document info
|
||||
const matchingChunks = await db
|
||||
|
|
@ -145,7 +141,6 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
orderInDocument: chunk.orderInDocument,
|
||||
metadata: chunk.metadata,
|
||||
similarity: vectorSimilarity,
|
||||
textRank: textSearchRank,
|
||||
// Document fields
|
||||
docId: documents.id,
|
||||
docUuid: documents.uuid,
|
||||
|
|
@ -159,16 +154,10 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
.from(chunk)
|
||||
.innerJoin(documents, eq(chunk.documentId, documents.id))
|
||||
.where(
|
||||
and(eq(documents.userId, user.id), sql`${vectorSimilarity} > 0.5`)
|
||||
and(eq(documents.userId, user.id), sql`${vectorSimilarity} > 0.3`)
|
||||
)
|
||||
.orderBy(
|
||||
desc(sql<number>`(
|
||||
0.6 * ${vectorSimilarity} +
|
||||
0.25 * ${textSearchRank} +
|
||||
0.15 * (1.0 / (1.0 + extract(epoch from age(${documents.updatedAt})) / (90 * 24 * 60 * 60)))
|
||||
)::float`)
|
||||
)
|
||||
.limit(15);
|
||||
.orderBy(desc(vectorSimilarity))
|
||||
.limit(25);
|
||||
|
||||
// Get unique document IDs from matching chunks
|
||||
const uniqueDocIds = [
|
||||
|
|
@ -201,9 +190,9 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
const docChunks = chunksByDocument.get(match.documentId) || [];
|
||||
const matchIndex = docChunks.findIndex((c) => c.id === match.chunkId);
|
||||
|
||||
// Get surrounding chunks (1 before and 1 after)
|
||||
const start = Math.max(0, matchIndex - 1);
|
||||
const end = Math.min(docChunks.length, matchIndex + 2);
|
||||
// Get surrounding chunks (2 before and 2 after for more context)
|
||||
const start = Math.max(0, matchIndex - 2);
|
||||
const end = Math.min(docChunks.length, matchIndex + 3);
|
||||
const relevantChunks = docChunks.slice(start, end);
|
||||
|
||||
return {
|
||||
|
|
@ -224,34 +213,23 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
};
|
||||
});
|
||||
|
||||
// Remove duplicates based on document ID
|
||||
const uniqueResults = contextualResults.reduce(
|
||||
(acc, current) => {
|
||||
const existingDoc = acc.find((doc) => doc.id === current.id);
|
||||
if (!existingDoc) {
|
||||
acc.push(current);
|
||||
} else if (current.similarity > existingDoc.similarity) {
|
||||
// Replace if current match is better
|
||||
const index = acc.findIndex((doc) => doc.id === current.id);
|
||||
acc[index] = current;
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
[] as typeof contextualResults
|
||||
);
|
||||
// Sort by similarity and take top results
|
||||
const topResults = contextualResults
|
||||
.sort((a, b) => b.similarity - a.similarity)
|
||||
.slice(0, 10);
|
||||
|
||||
data.appendMessageAnnotation(uniqueResults);
|
||||
data.appendMessageAnnotation(topResults);
|
||||
|
||||
if (lastUserMessage) {
|
||||
lastUserMessage.content =
|
||||
typeof lastUserMessage.content === "string"
|
||||
? lastUserMessage.content +
|
||||
`<context>${JSON.stringify(uniqueResults)}</context>`
|
||||
`<context>${JSON.stringify(topResults)}</context>`
|
||||
: [
|
||||
...lastUserMessage.content,
|
||||
{
|
||||
type: "text",
|
||||
text: `<context>${JSON.stringify(uniqueResults)}</context>`,
|
||||
text: `<context>${JSON.stringify(topResults)}</context>`,
|
||||
},
|
||||
];
|
||||
coreMessages[coreMessages.length - 1] = lastUserMessage;
|
||||
|
|
@ -310,7 +288,7 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
role: "assistant",
|
||||
content:
|
||||
completion.text +
|
||||
`<context>[${JSON.stringify(uniqueResults)}]</context>`,
|
||||
`<context>[${JSON.stringify(topResults)}]</context>`,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -602,14 +580,10 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
);
|
||||
}
|
||||
|
||||
// Pre-compute the vector similarity expression to avoid multiple calculations
|
||||
// Pre-compute the vector similarity expression
|
||||
const vectorSimilarity = sql<number>`1 - (embeddings <=> ${JSON.stringify(embeddings.data[0])}::vector)`;
|
||||
const textSearchRank = sql<number>`ts_rank_cd(
|
||||
to_tsvector('english', coalesce(${chunk.textContent}, '')),
|
||||
plainto_tsquery('english', ${query})
|
||||
)`;
|
||||
|
||||
// First get the top matching chunks
|
||||
// Get matching chunks
|
||||
const results = await db
|
||||
.select({
|
||||
chunkId: chunk.id,
|
||||
|
|
@ -618,7 +592,6 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
orderInDocument: chunk.orderInDocument,
|
||||
metadata: chunk.metadata,
|
||||
similarity: vectorSimilarity,
|
||||
textRank: textSearchRank,
|
||||
// Document fields
|
||||
docUuid: documents.uuid,
|
||||
docContent: documents.content,
|
||||
|
|
@ -657,13 +630,7 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
: [])
|
||||
)
|
||||
)
|
||||
.orderBy(
|
||||
desc(sql<number>`(
|
||||
0.6 * ${vectorSimilarity} +
|
||||
0.25 * ${textSearchRank} +
|
||||
0.15 * (1.0 / (1.0 + extract(epoch from age(${documents.updatedAt})) / (90 * 24 * 60 * 60)))
|
||||
)::float`)
|
||||
)
|
||||
.orderBy(desc(vectorSimilarity))
|
||||
.limit(limit);
|
||||
|
||||
// Group results by document and take the best matching chunk
|
||||
|
|
@ -679,26 +646,28 @@ const actions = fromHono(new Hono<{ Variables: Variables; Bindings: Env }>())
|
|||
}
|
||||
|
||||
// Convert back to array and format response
|
||||
const finalResults = Array.from(documentResults.values()).map((r) => ({
|
||||
id: r.documentId,
|
||||
uuid: r.docUuid,
|
||||
content: r.docContent,
|
||||
type: r.docType,
|
||||
url: r.docUrl,
|
||||
title: r.docTitle,
|
||||
createdAt: r.docCreatedAt,
|
||||
updatedAt: r.docUpdatedAt,
|
||||
userId: r.docUserId,
|
||||
description: r.docDescription,
|
||||
ogImage: r.docOgImage,
|
||||
similarity: Number(r.similarity.toFixed(4)),
|
||||
matchingChunk: {
|
||||
id: r.chunkId,
|
||||
content: r.textContent,
|
||||
orderInDocument: r.orderInDocument,
|
||||
metadata: r.metadata,
|
||||
},
|
||||
}));
|
||||
const finalResults = Array.from(documentResults.values())
|
||||
.sort((a, b) => b.similarity - a.similarity)
|
||||
.map((r) => ({
|
||||
id: r.documentId,
|
||||
uuid: r.docUuid,
|
||||
content: r.docContent,
|
||||
type: r.docType,
|
||||
url: r.docUrl,
|
||||
title: r.docTitle,
|
||||
createdAt: r.docCreatedAt,
|
||||
updatedAt: r.docUpdatedAt,
|
||||
userId: r.docUserId,
|
||||
description: r.docDescription,
|
||||
ogImage: r.docOgImage,
|
||||
similarity: Number(r.similarity.toFixed(4)),
|
||||
matchingChunk: {
|
||||
id: r.chunkId,
|
||||
content: r.textContent,
|
||||
orderInDocument: r.orderInDocument,
|
||||
metadata: r.metadata,
|
||||
},
|
||||
}));
|
||||
|
||||
return c.json({ results: finalResults });
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,10 @@ export default function Hero() {
|
|||
</Popover>
|
||||
*/}
|
||||
|
||||
<a href="https://docs.supermemory.ai" className="text-gray-600 hover:text-gray-900 transition-colors">
|
||||
<a
|
||||
href="https://docs.supermemory.ai"
|
||||
className="text-gray-600 hover:text-gray-900 transition-colors"
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
</nav>
|
||||
|
|
@ -86,10 +89,16 @@ export default function Hero() {
|
|||
{/* Right section */}
|
||||
<div className="flex items-center space-x-6">
|
||||
<div className="hidden sm:flex items-center space-x-6">
|
||||
<a href="#" className="text-gray-600 hover:text-gray-900 transition-colors">
|
||||
<a
|
||||
href="https://git.new/memory"
|
||||
className="text-gray-600 hover:text-gray-900 transition-colors"
|
||||
>
|
||||
<GithubIcon className="h-6 w-6" />
|
||||
</a>
|
||||
<a href="#" className="text-gray-600 hover:text-gray-900 transition-colors">
|
||||
<a
|
||||
href="https://discord.gg/b3BgKWpbtR"
|
||||
className="text-gray-600 hover:text-gray-900 transition-colors"
|
||||
>
|
||||
<DiscordIcon className="h-6 w-6" />
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { LoaderFunctionArgs, redirect } from "@remix-run/cloudflare";
|
||||
|
||||
export async function loader({ context }: LoaderFunctionArgs) {
|
||||
return redirect("https://chromewebstore.google.com/detail/supermemory/afpgkkipfdpeaflnpoaffkcankadgjfc?hl=en");
|
||||
return redirect(
|
||||
"https://chromewebstore.google.com/detail/supermemory/afpgkkipfdpeaflnpoaffkcankadgjfc?hl=en",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,84 +48,6 @@ export default function Onboarding() {
|
|||
animate={{ opacity: 1 }}
|
||||
className="flex flex-col min-h-screen items-center pt-40 relative overflow-hidden bg-gradient-to-b from-gray-900 to-gray-800 bg-opacity-40"
|
||||
>
|
||||
{/* Neural network background pattern */}
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
{/* Subtle gradient orbs */}
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<motion.div
|
||||
key={`orb-${i}`}
|
||||
className="absolute rounded-full blur-3xl opacity-20"
|
||||
style={{
|
||||
background: `radial-gradient(circle, ${
|
||||
i % 2 === 0 ? "#3b82f6" : "#4f46e5"
|
||||
} 0%, transparent 70%)`,
|
||||
width: `${Math.random() * 300 + 200}px`,
|
||||
height: `${Math.random() * 300 + 200}px`,
|
||||
}}
|
||||
animate={{
|
||||
x: [Math.random() * window.innerWidth, Math.random() * window.innerWidth],
|
||||
y: [Math.random() * window.innerHeight, Math.random() * window.innerHeight],
|
||||
}}
|
||||
transition={{
|
||||
duration: 25,
|
||||
repeat: Infinity,
|
||||
repeatType: "reverse",
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Neurons */}
|
||||
{[...Array(30)].map((_, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="absolute w-3 h-3 bg-blue-400/30 rounded-full"
|
||||
initial={{
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
scale: Math.random() * 0.5 + 0.5,
|
||||
}}
|
||||
animate={{
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
scale: [null, 1.2, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 10 + Math.random() * 5,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
delay: Math.random() * 2,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Synaptic connections */}
|
||||
{[...Array(40)].map((_, i) => (
|
||||
<motion.div
|
||||
key={`line-${i}`}
|
||||
className="absolute h-[1px] bg-gradient-to-r from-blue-400/20 to-transparent"
|
||||
style={{
|
||||
width: `${Math.random() * 200 + 100}px`,
|
||||
transform: `rotate(${Math.random() * 360}deg)`,
|
||||
}}
|
||||
initial={{
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
opacity: 0.1,
|
||||
}}
|
||||
animate={{
|
||||
opacity: [0.1, 0.3, 0.1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 4 + Math.random() * 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
delay: Math.random() * 2,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Logo */}
|
||||
<motion.div
|
||||
initial={{ y: 20, opacity: 0 }}
|
||||
|
|
|
|||
|
|
@ -27,83 +27,6 @@ export default function Onboarding() {
|
|||
animate={{ opacity: 1 }}
|
||||
className="flex flex-col min-h-screen items-center pt-20 relative overflow-hidden bg-gradient-to-b from-gray-900 to-gray-800 bg-opacity-40"
|
||||
>
|
||||
{/* Neural network background pattern */}
|
||||
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
||||
{/* Subtle gradient orbs */}
|
||||
{[...Array(4)].map((_, i) => (
|
||||
<motion.div
|
||||
key={`orb-${i}`}
|
||||
className="absolute rounded-full blur-3xl opacity-20"
|
||||
style={{
|
||||
background: `radial-gradient(circle, ${
|
||||
i % 2 === 0 ? "#3b82f6" : "#4f46e5"
|
||||
} 0%, transparent 70%)`,
|
||||
width: `${Math.random() * 300 + 200}px`,
|
||||
height: `${Math.random() * 300 + 200}px`,
|
||||
}}
|
||||
animate={{
|
||||
x: [Math.random() * window.innerWidth, Math.random() * window.innerWidth],
|
||||
y: [Math.random() * window.innerHeight, Math.random() * window.innerHeight],
|
||||
}}
|
||||
transition={{
|
||||
duration: 25,
|
||||
repeat: Infinity,
|
||||
repeatType: "reverse",
|
||||
ease: "easeInOut",
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Neurons */}
|
||||
{[...Array(30)].map((_, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="absolute w-3 h-3 bg-blue-400/30 rounded-full"
|
||||
initial={{
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
scale: Math.random() * 0.5 + 0.5,
|
||||
}}
|
||||
animate={{
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
scale: [null, 1.2, 1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 10 + Math.random() * 5,
|
||||
repeat: Infinity,
|
||||
ease: "linear",
|
||||
delay: Math.random() * 2,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{/* Synaptic connections */}
|
||||
{[...Array(40)].map((_, i) => (
|
||||
<motion.div
|
||||
key={`line-${i}`}
|
||||
className="absolute h-[1px] bg-gradient-to-r from-blue-400/20 to-transparent"
|
||||
style={{
|
||||
width: `${Math.random() * 200 + 100}px`,
|
||||
transform: `rotate(${Math.random() * 360}deg)`,
|
||||
}}
|
||||
initial={{
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
opacity: 0.1,
|
||||
}}
|
||||
animate={{
|
||||
opacity: [0.1, 0.3, 0.1],
|
||||
}}
|
||||
transition={{
|
||||
duration: 4 + Math.random() * 2,
|
||||
repeat: Infinity,
|
||||
ease: "easeInOut",
|
||||
delay: Math.random() * 2,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Logo */}
|
||||
<motion.div
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue