Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| from sklearn.feature_extraction.text import TfidfVectorizer | |
| from sklearn.metrics.pairwise import cosine_similarity | |
| import re | |
| import nltk | |
| from nltk.corpus import stopwords | |
| from nltk.tokenize import word_tokenize | |
| import string | |
| import json | |
| import os | |
| from utils import load_job_data, preprocess_text, get_top_skills, get_job_recommendations | |
| # Download NLTK resources | |
| try: | |
| nltk.download('punkt') | |
| nltk.download('stopwords') | |
| except: | |
| pass # In case downloads fail, continue with what's available | |
| # Page configuration | |
| st.set_page_config( | |
| page_title="Job Title Recommender", | |
| page_icon="πΌ", | |
| layout="wide" | |
| ) | |
| # Custom CSS | |
| st.markdown(""" | |
| <style> | |
| .main-header { | |
| font-size: 2.5rem; | |
| font-weight: bold; | |
| color: #0A66C2; | |
| text-align: center; | |
| margin-bottom: 1rem; | |
| } | |
| .sub-header { | |
| font-size: 1.2rem; | |
| color: #666; | |
| text-align: center; | |
| margin-bottom: 2rem; | |
| } | |
| .footer { | |
| text-align: center; | |
| margin-top: 2rem; | |
| color: #666; | |
| font-size: 0.9rem; | |
| } | |
| .recommendation-card { | |
| border: 1px solid #ddd; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin-bottom: 1rem; | |
| background-color: #f9f9f9; | |
| } | |
| .skill-tag { | |
| display: inline-block; | |
| background-color: #0A66C2; | |
| color: white; | |
| padding: 0.3rem 0.8rem; | |
| border-radius: 15px; | |
| margin: 0.2rem; | |
| font-size: 0.9rem; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Initialize session state | |
| if 'job_data' not in st.session_state: | |
| st.session_state.job_data = load_job_data() | |
| if 'vectorizer' not in st.session_state: | |
| st.session_state.vectorizer = None | |
| if 'job_vectors' not in st.session_state: | |
| st.session_state.job_vectors = None | |
| # Header | |
| st.markdown('<div class="main-header">πΌ Job Title Recommender</div>', unsafe_allow_html=True) | |
| st.markdown('<div class="sub-header">Find the perfect job titles based on your LinkedIn profile or resume</div>', unsafe_allow_html=True) | |
| # Built with anycoder | |
| st.markdown('<div style="text-align: center; margin-bottom: 1rem;">Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></div>', unsafe_allow_html=True) | |
| # Main content | |
| col1, col2 = st.columns([1, 1]) | |
| with col1: | |
| st.header("π Input Your Profile") | |
| # Input method selection | |
| input_method = st.radio( | |
| "Choose input method:", | |
| ["Text Input", "File Upload"], | |
| horizontal=True | |
| ) | |
| if input_method == "Text Input": | |
| profile_text = st.text_area( | |
| "Paste your LinkedIn profile or resume text here:", | |
| height=300, | |
| placeholder="Include your work experience, skills, education, and any other relevant information..." | |
| ) | |
| else: | |
| uploaded_file = st.file_uploader( | |
| "Upload your resume (PDF or TXT):", | |
| type=["pdf", "txt"], | |
| help="Upload your resume file to analyze" | |
| ) | |
| if uploaded_file: | |
| try: | |
| if uploaded_file.type == "application/pdf": | |
| # For PDF files (would need additional libraries) | |
| st.warning("PDF parsing requires additional libraries. Please use text input or upload a .txt file.") | |
| profile_text = "" | |
| else: | |
| # For text files | |
| profile_text = uploaded_file.read().decode("utf-8") | |
| st.success("File uploaded successfully!") | |
| except Exception as e: | |
| st.error(f"Error reading file: {e}") | |
| profile_text = "" | |
| # Skills input | |
| st.subheader("Key Skills") | |
| skills_input = st.text_input( | |
| "Enter your key skills (comma separated):", | |
| placeholder="e.g., Python, Machine Learning, Project Management" | |
| ) | |
| # Experience level | |
| experience_level = st.select_slider( | |
| "Years of Experience:", | |
| options=["0-2 years", "3-5 years", "6-10 years", "10+ years"], | |
| value="3-5 years" | |
| ) | |
| # Education level | |
| education_level = st.selectbox( | |
| "Highest Education Level:", | |
| ["High School", "Associate Degree", "Bachelor's Degree", "Master's Degree", "PhD"] | |
| ) | |
| # Analyze button | |
| analyze_button = st.button("π Analyze & Get Recommendations", type="primary") | |
| with col2: | |
| st.header("π― Your Recommendations") | |
| if analyze_button and profile_text: | |
| with st.spinner("Analyzing your profile..."): | |
| try: | |
| # Preprocess the input text | |
| processed_text = preprocess_text(profile_text) | |
| # Extract skills from input | |
| input_skills = [skill.strip() for skill in skills_input.split(",")] if skills_input else [] | |
| extracted_skills = get_top_skills(processed_text, top_n=10) | |
| # Combine all skills | |
| all_skills = list(set(input_skills + extracted_skills)) | |
| # Create user profile vector | |
| if st.session_state.vectorizer is None or st.session_state.job_vectors is None: | |
| # Initialize vectorizer and job vectors if not already done | |
| job_descriptions = st.session_state.job_data['description'].tolist() | |
| st.session_state.vectorizer = TfidfVectorizer(stop_words='english', max_features=5000) | |
| st.session_state.job_vectors = st.session_state.vectorizer.fit_transform(job_descriptions) | |
| # Transform user profile | |
| user_vector = st.session_state.vectorizer.transform([processed_text]) | |
| # Get recommendations | |
| recommendations = get_job_recommendations( | |
| user_vector, | |
| st.session_state.job_vectors, | |
| st.session_state.job_data, | |
| all_skills, | |
| experience_level, | |
| education_level, | |
| top_n=5 | |
| ) | |
| if recommendations.empty: | |
| st.warning("No suitable job titles found. Try adding more details to your profile.") | |
| else: | |
| st.success(f"Found {len(recommendations)} suitable job titles for you!") | |
| for idx, row in recommendations.iterrows(): | |
| with st.expander(f"π {row['job_title']} (Match: {row['match_score']:.1%})"): | |
| st.markdown(f"**Industry:** {row['industry']}") | |
| st.markdown(f"**Experience Level:** {row['experience_level']}") | |
| st.markdown(f"**Education Requirement:** {row['education_requirement']}") | |
| # Display skills | |
| st.markdown("**Key Skills:**") | |
| job_skills = [skill.strip() for skill in row['required_skills'].split(",")] | |
| for skill in job_skills[:5]: # Show top 5 skills | |
| st.markdown(f'<span class="skill-tag">{skill}</span>', unsafe_allow_html=True) | |
| st.markdown(f"**Average Salary:** {row['avg_salary']}") | |
| if st.button(f"Learn more about {row['job_title']}", key=f"learn_{idx}"): | |
| st.info(f"This would typically link to more information about the {row['job_title']} role.") | |
| # Show skills analysis | |
| st.subheader("Your Skills Analysis") | |
| if all_skills: | |
| st.markdown("**Detected Skills:**") | |
| for skill in all_skills[:10]: # Show top 10 skills | |
| st.markdown(f'<span class="skill-tag">{skill}</span>', unsafe_allow_html=True) | |
| else: | |
| st.info("No specific skills detected. Consider adding more details to your profile.") | |
| except Exception as e: | |
| st.error(f"An error occurred during analysis: {e}") | |
| elif analyze_button and not profile_text: | |
| st.warning("Please enter your profile information or upload a file.") | |
| else: | |
| st.info("Enter your LinkedIn profile or resume information and click 'Analyze' to get job recommendations.") | |
| # Footer | |
| st.markdown(""" | |
| <div class="footer"> | |
| <p>This tool uses natural language processing to match your skills and experience with suitable job titles.</p> | |
| <p>For best results, provide detailed information about your work experience, skills, and education.</p> | |
| </div> | |
| """, unsafe_allow_html=True) |