diff --git a/packages/api/src/generated/graphql.ts b/packages/api/src/generated/graphql.ts index a4392d52e..158adacca 100644 --- a/packages/api/src/generated/graphql.ts +++ b/packages/api/src/generated/graphql.ts @@ -1310,7 +1310,7 @@ export type HomeItem = { likeCount?: Maybe; previewContent?: Maybe; saveCount?: Maybe; - score: Scalars['Float']; + score?: Maybe; seen_at?: Maybe; slug?: Maybe; source?: Maybe; @@ -6103,7 +6103,7 @@ export type HomeItemResolvers, ParentType, ContextType>; previewContent?: Resolver, ParentType, ContextType>; saveCount?: Resolver, ParentType, ContextType>; - score?: Resolver; + score?: Resolver, ParentType, ContextType>; 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 1642622d7..18a8fca83 100644 --- a/packages/api/src/generated/schema.graphql +++ b/packages/api/src/generated/schema.graphql @@ -1179,7 +1179,7 @@ type HomeItem { likeCount: Int previewContent: String saveCount: Int - score: Float! + 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 504b9aaa9..2b863e6f3 100644 --- a/packages/api/src/jobs/update_home.ts +++ b/packages/api/src/jobs/update_home.ts @@ -9,7 +9,7 @@ import { Feature, getScores } from '../services/score' import { findSubscriptionsByNames } from '../services/subscriptions' import { findActiveUser } from '../services/user' import { lanaugeToCode } from '../utils/helpers' -import { logger } from '../utils/logger' +import { logError, logger } from '../utils/logger' export const UPDATE_HOME_JOB = 'UPDATE_HOME_JOB' @@ -159,6 +159,11 @@ const rankCandidates = async ( userId: string, candidates: Array ): Promise> => { + if (candidates.length <= 10) { + logger.info('Not enough candidates to rank') + return candidates + } + const unscoredCandidates = candidates.filter((item) => item.score === 0) const data = { @@ -381,38 +386,56 @@ export const updateHome = async (data: UpdateHomeJobData) => { const { userId, cursor } = data logger.info('Updating home for user', data) - const user = await findActiveUser(userId) - if (!user) { - logger.error(`User ${userId} not found`) - return + try { + const user = await findActiveUser(userId) + if (!user) { + logger.error(`User ${userId} not found`) + return + } + + logger.info(`Updating home for user ${userId}`) + + logger.profile('selecting') + const candidates = await selectCandidates(user) + logger.profile('selecting', { + level: 'info', + message: `Found ${candidates.length} candidates`, + }) + + if (candidates.length === 0) { + logger.info('No candidates found') + return + } + + // TODO: integrity check on candidates + + logger.profile('ranking') + const rankedCandidates = await rankCandidates(userId, candidates) + logger.profile('ranking', { + level: 'info', + message: `Ranked ${rankedCandidates.length} candidates`, + }) + + // TODO: filter candidates + + logger.profile('mixing') + const rankedSections = mixHomeItems(rankedCandidates) + logger.profile('mixing', { + level: 'info', + message: `Created ${rankedSections.length} sections`, + }) + + logger.profile('saving') + await appendSectionsToHome(userId, rankedSections, cursor) + logger.profile('saving', { + level: 'info', + message: 'Sections appended to home', + }) + + logger.info('Home updated for user', { userId }) + } catch (error) { + logError(error) + + throw error } - - logger.info(`Updating home for user ${userId}`) - - 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') - const rankedCandidates = await rankCandidates(userId, candidates) - if (rankedCandidates.length === 0) { - logger.info('No candidates found') - return - } - - // TODO: filter candidates - - logger.info('Mix home items to create sections') - const rankedSections = mixHomeItems(rankedCandidates) - logger.info(`Created ${rankedSections.length} sections`) - - logger.info('Appending sections to home') - await appendSectionsToHome(userId, rankedSections, cursor) - logger.info('Home updated for user', { userId }) } diff --git a/packages/api/src/resolvers/function_resolvers.ts b/packages/api/src/resolvers/function_resolvers.ts index 4de6224fa..d4692561f 100644 --- a/packages/api/src/resolvers/function_resolvers.ts +++ b/packages/api/src/resolvers/function_resolvers.ts @@ -647,16 +647,13 @@ export const functionResolvers = { ctx: WithDataSourcesContext ) { const items = section.items - console.log('items', items) const libraryItemIds = items .filter((item) => item.type === 'library_item') .map((item) => item.id) - console.log('libraryItemIds', libraryItemIds) const libraryItems = ( await ctx.dataLoaders.libraryItems.loadMany(libraryItemIds) ).filter((libraryItem) => !isError(libraryItem)) as Array - console.log('libraryItems', libraryItems) const publicItemIds = section.items .filter((item) => item.type === 'public_item') @@ -667,11 +664,9 @@ export const functionResolvers = { return items .map((item) => { - console.log('item', item) const libraryItem = libraryItems.find( (libraryItem) => item.id === libraryItem.id ) - console.log('libraryItem', libraryItem) if (libraryItem) { return { id: libraryItem.id, diff --git a/packages/api/src/schema.ts b/packages/api/src/schema.ts index 2e51e3b00..329961d37 100755 --- a/packages/api/src/schema.ts +++ b/packages/api/src/schema.ts @@ -3148,7 +3148,7 @@ const schema = gql` canShare: Boolean canArchive: Boolean canDelete: Boolean - score: Float! + score: Float } type HomeSection { diff --git a/packages/api/src/services/score.ts b/packages/api/src/services/score.ts index 981eb6f08..bad4519be 100644 --- a/packages/api/src/services/score.ts +++ b/packages/api/src/services/score.ts @@ -1,3 +1,5 @@ +import { env } from '../env' + export interface Feature { library_item_id?: string title: string @@ -29,18 +31,12 @@ export type ScoreApiResponse = Record // item_id -> score export const getScores = async ( data: ScoreApiRequestBody ): Promise => { - const API_URL = 'http://digest-score/batch' - // const token = process.env.SCORE_API_TOKEN - - // if (!token) { - // throw new Error('No score API token found') - // } + const API_URL = env.score.apiUrl const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', - // Authorization: `Bearer ${token}`, }, body: JSON.stringify(data), }) diff --git a/packages/api/src/util.ts b/packages/api/src/util.ts index fceea60b3..096acf0a0 100755 --- a/packages/api/src/util.ts +++ b/packages/api/src/util.ts @@ -119,6 +119,9 @@ export interface BackendEnv { clientSecret: string authUrl: string } + score: { + apiUrl: string + } } const nullableEnvVars = [ @@ -175,6 +178,7 @@ const nullableEnvVars = [ 'NOTION_CLIENT_ID', 'NOTION_CLIENT_SECRET', 'NOTION_AUTH_URL', + 'SCORE_API_URL', ] // Allow some vars to be null/empty const envParser = @@ -329,6 +333,9 @@ export function getEnv(): BackendEnv { clientSecret: parse('NOTION_CLIENT_SECRET'), authUrl: parse('NOTION_AUTH_URL'), } + const score = { + apiUrl: parse('SCORE_API_URL') || 'http://digest-score/batch', + } return { pg, @@ -352,6 +359,7 @@ export function getEnv(): BackendEnv { subscription, redis, notion, + score, } }