File size: 4,244 Bytes
5e6df1f
 
 
bfc8ca4
866b9c1
bfc8ca4
5e6df1f
bfc8ca4
e546e82
bfc8ca4
 
e546e82
5e6df1f
bfc8ca4
 
866b9c1
bfc8ca4
 
 
866b9c1
5e6df1f
bfc8ca4
866b9c1
bfc8ca4
 
866b9c1
5e6df1f
bfc8ca4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e6df1f
 
866b9c1
bfc8ca4
 
 
866b9c1
bfc8ca4
5e6df1f
bfc8ca4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
866b9c1
bfc8ca4
 
 
866b9c1
bfc8ca4
 
5e6df1f
bfc8ca4
 
5e6df1f
bfc8ca4
 
 
 
 
5e6df1f
866b9c1
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import gradio as gr
import os
import docx2txt
import PyPDF2
import json
from openai import OpenAI

# Replace this with your actual API key
client = OpenAI(
    base_url="https://api.aimlapi.com/v1",
    api_key=os.getenv("AIML_API_KEY")
)

# -------- Resume Parsing --------
def extract_text_from_pdf(file):
    try:
        reader = PyPDF2.PdfReader(file)
        return "\n".join([page.extract_text() or "" for page in reader.pages])
    except Exception:
        return ""

def extract_text_from_docx(file):
    try:
        return docx2txt.process(file)
    except Exception:
        return ""

def parse_resume(file):
    ext = os.path.splitext(file.name)[1].lower()
    if ext == ".pdf":
        return extract_text_from_pdf(file)
    elif ext == ".docx":
        return extract_text_from_docx(file)
    else:
        return None

# -------- AI Screening --------
def call_ai_screening_agent(resume_texts, job_description, min_experience):
    prompt = f"""
You are an AI resume screening assistant. Compare each candidate's resume to the job description below.
Only include candidates who meet the minimum required years of experience: {min_experience}.
For each candidate, return:
- name (from filename or parsed text)
- strengths (2–5 key strengths)
- risks (0–3 potential risks)
- score (from 1 to 10)

Job Description:
\"\"\"{job_description}\"\"\"

Resumes:
{resume_texts}

Return a JSON list of candidates as described.
"""
    try:
        response = client.chat.completions.create(
            model="gpt-4-turbo",
            messages=[{"role": "user", "content": prompt}],
            temperature=0.2
        )
        return json.loads(response.choices[0].message.content)
    except Exception as e:
        return {"error": str(e)}

# -------- Main App Logic --------
def process_resumes(files, job_description, min_experience):
    if not files:
        return "⚠️ Please upload at least one resume.", None
    if not job_description.strip():
        return "⚠️ Job description cannot be empty.", None

    parsed_resumes = []
    for file in files:
        content = parse_resume(file)
        if not content or len(content.strip()) == 0:
            continue
        parsed_resumes.append({"name": os.path.basename(file.name), "text": content})

    if not parsed_resumes:
        return "⚠️ Could not parse any valid resumes.", None

    resume_texts = "\n\n".join([f"{r['name']}:\n{r['text']}" for r in parsed_resumes])
    results = call_ai_screening_agent(resume_texts, job_description, min_experience)

    if isinstance(results, dict) and "error" in results:
        return f"⚠️ API Error: {results['error']}", None

    # Display top 3 candidates
    top_candidates = sorted(results, key=lambda x: x["score"], reverse=True)[:3]
    display_md = ""
    for candidate in top_candidates:
        display_md += f"### {candidate['name']}  \n"
        display_md += f"⭐ **Score**: {candidate['score']}  \n"
        display_md += "✅ **Strengths**:\n"
        for s in candidate['strengths']:
            display_md += f"- ✅ {s}\n"
        if candidate['risks']:
            display_md += "⚠️ **Risks**:\n"
            for r in candidate['risks']:
                display_md += f"- ⚠️ {r}\n"
        display_md += "\n---\n"

    return None, display_md

# -------- Gradio UI --------
with gr.Blocks(title="SmartHire - AI Job Screening Assistant") as demo:
    gr.Markdown("# 🤖 SmartHire — AI Job Screening Assistant")
    gr.Markdown("Upload resumes and paste a job description to find the best candidates automatically!")

    with gr.Row():
        resume_input = gr.File(file_types=[".pdf", ".docx"], file_count="multiple", label="Upload Resumes")
        experience_input = gr.Number(label="Minimum Years of Experience", value=0)

    job_desc_input = gr.Textbox(lines=8, placeholder="Paste the job description here...", label="Job Description")
    process_button = gr.Button("Run Screening")

    error_output = gr.Textbox(label="Warnings / Errors", visible=False)
    output_md = gr.Markdown()

    process_button.click(
        fn=process_resumes,
        inputs=[resume_input, job_desc_input, experience_input],
        outputs=[error_output, output_md]
    )

demo.launch()