import fs from 'fs/promises'; import path from 'path'; import { Prompt, PromptCache } from '@/lib/types'; import { JimmyLvCrawler, YouMindCrawler, ZeroLuCrawler } from '@/lib/crawler'; const DATA_FILE = path.join(process.cwd(), 'data', 'prompts.json'); export async function getPrompts(): Promise { try { const fileContent = await fs.readFile(DATA_FILE, 'utf-8'); return JSON.parse(fileContent); } catch (e) { return { prompts: [], last_updated: null, categories: {}, total_count: 0, sources: [] }; } } export async function syncPromptsService(): Promise<{ success: boolean, count: number, added: number }> { console.log("[SyncService] Starting sync..."); // 1. Crawl all sources const jimmyCrawler = new JimmyLvCrawler(); const youMindCrawler = new YouMindCrawler(); const zeroLuCrawler = new ZeroLuCrawler(); const [jimmyPrompts, youMindPrompts, zeroLuPrompts] = await Promise.all([ jimmyCrawler.crawl(), youMindCrawler.crawl(), zeroLuCrawler.crawl() ]); const crawledPrompts = [...jimmyPrompts, ...youMindPrompts, ...zeroLuPrompts]; console.log(`[SyncService] Total crawled ${crawledPrompts.length} prompts (Jimmy: ${jimmyPrompts.length}, YouMind: ${youMindPrompts.length}, ZeroLu: ${zeroLuPrompts.length}).`); // 2. Read existing const cache = await getPrompts(); const existingPrompts = cache.prompts || []; // 3. Merge let addedCount = 0; const now = Date.now(); const finalPrompts: Prompt[] = []; const existingMap = new Map(); existingPrompts.forEach(p => { if (p.source_url) { existingMap.set(p.source_url, p); } else { finalPrompts.push(p); } }); crawledPrompts.forEach(newP => { const existing = existingMap.get(newP.source_url); if (existing) { finalPrompts.push({ ...newP, id: existing.id, images: existing.images, createdAt: existing.createdAt || (existing.published ? new Date(existing.published).getTime() : undefined), useCount: existing.useCount, lastUsedAt: existing.lastUsedAt }); existingMap.delete(newP.source_url); } else { addedCount++; finalPrompts.push({ ...newP, createdAt: now, useCount: 0 }); } }); // Add remaining existing existingMap.forEach(p => finalPrompts.push(p)); // Re-ID finalPrompts.forEach((p, i) => p.id = i + 1); // Meta const categories: Record = { "style": Array.from(new Set(finalPrompts.map(p => p.category))) }; const newCache: PromptCache = { last_updated: new Date(now).toISOString(), lastSync: now, categories, total_count: finalPrompts.length, sources: Array.from(new Set(finalPrompts.map(p => p.source))), prompts: finalPrompts }; await fs.writeFile(DATA_FILE, JSON.stringify(newCache, null, 2), 'utf-8'); return { success: true, count: finalPrompts.length, added: addedCount }; }