Spaces:
Sleeping
Sleeping
File size: 5,216 Bytes
7f21468 88dce1c 7f21468 88dce1c 7f21468 88dce1c 7f21468 88dce1c 7f21468 88dce1c 7f21468 88dce1c 7f21468 88dce1c 7f21468 88dce1c 7f21468 |
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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import streamlit as st
import fitz # PyMuPDF for PDF extraction
import pandas as pd
import torch
from sentence_transformers import SentenceTransformer
from model import JobRecommendationSystem
# ----------------- CACHE HEAVY STUFF -----------------
@st.cache_resource
def load_model():
"""Load and quantize the SentenceTransformer model once"""
try:
model = SentenceTransformer("./paraphrase-MiniLM-L6-v2", device="cpu") # local
except Exception:
model = SentenceTransformer("sentence-transformers/paraphrase-MiniLM-L6-v2", device="cpu") # fallback
return torch.quantization.quantize_dynamic(model, {torch.nn.Linear}, dtype=torch.qint8)
@st.cache_resource
def load_recommender():
"""Load recommender system once with cached embeddings + FAISS index"""
return JobRecommendationSystem("JobsFE.csv")
MODEL = load_model()
recommender = load_recommender()
# ----------------- STREAMLIT APP -----------------
st.set_page_config(page_title="AI Job Recommender", page_icon="πΌ", layout="wide")
st.markdown(
"""
<style>
.recommend-card {
padding: 20px;
border-radius: 15px;
background-color: #f9f9f9;
margin-bottom: 20px;
box-shadow: 0 4px 8px rgba(0,0,0,0.05);
}
.job-title {
font-size: 20px;
font-weight: 700;
color: #2c3e50;
}
.company-name {
font-size: 16px;
font-weight: 500;
color: #16a085;
}
.salary {
font-size: 15px;
font-weight: 500;
color: #e67e22;
}
</style>
""",
unsafe_allow_html=True
)
st.title("πΌ AI-Powered Job Recommendation System")
st.write(
"π Upload your resume as a **PDF file** and get tailored job recommendations with direct apply links."
)
# File uploader for PDF resume
uploaded_file = st.file_uploader("Upload your resume (PDF only)", type=["pdf"], help="Only PDF resumes are supported.")
def extract_text_from_pdf(pdf_file):
"""Extract text from uploaded PDF resume"""
doc = fitz.open(stream=pdf_file.read(), filetype="pdf")
text = "\n".join([page.get_text("text") for page in doc])
return text.strip()
resume_text = ""
if uploaded_file:
with st.spinner("β³ Extracting text from your resume..."):
resume_text = extract_text_from_pdf(uploaded_file)
if st.button("π Recommend Jobs"):
if resume_text:
with st.spinner("π€ Analyzing your resume and finding best matches..."):
job_results = recommender.recommend_jobs(resume_text, top_n=20)
st.success(f"β
Found {len(job_results)} job recommendations for you!")
# Display recommended jobs
for i, job in enumerate(job_results, start=1):
with st.container():
st.markdown('<div class="recommend-card">', unsafe_allow_html=True)
# Title + Company
st.markdown(f"<div class='job-title'> {i}. {job.get('position', 'N/A')} </div>", unsafe_allow_html=True)
st.markdown(
f"<div class='company-name'>π’ {job.get('workplace', 'N/A')} ({job.get('formatted_work_type', 'N/A')})</div>",
unsafe_allow_html=True,
)
# Salary Range
if job.get("salary_range") and "N/A" not in job.get("salary_range"):
st.markdown(f"<div class='salary'>π° {job['salary_range']}</div>", unsafe_allow_html=True)
# Experience
if job.get("experience_level") and job.get("experience_level") != "N/A":
st.write(f"**π― Experience Level:** {job['experience_level']}")
# Duties
if job.get("job_role_and_duties"):
st.write(f"**π Duties:** {job['job_role_and_duties']}")
# Skills
if job.get("skills"):
st.write(f"**π Required Skills:** {job['skills']}")
# Benefits
if job.get("benefits"):
st.write(f"**π Benefits:** {job['benefits']}")
# Location
if job.get("location") and job.get("location").strip(", "):
st.write(f"**π Location:** {job['location']}")
# Company size & employees
if job.get("company_size") and job.get("company_size") != "N/A":
st.write(f"**π’ Company Size:** {job['company_size']}")
if job.get("employee_count") and job.get("employee_count") != "N/A":
st.write(f"**π₯ Employees:** {job['employee_count']}")
# Company website
if job.get("company_website") and job.get("company_website") != "N/A":
st.markdown(f"[π Company Website]({job['company_website']})", unsafe_allow_html=True)
# Apply Links
if job.get("apply_link") and job.get("apply_link") != "N/A":
st.markdown(f"[π Apply Here]({job['apply_link']})", unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)
else:
st.warning("β οΈ Please upload a valid PDF resume before proceeding.")
|