refactor: migrate sticker cache to PostgreSQL, remove versioning

- Replace file-based sticker cache (.dat + index.json) with PostgreSQL sticker_cache table
- Remove model_version column and all versioning logic (git branch detection, GitHub API, CACHE_MODEL_VERSION)
- Strip VISION_MODEL_VERSION, logCacheEvent calls, and version filtering from SQL queries
- Remove STICKER_CACHE_DIR and STICKER_CACHE_MAX_SIZE_MB config variables
- Delete dead migration add_model_version_to_cache.sql

textCacheStore.ts reduced 482→204 lines (-57%)
stickerCache.ts reduced 210→144 lines (-31%)
Total: 11 files changed, 233 insertions, 591 deletions
This commit is contained in:
MythEclipse
2026-06-02 14:05:51 +07:00
parent e584a7941e
commit 406a6cbf79
11 changed files with 233 additions and 591 deletions
@@ -14,6 +14,7 @@ import type {
import { withLlmConcurrency } from "./concurrencyLimiter.js";
import { formatModerationTextEvidenceForPrompt } from "./indonesianTextNormalizer.js";
import { buildSystemPrompt as buildSystemPromptModular } from "./moderationPrompt.js";
import { logModerationAnalysis, logModerationError } from "./responseLogger.js";
import {
getStickerFromCache,
initStickerCache,
@@ -32,14 +33,8 @@ import {
makeImageCacheKey,
makeStickerCacheKey,
upsertCachedMediaAnalysis,
VISION_MODEL_VERSION,
} from "./textCacheStore.js";
import { extractUrlsFromText, fetchUrlSafely } from "./urlFetcher.js";
import {
logCacheEvent,
logModerationAnalysis,
logModerationError,
} from "./responseLogger.js";
const SeveritySchema = z.enum(["none", "low", "medium", "high", "critical"]);
const RecommendedActionSchema = z.enum([
@@ -793,11 +788,16 @@ async function callModerationLLM(
);
// Log error with responseLogger
logModerationError(targetIds, config.AI_LLM_MODEL, parseError as Error | string, {
phase: "parse_response",
label,
contentLength: state.lastInvalidContent.length,
});
logModerationError(
targetIds,
config.AI_LLM_MODEL,
parseError as Error | string,
{
phase: "parse_response",
label,
contentLength: state.lastInvalidContent.length,
},
);
// Sanitized error messages — no internal details exposed (R10)
const errorCode = `MOD_${Date.now().toString(36).slice(0, 6)}`;
@@ -996,10 +996,7 @@ async function _runSingleMediaAnalysis(
): Promise<{ results: AnalysisResult[]; raw: unknown }> {
// Lazy init sticker cache
if (!isStickerCacheReady()) {
await initStickerCache({
cacheDir: config.STICKER_CACHE_DIR,
maxSizeBytes: config.STICKER_CACHE_MAX_SIZE_MB * 1024 * 1024,
}).catch((err: unknown) => {
await initStickerCache().catch((err: unknown) => {
log.warn(
{ error: err instanceof Error ? err.message : String(err) },
"Sticker cache init failed — continuing without cache",
@@ -1040,7 +1037,6 @@ async function _runSingleMediaAnalysis(
{ attachmentId: att.id, cacheKey: attVisionKey },
"Vision cache HIT for attachment — skipped download",
);
logCacheEvent("hit", attVisionKey, "media", VISION_MODEL_VERSION);
const sourceLabel = `[gambar di atas adalah attachment ${att.filename} dari pesan id=${att.message_id}]`;
const analysisText = `[Media analysis for message ${att.message_id}] ${sourceLabel}: ${cachedVision}`;
const existing = mediaAnalysisMap.get(targetId) ?? [];
@@ -1049,8 +1045,6 @@ async function _runSingleMediaAnalysis(
return;
}
logCacheEvent("miss", attVisionKey, "media", VISION_MODEL_VERSION);
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 15000);