import { writeFileSync, mkdirSync } from "node:fs"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { SEED_PRODUCTS } from "./categories"; import { fetchAllBestBuy } from "./fetch-bestbuy"; import { scrapeAmazonProducts } from "./scrape-amazon"; import { matchProducts } from "./match-products"; import { generateAllReviews } from "./generate-reviews"; const __dirname = dirname(fileURLToPath(import.meta.url)); async function main() { const BESTBUY_API_KEY = process.env.BESTBUY_API_KEY; const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; if (!ANTHROPIC_API_KEY) { throw new Error("ANTHROPIC_API_KEY is required"); } const searchTerms = SEED_PRODUCTS.map((s) => ({ name: s.name, term: s.bestBuySearchTerm, })); let bestBuyData = new Map(); if (BESTBUY_API_KEY) { console.log( `[pipeline] Fetching ${searchTerms.length} products from Best Buy...`, ); bestBuyData = await fetchAllBestBuy(searchTerms, BESTBUY_API_KEY); console.log(`[pipeline] Got ${bestBuyData.size} Best Buy results`); } else { console.log("[pipeline] No BESTBUY_API_KEY — skipping Best Buy"); } const asins = SEED_PRODUCTS.filter((s) => s.amazonASIN).map((s) => ({ name: s.name, asin: s.amazonASIN!, })); let amazonData = new Map(); const skipAmazon = process.env.SKIP_AMAZON === "1"; if (!skipAmazon && asins.length > 0) { console.log(`[pipeline] Scraping ${asins.length} Amazon products...`); amazonData = await scrapeAmazonProducts(asins); console.log(`[pipeline] Got ${amazonData.size} Amazon results`); } else { console.log("[pipeline] Skipping Amazon scraping"); } const unified = matchProducts(SEED_PRODUCTS, bestBuyData, amazonData); console.log(`[pipeline] ${unified.length} unified products with price data`); if (unified.length === 0) { throw new Error( "No products found. Check API keys and network connectivity.", ); } console.log(`[pipeline] Generating AI reviews for ${unified.length} products...`); const reviews = await generateAllReviews(unified, ANTHROPIC_API_KEY); const products = unified.map((p) => { const review = reviews.get(p.id); return { id: p.id, name: p.name, category: p.category, rating: p.rating, reviewCount: p.reviewCount, image: p.image, prices: p.prices, summary: review?.summary ?? "", pros: review?.pros ?? [], cons: review?.cons ?? [], bestValue: review?.bestValue ?? "", }; }); const dataDir = join(__dirname, "..", "data"); mkdirSync(dataDir, { recursive: true }); const outputPath = join(dataDir, "products.json"); writeFileSync( outputPath, JSON.stringify( { products, buildTime: new Date().toISOString() }, null, 2, ), ); console.log(`[pipeline] Wrote ${products.length} products to ${outputPath}`); const metaPath = join(dataDir, "build-meta.json"); writeFileSync( metaPath, JSON.stringify( { buildTime: new Date().toISOString(), productCount: products.length, bestBuyHits: bestBuyData.size, amazonHits: amazonData.size, reviewsGenerated: reviews.size, }, null, 2, ), ); console.log("[pipeline] Done."); } main().catch((err) => { console.error("[pipeline] Fatal:", err); process.exit(1); });