ShubhamD95 commited on
Commit
9332f7e
Β·
verified Β·
1 Parent(s): 7c8d169

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -43
app.py CHANGED
@@ -1,57 +1,74 @@
1
  import gradio as gr
2
- from keybert import KeyBERT
3
- from sentence_transformers import SentenceTransformer
4
  import re
5
 
6
- # βœ… Load Hugging Face model (no API key needed)
7
- model = SentenceTransformer('all-MiniLM-L6-v2')
8
- kw_model = KeyBERT(model)
9
 
10
- # πŸ” Helper: Clean keywords from text (split on commas, newlines)
11
- def clean_keywords(text):
12
- # Lowercase, remove special characters, and split on space/comma
13
- text = re.sub(r"[^a-zA-Z0-9\s]", " ", text.lower())
14
- words = re.split(r"\s+", text)
15
- return set(w for w in words if w and len(w) > 2) # ignore very short words
16
 
 
 
 
 
 
 
 
 
17
 
18
- # πŸ” Main function
19
- def extract_keywords(job_desc, resume_text, analyze_with_jd):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  if not resume_text.strip():
21
  return "⚠️ Please paste your resume text."
22
 
23
- # Step 1: Combine input for keyword extraction
24
- combined_text = job_desc + "\n\n" + resume_text if analyze_with_jd and job_desc else resume_text
25
- extracted_keywords = kw_model.extract_keywords(combined_text, top_n=15, stop_words='english')
26
- extracted_set = set([kw.lower() for kw, _ in extracted_keywords])
27
 
28
- # Step 2: Tokenize job description and resume separately
29
- jd_tokens = clean_keywords(job_desc) if analyze_with_jd and job_desc else set()
30
- resume_tokens = clean_keywords(resume_text)
 
 
 
 
 
 
31
 
32
- # Step 3: Match and miss
33
- matched = sorted(jd_tokens & resume_tokens)
34
- missing = sorted(jd_tokens - resume_tokens)
 
 
 
 
 
 
 
35
 
36
- # Step 4: Output
37
- result = ""
38
- result += f"πŸ” **Extracted Keywords:** {', '.join(extracted_set)}\n\n"
39
- result += f"βœ… **Matched (Job & Resume):** {', '.join(matched) or 'None'}\n"
40
- result += f"❌ **Missing in Resume:** {', '.join(missing) or 'None'}\n"
41
 
42
- return result
43
 
44
- # πŸŽ›οΈ Gradio UI
45
- with gr.Blocks() as demo:
46
- with gr.Row():
47
- with gr.Column():
48
- analyze_checkbox = gr.Checkbox(label="Analyze with Job Description", value=True)
49
- job_desc = gr.Textbox(label="Job Description", lines=6, placeholder="Paste job description here...")
50
- resume_text = gr.Textbox(label="Resume Text", lines=12, placeholder="Paste resume content here...")
51
- with gr.Column():
52
- output_keywords = gr.Markdown(label="Keyword Match Result") # Markdown for styled output
53
-
54
- resume_text.change(fn=extract_keywords, inputs=[job_desc, resume_text, analyze_checkbox], outputs=output_keywords)
55
- job_desc.change(fn=extract_keywords, inputs=[job_desc, resume_text, analyze_checkbox], outputs=output_keywords)
56
-
57
- demo.launch()
 
1
  import gradio as gr
2
+ from transformers import pipeline
 
3
  import re
4
 
5
+ # βœ… Load Hugging Face summarization/chat model
6
+ summarizer = pipeline("text-generation", model="mistralai/Mistral-7B-Instruct-v0.1")
 
7
 
8
+ # βœ… Highlight matching keywords
9
+ from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS
 
 
 
 
10
 
11
+ def highlight_keywords(resume_text, job_desc):
12
+ resume_words = set(re.findall(r"\b\w{3,}\b", resume_text.lower())) - ENGLISH_STOP_WORDS
13
+ job_words = set(re.findall(r"\b\w{3,}\b", job_desc.lower())) - ENGLISH_STOP_WORDS
14
+ matched = resume_words & job_words
15
+ highlighted = resume_text
16
+ for word in sorted(matched, key=len, reverse=True):
17
+ highlighted = re.sub(rf"\\b({re.escape(word)})\\b", r"**\1**", highlighted, flags=re.IGNORECASE)
18
+ return highlighted
19
 
20
+ # πŸ” Prompt for dynamic section classification and feedback
21
+ def build_dynamic_prompt(job_desc, resume_text, analyze_with_jd):
22
+ prompt = f"""
23
+ You are an expert resume analyst.
24
+ Classify the content of the resume into meaningful categories based on the text (e.g., Technical Skills, Soft Skills, Certifications, Projects, Work Experience, Education, Personal Information).
25
+
26
+ You do not need a fixed list of section namesβ€”choose the most suitable ones based on the content.
27
+
28
+ Then:
29
+ - For each section, summarize its contents.
30
+ - If a job description is provided, compare each section against it.
31
+ - Highlight missing or weak areas relevant to the job.
32
+ - Provide smart, actionable suggestions to improve each section.
33
+ - Output in structured Markdown with headings for each section.
34
+ """
35
+ if analyze_with_jd and job_desc:
36
+ prompt += f"\nJob Description:\n{job_desc}\n"
37
+ prompt += f"\nResume:\n{resume_text}"
38
+ return prompt
39
+
40
+ # 🧠 Function to call Hugging Face model and get structured resume feedback
41
+ def analyze_resume(job_desc, resume_text, analyze_with_jd):
42
  if not resume_text.strip():
43
  return "⚠️ Please paste your resume text."
44
 
45
+ user_prompt = build_dynamic_prompt(job_desc, resume_text, analyze_with_jd)
 
 
 
46
 
47
+ try:
48
+ response = summarizer(user_prompt, max_new_tokens=768, do_sample=True, temperature=0.7)[0]['generated_text']
49
+ cleaned = re.sub(rf".*?{re.escape(resume_text)}", "", response, flags=re.DOTALL).strip()
50
+ if analyze_with_jd and job_desc:
51
+ highlighted_resume = highlight_keywords(resume_text, job_desc)
52
+ return f"### πŸ” Resume with Highlighted Matches\n\n{highlighted_resume}\n\n---\n{cleaned}"
53
+ return cleaned
54
+ except Exception as e:
55
+ return f"❌ Error: {str(e)}"
56
 
57
+ # πŸŽ›οΈ Gradio UI
58
+ def create_ui():
59
+ with gr.Blocks() as demo:
60
+ with gr.Row():
61
+ with gr.Column():
62
+ analyze_checkbox = gr.Checkbox(label="Analyze with Job Description", value=True)
63
+ job_desc = gr.Textbox(label="Job Description", lines=6, placeholder="Paste job description here...")
64
+ resume_text = gr.Textbox(label="Resume Text", lines=16, placeholder="Paste resume content here...")
65
+ with gr.Column():
66
+ output_analysis = gr.Markdown(label="Resume Analysis and Suggestions")
67
 
68
+ resume_text.change(fn=analyze_resume, inputs=[job_desc, resume_text, analyze_checkbox], outputs=output_analysis)
69
+ job_desc.change(fn=analyze_resume, inputs=[job_desc, resume_text, analyze_checkbox], outputs=output_analysis)
 
 
 
70
 
71
+ return demo
72
 
73
+ if __name__ == '__main__':
74
+ create_ui().launch()