cvranker-pro / index.html
Rehyor's picture
perfect, now:
6f0605d verified
raw
history blame
13.1 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI CV Screener</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
colors: {
slate: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
},
indigo: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
}
}
}
}
}
</script>
</head>
<body class="font-sans bg-slate-50 min-h-screen">
<!-- Header -->
<header class="bg-white shadow-sm border-b border-slate-200">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center py-4">
<h1 class="text-2xl font-bold text-slate-800">AI CV Screener</h1>
</div>
</div>
</header>
<!-- Main Container -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Application Sections -->
<div class="space-y-8">
<!-- Section 1: Enter Job Details -->
<div class="bg-white rounded-lg shadow-sm border border-slate-200 p-6">
<h2 class="text-xl font-semibold text-slate-800 mb-4">1. Enter Job Details</h2>
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Job Title</label>
<input type="text" id="job-title" class="w-full px-3 py-2 border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="e.g., Senior Software Engineer">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Seniority Level</label>
<select id="seniority-level" class="w-full px-3 py-2 border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
<option value="">Select seniority level</option>
<option value="internship">Internship</option>
<option value="junior">Junior</option>
<option value="mid-level">Mid-Level</option>
<option value="senior">Senior</option>
<option value="lead">Lead</option>
<option value="manager">Manager</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Minimum Years of Experience</label>
<input type="number" id="min-experience" class="w-full px-3 py-2 border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="e.g., 5" min="0">
</div>
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Job Description</label>
<textarea id="job-description" class="w-full px-3 py-2 border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 h-32" placeholder="Describe the role, responsibilities, and requirements..."></textarea>
</div>
<div>
<button id="extract-skills-btn" class="bg-indigo-600 text-white px-6 py-2 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition-colors">
Extract Key Skills & Responsibilities
</button>
</div>
</div>
</div>
<!-- Section 2: Define Screening Criteria -->
<div id="screening-criteria" class="bg-white rounded-lg shadow-sm border border-slate-200 p-6 hidden">
<h2 class="text-xl font-semibold text-slate-800 mb-4">2. Define Screening Criteria</h2>
<div class="space-y-6">
<!-- Must-Have Skills -->
<div>
<h3 class="text-lg font-medium text-slate-800 mb-3">Must-Have Skills</h3>
<div id="must-have-skills" class="flex flex-wrap gap-2 min-h-12 p-2 border border-slate-200 rounded-md">
<div class="text-slate-500 italic text-sm">Extracted skills will appear here</div>
</div>
</div>
<!-- Nice-to-Have Skills -->
<div>
<h3 class="text-lg font-medium text-slate-800 mb-3">Nice-to-Have Skills</h3>
<div id="nice-to-have-skills" class="flex flex-wrap gap-2 min-h-12 p-2 border border-slate-200 rounded-md">
<div class="text-slate-500 italic text-sm">Extracted skills will appear here</div>
</div>
</div>
<!-- Key Responsibilities & Phrases -->
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Key Responsibilities & Phrases</label>
<textarea id="key-responsibilities" class="w-full px-3 py-2 border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 h-24" placeholder="Key responsibilities and phrases to look for..."></textarea>
</div>
<!-- Negative Keywords -->
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Negative Keywords</label>
<input type="text" id="negative-keywords" class="w-full px-3 py-2 border border-slate-300 rounded-md focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500" placeholder="Keywords that would disqualify candidates...">
</div>
</div>
</div>
<!-- Section 3: Set Education & Upload CVs -->
<div class="bg-white rounded-lg shadow-sm border border-slate-200 p-6">
<h2 class="text-xl font-semibold text-slate-800 mb-4">3. Set Education & Upload CVs</h2>
<div class="space-y-4">
<div class="text-slate-500 italic">
Education requirements and CV upload functionality will appear here.
</div>
</div>
</div>
<!-- Section 4: Screening Results -->
<div id="screening-results" class="bg-white rounded-lg shadow-sm border border-slate-200 p-6 hidden">
<h2 class="text-xl font-semibold text-slate-800 mb-4">4. Screening Results: Top Candidates</h2>
<div class="space-y-4">
<div class="text-slate-500 italic">
Screening results will appear here after CVs are processed.
</div>
</div>
</div>
</div>
</main>
<script>
// Skill extraction function
function extractSkillsFromDescription(text) {
const commonSkills = [
'JavaScript', 'React', 'Python', 'Java', 'HTML', 'CSS', 'Node.js', 'TypeScript',
'SQL', 'MongoDB', 'Git', 'AWS', 'Docker', 'Agile', 'Scrum', 'REST', 'API',
'Machine Learning', 'AI', 'Data Analysis', 'Project Management', 'Leadership',
'Communication', 'Problem Solving', 'Teamwork', 'Testing', 'Debugging'
];
const extracted = [];
const words = text.toLowerCase().split(/\W+/);
commonSkills.forEach(skill => {
if (words.includes(skill.toLowerCase()) || text.toLowerCase().includes(skill.toLowerCase())) {
extracted.push(skill);
}
});
// Add some random skills if not enough were found
if (extracted.length < 3) {
const additionalSkills = commonSkills.filter(skill => !extracted.includes(skill));
const randomSkills = additionalSkills.sort(() => 0.5 - Math.random()).slice(0, 3);
extracted.push(...randomSkills);
}
return extracted.slice(0, 8); // Limit to 8 skills
}
// Function to create skill tag element
function createSkillTag(skill) {
const tag = document.createElement('div');
tag.className = 'inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-indigo-100 text-indigo-800 cursor-pointer hover:bg-indigo-200 transition-colors';
tag.innerHTML = `
${skill}
<span class="ml-2 text-indigo-600 hover:text-indigo-800">Γ—</span>
`;
tag.addEventListener('click', function(e) {
if (e.target.tagName === 'SPAN') {
tag.remove();
}
});
return tag;
}
// Event listener for extract skills button
document.getElementById('extract-skills-btn').addEventListener('click', function() {
const jobDescription = document.getElementById('job-description').value;
const button = this;
const originalText = button.textContent;
if (!jobDescription.trim()) {
alert('Please enter a job description first.');
return;
}
// Show loading state
button.disabled = true;
button.textContent = 'Extracting skills...';
button.classList.add('opacity-50');
// Show loading indicator
const loadingText = document.createElement('div');
loadingText.className = 'text-sm text-slate-500 mt-2';
loadingText.textContent = 'Analyzing job description...';
button.parentNode.appendChild(loadingText);
// Simulate API call with timeout
setTimeout(() => {
// Hide loading indicator
loadingText.remove();
// Reset button
button.disabled = false;
button.textContent = originalText;
button.classList.remove('opacity-50');
// Extract skills
const skills = extractSkillsFromDescription(jobDescription);
// Clear existing skills
const mustHaveDiv = document.getElementById('must-have-skills');
const niceToHaveDiv = document.getElementById('nice-to-have-skills');
mustHaveDiv.innerHTML = '';
niceToHaveDiv.innerHTML = '';
// Split skills between must-have and nice-to-have
const mustHaveCount = Math.min(Math.ceil(skills.length * 0.6), 5); // 60% as must-have, max 5
skills.forEach((skill, index) => {
const tag = createSkillTag(skill);
if (index < mustHaveCount) {
mustHaveDiv.appendChild(tag);
} else {
niceToHaveDiv.appendChild(tag);
}
});
// Show the screening criteria section
document.getElementById('screening-criteria').classList.remove('hidden');
}, 1000);
});
</script>
</body>
</html>