@hasna/experts 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +44 -1
- package/dist/enrich.d.ts +17 -0
- package/dist/enrich.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1208,6 +1208,34 @@ async function enrichExpert(db, e, opts) {
|
|
|
1208
1208
|
}
|
|
1209
1209
|
return { ok: true, notFound: false, tweets: tweetCount, avatar, rateLimited: false, quotaExhausted: false };
|
|
1210
1210
|
}
|
|
1211
|
+
async function backfillAvatars(db, opts = {}) {
|
|
1212
|
+
const log = opts.onLog ?? (() => {});
|
|
1213
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
1214
|
+
const delayMs = opts.delayMs ?? 150;
|
|
1215
|
+
const experts = db.list({ source: opts.source });
|
|
1216
|
+
const res = { downloaded: 0, skipped: 0, failed: 0 };
|
|
1217
|
+
for (const e of experts) {
|
|
1218
|
+
if (e.avatarLocal || !e.avatar) {
|
|
1219
|
+
res.skipped++;
|
|
1220
|
+
continue;
|
|
1221
|
+
}
|
|
1222
|
+
try {
|
|
1223
|
+
const path = await downloadAvatar(e.avatar, e, fetchFn);
|
|
1224
|
+
if (path) {
|
|
1225
|
+
db.setAvatarLocal(e.source, e.sourceId, path);
|
|
1226
|
+
res.downloaded++;
|
|
1227
|
+
if (res.downloaded % 100 === 0)
|
|
1228
|
+
log(` avatars: ${res.downloaded} downloaded`);
|
|
1229
|
+
} else {
|
|
1230
|
+
res.failed++;
|
|
1231
|
+
}
|
|
1232
|
+
} catch {
|
|
1233
|
+
res.failed++;
|
|
1234
|
+
}
|
|
1235
|
+
await sleep2(delayMs);
|
|
1236
|
+
}
|
|
1237
|
+
return res;
|
|
1238
|
+
}
|
|
1211
1239
|
async function enrichX(db, opts = {}) {
|
|
1212
1240
|
const log = opts.onLog ?? (() => {});
|
|
1213
1241
|
const client = opts.client ?? new ConnectorsClient;
|
|
@@ -1269,7 +1297,7 @@ async function enrichX(db, opts = {}) {
|
|
|
1269
1297
|
}
|
|
1270
1298
|
|
|
1271
1299
|
// src/cli/index.ts
|
|
1272
|
-
var VERSION = "0.0.
|
|
1300
|
+
var VERSION = "0.0.6";
|
|
1273
1301
|
function openDb() {
|
|
1274
1302
|
const opts = program.opts();
|
|
1275
1303
|
return new ExpertsDB(opts.db || defaultDbPath());
|
|
@@ -1333,6 +1361,21 @@ program.command("enrich [source]").description("Enrich experts via X/Twitter: pr
|
|
|
1333
1361
|
console.log(chalk2.dim(`progress: ${after.enriched}/${after.withHandle} enriched`));
|
|
1334
1362
|
db.close();
|
|
1335
1363
|
});
|
|
1364
|
+
program.command("avatars [source]").description("Download + properly name profile pictures for experts missing one").option("--delay <ms>", "delay between downloads", (v) => parseInt(v, 10), 150).action(async (source, cmdOpts) => {
|
|
1365
|
+
const db = openDb();
|
|
1366
|
+
requireData(db);
|
|
1367
|
+
console.error(chalk2.dim("Backfilling profile pictures from source media\u2026"));
|
|
1368
|
+
const res = await backfillAvatars(db, {
|
|
1369
|
+
source,
|
|
1370
|
+
delayMs: cmdOpts.delay,
|
|
1371
|
+
onLog: (m) => process.stderr.write(chalk2.dim(m + `
|
|
1372
|
+
`))
|
|
1373
|
+
});
|
|
1374
|
+
console.log(chalk2.green(`\u2713 ${res.downloaded} avatars downloaded`) + chalk2.dim(` (${res.skipped} already had one or no URL, ${res.failed} failed)`));
|
|
1375
|
+
const total = db.enrichmentStats(source).avatars;
|
|
1376
|
+
console.log(chalk2.dim(`total experts with a named avatar: ${total}`));
|
|
1377
|
+
db.close();
|
|
1378
|
+
});
|
|
1336
1379
|
program.command("tweets <idOrSlug>").description("Show an expert's stored recent tweets").option("-s, --source <name>", "disambiguate by source").option("-n, --limit <n>", "max tweets", (v) => parseInt(v, 10), 10).action((idOrSlug, cmdOpts) => {
|
|
1337
1380
|
const db = openDb();
|
|
1338
1381
|
const e = db.get(idOrSlug, cmdOpts.source);
|
package/dist/enrich.d.ts
CHANGED
|
@@ -41,6 +41,23 @@ export declare function enrichExpert(db: ExpertsDB, e: Expert, opts: EnrichOptio
|
|
|
41
41
|
rateLimited: boolean;
|
|
42
42
|
quotaExhausted: boolean;
|
|
43
43
|
}>;
|
|
44
|
+
export interface AvatarBackfillResult {
|
|
45
|
+
downloaded: number;
|
|
46
|
+
skipped: number;
|
|
47
|
+
failed: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Download + properly name profile pictures for every expert that doesn't have
|
|
51
|
+
* a local one yet, using the source's own avatar URL (e.g. intro.co media). This
|
|
52
|
+
* needs no third-party API, so it completes "a named profile picture for every
|
|
53
|
+
* expert" even when X enrichment is unavailable.
|
|
54
|
+
*/
|
|
55
|
+
export declare function backfillAvatars(db: ExpertsDB, opts?: {
|
|
56
|
+
source?: string;
|
|
57
|
+
delayMs?: number;
|
|
58
|
+
fetchFn?: typeof fetch;
|
|
59
|
+
onLog?: (m: string) => void;
|
|
60
|
+
}): Promise<AvatarBackfillResult>;
|
|
44
61
|
/** Resumable, throttled enrichment over all experts with a Twitter handle. */
|
|
45
62
|
export declare function enrichX(db: ExpertsDB, opts?: EnrichOptions): Promise<EnrichResult>;
|
|
46
63
|
//# sourceMappingURL=enrich.d.ts.map
|
package/dist/enrich.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,SAAS,CAAC;AAIvD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC,GAAG,MAAM,CAQxF;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,mFAAmF;AACnF,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC,EAC5D,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uEAAuE;AACvE,wBAAsB,YAAY,CAChC,EAAE,EAAE,SAAS,EACb,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CAyE7H;AAED,8EAA8E;AAC9E,wBAAsB,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAqE5F"}
|
|
1
|
+
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../src/enrich.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAmB,MAAM,SAAS,CAAC;AAIvD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC,GAAG,MAAM,CAQxF;AAED,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKtD;AAED,qEAAqE;AACrE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,mFAAmF;AACnF,wBAAsB,cAAc,CAClC,GAAG,EAAE,MAAM,EACX,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,UAAU,CAAC,EAC5D,OAAO,GAAE,OAAO,KAAa,GAC5B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uEAAuE;AACvE,wBAAsB,YAAY,CAChC,EAAE,EAAE,SAAS,EACb,CAAC,EAAE,MAAM,EACT,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAC;IAAC,cAAc,EAAE,OAAO,CAAA;CAAE,CAAC,CAyE7H;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,SAAS,EACb,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IAAC,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GACpG,OAAO,CAAC,oBAAoB,CAAC,CA0B/B;AAED,8EAA8E;AAC9E,wBAAsB,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAqE5F"}
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export { crawlSource, type CrawlResult } from "./crawl";
|
|
|
10
10
|
export { getSource, listSources, registerSource, IntroSource } from "./sources";
|
|
11
11
|
export { IntroClient } from "./sources/intro-api";
|
|
12
12
|
export { normalizeIntroExpert, slugFromUrl } from "./sources/intro";
|
|
13
|
-
export { enrichX, enrichExpert, downloadAvatar, avatarBasename, handleFromSocial, type EnrichOptions, type EnrichResult } from "./enrich";
|
|
13
|
+
export { enrichX, enrichExpert, backfillAvatars, downloadAvatar, avatarBasename, handleFromSocial, type EnrichOptions, type EnrichResult, type AvatarBackfillResult } from "./enrich";
|
|
14
14
|
export { ConnectorsClient, defaultRunner, extractJson, type ConnectorRunner, type ConnectorResult } from "./connectors";
|
|
15
15
|
export { inferTags, expertText } from "./graph";
|
|
16
16
|
export * as format from "./format";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,MAAM,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,MAAM,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACtL,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACxH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1080,6 +1080,34 @@ async function enrichExpert(db, e, opts) {
|
|
|
1080
1080
|
}
|
|
1081
1081
|
return { ok: true, notFound: false, tweets: tweetCount, avatar, rateLimited: false, quotaExhausted: false };
|
|
1082
1082
|
}
|
|
1083
|
+
async function backfillAvatars(db, opts = {}) {
|
|
1084
|
+
const log = opts.onLog ?? (() => {});
|
|
1085
|
+
const fetchFn = opts.fetchFn ?? fetch;
|
|
1086
|
+
const delayMs = opts.delayMs ?? 150;
|
|
1087
|
+
const experts = db.list({ source: opts.source });
|
|
1088
|
+
const res = { downloaded: 0, skipped: 0, failed: 0 };
|
|
1089
|
+
for (const e of experts) {
|
|
1090
|
+
if (e.avatarLocal || !e.avatar) {
|
|
1091
|
+
res.skipped++;
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
try {
|
|
1095
|
+
const path = await downloadAvatar(e.avatar, e, fetchFn);
|
|
1096
|
+
if (path) {
|
|
1097
|
+
db.setAvatarLocal(e.source, e.sourceId, path);
|
|
1098
|
+
res.downloaded++;
|
|
1099
|
+
if (res.downloaded % 100 === 0)
|
|
1100
|
+
log(` avatars: ${res.downloaded} downloaded`);
|
|
1101
|
+
} else {
|
|
1102
|
+
res.failed++;
|
|
1103
|
+
}
|
|
1104
|
+
} catch {
|
|
1105
|
+
res.failed++;
|
|
1106
|
+
}
|
|
1107
|
+
await sleep2(delayMs);
|
|
1108
|
+
}
|
|
1109
|
+
return res;
|
|
1110
|
+
}
|
|
1083
1111
|
async function enrichX(db, opts = {}) {
|
|
1084
1112
|
const log = opts.onLog ?? (() => {});
|
|
1085
1113
|
const client = opts.client ?? new ConnectorsClient;
|
|
@@ -1781,6 +1809,7 @@ export {
|
|
|
1781
1809
|
defaultRunner,
|
|
1782
1810
|
defaultDbPath,
|
|
1783
1811
|
crawlSource,
|
|
1812
|
+
backfillAvatars,
|
|
1784
1813
|
avatarBasename,
|
|
1785
1814
|
IntroSource,
|
|
1786
1815
|
IntroClient,
|
package/package.json
CHANGED