Spaces:
Running
Running
File size: 3,021 Bytes
92a138e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | const aiService = require('../services/aiService');
const localAtsService = require('../services/localAtsService');
const logger = require('../config/logger');
/**
* Scan Resume - Hybrid Approach
* Uses local rules for the core score (FREE) and AI for deeper insights if needed.
*/
exports.scanResume = async (req, res) => {
try {
const { resumeData, useAi = false, jobDescription = '', targetJob = '' } = req.body;
if (!resumeData) {
return res.status(400).json({ success: false, message: 'resumeData is required' });
}
// 1. Always do local analysis (FAST & FREE)
const localResult = localAtsService.analyze(resumeData);
// 2. If user wants AI "Deep Scan", merge results
if (useAi) {
try {
const aiResult = await aiService.analyzeAts(resumeData, jobDescription, targetJob);
// Add AI results to the response
localResult.aiScore = aiResult.score;
localResult.aiGrade = aiResult.grade;
localResult.aiFeedback = aiResult.feedback;
localResult.topImprovements = aiResult.topImprovements || localResult.topImprovements;
} catch (aiErr) {
logger.error(`AI Deep Scan failed: ${aiErr.message}`);
}
}
res.json({ success: true, data: localResult });
} catch (error) {
logger.error(`ATS Scan Error: ${error.message}`);
res.status(500).json({ success: false, message: error.message });
}
};
exports.translateResume = async (req, res) => {
try {
const { resumeData, language } = req.body;
if (!resumeData || !language) {
return res.status(400).json({ success: false, message: 'resumeData and language are required' });
}
const result = await aiService.translateResume(resumeData, language);
res.json({ success: true, data: result });
} catch (error) {
logger.error(`Translation Error: ${error.message}`);
res.status(500).json({ success: false, message: error.message });
}
};
exports.generateSuggestion = async (req, res) => {
try {
const { type, context, stream = false } = req.body;
if (!type || !context) {
return res.status(400).json({ success: false, message: 'type and context are required' });
}
if (stream) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
await aiService.generateSuggestionStream(type, context, (chunk) => {
res.write(`data: ${JSON.stringify({ chunk })}\n\n`);
});
res.write('data: [DONE]\n\n');
return res.end();
}
const result = await aiService.generateSuggestion(type, context);
res.json({ success: true, data: result });
} catch (error) {
logger.error(`AI Suggestion Error: ${error.message}`, { stack: error.stack });
if (!res.headersSent) {
res.status(500).json({ success: false, message: error.message });
} else {
res.write(`data: ${JSON.stringify({ error: error.message })}\n\n`);
res.end();
}
}
};
|