Spaces:
Sleeping
Sleeping
| 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 | |
| # ----------------- PAGE CONFIG (must be FIRST) ----------------- | |
| st.set_page_config(page_title="AI Job Recommender", page_icon="πΌ", layout="wide") | |
| # ----------------- CACHE HEAVY STUFF ----------------- | |
| 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) | |
| def load_recommender(): | |
| """Load recommender system once with cached embeddings""" | |
| return JobRecommendationSystem("JobsFE.csv") | |
| MODEL = load_model() | |
| recommender = load_recommender() | |
| # ----------------- STREAMLIT UI ----------------- | |
| 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 ----------------- | |
| 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) | |
| # ----------------- JOB RECOMMENDATIONS ----------------- | |
| 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!") | |
| for i, job in enumerate(job_results, start=1): | |
| with st.container(): | |
| st.markdown('<div class="recommend-card">', unsafe_allow_html=True) | |
| 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, | |
| ) | |
| 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) | |
| if job.get("experience_level") and job.get("experience_level") != "N/A": | |
| st.write(f"**π― Experience Level:** {job['experience_level']}") | |
| if job.get("job_role_and_duties"): | |
| st.write(f"**π Duties:** {job['job_role_and_duties']}") | |
| if job.get("skills"): | |
| st.write(f"**π Required Skills:** {job['skills']}") | |
| if job.get("benefits"): | |
| st.write(f"**π Benefits:** {job['benefits']}") | |
| if job.get("location") and job.get("location").strip(", "): | |
| st.write(f"**π Location:** {job['location']}") | |
| 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']}") | |
| if job.get("company_website") and job.get("company_website") != "N/A": | |
| st.markdown(f"[π Company Website]({job['company_website']})", unsafe_allow_html=True) | |
| 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.") | |