Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
971 changes: 924 additions & 47 deletions README.md

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions backend/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
from dotenv import load_dotenv
import os

from flask import Flask
from flask_cors import CORS
from routes.resume_routes import resume_bp

app = Flask(__name__)
CORS(app)

# Register resume blueprint
app.register_blueprint(resume_bp, url_prefix='/api/resume')

# ... rest of your existing code

def create_app():
# Load environment variables
load_dotenv()
Expand Down
22 changes: 22 additions & 0 deletions backend/app/models/resume_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
Resume Database Model
Author: Akshit
"""

from datetime import datetime
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Resume(db.Model):
"""Resume model for database"""
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
filename = db.Column(db.String(255), nullable=False)
filepath = db.Column(db.String(500), nullable=False)
upload_date = db.Column(db.DateTime, default=datetime.utcnow)
analysis_score = db.Column(db.Integer)
skills = db.Column(db.JSON)

def __repr__(self):
return f'<Resume {self.filename}>'
59 changes: 59 additions & 0 deletions backend/app/routes/resume_routes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Resume Upload Routes
Author: Akshit
Date: October 13, 2025
"""

from flask import Blueprint, request, jsonify
from werkzeug.utils import secure_filename
import os
from services.resume_analyzer import ResumeAnalyzer

resume_bp = Blueprint('resume', __name__)
UPLOAD_FOLDER = 'backend/uploads'
ALLOWED_EXTENSIONS = {'pdf', 'docx', 'txt'}

def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@resume_bp.route('/upload', methods=['POST'])
def upload_resume():
"""Upload and analyze resume"""
if 'file' not in request.files:
return jsonify({'error': 'No file provided'}), 400

file = request.files['file']

if file.filename == '':
return jsonify({'error': 'No file selected'}), 400

if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(UPLOAD_FOLDER, filename)
file.save(filepath)

# Analyze resume
analyzer = ResumeAnalyzer()
analysis = analyzer.analyze_file(filepath)

return jsonify({
'success': True,
'filename': filename,
'analysis': analysis
}), 200

return jsonify({'error': 'Invalid file type'}), 400

@resume_bp.route('/analyze', methods=['POST'])
def analyze_resume():
"""Analyze resume text"""
data = request.json
text = data.get('text', '')

analyzer = ResumeAnalyzer()
analysis = analyzer.analyze_text(text)

return jsonify({
'success': True,
'analysis': analysis
}), 200
78 changes: 78 additions & 0 deletions backend/app/services/resume_analyzer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
AI Resume Analyzer Service
Author: Akshit
Date: October 13, 2025
"""

import PyPDF2
import docx
import re
from collections import Counter

class ResumeAnalyzer:
def __init__(self):
self.tech_skills = [
'Python', 'Java', 'JavaScript', 'React', 'Node.js',
'SQL', 'MongoDB', 'AWS', 'Docker', 'Kubernetes',
'Machine Learning', 'Deep Learning', 'TensorFlow',
'PyTorch', 'HTML', 'CSS', 'Git', 'REST API'
]

def extract_text_from_pdf(self, filepath):
"""Extract text from PDF"""
with open(filepath, 'rb') as file:
reader = PyPDF2.PdfReader(file)
text = ''
for page in reader.pages:
text += page.extract_text()
return text

def extract_text_from_docx(self, filepath):
"""Extract text from DOCX"""
doc = docx.Document(filepath)
text = '\n'.join([para.text for para in doc.paragraphs])
return text

def extract_text_from_txt(self, filepath):
"""Extract text from TXT"""
with open(filepath, 'r', encoding='utf-8') as file:
return file.read()

def analyze_file(self, filepath):
"""Analyze resume file"""
ext = filepath.rsplit('.', 1)[1].lower()

if ext == 'pdf':
text = self.extract_text_from_pdf(filepath)
elif ext == 'docx':
text = self.extract_text_from_docx(filepath)
else:
text = self.extract_text_from_txt(filepath)

return self.analyze_text(text)

def analyze_text(self, text):
"""Analyze resume text with AI"""
# Detect skills
detected_skills = [skill for skill in self.tech_skills
if skill.lower() in text.lower()]

# Extract email
email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
emails = re.findall(email_pattern, text)

# Extract phone
phone_pattern = r'[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}'
phones = re.findall(phone_pattern, text)

# Calculate score
score = min(100, len(detected_skills) * 10 + 20)

return {
'skills': detected_skills,
'email': emails[0] if emails else None,
'phone': phones[0] if phones else None,
'score': score,
'word_count': len(text.split()),
'experience_level': 'Mid-Level' if len(detected_skills) > 5 else 'Junior'
}
53 changes: 53 additions & 0 deletions frontend/src/components/resumeupload.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Resume Upload Component
* Author: Akshit
*/

import React, { useState } from 'react';
import resumeApi from '../utils/resumeApi';

const ResumeUpload = () => {
const [file, setFile] = useState(null);
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
const [analysis, setAnalysis] = useState(null);

const handleFileChange = (e) => {
setFile(e.target.files[0]);
};

const handleUpload = async () => {
if (!file) return;

setUploading(true);
const response = await resumeApi.uploadResume(file, (prog) => {
setProgress(prog);
});

if (response.success) {
setAnalysis(response.data.analysis);
}
setUploading(false);
};

return (
<div className="resume-upload">
<h2>📤 Upload Resume</h2>
<input type="file" accept=".pdf,.docx,.txt" onChange={handleFileChange} />
<button onClick={handleUpload} disabled={uploading}>
{uploading ? `Uploading ${progress}%` : 'Upload & Analyze'}
</button>

{analysis && (
<div className="analysis-results">
<h3>Analysis Results</h3>
<p>Score: {analysis.score}/100</p>
<p>Skills: {analysis.skills.join(', ')}</p>
<p>Experience: {analysis.experience_level}</p>
</div>
)}
</div>
);
};

export default ResumeUpload;
18 changes: 18 additions & 0 deletions frontend/src/pages/profilepage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Profile Page with Resume Upload
* Author: Akshit
*/

import React from 'react';
import ResumeUpload from '../components/ResumeUpload';

const ProfilePage = () => {
return (
<div className="profile-page">
<h1>👤 User Profile</h1>
<ResumeUpload />
</div>
);
};

export default ProfilePage;
Loading