}); sql += " LIMIT 30000"; const { activityStreamProvider } = lazy.NewTabUtils; const history = await activityStreamProvider.executePlacesQuery(sql, { columns, params: {}, }); return history; } /** * Handles setup and metrics of history fetch. */ async getHistory() { let endTimeSecs = new Date().getTime() / 1000; let beginTimeSecs = endTimeSecs - this.interestConfig.history_limit_secs; if ( !this.interestConfig || !this.interestConfig.history_required_fields || !this.interestConfig.history_required_fields.length ) { return []; } let history = await this.fetchHistory( this.interestConfig.history_required_fields, beginTimeSecs, endTimeSecs ); return history; } async setBaseAttachmentsURL() { await this.personalityProviderWorker.post("setBaseAttachmentsURL", [ await lazy.Utils.baseAttachmentsURL(), ]); } async setInterestConfig() { this.interestConfig = this.interestConfig || (await this.getRecipe()); await this.personalityProviderWorker.post("setInterestConfig", [ this.interestConfig, ]); } async setInterestVector() { await this.personalityProviderWorker.post("setInterestVector", [ this.interestVector, ]); } async fetchModels() { const models = await lazy.RemoteSettings(MODELS_NAME).get(); return this.personalityProviderWorker.post("fetchModels", [models]); } async generateTaggers() { await this.personalityProviderWorker.post("generateTaggers", [ this.modelKeys, ]); } async generateRecipeExecutor() { await this.personalityProviderWorker.post("generateRecipeExecutor"); } async createInterestVector() { const history = await this.getHistory(); const interestVectorResult = await this.personalityProviderWorker.post( "createInterestVector", [history] ); return interestVectorResult; } async init(callback) { await this.setBaseAttachmentsURL(); await this.setInterestConfig(); if (!this.interestConfig) { return; } // We always generate a recipe executor, no cache used here. // This is because the result of this is an object with // functions (taggers) so storing it in cache is not possible. // Thus we cannot use it to rehydrate anything. const fetchModelsResult = await this.fetchModels(); // If this fails, log an error and return. if (!fetchModelsResult.ok) { return; } await this.generateTaggers(); await this.generateRecipeExecutor(); // If we don't have a cached vector, create a new one. if (!this.interestVector) { const interestVectorResult = await this.createInterestVector(); // If that failed, log an error and return. if (!interestVectorResult.ok) { return; } this.interestVector = interestVectorResult.interestVector; } // This happens outside the createInterestVector call above, // because create can be skipped if rehydrating from cache. // In that case, the interest vector is provided and not created, so we just set it. await this.setInterestVector(); this.initialized = true; if (callback) { callback(); } } async calculateItemRelevanceScore(pocketItem) { if (!this.initialized) { return pocketItem.item_score || 1; } const itemRelevanceScore = await this.personalityProviderWorker.post( "calculateItemRelevanceScore", [pocketItem] ); if (!itemRelevanceScore) { return -1; } const { scorableItem, rankingVector } = itemRelevanceScore; // Put the results on the item for debugging purposes. pocketItem.scorableItem = scorableItem; pocketItem.rankingVector = rankingVector; return rankingVector.score; } /** * Returns an object holding the personalization scores of this provider instance. */ getScores() { return { // We cannot return taggers here. // What we return here goes into persistent cache, and taggers have functions on it. // If we attempted to save taggers into persistent cache, it would store it to disk, // and the next time we load it, it would start thowing function is not defined. interestConfig: this.interestConfig, interestVector: this.interestVector, }; } } PK