focal-point: trajni predpomnilnik zarisov na /uploads, da deploy ne analizira vseh slik znova
This commit is contained in:
@@ -26,6 +26,42 @@ function loadDetected() {
|
||||
|
||||
const cache = new Map<string, { x: number; y: number }>();
|
||||
|
||||
// Trajni predpomnilnik LLM zarisov. Lezi na /opt/folxtv-uploads (bind mount),
|
||||
// zato prezivi deploy in restart — brez tega je vsak deploy pomenil ponovno
|
||||
// analizo vseh naslovnih slik na gpt-4o-mini.
|
||||
const CACHE_PATH = path.join(process.cwd(), "client/public/uploads/focal_cache.json");
|
||||
let cacheLoaded = false;
|
||||
let cacheDirty = false;
|
||||
|
||||
function loadCache() {
|
||||
if (cacheLoaded) return;
|
||||
cacheLoaded = true;
|
||||
try {
|
||||
const raw = JSON.parse(fs.readFileSync(CACHE_PATH, "utf-8")) as Record<string, { x: number; y: number }>;
|
||||
for (const [k, v] of Object.entries(raw)) {
|
||||
if (v && typeof v.x === "number" && typeof v.y === "number") cache.set(k, v);
|
||||
}
|
||||
console.log("[focal-point] iz predpomnilnika nalozenih:", cache.size);
|
||||
} catch {
|
||||
console.log("[focal-point] predpomnilnika se ni, zacenjam prazen");
|
||||
}
|
||||
}
|
||||
|
||||
function saveCache() {
|
||||
if (!cacheDirty) return;
|
||||
try {
|
||||
const obj: Record<string, { x: number; y: number }> = {};
|
||||
for (const [k, v] of cache.entries()) obj[k] = v;
|
||||
fs.mkdirSync(path.dirname(CACHE_PATH), { recursive: true });
|
||||
fs.writeFileSync(CACHE_PATH + ".tmp", JSON.stringify(obj));
|
||||
fs.renameSync(CACHE_PATH + ".tmp", CACHE_PATH);
|
||||
cacheDirty = false;
|
||||
console.log("[focal-point] predpomnilnik shranjen, vnosov:", cache.size);
|
||||
} catch (e) {
|
||||
console.log("[focal-point] predpomnilnika ni bilo mogoce shraniti:", (e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
const manualOverrides: Record<string, { x: number; y: number }> = {
|
||||
"/uploads/70-jahre-oberkrainer.webp": { x: 50, y: 55 },
|
||||
};
|
||||
@@ -46,6 +82,7 @@ Return ONLY a JSON object like {"x":42,"y":38} with no other text.`;
|
||||
|
||||
export async function analyzeFocalPoint(imagePath: string): Promise<{ x: number; y: number }> {
|
||||
const originalPath = imagePath;
|
||||
loadCache();
|
||||
if (manualOverrides[originalPath]) {
|
||||
cache.set(originalPath, manualOverrides[originalPath]);
|
||||
return manualOverrides[originalPath];
|
||||
@@ -104,6 +141,7 @@ export async function analyzeFocalPoint(imagePath: string): Promise<{ x: number;
|
||||
y: Math.max(0, Math.min(100, Number(parsed.y) || 30)),
|
||||
};
|
||||
cache.set(originalPath, point);
|
||||
cacheDirty = true;
|
||||
return point;
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -120,10 +158,12 @@ export async function analyzeAllArticleImages(articles: Array<{ coverImage: stri
|
||||
if (!article.coverImage) continue;
|
||||
await analyzeFocalPoint(article.coverImage);
|
||||
}
|
||||
saveCache();
|
||||
console.log("[focal-point] Analyzed", cache.size, "images");
|
||||
}
|
||||
|
||||
export function getCachedFocalPoints(): Record<string, { x: number; y: number }> {
|
||||
loadCache();
|
||||
loadDetected();
|
||||
const result: Record<string, { x: number; y: number }> = {};
|
||||
for (const [key, value] of cache.entries()) {
|
||||
|
||||
Reference in New Issue
Block a user