Spaces:
Sleeping
Sleeping
File size: 3,383 Bytes
1a47e5f | 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 | import pdfplumber
from sentence_transformers import SentenceTransformer, util
import gradio as gr
model = SentenceTransformer('all-MiniLM-L6-v2')
def extract_text_from_pdf(uploaded_file):
"""
uploaded_file: Gradio file object or file-like object
Returns extracted text
"""
try:
# Gradio sometimes gives a dict, sometimes a file-like object
if hasattr(uploaded_file, "name"): # file-like object
path = uploaded_file.name
elif isinstance(uploaded_file, dict) and "name" in uploaded_file:
path = uploaded_file["name"]
else:
return "β Cannot read uploaded file."
text = ""
with pdfplumber.open(path) as pdf:
for page in pdf.pages:
page_text = page.extract_text()
if page_text:
text += page_text + "\n"
return text.strip() if text else "β No text found in PDF."
except Exception as e:
return f"β Error reading PDF: {e}"
common_skills = [
"python","django","flask","fastapi","sql","postgresql","mysql","angular",
"docker","aws","git","rest api","machine learning","pandas","numpy","appian"
]
def evaluate_fit(cv_file, cv_text, job_text):
print(extract_text_from_pdf(cv_file))
# Decide which CV to use
if cv_file is not None:
cv_text = extract_text_from_pdf(cv_file)
if cv_text.startswith("β"): # extraction failed
return cv_text
elif cv_text:
cv_text = cv_text
else:
return "β Please provide a CV file or paste text!"
# --- Compute semantic similarity ---
cv_emb = model.encode(cv_text, convert_to_tensor=True)
job_emb = model.encode(job_text, convert_to_tensor=True)
sim = util.cos_sim(cv_emb, job_emb).item()
score = round(sim * 100, 2)
# --- Skill matching ---
job_skills = [s for s in common_skills if s in job_text.lower()]
matched = [s for s in job_skills if s in cv_text.lower()]
missing = [s for s in job_skills if s not in cv_text.lower()]
skill_match = round((len(matched)/len(job_skills))*100, 2) if job_skills else 0
# --- Build feedback ---
if score > 70 and skill_match > 60:
summary = f"β
Strong Match! (Semantic: {score}%, Skills: {skill_match}%)"
elif score > 50:
summary = f"β οΈ Partial Match (Semantic: {score}%, Skills: {skill_match}%)"
else:
summary = f"β Weak Match (Semantic: {score}%, Skills: {skill_match}%)"
result = summary + "\n\n"
if matched:
result += f"β
Found skills: {', '.join(matched)}\n"
if missing:
result += f"β Missing skills: {', '.join(missing)}\n"
# --- Extra feedback ---
if skill_match == 100 and score < 60:
result += "\nπ‘ Tip: All required skills found, but CV wording may differ from job duties. Try describing how you used those skills."
return result
demo = gr.Interface(
fn=evaluate_fit,
inputs=[
gr.File(label="Upload CV (PDF) (optional)"),
gr.Textbox(label="Or paste CV text (optional)", lines=6),
gr.Textbox(label="Paste job description", lines=8)
],
outputs="text",
title="π§ CV Fit Checker with PDF Upload",
description="Upload your CV PDF or paste text to compare it with a job description using semantic and skill analysis."
)
demo.launch()
|