Files
memorium/lib/recommendation.ts
2025-11-07 18:58:23 +01:00

101 lines
2.4 KiB
TypeScript

import * as openai from "@lib/openai.ts";
import * as tmdb from "@lib/tmdb.ts";
import { parseRating } from "@lib/helpers.ts";
import { createCache } from "@lib/cache.ts";
import { ReviewResource } from "./marka/schema.ts";
export type RecommendationResource = {
id: string;
type: string;
rating: number;
tags?: string[];
description?: string;
keywords?: string[];
author?: string;
year?: number;
};
const cache = createCache<RecommendationResource>("recommendations");
export async function createRecommendationResource(
res: ReviewResource,
description?: string,
) {
const cacheId = `${res.type}:${res.name.replaceAll(":", "")}`;
const resource = cache.get(cacheId) || {
id: res.name,
type: res.type,
rating: -1,
};
if (description && !resource.keywords) {
const keywords = await openai.createKeywords(
res.type,
description,
res.name,
);
if (keywords?.length) {
resource.keywords = keywords;
}
}
const { author, datePublished, reviewRating } = res.content;
if (res?.content?.keywords) {
resource.keywords = res.content.keywords;
}
if (typeof reviewRating?.ratingValue !== "undefined") {
resource.rating = parseRating(reviewRating?.ratingValue);
}
if (author?.name) {
resource.author = author.name;
}
if (description) {
resource.description = description;
}
if (datePublished) {
const d = typeof datePublished === "string"
? new Date(datePublished)
: datePublished;
resource.year = d.getFullYear();
}
cache.set(cacheId, JSON.stringify(resource));
}
export function getRecommendation(
id: string,
type: string,
): RecommendationResource | undefined {
return cache.get(`recommendations:${type}:${id}`);
}
export async function getSimilarMovies(id: string) {
const recs = getRecommendation(id, "movies");
if (!recs?.keywords?.length) return;
const recommendations = await openai.getMovieRecommendations(
recs.keywords.join(),
[recs.id],
);
if (!recommendations) return;
const movies = await Promise.all(recommendations.map(async (rec) => {
const m = await tmdb.searchMovie(rec.title, rec.year);
return m?.results?.[0];
}));
return movies.filter(Boolean);
}
export async function getAllRecommendations(): Promise<
RecommendationResource[]
> {
const keys = cache.keys();
const res = await Promise.all(keys.map((k) => cache.get(k)));
return res.filter((s) => !!s).map((r) => JSON.parse(r));
}