Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Resume Analysis | ResumeWizard</title> | |
| <link rel="icon" type="image/x-icon" href="/static/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| document.getElementById('load-more-jobs').addEventListener('click', loadMoreJobs); | |
| document.getElementById('download-report').addEventListener('click', downloadReport); | |
| }); | |
| tailwind.config = { | |
| theme: { | |
| extend: { | |
| colors: { | |
| primary: '#6366f1', | |
| secondary: '#8b5cf6', | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| </head> | |
| <body class="min-h-screen hero-gradient text-slate-200"> | |
| <div class="fixed top-0 left-0 w-full h-full z-0 opacity-30"> | |
| <div class="absolute top-20 left-20 w-64 h-64 rounded-full bg-primary/20 blur-3xl animate-pulse"></div> | |
| <div class="absolute bottom-20 right-20 w-64 h-64 rounded-full bg-secondary/20 blur-3xl animate-pulse delay-500"></div> | |
| </div> | |
| <div class="container mx-auto px-4 py-12"> | |
| <!-- Header --> | |
| <header class="text-center mb-12"> | |
| <h1 class="text-3xl md:text-4xl font-bold text-gray-800 mb-2">Your Resume Analysis</h1> | |
| <p class="text-lg text-gray-600">Here's how your resume performs</p> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="max-w-6xl mx-auto"> | |
| <!-- Score Card --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 mb-8 border border-white/10" id="score-card"> | |
| <!-- Dynamic content will be inserted here by JavaScript --> | |
| </div> | |
| <!-- Analysis Sections --> | |
| <div class="grid md:grid-cols-2 gap-6 mb-8"> | |
| <!-- Key Findings --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 border border-white/10" id="key-findings"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 bg-primary-100 rounded-full flex items-center justify-center mr-3"> | |
| <i data-feather="alert-circle" class="text-primary"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Key Findings</h3> | |
| </div> | |
| <ul class="space-y-3"> | |
| <!-- Dynamic content will be inserted here by JavaScript --> | |
| </ul> | |
| </div> | |
| <!-- Suggested Improvements --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 border border-white/10" id="suggestions"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 bg-secondary-100 rounded-full flex items-center justify-center mr-3"> | |
| <i data-feather="edit-3" class="text-secondary"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Suggested Improvements</h3> | |
| </div> | |
| <ul class="space-y-3"> | |
| <!-- Dynamic content will be inserted here by JavaScript --> | |
| </ul> | |
| </div> | |
| </div> | |
| <!-- Target Companies --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 mb-6 border border-white/10"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 bg-yellow-100 rounded-full flex items-center justify-center mr-3"> | |
| <i data-feather="target" class="text-yellow-500"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Target Company Analysis</h3> | |
| </div> | |
| <div class="space-y-4"> | |
| <div> | |
| <h4 class="font-medium text-gray-700 mb-2">Your Target Companies</h4> | |
| <div class="flex flex-wrap gap-2"> | |
| <span class="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm">Google</span> | |
| <span class="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm">Amazon</span> | |
| <span class="bg-yellow-100 text-yellow-800 px-3 py-1 rounded-full text-sm">Microsoft</span> | |
| </div> | |
| </div> | |
| <div> | |
| <h4 class="font-medium text-gray-700 mb-2">Common Keywords in These Companies</h4> | |
| <div class="flex flex-wrap gap-2"> | |
| <span class="bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm">cloud computing</span> | |
| <span class="bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm">machine learning</span> | |
| <span class="bg-blue-100 text-blue-800 px-3 py-1 rounded-full text-sm">scalability</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Keyword Analysis --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 mb-8 border border-white/10" id="keywords"> | |
| <div class="flex items-center mb-6"> | |
| <div class="w-10 h-10 bg-purple-100 rounded-full flex items-center justify-center mr-3"> | |
| <i data-feather="hash" class="text-purple-500"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Keyword Analysis</h3> | |
| </div> | |
| <div class="grid md:grid-cols-2 gap-4"> | |
| <!-- Dynamic content will be inserted here by JavaScript --> | |
| </div> | |
| </div> | |
| <!-- Skills Development --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 mb-6 border border-white/10" id="skills-dev"> | |
| <div class="flex items-center mb-4"> | |
| <div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center mr-3"> | |
| <i data-feather="trending-up" class="text-green-500"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Skills Development Roadmap</h3> | |
| </div> | |
| <!-- Dynamic content will be inserted here by JavaScript --> | |
| </div> | |
| <!-- Job Matches --> | |
| <div class="backdrop-blur-lg bg-white/5 rounded-2xl shadow-lg p-6 border border-white/10"> | |
| <div class="flex items-center mb-6"> | |
| <div class="w-10 h-10 bg-indigo-100 rounded-full flex items-center justify-center mr-3"> | |
| <i data-feather="briefcase" class="text-indigo-500"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800">Recommended Job Matches</h3> | |
| </div> | |
| <div id="job-matches-container" class="space-y-4"> | |
| <!-- Jobs will be loaded here dynamically --> | |
| </div> | |
| <div class="text-center mt-6"> | |
| <button id="load-more-jobs" class="bg-gradient-to-r from-primary to-secondary text-white font-medium py-2 px-6 rounded-lg transition duration-300 hover:shadow-lg hover:shadow-primary/20"> | |
| View More Matches | |
| </button> | |
| </div> | |
| </div> | |
| <script> | |
| // Load and display analysis results | |
| function loadAnalysis() { | |
| const analysis = JSON.parse('{{ analysis|tojson|safe }}'); | |
| if (!analysis) { | |
| window.location.href = '/'; | |
| return; | |
| } | |
| // Update score card | |
| const scoreCard = document.getElementById('score-card'); | |
| scoreCard.innerHTML = ` | |
| <div class="flex flex-col md:flex-row items-center"> | |
| <div class="w-full md:w-1/3 text-center mb-6 md:mb-0"> | |
| <div class="relative inline-block"> | |
| <svg class="w-32 h-32" viewBox="0 0 36 36"> | |
| <path d="M18 2.0845 | |
| a 15.9155 15.9155 0 0 1 0 31.831 | |
| a 15.9155 15.9155 0 0 1 0 -31.831" | |
| fill="none" stroke="#e6e6e6" stroke-width="3" /> | |
| <path d="M18 2.0845 | |
| a 15.9155 15.9155 0 0 1 0 31.831 | |
| a 15.9155 15.9155 0 0 1 0 -31.831" | |
| fill="none" stroke="#6366f1" stroke-width="3" stroke-dasharray="${analysis.score}, 100" /> | |
| <text x="18" y="20.5" text-anchor="middle" fill="#6366f1" font-size="8" font-weight="bold">${analysis.score}%</text> | |
| <text x="18" y="24.5" text-anchor="middle" fill="#6b7280" font-size="4">ATS Score</text> | |
| </svg> | |
| </div> | |
| </div> | |
| <div class="w-full md:w-2/3"> | |
| <h2 class="text-2xl font-semibold text-gray-800 mb-4">${analysis.score >= 80 ? 'Excellent!' : analysis.score >= 60 ? 'Good Start!' : 'Needs Improvement'}</h2> | |
| <p class="text-gray-600 mb-4">${analysis.summary}</p> | |
| <div class="w-full bg-gray-200 rounded-full h-2.5 mb-4"> | |
| <div class="bg-primary h-2.5 rounded-full" style="width: ${analysis.score}%"></div> | |
| </div> | |
| <div class="flex justify-between text-sm text-gray-600"> | |
| <span>Needs Work</span> | |
| <span>ATS Ready</span> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| // Update other sections with analysis data | |
| updateSection('key-findings', analysis.keyFindings); | |
| updateSection('suggestions', analysis.suggestions); | |
| updateSection('keywords', analysis.keywords); | |
| updateSkillsSection(analysis.skills); | |
| // Fetch relevant jobs based on analysis | |
| fetchJobs(analysis.jobTitle); | |
| } | |
| // Update content section with data | |
| function updateSection(sectionId, data) { | |
| const section = document.getElementById(sectionId); | |
| if (!section) return; | |
| let html = ''; | |
| if (Array.isArray(data)) { | |
| html = data.map(item => ` | |
| <li class="flex"> | |
| <div class="w-5 h-5 ${item.type === 'positive' ? 'bg-green-100' : item.type === 'warning' ? 'bg-yellow-100' : 'bg-red-100'} rounded-full flex items-center justify-center mr-2 mt-0.5"> | |
| ${item.type === 'positive' ? '<i data-feather="check" class="w-3 h-3 text-green-500"></i>' : | |
| item.type === 'warning' ? '<i data-feather="alert-triangle" class="w-3 h-3 text-yellow-500"></i>' : | |
| '<i data-feather="x" class="w-3 h-3 text-red-500"></i>'} | |
| </div> | |
| <span class="text-gray-700">${item.text}</span> | |
| </li> | |
| `).join(''); | |
| } else if (typeof data === 'object') { | |
| // Handle keyword sections | |
| html = Object.entries(data).map(([category, items]) => ` | |
| <div> | |
| <h4 class="font-medium text-gray-700 mb-2">${category}</h4> | |
| <div class="flex flex-wrap gap-2"> | |
| ${items.map(item => `<span class="${category === 'Missing Keywords' ? 'bg-blue-100 text-blue-800' : 'bg-green-100 text-green-800'} px-3 py-1 rounded-full text-sm">${item}</span>`).join('')} | |
| </div> | |
| </div> | |
| `).join(''); | |
| } | |
| section.querySelector('ul') ? section.querySelector('ul').innerHTML = html : section.innerHTML += html; | |
| } | |
| // Update skills section | |
| function updateSkillsSection(skills) { | |
| const section = document.getElementById('skills-dev'); | |
| if (!section || !skills) return; | |
| section.innerHTML = ` | |
| <div class="grid md:grid-cols-3 gap-4"> | |
| ${skills.map(skillGroup => ` | |
| <div class="bg-gray-700 p-4 rounded-lg"> | |
| <h4 class="font-medium text-gray-300 mb-2">${skillGroup.title}</h4> | |
| <ul class="text-sm text-gray-400 space-y-1"> | |
| ${skillGroup.items.map(item => `<li>• ${item}</li>`).join('')} | |
| </ul> | |
| </div> | |
| `).join('')} | |
| </div> | |
| `; | |
| } | |
| // Fetch relevant jobs | |
| async function fetchJobs(jobTitle) { | |
| try { | |
| const response = await fetch(`/api/jobs?title=${encodeURIComponent(jobTitle)}`); | |
| const data = await response.json(); | |
| displayJobs(data.results || []); | |
| } catch (error) { | |
| console.error('Error fetching jobs:', error); | |
| displaySampleJobs(); | |
| } | |
| } | |
| function displayJobs(jobs) { | |
| const container = document.getElementById('job-matches-container'); | |
| container.innerHTML = ''; | |
| jobs.forEach(job => { | |
| const matchPercentage = Math.floor(Math.random() * (95 - 70 + 1)) + 70; | |
| const jobType = job.contract_time ? job.contract_time : 'Full-time'; | |
| const salary = job.salary_min && job.salary_max ? | |
| `${(job.salary_min/1000).toFixed(0)}k-${(job.salary_max/1000).toFixed(0)}k` : | |
| (job.salary_min ? `${(job.salary_min/1000).toFixed(0)}k+` : 'Salary not listed'); | |
| const jobElement = document.createElement('div'); | |
| jobElement.className = 'border border-gray-700 rounded-lg p-4 hover:bg-gray-700/50 transition duration-200'; | |
| jobElement.innerHTML = ` | |
| <div class="flex justify-between items-start"> | |
| <div> | |
| <h4 class="font-bold text-gray-800">${job.title}</h4> | |
| <p class="text-gray-600 text-sm">${job.company.display_name} • ${job.location.display_name}</p> | |
| </div> | |
| <span class="bg-${getMatchColor(matchPercentage)}-100 text-${getMatchColor(matchPercentage)}-800 px-2 py-1 rounded text-xs font-medium">${matchPercentage}% match</span> | |
| </div> | |
| <p class="text-gray-700 text-sm mt-2">${job.description.substring(0, 120)}...</p> | |
| <div class="mt-3 flex justify-between items-center"> | |
| <div class="flex space-x-2"> | |
| <span class="bg-gray-100 text-gray-800 px-2 py-0.5 rounded text-xs">${jobType}</span> | |
| <span class="bg-gray-100 text-gray-800 px-2 py-0.5 rounded text-xs">${salary}</span> | |
| </div> | |
| <a href="${job.redirect_url}" target="_blank" class="text-primary hover:text-primary-600 text-sm font-medium">View details →</a> | |
| </div> | |
| `; | |
| container.appendChild(jobElement); | |
| }); | |
| } | |
| function getMatchColor(percentage) { | |
| if (percentage >= 85) return 'green'; | |
| if (percentage >= 75) return 'blue'; | |
| return 'purple'; | |
| } | |
| function displaySampleJobs() { | |
| // Fallback sample data | |
| const sampleJobs = [ | |
| { | |
| title: "Project Manager", | |
| company: { display_name: "TechSolutions Inc." }, | |
| location: { display_name: "San Francisco, CA" }, | |
| description: "We're looking for an experienced Project Manager to lead our software development teams...", | |
| contract_time: "Full-time", | |
| salary_min: 90000, | |
| salary_max: 110000, | |
| redirect_url: "#" | |
| }, | |
| { | |
| title: "Operations Manager", | |
| company: { display_name: "GrowthCorp" }, | |
| location: { display_name: "New York, NY" }, | |
| description: "Seeking an Operations Manager to oversee daily activities and improve organizational efficiency...", | |
| contract_time: "Full-time", | |
| salary_min: 85000, | |
| salary_max: 95000, | |
| redirect_url: "#" | |
| } | |
| ]; | |
| displayJobs(sampleJobs); | |
| } | |
| function loadMoreJobs() { | |
| // Implement pagination or fetch more jobs here | |
| alert("This would load more jobs in a real implementation"); | |
| } | |
| // Initialize analysis when page loads | |
| document.addEventListener('DOMContentLoaded', () => { | |
| try { | |
| loadAnalysis(); | |
| } catch (e) { | |
| console.error("Error loading analysis:", e); | |
| window.location.href = '/'; | |
| } | |
| feather.replace(); | |
| // Animate sections | |
| anime({ | |
| targets: '.bg-gray-800', | |
| translateY: [20, 0], | |
| opacity: [0, 1], | |
| delay: anime.stagger(100), | |
| easing: 'easeOutQuad' | |
| }); | |
| }); | |
| </script> | |
| <!-- Download Report --> | |
| <div class="mt-12 text-center"> | |
| <button id="download-report" class="backdrop-blur-lg bg-white/5 hover:bg-white/10 border border-primary/30 text-primary font-medium py-3 px-8 rounded-lg transition duration-300 shadow-sm flex items-center mx-auto"> | |
| <i data-feather="download" class="mr-2 w-5 h-5"></i> Download Full Analysis Report (PDF) | |
| </button> | |
| </div> | |
| <script> | |
| function downloadReport() { | |
| const analysis = JSON.parse(sessionStorage.getItem('resumeAnalysis')); | |
| // In a real implementation, this would call your backend to generate a PDF | |
| alert('This would download a PDF report in a real implementation'); | |
| // Example API call (would need backend implementation) | |
| /* | |
| fetch('/api/generate-report', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(analysis) | |
| }) | |
| .then(response => response.blob()) | |
| .then(blob => { | |
| const url = window.URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'Resume-Analysis-Report.pdf'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| window.URL.revokeObjectURL(url); | |
| }); | |
| */ | |
| } | |
| </script> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="text-center mt-16 text-gray-600 text-sm"> | |
| <p>© 2023 ResumeWizard. All rights reserved.</p> | |
| <p class="text-xs text-gray-500 mt-1">Analysis powered by natural language processing</p> | |
| </footer> | |
| </div> | |
| <script> | |
| feather.replace(); | |
| // Initialize animations for job matches | |
| anime({ | |
| targets: '#job-matches-container div', | |
| translateY: [20, 0], | |
| opacity: [0, 1], | |
| delay: anime.stagger(100), | |
| easing: 'easeOutQuad' | |
| }); | |
| </script> | |
| </body> | |
| </html> | |