Enhance job search parser with AI analysis capabilities

- Added support for customizable AI context and model selection in job search analysis.
- Improved logging to provide detailed information about AI analysis status and parameters.
- Updated README to mask sensitive LinkedIn credentials for security.
- Refactored AI analysis integration to streamline data preparation and result embedding.
This commit is contained in:
tanyar09 2025-12-16 23:38:25 -05:00
parent 4099b23744
commit c692853c38
3 changed files with 42 additions and 8 deletions

View File

@ -64,3 +64,4 @@ module.exports = CoreParser;

View File

@ -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
```

View File

@ -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,
},