test_2 / app.py
leodellosa85's picture
Update app.py
1a47e5f verified
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()