diff --git a/core-parser/index.js b/core-parser/index.js index a721783..4239594 100644 --- a/core-parser/index.js +++ b/core-parser/index.js @@ -64,3 +64,4 @@ module.exports = CoreParser; + diff --git a/job-search-parser/README.md b/job-search-parser/README.md index 5896666..f5d4789 100644 --- a/job-search-parser/README.md +++ b/job-search-parser/README.md @@ -78,8 +78,8 @@ Professional network job postings with comprehensive job data. - LinkedIn credentials (username and password) must be set in `.env` file: ```env - LINKEDIN_USERNAME=tatiana.litvak25@gmail.com - LINKEDIN_PASSWORD=Sladkiy99( + LINKEDIN_USERNAME=******@gmail.com + LINKEDIN_PASSWORD=*** LINKEDIN_JOB_LOCATION=Canada # Optional: LinkedIn location filter ``` diff --git a/job-search-parser/index.js b/job-search-parser/index.js index 656eed9..caeeda0 100644 --- a/job-search-parser/index.js +++ b/job-search-parser/index.js @@ -11,7 +11,7 @@ const fs = require("fs"); const CoreParser = require("../core-parser"); const { skipthedriveStrategy } = require("./strategies/skipthedrive-strategy"); const { linkedinJobsStrategy } = require("./strategies/linkedin-jobs-strategy"); -const { logger, analyzeBatch, checkOllamaStatus } = require("ai-analyzer"); +const { logger, analyzeBatch, checkOllamaStatus, DEFAULT_MODEL } = require("ai-analyzer"); // Load environment variables require("dotenv").config({ path: path.join(__dirname, ".env") }); @@ -22,6 +22,8 @@ const SEARCH_KEYWORDS = process.env.SEARCH_KEYWORDS || "co-op,intern";//"software engineer,developer,programmer"; const LOCATION_FILTER = process.env.LOCATION_FILTER; const ENABLE_AI_ANALYSIS = process.env.ENABLE_AI_ANALYSIS === "true"; +const AI_CONTEXT = process.env.AI_CONTEXT || "Job market analysis focusing on job postings, skills, and trends"; +const OLLAMA_MODEL = process.env.OLLAMA_MODEL || DEFAULT_MODEL; const MAX_PAGES = parseInt(process.env.MAX_PAGES) || 5; const EXCLUDE_REJECTED = process.env.EXCLUDE_REJECTED === "true"; @@ -104,6 +106,10 @@ async function startJobSearchParser(options = {}) { logger.info( `🧠 AI Analysis: ${ENABLE_AI_ANALYSIS ? "Enabled" : "Disabled"}` ); + if (ENABLE_AI_ANALYSIS) { + logger.info(` Context: "${AI_CONTEXT}"`); + logger.info(` Model: ${OLLAMA_MODEL}`); + } const allResults = []; const allRejectedResults = []; @@ -188,12 +194,36 @@ async function startJobSearchParser(options = {}) { if (ENABLE_AI_ANALYSIS && allResults.length > 0) { logger.step("🧠 Running AI Analysis..."); - const ollamaStatus = await checkOllamaStatus(); - if (ollamaStatus.available) { - analysisResults = await analyzeBatch(allResults, { - context: - "Job market analysis focusing on job postings, skills, and trends", + const ollamaAvailable = await checkOllamaStatus(OLLAMA_MODEL); + if (ollamaAvailable) { + // Prepare data for analysis (analyzeBatch expects objects with 'text' field) + const analysisData = allResults.map((job) => ({ + text: `${job.title || ""} at ${job.company || ""}. ${job.description || ""}`.trim(), + location: job.location || "", + keyword: job.keyword || "", + timestamp: job.extractedAt || job.postedDate || "", + })); + + analysisResults = await analyzeBatch( + analysisData, + AI_CONTEXT, + OLLAMA_MODEL + ); + + // Embed AI analysis into each job result + allResults.forEach((job, index) => { + if (analysisResults && analysisResults[index]) { + job.aiAnalysis = { + isRelevant: analysisResults[index].isRelevant, + confidence: analysisResults[index].confidence, + reasoning: analysisResults[index].reasoning, + context: AI_CONTEXT, + model: OLLAMA_MODEL, + analyzedAt: new Date().toISOString(), + }; + } }); + logger.success( `✅ AI Analysis completed for ${allResults.length} jobs` ); @@ -214,6 +244,9 @@ async function startJobSearchParser(options = {}) { sites: sites, keywords: keywords.join(", "), locationFilter, + aiAnalysisEnabled: ENABLE_AI_ANALYSIS, + aiContext: ENABLE_AI_ANALYSIS ? AI_CONTEXT : undefined, + aiModel: ENABLE_AI_ANALYSIS ? OLLAMA_MODEL : undefined, analysisResults, rejectedJobsExcluded: excludeRejected, },