import type { PrismaClient, Attachment, Meme } from '@prisma/client'; import type { Meilisearch } from 'meilisearch'; import type { Logger } from 'pino'; import _ from 'lodash' import * as attachments from './attachments' const STORAGE_BUCKET = process.env.STORAGE_BUCKET function memeUrl(a: Attachment) { const STORAGE_URL = process.env.STORAGE_URL const u = new URL(`${STORAGE_BUCKET}/${attachments.objectName(a)}`, `https://${STORAGE_URL}`) return u.href } export default async function memeService(baseLog: Logger, prisma: PrismaClient, meili: Meilisearch) { const log = baseLog.child({ service: 'meme' }) function fromAttachment(a: Attachment) { const text = a.vision.fullTextAnnotation?.text || '' const tags = [ a.guild.name, a.channel.name, a.message.author.username, ] const m: Meme = { id: a.memeId, url: memeUrl(a), text, tags: tags, attachmentId: a.id, postedAt: a.postedAt, createdAt: undefined, updatedAt: undefined } return m } async function ensureMeiliIndex() { const task = await meili.createIndex('memes', { primaryKey: 'id' }) const result = await meili.waitForTask(task.taskUid) log.debug(result); const index = await meili.index('memes') await index.updateSortableAttributes(['postedAt']) return index; } // BLOWS IT UP async function resetMeili() { const delTask = await meili.deleteIndex('memes') const delResult = await meili.waitForTask(delTask.taskUid) const index = await ensureMeiliIndex() const memes = (await prisma.meme.findMany()) .map(m => ({ ...m, postedAt: m.postedAt.valueOf() })); for await (const batch of _.chunk(memes, 1000)) { const task = await index.updateDocuments(batch) const res = await meili.waitForTask(task.taskUid) log.info({ res }, 'added meme batch') } } async function persist(m: Meme) { const index = meili.index('memes') const doc = ({ ...m, postedAt: m.postedAt.valueOf() }) return index.updateDocuments([doc]) } await ensureMeiliIndex(); // BAM // await resetMeili(); return { ensureMeiliIndex, resetMeili, fromAttachment, persist, } } export type MemeService = Awaited>