From 974c910846f1ef785d3486abcb2329d05a1cc640 Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Wed, 29 May 2024 15:02:10 +0800 Subject: [PATCH 1/2] add score to home item --- packages/api/src/generated/graphql.ts | 2 + packages/api/src/generated/schema.graphql | 1 + packages/api/src/jobs/update_home.ts | 43 ++++++++----------- .../api/src/resolvers/function_resolvers.ts | 8 +++- packages/api/src/schema.ts | 1 + 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index 63d4e2b14..f75e9a3db 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1302,6 +1302,7 @@ export type HomeItem = { likeCount?: Maybe; previewContent?: Maybe; saveCount?: Maybe; + score: Scalars['Float']; seen_at?: Maybe; slug?: Maybe; source?: Maybe; @@ -6043,6 +6044,7 @@ export type HomeItemResolvers, ParentType, ContextType>; previewContent?: Resolver, ParentType, ContextType>; saveCount?: Resolver, ParentType, ContextType>; + score?: Resolver; seen_at?: Resolver, ParentType, ContextType>; slug?: Resolver, ParentType, ContextType>; source?: Resolver, ParentType, ContextType>; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index c60a0689c..0e2f57d07 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1171,6 +1171,7 @@ type HomeItem { likeCount: Int previewContent: String saveCount: Int + score: Float! seen_at: Date slug: String source: HomeItemSource diff --git a/packages/api/src/jobs/update_home.ts b/packages/api/src/jobs/update_home.ts index f2d6d5e59..cd3afdb40 100644 --- a/packages/api/src/jobs/update_home.ts +++ b/packages/api/src/jobs/update_home.ts @@ -5,7 +5,7 @@ import { User } from '../entity/user' import { redisDataSource } from '../redis_data_source' import { findUnseenPublicItems } from '../services/home' import { searchLibraryItems } from '../services/library_item' -import { Feature, getScores, ScoreApiResponse } from '../services/score' +import { Feature, getScores } from '../services/score' import { findSubscriptionsByNames } from '../services/subscriptions' import { findActiveUser } from '../services/user' import { lanaugeToCode } from '../utils/helpers' @@ -34,7 +34,7 @@ interface Candidate { siteIcon?: string siteName?: string folder?: string - score?: number + score: number publishedAt?: Date subscription?: { name: string @@ -45,6 +45,7 @@ interface Candidate { interface Item { id: string type: string + score: number } interface Section { @@ -71,7 +72,7 @@ const libraryItemToCandidate = ( siteName: item.siteName || undefined, siteIcon: item.siteIcon || undefined, folder: item.folder, - score: item.score, + score: item.score || 0, publishedAt: item.publishedAt || undefined, subscription: subscriptions.find( (subscription) => @@ -100,6 +101,7 @@ const publicItemToCandidate = (item: PublicItem): Candidate => ({ name: item.source.name, type: item.source.type, }, + score: 0, }) const selectCandidates = async (user: User): Promise> => { @@ -157,14 +159,7 @@ const rankCandidates = async ( userId: string, candidates: Array ): Promise> => { - if (candidates.length <= 10) { - // no need to rank if there are less than 10 candidates - return candidates - } - - const unscoredCandidates = candidates.filter( - (item) => item.score === undefined - ) + const unscoredCandidates = candidates.filter((item) => item.score === 0) const data = { user_id: userId, @@ -190,21 +185,13 @@ const rankCandidates = async ( } const newScores = await getScores(data) - const preCalculatedScores = candidates - .filter((item) => item.score !== undefined) - .reduce((acc, item) => { - acc[item.id] = item.score as number - return acc - }, {} as ScoreApiResponse) - const scores = { ...preCalculatedScores, ...newScores } + // update scores for candidates + candidates.forEach((item) => { + item.score = newScores[item.id] || 0 + }) // rank candidates by score in ascending order - candidates.sort((a, b) => { - const scoreA = scores[a.id] || 0 - const scoreB = scores[b.id] || 0 - - return scoreA - scoreB - }) + candidates.sort((a, b) => a.score - b.score) return candidates } @@ -360,6 +347,7 @@ const mixHomeItems = (rankedHomeItems: Array): Array
=> { items: batch.slice(0, 5).map((item) => ({ id: item.id, type: item.type, + score: item.score, })), layout: 'quick links', }) @@ -367,7 +355,7 @@ const mixHomeItems = (rankedHomeItems: Array): Array
=> { // create a section for each long item sections.push( ...batch.slice(5).map((item) => ({ - items: [{ id: item.id, type: item.type }], + items: [{ id: item.id, type: item.type, score: item.score }], layout: 'long', })) ) @@ -391,6 +379,11 @@ export const updateHome = async (data: UpdateHomeJobData) => { const candidates = await selectCandidates(user) logger.info(`Found ${candidates.length} candidates`) + if (candidates.length <= 10) { + logger.info('Not enough candidates found') + return + } + // TODO: integrity check on candidates logger.info('Ranking candidates') diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index d29f6229e..0d925b86c 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -634,7 +634,11 @@ export const functionResolvers = { HomeSection: { async items( section: { - items: Array<{ id: string; type: 'library_item' | 'public_item' }> + items: Array<{ + id: string + type: 'library_item' | 'public_item' + score: number + }> }, _: unknown, ctx: WithDataSourcesContext @@ -685,6 +689,7 @@ export const functionResolvers = { siteName: libraryItem.siteName, siteIcon: libraryItem.siteIcon, slug: libraryItem.slug, + score: item.score, } } @@ -711,6 +716,7 @@ export const functionResolvers = { likeCount: publicItem.stats.likeCount, saveCount: publicItem.stats.saveCount, source: publicItem.source, + score: item.score, } } }) diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index c478014e8..028c1d34b 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -3137,6 +3137,7 @@ const schema = gql` canShare: Boolean canArchive: Boolean canDelete: Boolean + score: Float! } type HomeSection { From 8e8db02633392e7bfe2cb9748d28f67065cae34d Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Wed, 29 May 2024 15:07:22 +0800 Subject: [PATCH 2/2] add score to search item --- packages/api/src/generated/graphql.ts | 2 ++ packages/api/src/generated/schema.graphql | 1 + packages/api/src/schema.ts | 1 + 3 files changed, 4 insertions(+) diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index f75e9a3db..251dc869e 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -2860,6 +2860,7 @@ export type SearchItem = { readingProgressTopPercent?: Maybe; recommendations?: Maybe>; savedAt: Scalars['Date']; + score?: Maybe; shortId?: Maybe; siteIcon?: Maybe; siteName?: Maybe; @@ -6828,6 +6829,7 @@ export type SearchItemResolvers, ParentType, ContextType>; recommendations?: Resolver>, ParentType, ContextType>; savedAt?: Resolver; + score?: Resolver, ParentType, ContextType>; shortId?: Resolver, ParentType, ContextType>; siteIcon?: Resolver, ParentType, ContextType>; siteName?: Resolver, ParentType, ContextType>; diff --git a/packages/api/src/generated/schema.graphql b/packages/api/src/generated/schema.graphql index 0e2f57d07..ccf2c1841 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -2207,6 +2207,7 @@ type SearchItem { readingProgressTopPercent: Float recommendations: [Recommendation!] savedAt: Date! + score: Float shortId: String siteIcon: String siteName: String diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 028c1d34b..e6a2fa2a9 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -1668,6 +1668,7 @@ const schema = gql` aiSummary: String directionality: DirectionalityType format: String + score: Float } type SearchItemEdge {