feat: add mid-range sellers by category analysis pipeline
This new pipeline identifies products meeting specific monthly sold, price, seller count, and Amazon buy box share criteria across categories. It fetches comprehensive product data from Keepa and SP-API, analyzes it using an LLM, and persists the results. A key enhancement is the introduction of a dedicated Redis cache for Keepa and SP-API responses. This reduces API token consumption and improves performance for subsequent runs by caching enriched ASIN data with a 12-hour TTL. Products are saved regardless of their sellability status to provide a complete view.
This commit is contained in:
42
src/cache.ts
42
src/cache.ts
@@ -1,10 +1,21 @@
|
||||
import Redis from "ioredis";
|
||||
import { config } from "./config.ts";
|
||||
import type { EnrichedProduct } from "./types.ts";
|
||||
import type { EnrichedProduct, KeepaData, SpApiData } from "./types.ts";
|
||||
|
||||
let redis: Redis | null = null;
|
||||
let disabled = false;
|
||||
|
||||
export type ApiCacheEntry = {
|
||||
title: string;
|
||||
keepa: KeepaData | null;
|
||||
spApi: SpApiData;
|
||||
fetchedAt: string;
|
||||
};
|
||||
|
||||
function getApiCacheKey(asin: string): string {
|
||||
return `api:asin:${asin}`;
|
||||
}
|
||||
|
||||
export async function connectCache(): Promise<void> {
|
||||
if (disabled) return;
|
||||
try {
|
||||
@@ -58,6 +69,35 @@ export async function setCache(
|
||||
}
|
||||
}
|
||||
|
||||
export async function getApiCache(asin: string): Promise<ApiCacheEntry | null> {
|
||||
if (!redis) return null;
|
||||
try {
|
||||
const raw = await redis.get(getApiCacheKey(asin));
|
||||
if (!raw) return null;
|
||||
return JSON.parse(raw) as ApiCacheEntry;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function setApiCache(
|
||||
asin: string,
|
||||
data: ApiCacheEntry,
|
||||
ttlSeconds: number,
|
||||
): Promise<void> {
|
||||
if (!redis) return;
|
||||
try {
|
||||
await redis.set(
|
||||
getApiCacheKey(asin),
|
||||
JSON.stringify(data),
|
||||
"EX",
|
||||
ttlSeconds,
|
||||
);
|
||||
} catch {
|
||||
// Non-critical, continue without caching
|
||||
}
|
||||
}
|
||||
|
||||
export async function disconnectCache(): Promise<void> {
|
||||
if (redis) {
|
||||
await redis.quit();
|
||||
|
||||
Reference in New Issue
Block a user