Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
d292506
Add program similarity calculations and related API endpoints
devkiran Oct 12, 2025
a7947f8
Update route.ts
devkiran Oct 13, 2025
da0fd9b
Function to categorize content using AI
devkiran Oct 13, 2025
ac95d9c
Merge branch 'main' into network-v2
devkiran Oct 13, 2025
4668687
Update verify-vercel.ts
devkiran Oct 13, 2025
d2918c8
Update route.ts
devkiran Oct 13, 2025
a375c76
Refactor similarity calculation functions to improve accuracy
devkiran Oct 13, 2025
6ba8878
Merge branch 'main' into network-v2
devkiran Oct 15, 2025
44c0eef
Update route.ts
devkiran Oct 15, 2025
348c13c
Add calculated metrics to partner enrollment stats
devkiran Oct 15, 2025
c410794
Update route.ts
devkiran Oct 15, 2025
ed55a0f
Update route.ts
devkiran Oct 15, 2025
3246dc0
Create partner-ranking.ts
devkiran Oct 15, 2025
60eb77b
improved the cron job
devkiran Oct 15, 2025
6976d49
Update page-client.tsx
devkiran Oct 15, 2025
8555ac1
Update route.ts
devkiran Oct 15, 2025
7a2d527
Update use-partner-network-filters.tsx
devkiran Oct 15, 2025
62292ab
Improve the network filter and API
devkiran Oct 15, 2025
2465375
Update partner ranking logic to include all partners
devkiran Oct 15, 2025
4c36311
Update route.ts
devkiran Oct 15, 2025
0625136
display the categories
devkiran Oct 15, 2025
99e40c9
Refactor partner ranking metrics and add DB indexes
devkiran Oct 15, 2025
a030fe6
Increase similarity threshold and batch size
devkiran Oct 15, 2025
ac7e4a8
simplify the query
devkiran Oct 15, 2025
1420f30
Update partner-ranking.ts
devkiran Oct 15, 2025
2233786
Update partner-ranking.ts
devkiran Oct 15, 2025
36d6cae
Update verify-vercel.ts
devkiran Oct 15, 2025
d179d57
Update backfill-program-categories.ts
devkiran Oct 15, 2025
4b6283e
Merge branch 'main' into network-v2
devkiran Oct 15, 2025
7d19db0
Update vercel.json
devkiran Oct 15, 2025
e77ef48
Merge branch 'main' into network-v2
TWilson023 Oct 20, 2025
70358cf
Merge branch 'main' into network-v2
steven-tey Oct 21, 2025
fb09229
Update use-partner-network-filters.tsx
TWilson023 Oct 21, 2025
75b5513
Merge branch 'main' into network-v2
TWilson023 Oct 22, 2025
9c7d4db
Merge branch 'main' into network-v2
TWilson023 Oct 23, 2025
dbac9a5
Merge branch 'main' into network-v2
TWilson023 Oct 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { prisma } from "@dub/prisma";

// Calculate category similarity using Jaccard similarity
export async function calculateCategorySimilarity(
program1Id: string,
program2Id: string,
): Promise<number> {
const [categories1, categories2] = await Promise.all([
prisma.programCategory.findMany({
where: {
programId: program1Id,
},
select: {
category: true,
},
}),

prisma.programCategory.findMany({
where: {
programId: program2Id,
},
select: {
category: true,
},
}),
]);

const categories1Set = new Set(categories1.map(({ category }) => category));
const categories2Set = new Set(categories2.map(({ category }) => category));

const sharedCount = [...categories1Set].filter((c) =>
categories2Set.has(c),
).length;

const totalUniqueCount =
categories1Set.size + categories2Set.size - sharedCount;

if (totalUniqueCount === 0) {
return 0;
}

return sharedCount / totalUniqueCount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { prisma } from "@dub/prisma";

interface PartnerSimilarityResult {
sharedPartnersCount: bigint;
program1PartnersCount: bigint;
program2PartnersCount: bigint;
}

// Calculate partner similarity using Jaccard similarity
export async function calculatePartnerSimilarity(
program1Id: string,
program2Id: string,
): Promise<number> {
const [result] = await prisma.$queryRaw<PartnerSimilarityResult[]>`
SELECT
COUNT(DISTINCT CASE WHEN e1.partnerId IS NOT NULL AND e2.partnerId IS NOT NULL THEN e1.partnerId END) AS sharedPartnersCount,
(SELECT COUNT(*) FROM ProgramEnrollment WHERE programId = ${program1Id}) AS program1PartnersCount,
(SELECT COUNT(*) FROM ProgramEnrollment WHERE programId = ${program2Id}) AS program2PartnersCount
FROM
ProgramEnrollment e1
JOIN
ProgramEnrollment e2 ON e1.partnerId = e2.partnerId
WHERE
e1.programId = ${program1Id} AND e2.programId = ${program2Id}
`;

const { sharedPartnersCount, program1PartnersCount, program2PartnersCount } =
result ?? {
sharedPartnersCount: BigInt(0),
program1PartnersCount: BigInt(0),
program2PartnersCount: BigInt(0),
};

const unionCount =
Number(program1PartnersCount) +
Number(program2PartnersCount) -
Number(sharedPartnersCount);

if (unionCount === 0) {
return 0;
}

return Number(sharedPartnersCount) / unionCount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { prisma } from "@dub/prisma";

const METRIC_KEYS = [
"totalClicks",
"totalLeads",
"totalConversions",
"totalSales",
"totalSaleAmount",
] as const;

// Calculate performance similarity using Cosine similarity
export async function calculatePerformanceSimilarity(
program1Id: string,
program2Id: string,
): Promise<number> {
const [performance1, performance2] = await Promise.all([
prisma.programEnrollment.aggregate({
where: {
programId: program1Id,
},
_avg: {
totalClicks: true,
totalLeads: true,
totalSales: true,
totalConversions: true,
totalSaleAmount: true,
},
}),

prisma.programEnrollment.aggregate({
where: {
programId: program2Id,
},
_avg: {
totalClicks: true,
totalLeads: true,
totalSales: true,
totalConversions: true,
totalSaleAmount: true,
},
}),
]);

const program1Vector = METRIC_KEYS.map((key) => performance1._avg[key] ?? 0);
const program2Vector = METRIC_KEYS.map((key) => performance2._avg[key] ?? 0);

const dotProduct = program1Vector.reduce(
(sum, val, i) => sum + val * program2Vector[i],
0,
);

const magnitude1 = Math.sqrt(
program1Vector.reduce((sum, val) => sum + val ** 2, 0),
);

const magnitude2 = Math.sqrt(
program2Vector.reduce((sum, val) => sum + val ** 2, 0),
);

if (magnitude1 === 0 || magnitude2 === 0) {
return 0;
}

return dotProduct / (magnitude1 * magnitude2);
}
Loading
Loading