File size: 3,352 Bytes
25c62c3
 
 
 
b740a24
25c62c3
b740a24
25c62c3
 
 
e39d53c
b740a24
 
 
 
 
 
25c62c3
 
e39d53c
25c62c3
 
 
 
e39d53c
 
 
 
b740a24
 
25c62c3
b740a24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25c62c3
e39d53c
b740a24
 
 
 
 
 
e39d53c
 
b740a24
e39d53c
b740a24
25c62c3
b740a24
25c62c3
b740a24
 
 
 
 
25c62c3
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import re
import PyPDF2
import gradio as gr
from transformers import pipeline
from collections import Counter

# Load the Hugging Face NER pipeline
ner_pipeline = pipeline("ner", model="dslim/bert-base-NER", tokenizer="dslim/bert-base-NER", aggregation_strategy="simple")

def clean_resume_text(text):
    """Clean resume text by removing unwanted characters and formatting."""
    text = re.sub(r'http\S+', ' ', text)
    text = re.sub(r'#\S+', '', text)
    text = re.sub(r'@\S+', ' ', text)
    text = re.sub(r'[^\w\s]', ' ', text)
    text = re.sub(r'[^\x00-\x7f]', ' ', text)
    return re.sub(r'\s+', ' ', text).strip()

def extract_resume_text(file):
    """Extract raw text from uploaded PDF file."""
    try:
        reader = PyPDF2.PdfReader(file)
        text = ""
        for page in reader.pages:
            page_text = page.extract_text()
            if page_text:
                text += page_text + " "
        if not text.strip():
            return None, "Error: No text extracted from PDF."
        return text, None
    except Exception as e:
        return None, f"Error reading PDF: {str(e)}"

def classify_resume(entities):
    """Classify resume based on dominant entity types."""
    orgs = [e['word'] for e in entities if e['entity_group'] == 'ORG']
    locs = [e['word'] for e in entities if e['entity_group'] == 'LOC']
    jobs = [e['word'] for e in entities if e['entity_group'] == 'MISC']

    dominant_org = Counter(orgs).most_common(1)
    dominant_loc = Counter(locs).most_common(1)
    dominant_job = Counter(jobs).most_common(1)

    return {
        "Main_Organization": dominant_org[0][0] if dominant_org else "Unknown",
        "Main_Location": dominant_loc[0][0] if dominant_loc else "Unknown",
        "Possible_Job/Field": dominant_job[0][0] if dominant_job else "General"
    }

def extract_entities_from_pdfs(files):
    """Process multiple resumes, extract entities, and classify."""
    summary = {}

    for file in files:
        file_name = file.name.split("/")[-1]
        resume_text, error = extract_resume_text(file)

        if error:
            summary[file_name] = {"error": error}
            continue

        cleaned_text = clean_resume_text(resume_text)
        entities = ner_pipeline(cleaned_text)

        result = {
            "Persons": list({e["word"] for e in entities if e["entity_group"] == "PER"}),
            "Organizations": list({e["word"] for e in entities if e["entity_group"] == "ORG"}),
            "Locations": list({e["word"] for e in entities if e["entity_group"] == "LOC"}),
            "Other": list({e["word"] for e in entities if e["entity_group"] not in ["PER", "ORG", "LOC"]}),
            "Cleaned_Text": cleaned_text,
            "Classification": classify_resume(entities)
        }

        summary[file_name] = result

    return summary

# Gradio UI
iface = gr.Interface(
    fn=extract_entities_from_pdfs,
    inputs=gr.File(file_types=[".pdf"], label="Upload Resumes (PDF)", file_count="multiple"),
    outputs=gr.JSON(label="Resume Classification & Entity Summary"),
    title="πŸ“‚ Multi-Resume Entity Extractor & Classifier",
    description="Upload multiple PDF resumes. This tool extracts text, identifies key entities, and classifies each resume by organizations, locations, and possible job/field."
)

if __name__ == "__main__":
    iface.launch()