From 97b753d401b331e77399ba17c933cc6af437187d Mon Sep 17 00:00:00 2001 From: Claw Date: Fri, 6 Mar 2026 02:24:54 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20cache=20keywords=20in=20search=5Fprogre?= =?UTF-8?q?ss.json=20=E2=80=94=20restarts=20reuse=20same=20keywords,=20no?= =?UTF-8?q?=20regeneration=20mid-run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- job_searcher.mjs | 39 ++++++++++++++++++++++----------------- lib/search_progress.mjs | 13 +++++++++++++ 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/job_searcher.mjs b/job_searcher.mjs index e28c44c..b957790 100644 --- a/job_searcher.mjs +++ b/job_searcher.mjs @@ -22,7 +22,7 @@ import { verifyLogin as wfLogin, searchWellfound } from './lib/wellfound.mjs'; import { sendTelegram, formatSearchSummary } from './lib/notify.mjs'; import { DEFAULT_FIRST_RUN_DAYS } from './lib/constants.mjs'; import { generateKeywords } from './lib/keywords.mjs'; -import { initProgress, isCompleted, markComplete, getKeywordStart, markKeywordComplete } from './lib/search_progress.mjs'; +import { initProgress, isCompleted, markComplete, getKeywordStart, markKeywordComplete, saveKeywords, getSavedKeywords } from './lib/search_progress.mjs'; import { ensureLoggedIn } from './lib/session.mjs'; async function main() { @@ -58,22 +58,6 @@ async function main() { const profile = loadConfig(resolve(__dir, 'config/profile.json')); const anthropicKey = process.env.ANTHROPIC_API_KEY || settings.anthropic_api_key; - // Enhance keywords with AI if API key available - if (anthropicKey) { - console.log('🤖 Generating AI-enhanced search keywords...'); - for (const search of searchConfig.searches) { - try { - const aiKeywords = await generateKeywords(search, profile, anthropicKey); - const merged = [...new Set([...search.keywords, ...aiKeywords])]; - console.log(` [${search.name}] ${search.keywords.length} → ${merged.length} keywords`); - search.keywords = merged; - } catch (e) { - console.warn(` [${search.name}] AI keywords failed, using static: ${e.message}`); - } - } - console.log(''); - } - // Determine lookback: check for an in-progress run first, then fall back to first-run/normal logic const savedProgress = existsSync(resolve(__dir, 'data/search_progress.json')) ? JSON.parse(readFileSync(resolve(__dir, 'data/search_progress.json'), 'utf8')) @@ -91,6 +75,27 @@ async function main() { // Init progress tracking — enables resume on restart initProgress(resolve(__dir, 'data'), lookbackDays); + // Enhance keywords with AI — reuse saved keywords from progress if resuming, never regenerate mid-run + for (const search of searchConfig.searches) { + const saved = getSavedKeywords('linkedin', search.name) ?? getSavedKeywords('wellfound', search.name); + if (saved) { + console.log(` [${search.name}] reusing ${saved.length} saved keywords`); + search.keywords = saved; + } else if (anthropicKey) { + try { + const aiKeywords = await generateKeywords(search, profile, anthropicKey); + const merged = [...new Set([...search.keywords, ...aiKeywords])]; + console.log(`🤖 [${search.name}] ${search.keywords.length} → ${merged.length} keywords (AI-enhanced)`); + search.keywords = merged; + } catch (e) { + console.warn(` [${search.name}] AI keywords failed, using static: ${e.message}`); + } + } + saveKeywords('linkedin', search.name, search.keywords); + saveKeywords('wellfound', search.name, search.keywords); + } + console.log(''); + // Group searches by platform const liSearches = searchConfig.searches.filter(s => s.platforms?.includes('linkedin')); const wfSearches = searchConfig.searches.filter(s => s.platforms?.includes('wellfound')); diff --git a/lib/search_progress.mjs b/lib/search_progress.mjs index 09c58a9..6918354 100644 --- a/lib/search_progress.mjs +++ b/lib/search_progress.mjs @@ -33,6 +33,19 @@ export function initProgress(dataDir, lookbackDays) { return progress; } +/** Save generated keywords for a track — reused on resume, never regenerated mid-run */ +export function saveKeywords(platform, track, keywords) { + if (!progress) return; + if (!progress.keywords) progress.keywords = {}; + progress.keywords[`${platform}:${track}`] = keywords; + save(); +} + +/** Get saved keywords for a track, or null if not yet generated */ +export function getSavedKeywords(platform, track) { + return progress?.keywords?.[`${platform}:${track}`] ?? null; +} + export function isCompleted(platform, track) { if (!progress) return false; return progress.completed.includes(`${platform}:${track}`);