File size: 4,106 Bytes
3c06ec2
9332f7e
cdf6731
02bafb6
 
 
 
 
f93c703
fc823d8
1221d76
 
749f56d
9332f7e
7c8d169
749f56d
9332f7e
 
 
749f56d
 
 
 
9332f7e
 
749f56d
9332f7e
cdf6731
38b8d8b
 
 
fc823d8
38b8d8b
 
 
 
 
 
fc823d8
 
38b8d8b
fc823d8
38b8d8b
 
9332f7e
 
 
fc823d8
 
 
 
 
 
 
 
 
 
 
9332f7e
 
 
 
 
50c02b0
cdf6731
 
9332f7e
cdf6731
9332f7e
fc823d8
9332f7e
38b8d8b
749f56d
38b8d8b
fc823d8
 
9332f7e
 
cdf6731
9332f7e
 
 
 
 
 
 
 
 
 
cdf6731
9332f7e
 
3c06ec2
9332f7e
1ab7e62
9332f7e
02bafb6
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
import gradio as gr
from transformers import pipeline
import re
import os
from huggingface_hub import login

# βœ… Authenticate using HF token stored in secret
login(token=os.environ.get("HUGGINGFACEHUB_API_TOKEN"))

# βœ… Use a lightweight instruction-tuned model compatible with CPU
summarizer = pipeline("text2text-generation", model="declare-lab/flan-alpaca-base")

# βœ… Highlight matching and find missing keywords
from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS

def compare_keywords(resume_text, job_desc):
    resume_words = set(re.findall(r"\b\w{3,}\b", resume_text.lower())) - ENGLISH_STOP_WORDS
    job_words = set(re.findall(r"\b\w{3,}\b", job_desc.lower())) - ENGLISH_STOP_WORDS
    matched = resume_words & job_words
    missing = job_words - resume_words
    return matched, missing

def highlight_keywords(resume_text, matched):
    highlighted = resume_text
    for word in sorted(matched, key=len, reverse=True):
        highlighted = re.sub(rf"\b({re.escape(word)})\b", r"**\1**", highlighted, flags=re.IGNORECASE)
    return highlighted

# πŸ” Use LLM to extract missing keywords contextually from JD
def extract_missing_keywords_with_llm(job_desc, resume_text):
    prompt = f"""
Given the following job description and resume, list the important skills, tools, and concepts from the job description that are missing or weakly represented in the resume.

Job Description:
{job_desc}

Resume:
{resume_text}

Only list the missing keywords as bullet points.
"""
    result = summarizer(prompt, max_new_tokens=300, do_sample=True)[0]['generated_text']
    return result.strip()

# πŸ” Prompt for dynamic section classification and feedback
def build_dynamic_prompt(job_desc, resume_text, analyze_with_jd):
    prompt = f"""
Analyze the resume below and organize it into meaningful categories (e.g., Skills, Education, Work Experience, etc.).

If a job description is provided, compare it against the resume and suggest improvements section by section.

Job Description:
{job_desc if analyze_with_jd else '[None provided]'}

Resume:
{resume_text}

Return structured Markdown with headers for each section and improvement suggestions.
"""
    return prompt

# 🧠 Function to call Hugging Face model and get structured resume feedback
def analyze_resume(job_desc, resume_text, analyze_with_jd):
    if not resume_text.strip():
        return "⚠️ Please paste your resume text."

    user_prompt = build_dynamic_prompt(job_desc, resume_text, analyze_with_jd)

    try:
        response = summarizer(user_prompt, max_new_tokens=512, do_sample=True)[0]['generated_text']
        if analyze_with_jd and job_desc:
            matched, _ = compare_keywords(resume_text, job_desc)
            highlighted_resume = highlight_keywords(resume_text, matched)
            llm_missing_keywords = extract_missing_keywords_with_llm(job_desc, resume_text)
            return f"### πŸ” Resume with Highlighted Matches\n\n{highlighted_resume}\n\n---\n**βœ… Matched Keywords:** {', '.join(sorted(matched)) or 'None'}\n\n**❌ LLM-Inferred Missing Keywords:**\n{llm_missing_keywords}\n\n---\n{response.strip()}"
        return response.strip()
    except Exception as e:
        return f"❌ Error: {str(e)}"

# πŸŽ›οΈ Gradio UI
def create_ui():
    with gr.Blocks() as demo:
        with gr.Row():
            with gr.Column():
                analyze_checkbox = gr.Checkbox(label="Analyze with Job Description", value=True)
                job_desc = gr.Textbox(label="Job Description", lines=6, placeholder="Paste job description here...")
                resume_text = gr.Textbox(label="Resume Text", lines=16, placeholder="Paste resume content here...")
            with gr.Column():
                output_analysis = gr.Markdown(label="Resume Analysis and Suggestions")

        resume_text.change(fn=analyze_resume, inputs=[job_desc, resume_text, analyze_checkbox], outputs=output_analysis)
        job_desc.change(fn=analyze_resume, inputs=[job_desc, resume_text, analyze_checkbox], outputs=output_analysis)

    return demo

if __name__ == '__main__':
    create_ui().launch()