Save trending hashtags as labels

This commit is contained in:
Alex Gleason 2024-06-02 13:15:05 -05:00
parent 3363688977
commit c969738736
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
2 changed files with 64 additions and 0 deletions

View File

@ -5,6 +5,7 @@ import { getTrendingNotes } from '@/trends/trending-notes.ts';
import { Time } from '@/utils/time.ts'; import { Time } from '@/utils/time.ts';
import { AdminSigner } from '@/signers/AdminSigner.ts'; import { AdminSigner } from '@/signers/AdminSigner.ts';
import { handleEvent } from '@/pipeline.ts'; import { handleEvent } from '@/pipeline.ts';
import { getTrendingHashtags } from '@/trends/trending-hashtags.ts';
const console = new Stickynotes('ditto:trends'); const console = new Stickynotes('ditto:trends');
@ -32,7 +33,32 @@ async function updateTrendingNotesCache() {
console.info('Trending notes cache updated.'); console.info('Trending notes cache updated.');
} }
async function updateTrendingHashtagsCache() {
console.info('Updating trending hashtags cache...');
const kysely = await DittoDB.getInstance();
const yesterday = Math.floor((Date.now() - Time.days(1)) / 1000);
const signal = AbortSignal.timeout(1000);
const hashtags = await getTrendingHashtags(kysely, { since: yesterday, limit: 20, threshold: 3 });
const signer = new AdminSigner();
const label = await signer.signEvent({
kind: 1985,
content: '',
tags: [
['L', 'pub.ditto.trends'],
['l', 'hashtags', 'pub.ditto.trends'],
...hashtags.map(({ tag }) => ['t', tag]),
],
created_at: Math.floor(Date.now() / 1000),
});
await handleEvent(label, signal);
console.info('Trending hashtags cache updated.');
}
/** Start cron jobs for the application. */ /** Start cron jobs for the application. */
export function cron() { export function cron() {
Deno.cron('update trending notes cache', { minute: { every: 15 } }, updateTrendingNotesCache); Deno.cron('update trending notes cache', { minute: { every: 15 } }, updateTrendingNotesCache);
Deno.cron('update trending hashtags cache', { dayOfMonth: { every: 1 } }, updateTrendingHashtagsCache);
} }

View File

@ -0,0 +1,38 @@
import { Kysely } from 'kysely';
import { DittoTables } from '@/db/DittoTables.ts';
interface GetTrendingHashtagsOpts {
/** Unix timestamp in _seconds_ for the starting point of this query. */
since: number;
/** Maximum number of trending hashtags to return. */
limit: number;
/** Minimum number of unique accounts that have used a hashtag to be considered trending. */
threshold: number;
}
/** Get the trending hashtags in the given time frame. */
export async function getTrendingHashtags(
/** Kysely instance to execute queries on. */
kysely: Kysely<DittoTables>,
/** Options for this query. */
opts: GetTrendingHashtagsOpts,
): Promise<{ tag: string; accounts: number; uses: number }[]> {
const { since, limit, threshold } = opts;
return await kysely
.selectFrom('nostr_tags')
.innerJoin('nostr_events', 'nostr_events.id', 'nostr_tags.event_id')
.select(({ fn }) => [
'nostr_tags.value as tag',
fn.agg<number>('count', ['nostr_events.pubkey']).distinct().as('accounts'),
fn.countAll<number>().as('uses'),
])
.where('nostr_tags.name', '=', 't')
.where('nostr_events.created_at', '>', since)
.groupBy('nostr_tags.value')
.having((c) => c(c.fn.agg('count', ['nostr_events.pubkey']).distinct(), '>=', threshold))
.orderBy((c) => c.fn.agg('count', ['nostr_events.pubkey']).distinct(), 'desc')
.limit(limit)
.execute();
}