UNPKG

@graperank/interpreter

Version:

The GrapeRank Interpreter module generates normalized ratings from ingested network data. It requires one or more Protocols plugins.

182 lines (181 loc) 9.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Interpreter = void 0; const util_1 = require("@graperank/util"); class Interpreter { protocols; updateStatus; stopping = false; constructor(protocols, updateStatus) { this.protocols = protocols; this.updateStatus = updateStatus; } stop() { this.stopping = true; } async interpret(raters, requests) { // var protocol = new Protocols(this.factories) var responses = []; var ratings = []; // var requests : ProtocolRequest[] = settings.interpreters // `allraters` map keys hold all raters added as input and between protocol requests // map value is the iteration number at which the rater was added // (this number ends up in the scorecard as `dos` from observer) const allraters = new Map(); var requestauthors; if (!!raters && !!requests) { console.log("GrapeRank : interpret : instantiating ", requests.length, " protocols for ", raters.length, " raters"); console.log("----------------------------------"); // add input raters to allraters raters.forEach((userid) => allraters.set(userid, 0)); // loop through each interpreter request // requests having `iterations` will ADD to `allraters` with each interation // each request will use the `allraters` list from previous requests for (let r in requests) { if (this.stopping) return undefined; let requestindex = r; let request = requests[requestindex]; this.protocols.setRequest(request); // reset newraters, protocolratings, and newratings between protocol requests const protocolratings = this.protocols.getInterpreted(request.protocol); let newraters = new Set(); let newratings = new Map(); let thisiteration = 0; let maxiterations = request.iterate || 1; let thisiterationraters; if (request.authors && request.authors.length) requestauthors = new Set(request.authors); let currentstatus; console.log("GrapeRank : interpret : calling " + request.protocol + " protocol with params : ", this.protocols.get(request.protocol).params); while (thisiteration < maxiterations) { if (this.stopping) return undefined; // increment for each protocol iteration thisiteration++; thisiterationraters = requestauthors || (newraters?.size ? newraters : new Set(allraters.keys())); console.log("GrapeRank : interpret : " + request.protocol + " protocol : begin iteration ", thisiteration, " of ", maxiterations, ", with ", thisiterationraters?.size, " raters"); // DEBUG if (thisiterationraters.has(util_1.DEBUGTARGET)) console.log('DEBUGTARGET : interpret : target found in thisiteration raters'); try { currentstatus = { protocol: request.protocol, // FIXME dos needs to be set on initial status ... // how to determine this acurately BEFORE fetchData() has been called? dos: request.iterate ? this.protocols.get(request.protocol)?.fetched?.length || 0 : undefined, authors: thisiterationraters.size }; if (this.updateStatus && !await this.updateStatus(currentstatus)) throw ('failed updating initial status'); let fetchstart = Date.now(); // fetch protocol specific dataset for requestauthors OR newraters OR allraters let dos = await this.protocols.fetchData(request.protocol, thisiterationraters); // TODO cache fetched data currentstatus.fetched = [ this.protocols.get(request.protocol).fetched[dos - 1]?.size || 0, // number of fetched events Date.now() - fetchstart, // duration of fetch request thisiteration == maxiterations ? true : undefined // final DOS iteration ? ]; if (this.updateStatus && !await this.updateStatus(currentstatus)) throw ('failed updating status after fetch'); let interpretstart = Date.now(); // interpret fetched data and add to newratings newratings = await this.protocols.interpret(request.protocol, dos); currentstatus.interpreted = [ countRatingsMap(newratings) || 0, // number of interpretations rated Date.now() - interpretstart, // duration of interpretation thisiteration == maxiterations ? true : undefined // final DOS iteration ? ]; if (this.updateStatus && !await this.updateStatus(currentstatus)) throw ('failed updating status after interpret'); console.log("GrapeRank : interpret : ", request.protocol, " protocol : interpretation complete for iteration ", thisiteration); // prepare for next iteration ONLY IF not on final iteration if (thisiteration < maxiterations) { // get new raters from interpreted newratings newraters = getNewRaters(newratings, allraters); // merge all raters to include new raters newraters.forEach((rater) => allraters.set(rater, thisiteration)); console.log("GrapeRank : interpret : " + request.protocol + " protocol : added ", newraters.size, " new raters"); } console.log("GrapeRank : interpretat : total ", allraters.size, " raters"); } catch (e) { console.log('GrapeRank : interpret : ERROR : ', e); } responses.push({ request: { ...request, params: this.protocols.get(request.protocol).params }, index: requestindex, iteration: thisiteration, numraters: thisiterationraters.size, // TODO get numfetched from protocol numfetched: undefined, numratings: newratings.size }); console.log("GrapeRank : interpret : " + request.protocol + " protocol : end iteration ", thisiteration, " of ", maxiterations); console.log("----------------------------------"); } // add the final map of protocolratings to ratings list addToRatingsList(request.protocol, r, protocolratings, ratings); } // DEBUG duplicate ratings let numtargetratings = new Map(); await (0, util_1.forEachBigArray)(ratings, (rating) => { if (rating.ratee == util_1.DEBUGTARGET) { let numratings = numtargetratings.get(rating.rater) || 0; numtargetratings.set(rating.rater, numratings + 1); } }); numtargetratings.forEach((num, key) => { if (num > 1) console.log('DEBUGTARGET : interperet : found more than ONE rating for ', key); }); } else { console.log('GrapeRank : ERROR in interpret() : no raterts && requests passed : ', raters, requests); } this.protocols.clear(); return { ratings, responses }; } } exports.Interpreter = Interpreter; // FIXME this ONLY works when USERS are being rated, not CONTENT // TODO extraction of new authors from rated content SHOULD be handled by each protocol ... // TODO some protocols, like `nostr-mutes` && `nostr-reports`, should NOT append new ratees to allraters // the scorecards generated should ONLY include "those ratees within the [`nostr-follows`] network" ... // maybe there should be a designated protocol that "defines the set of new raters" ? function getNewRaters(newratings, allraters) { let newraters = new Set(); newratings.forEach((rateemap, rater) => { rateemap.forEach((ratingdata, ratee) => { if (!allraters || !allraters.has(ratee)) newraters.add(ratee); }); }); // DEBUG if (newraters.has(util_1.DEBUGTARGET)) console.log('DEBUGTARGET : interpret : target found by getNewRaters()'); return newraters; } function addToRatingsList(protocol, index, ratingsmap, ratingslist) { ratingsmap.forEach((rateemap, rater) => { rateemap.forEach((ratingdata, ratee) => { ratingslist.push({ protocol, index, rater, ratee, ...ratingdata }); }); }); } function countRatingsMap(ratingsmap) { let count = 0; ratingsmap.forEach((rateemap) => { rateemap.forEach(() => { count++; }); }); return count; }