- Created core modules: `ai-analyzer`, `core-parser`, and `job-search-parser`. - Implemented LinkedIn and job search parsers with integrated AI analysis. - Added CLI tools for AI analysis and job parsing. - Included comprehensive README files for each module detailing usage and features. - Established a `.gitignore` file to exclude unnecessary files. - Introduced sample data for testing and demonstration purposes. - Set up package.json files for dependency management across modules. - Implemented logging and error handling utilities for better debugging and user feedback.
347 lines
10 KiB
JavaScript
347 lines
10 KiB
JavaScript
/**
|
||
* AI Analyzer Demo
|
||
*
|
||
* Demonstrates all the core utilities provided by the ai-analyzer package:
|
||
* - Logger functionality
|
||
* - Text processing utilities
|
||
* - Location validation
|
||
* - AI analysis capabilities
|
||
* - Test utilities
|
||
*/
|
||
|
||
const {
|
||
logger,
|
||
Logger,
|
||
cleanText,
|
||
containsAnyKeyword,
|
||
parseLocationFilters,
|
||
validateLocationAgainstFilters,
|
||
extractLocationFromProfile,
|
||
analyzeBatch,
|
||
} = require("./index");
|
||
|
||
// Terminal colors for demo output
|
||
const colors = {
|
||
reset: "\x1b[0m",
|
||
bright: "\x1b[1m",
|
||
cyan: "\x1b[36m",
|
||
green: "\x1b[32m",
|
||
yellow: "\x1b[33m",
|
||
blue: "\x1b[34m",
|
||
magenta: "\x1b[35m",
|
||
red: "\x1b[31m",
|
||
};
|
||
|
||
const demo = {
|
||
title: (text) =>
|
||
console.log(`\n${colors.bright}${colors.cyan}${text}${colors.reset}`),
|
||
section: (text) =>
|
||
console.log(`\n${colors.bright}${colors.magenta}${text}${colors.reset}`),
|
||
success: (text) => console.log(`${colors.green}✅ ${text}${colors.reset}`),
|
||
info: (text) => console.log(`${colors.blue}ℹ️ ${text}${colors.reset}`),
|
||
warning: (text) => console.log(`${colors.yellow}⚠️ ${text}${colors.reset}`),
|
||
error: (text) => console.log(`${colors.red}❌ ${text}${colors.reset}`),
|
||
code: (text) => console.log(`${colors.cyan}${text}${colors.reset}`),
|
||
};
|
||
|
||
async function runDemo() {
|
||
demo.title("=== AI Analyzer Demo ===");
|
||
demo.info(
|
||
"This demo showcases all the core utilities provided by the ai-analyzer package."
|
||
);
|
||
demo.info("Press Enter to continue through each section...\n");
|
||
|
||
await waitForEnter();
|
||
|
||
// 1. Logger Demo
|
||
await demonstrateLogger();
|
||
|
||
// 2. Text Processing Demo
|
||
await demonstrateTextProcessing();
|
||
|
||
// 3. Location Validation Demo
|
||
await demonstrateLocationValidation();
|
||
|
||
// 4. AI Analysis Demo
|
||
await demonstrateAIAnalysis();
|
||
|
||
// 5. Integration Demo
|
||
await demonstrateIntegration();
|
||
|
||
demo.title("=== Demo Complete ===");
|
||
demo.success("All ai-analyzer utilities demonstrated successfully!");
|
||
demo.info("Check the README.md for detailed API documentation.");
|
||
}
|
||
|
||
async function demonstrateLogger() {
|
||
demo.section("1. Logger Utilities");
|
||
demo.info(
|
||
"The logger provides consistent logging across all parsers with configurable levels and color support."
|
||
);
|
||
|
||
demo.code("// Using default logger");
|
||
logger.info("This is an info message");
|
||
logger.warning("This is a warning message");
|
||
logger.error("This is an error message");
|
||
logger.success("This is a success message");
|
||
logger.debug("This is a debug message (if enabled)");
|
||
|
||
demo.code("// Convenience methods with emoji prefixes");
|
||
logger.step("Starting demo process");
|
||
logger.search("Searching for keywords");
|
||
logger.ai("Running AI analysis");
|
||
logger.location("Validating location");
|
||
logger.file("Saving results");
|
||
|
||
demo.code("// Custom logger configuration");
|
||
const customLogger = new Logger({
|
||
debug: false,
|
||
colors: true,
|
||
});
|
||
customLogger.info("Custom logger with debug disabled");
|
||
customLogger.debug("This won't show");
|
||
|
||
demo.code("// Silent mode");
|
||
const silentLogger = new Logger();
|
||
silentLogger.silent();
|
||
silentLogger.info("This won't show");
|
||
silentLogger.verbose(); // Re-enable all levels
|
||
|
||
await waitForEnter();
|
||
}
|
||
|
||
async function demonstrateTextProcessing() {
|
||
demo.section("2. Text Processing Utilities");
|
||
demo.info(
|
||
"Text utilities provide content cleaning and keyword matching capabilities."
|
||
);
|
||
|
||
const sampleTexts = [
|
||
"Check out this #awesome post! https://example.com 🚀",
|
||
"Just got #laidoff from my job. Looking for new opportunities!",
|
||
"Company is #downsizing and I'm affected. #RIF #layoff",
|
||
"Great news! We're #hiring new developers! 🎉",
|
||
];
|
||
|
||
demo.code("// Text cleaning examples:");
|
||
sampleTexts.forEach((text, index) => {
|
||
const cleaned = cleanText(text);
|
||
demo.info(`Original: ${text}`);
|
||
demo.success(`Cleaned: ${cleaned}`);
|
||
console.log();
|
||
});
|
||
|
||
demo.code("// Keyword matching:");
|
||
const keywords = ["layoff", "downsizing", "RIF", "hiring"];
|
||
|
||
sampleTexts.forEach((text, index) => {
|
||
const hasMatch = containsAnyKeyword(text, keywords);
|
||
const matchedKeywords = keywords.filter((keyword) =>
|
||
text.toLowerCase().includes(keyword.toLowerCase())
|
||
);
|
||
|
||
demo.info(
|
||
`Text ${index + 1}: ${hasMatch ? "✅" : "❌"} ${
|
||
matchedKeywords.join(", ") || "No matches"
|
||
}`
|
||
);
|
||
});
|
||
|
||
await waitForEnter();
|
||
}
|
||
|
||
async function demonstrateLocationValidation() {
|
||
demo.section("3. Location Validation Utilities");
|
||
demo.info(
|
||
"Location utilities provide geographic filtering and validation capabilities."
|
||
);
|
||
|
||
demo.code("// Location filter parsing:");
|
||
const filterStrings = [
|
||
"Ontario,Manitoba",
|
||
"Toronto,Vancouver",
|
||
"British Columbia,Alberta",
|
||
"Canada",
|
||
];
|
||
|
||
filterStrings.forEach((filterString) => {
|
||
const filters = parseLocationFilters(filterString);
|
||
demo.info(`Filter: "${filterString}"`);
|
||
demo.success(`Parsed: [${filters.join(", ")}]`);
|
||
console.log();
|
||
});
|
||
|
||
demo.code("// Location validation examples:");
|
||
const testLocations = [
|
||
{ location: "Toronto, Ontario, Canada", filters: ["Ontario"] },
|
||
{ location: "Vancouver, BC", filters: ["British Columbia"] },
|
||
{ location: "Calgary, Alberta", filters: ["Ontario"] },
|
||
{ location: "Montreal, Quebec", filters: ["Ontario", "Manitoba"] },
|
||
{ location: "New York, NY", filters: ["Ontario"] },
|
||
];
|
||
|
||
testLocations.forEach(({ location, filters }) => {
|
||
const isValid = validateLocationAgainstFilters(location, filters);
|
||
demo.info(`Location: "${location}"`);
|
||
demo.info(`Filters: [${filters.join(", ")}]`);
|
||
demo.success(`Valid: ${isValid ? "✅ Yes" : "❌ No"}`);
|
||
console.log();
|
||
});
|
||
|
||
demo.code("// Profile location extraction:");
|
||
const profileTexts = [
|
||
"Software Engineer at Tech Corp • Toronto, Ontario",
|
||
"Product Manager • Vancouver, BC",
|
||
"Data Scientist • Remote",
|
||
"CEO at Startup Inc • Montreal, Quebec, Canada",
|
||
];
|
||
|
||
profileTexts.forEach((profileText) => {
|
||
const location = extractLocationFromProfile(profileText);
|
||
demo.info(`Profile: "${profileText}"`);
|
||
demo.success(`Extracted: "${location || "No location found"}"`);
|
||
console.log();
|
||
});
|
||
|
||
await waitForEnter();
|
||
}
|
||
|
||
async function demonstrateAIAnalysis() {
|
||
demo.section("4. AI Analysis Utilities");
|
||
demo.info(
|
||
"AI utilities provide content analysis using OpenAI or local Ollama models."
|
||
);
|
||
|
||
// Mock posts for demo
|
||
const mockPosts = [
|
||
{
|
||
id: "1",
|
||
content:
|
||
"Just got laid off from my software engineering role. Looking for new opportunities in Toronto.",
|
||
author: "John Doe",
|
||
location: "Toronto, Ontario",
|
||
},
|
||
{
|
||
id: "2",
|
||
content:
|
||
"Our company is downsizing and I'm affected. This is really tough news.",
|
||
author: "Jane Smith",
|
||
location: "Vancouver, BC",
|
||
},
|
||
{
|
||
id: "3",
|
||
content:
|
||
"We're hiring! Looking for talented developers to join our team.",
|
||
author: "Bob Wilson",
|
||
location: "Calgary, Alberta",
|
||
},
|
||
];
|
||
|
||
demo.code("// Mock AI analysis (simulated):");
|
||
demo.info("In a real scenario, this would call Ollama or OpenAI API");
|
||
|
||
mockPosts.forEach((post, index) => {
|
||
demo.info(`Post ${index + 1}: ${post.content.substring(0, 50)}...`);
|
||
demo.success(
|
||
`Analysis: Relevant to job layoffs (confidence: 0.${85 + index * 5})`
|
||
);
|
||
console.log();
|
||
});
|
||
|
||
demo.code("// Batch analysis simulation:");
|
||
demo.info("Processing batch of 3 posts...");
|
||
await simulateProcessing();
|
||
demo.success("Batch analysis completed!");
|
||
|
||
await waitForEnter();
|
||
}
|
||
|
||
async function demonstrateIntegration() {
|
||
demo.section("5. Integration Example");
|
||
demo.info("Here's how all utilities work together in a real scenario:");
|
||
|
||
const samplePost = {
|
||
id: "demo-1",
|
||
content:
|
||
"Just got #laidoff from my job at TechCorp! Looking for new opportunities in #Toronto. This is really tough but I'm staying positive! 🚀",
|
||
author: "Demo User",
|
||
location: "Toronto, Ontario, Canada",
|
||
};
|
||
|
||
demo.code("// Processing pipeline:");
|
||
|
||
// 1. Log the start
|
||
logger.step("Processing new post");
|
||
|
||
// 2. Clean the text
|
||
const cleanedContent = cleanText(samplePost.content);
|
||
logger.info(`Cleaned content: ${cleanedContent}`);
|
||
|
||
// 3. Check for keywords
|
||
const keywords = ["layoff", "downsizing", "RIF"];
|
||
const hasKeywords = containsAnyKeyword(cleanedContent, keywords);
|
||
logger.search(`Keyword match: ${hasKeywords ? "Found" : "Not found"}`);
|
||
|
||
// 4. Validate location
|
||
const locationFilters = parseLocationFilters("Ontario,Manitoba");
|
||
const isValidLocation = validateLocationAgainstFilters(
|
||
samplePost.location,
|
||
locationFilters
|
||
);
|
||
logger.location(`Location valid: ${isValidLocation ? "Yes" : "No"}`);
|
||
|
||
// 5. Simulate AI analysis
|
||
if (hasKeywords && isValidLocation) {
|
||
logger.ai("Running AI analysis...");
|
||
await simulateProcessing();
|
||
logger.success("Post accepted and analyzed!");
|
||
} else {
|
||
logger.warning("Post rejected - doesn't meet criteria");
|
||
}
|
||
|
||
await waitForEnter();
|
||
}
|
||
|
||
// Helper functions
|
||
function waitForEnter() {
|
||
return new Promise((resolve) => {
|
||
const readline = require("readline");
|
||
const rl = readline.createInterface({
|
||
input: process.stdin,
|
||
output: process.stdout,
|
||
});
|
||
|
||
rl.question("\nPress Enter to continue...", () => {
|
||
rl.close();
|
||
resolve();
|
||
});
|
||
});
|
||
}
|
||
|
||
async function simulateProcessing() {
|
||
return new Promise((resolve) => {
|
||
const dots = [".", "..", "..."];
|
||
let i = 0;
|
||
const interval = setInterval(() => {
|
||
process.stdout.write(`\rProcessing${dots[i]}`);
|
||
i = (i + 1) % dots.length;
|
||
}, 500);
|
||
|
||
setTimeout(() => {
|
||
clearInterval(interval);
|
||
process.stdout.write("\r");
|
||
resolve();
|
||
}, 2000);
|
||
});
|
||
}
|
||
|
||
// Run the demo if this file is executed directly
|
||
if (require.main === module) {
|
||
runDemo().catch((error) => {
|
||
demo.error(`Demo failed: ${error.message}`);
|
||
process.exit(1);
|
||
});
|
||
}
|
||
|
||
module.exports = { runDemo };
|