JobHune 29112025

This commit is contained in:
Flatlogic Bot 2025-11-30 05:59:02 +00:00
parent 15994a64a1
commit c9d9ee75e6
3 changed files with 165 additions and 9 deletions

71
analyze.php Normal file
View File

@ -0,0 +1,71 @@
<?php
header('Content-Type: application/json');
require_once __DIR__ . '/ai/LocalAIApi.php';
if (isset($_FILES['resume']) && $_FILES['resume']['error'] === UPLOAD_ERR_OK) {
$fileTmpPath = $_FILES['resume']['tmp_name'];
// Read the file content
$resumeContent = file_get_contents($fileTmpPath);
if ($resumeContent === false) {
echo json_encode(['success' => false, 'message' => 'Failed to read resume file.']);
exit;
}
// Define the AI prompt
$prompt = <<<PROMPT
Act as an expert Applicant Tracking System (ATS) resume analyzer. Analyze the following resume content and return a JSON object with your analysis.
The JSON object must have the following structure:
{
"score": <an integer score from 0 to 100 representing ATS compatibility>,
"status": "<a short status like 'Strong Candidate', 'Needs Improvement', or 'Poor Fit'>",
"strengths": [
"<a brief description of a positive aspect of the resume>",
"<another positive aspect>"
],
"weaknesses": [
"<a brief description of a negative aspect or area for improvement>",
"<another area for improvement>"
]
}
Here is the resume content:
---
{$resumeContent}
---
PROMPT;
// Call the AI
$response = LocalAIApi::createResponse([
'input' => [
['role' => 'system', 'content' => 'You are an expert ATS resume analyzer that only responds with JSON.'],
['role' => 'user', 'content' => $prompt],
],
]);
if (empty($response['success'])) {
error_log('AI API Error: ' . ($response['error'] ?? 'Unknown error'));
echo json_encode(['success' => false, 'message' => 'AI analysis failed. Please try again later.']);
exit;
}
$analysisJson = LocalAIApi::decodeJsonFromResponse($response);
if ($analysisJson === null) {
error_log('AI API JSON Decode Error: ' . LocalAIApi::extractText($response));
echo json_encode(['success' => false, 'message' => 'Failed to parse AI response. The response may not be valid JSON.']);
exit;
}
echo json_encode(['success' => true, 'data' => $analysisJson]);
} else {
echo json_encode([
'success' => false,
'message' => 'File upload failed or no file was uploaded.'
]);
}
?>

View File

@ -1,15 +1,101 @@
document.addEventListener('DOMContentLoaded', function() {
const uploadForm = document.getElementById('upload-form');
const analyzeBtn = document.getElementById('analyze-btn');
const uploadSection = document.getElementById('upload-section');
const analysisSection = document.getElementById('analysis-section');
const resumeFileInput = document.getElementById('resume-file');
if (analyzeBtn) {
analyzeBtn.addEventListener('click', function(event) {
if (uploadForm) {
uploadForm.addEventListener('submit', function(event) {
event.preventDefault();
// Hide upload section and show analysis section
uploadSection.style.display = 'none';
analysisSection.style.display = 'block';
if (!resumeFileInput.files || resumeFileInput.files.length === 0) {
alert('Please select a resume file to analyze.');
return;
}
const formData = new FormData();
formData.append('resume', resumeFileInput.files[0]);
// Show loading state
analyzeBtn.disabled = true;
analyzeBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Analyzing...';
fetch('analyze.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
// Hide loading state
analyzeBtn.disabled = false;
analyzeBtn.innerHTML = '<i class="bi bi-magic me-2"></i>Analyze My Resume';
if (data.success && data.data) {
const analysis = data.data;
// Update Score and Status
document.getElementById('ats-score').textContent = analysis.score;
const scoreCircle = document.querySelector('.score-circle');
const statusElement = scoreCircle.parentElement.parentElement.querySelector('.fw-semibold');
statusElement.textContent = analysis.status;
if (analysis.score >= 80) {
statusElement.className = 'fw-semibold text-success';
} else if (analysis.score >= 60) {
statusElement.className = 'fw-semibold text-warning';
} else {
statusElement.className = 'fw-semibold text-danger';
}
// Update Strengths
const strengthsList = document.querySelector('#analysis-section .bg-success').parentElement.querySelector('.list-group');
strengthsList.innerHTML = ''; // Clear existing items
if (analysis.strengths && analysis.strengths.length > 0) {
analysis.strengths.forEach(item => {
const li = document.createElement('li');
li.className = 'list-group-item';
li.textContent = item;
strengthsList.appendChild(li);
});
} else {
const li = document.createElement('li');
li.className = 'list-group-item';
li.textContent = 'No specific strengths identified.';
strengthsList.appendChild(li);
}
// Update Weaknesses
const weaknessesList = document.querySelector('#analysis-section .bg-warning').parentElement.querySelector('.list-group');
weaknessesList.innerHTML = ''; // Clear existing items
if (analysis.weaknesses && analysis.weaknesses.length > 0) {
analysis.weaknesses.forEach(item => {
const li = document.createElement('li');
li.className = 'list-group-item';
li.textContent = item;
weaknessesList.appendChild(li);
});
} else {
const li = document.createElement('li');
li.className = 'list-group-item';
li.textContent = 'No specific areas for improvement identified.';
weaknessesList.appendChild(li);
}
// Show the analysis
uploadSection.style.display = 'none';
analysisSection.style.display = 'block';
} else {
alert('Error: ' + data.message);
}
})
.catch(error => {
// Hide loading state
analyzeBtn.disabled = false;
analyzeBtn.innerHTML = '<i class="bi bi-magic me-2"></i>Analyze My Resume';
alert('An unexpected error occurred. Please try again.');
console.error('Error:', error);
});
});
}
});

View File

@ -29,10 +29,10 @@
<h1 class="display-5 fw-bold">Get Your Resume ATS-Ready</h1>
<p class="lead mb-4">Upload your resume to see your ATS compatibility score and get actionable insights in seconds.</p>
<div class="col-lg-6 mx-auto">
<form>
<form id="upload-form">
<div class="mb-3">
<label for="resume-file" class="visually-hidden">Upload Resume</label>
<input class="form-control form-control-lg" type="file" id="resume-file" disabled>
<input class="form-control form-control-lg" type="file" id="resume-file" name="resume" required>
</div>
<div class="d-grid">
<button id="analyze-btn" type="submit" class="btn btn-primary-accent btn-lg">
@ -40,7 +40,6 @@
</button>
</div>
</form>
<p class="text-white-50 mt-3 small">For demo purposes, just click "Analyze" to see a sample report.</p>
</div>
</div>
</section>