alihaider1001
Final change
dfa9f62
Raw
History Blame Contribute Delete
5.55 kB
# app.py
import gradio as gr
import pdfplumber
import spacy
import os
import json
import matplotlib.pyplot as plt
import tempfile
import re
from wordcloud import WordCloud
# Load NLP model
try:
nlp = spacy.load("en_core_web_sm")
except:
from spacy.cli import download
download("en_core_web_sm")
nlp = spacy.load("en_core_web_sm")
# --- Helper functions ---
def extract_text_from_pdf(file):
with pdfplumber.open(file) as pdf:
text = "\n".join([page.extract_text() or "" for page in pdf.pages])
return clean_text(text)
def clean_text(text):
import re
text = re.sub(r'\n+', '\n', text)
text = re.sub(r'[^\x00-\x7F]+', ' ', text) # remove non-ASCII
text = re.sub(r'\s+', ' ', text) # collapse multiple spaces
return text.strip()
def extract_contact_info(text):
email = re.search(r"[\w.+-]+@[\w-]+\.[\w.-]+", text)
phone = re.search(r"\b\d{4}[-.\s]?\d{7}\b|\b\d{11}\b", text)
return email.group(0) if email else None, phone.group(0) if phone else None
def extract_skills(text):
words = set(re.findall(r"\b\w+\b", text.lower()))
custom_keywords = re.findall(r"(?i)(?<=skills[:\-\n]).+?(?=education|experience|projects|certification|$)", text, re.DOTALL)
skill_keywords = [
"python", "sql", "ml", "ai", "keras", "tensorflow", "html", "css", "nltk",
"pandas", "numpy", "power bi", "excel", "scikit-learn", "seaborn", "flask", "django"
]
found = {k for k in skill_keywords if k in words}
for chunk in custom_keywords:
found.update([s.strip().lower() for s in re.split(r",|\n|\||\s{2,}", chunk) if len(s.strip()) >= 2])
return sorted(set(found))
def extract_section(text, section_titles):
lines = text.split("\n")
section_data = []
capture = False
for line in lines:
clean_line = line.strip()
if not clean_line:
continue
# Detect section start
if any(title.lower() in clean_line.lower() for title in section_titles):
capture = True
continue
# Stop if a new main section starts
if capture and re.match(r"^(skills|certifications|projects|summary|languages|contact|references|achievements|publications)\s*[:\-]?$", clean_line, re.IGNORECASE):
break
# Collect section lines
if capture:
section_data.append(clean_line)
return section_data
def match_job_description(skills, job_desc):
job_desc = job_desc.lower()
matched_skills = [s for s in skills if s.lower() in job_desc]
return matched_skills, len(matched_skills), len(skills)
def visualize_skills(skills):
if not skills:
return None
plt.figure(figsize=(6, 4))
freq = {s: skills.count(s) for s in skills}
plt.bar(freq.keys(), freq.values(), color="skyblue")
plt.xticks(rotation=45)
plt.title("Skills Frequency")
plt.tight_layout()
temp_chart = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
plt.savefig(temp_chart.name)
return temp_chart.name
def parse_resume(file):
text = extract_text_from_pdf(file.name)
doc = nlp(text)
name = next((ent.text for ent in doc.ents if ent.label_ == "PERSON"), "Not Found")
email, phone = extract_contact_info(text)
skills = extract_skills(text)
education = extract_section(text, ["education", "academic background", "qualification", "university", "degree", "bachelor", "master"])
experience = extract_section(text, ["experience", "professional experience", "work history", "employment", "internship", "projects"])
print("=== DEBUG TEXT ===")
print(text)
parsed = {
"Name": name,
"Email": email,
"Phone": phone,
"Skills": skills,
"Education": education,
"Experience": experience,
}
chart = visualize_skills(skills)
return parsed, chart
def download_json(data):
with tempfile.NamedTemporaryFile(delete=False, suffix=".json", mode="w") as f:
json.dump(data, f, indent=4)
return f.name
def job_matcher(resume_json, job_desc):
skills = resume_json.get("Skills", [])
matched_skills, matched_count, total_skills = match_job_description(skills, job_desc)
return f"βœ… Matched Skills: {matched_skills}\n🎯 Match Score: {matched_count} / {total_skills}"
# --- Gradio Interface ---
with gr.Blocks(title="🧠 AI Resume Parser") as demo:
gr.Markdown("""
# 🧠 AI Resume Parser (with Skills Chart, JSON Download, and Job Match)
Upload a resume and extract structured data with NLP
""")
with gr.Row():
resume_input = gr.File(label="Upload Resume (PDF)", file_types=[".pdf"])
parse_btn = gr.Button("πŸ“„ Parse Resume")
parsed_output = gr.JSON(label="🧾 Parsed Resume")
chart_output = gr.Image(label="πŸ“Š Skills Chart")
download_btn = gr.File(label="⬇️ Download Resume JSON")
with gr.Accordion("πŸ“Œ Match with Job Description", open=False):
job_desc_input = gr.Textbox(label="Paste Job Description", lines=5)
match_btn = gr.Button("πŸ” Match Skills")
match_output = gr.Text(label="Match Result")
def full_pipeline(file):
parsed, chart_path = parse_resume(file)
json_path = download_json(parsed)
return parsed, chart_path, json_path
parse_btn.click(fn=full_pipeline, inputs=[resume_input], outputs=[parsed_output, chart_output, download_btn])
match_btn.click(fn=job_matcher, inputs=[parsed_output, job_desc_input], outputs=[match_output])
if __name__ == "__main__":
demo.launch()