""" HRHUB - Bilateral HR Matching System Main Streamlit Application A professional HR matching system that connects candidates with companies using NLP embeddings and cosine similarity matching. """ import streamlit as st import sys from pathlib import Path # Add parent directory to path for imports sys.path.append(str(Path(__file__).parent)) from config import * from data.mock_data import ( get_candidate_data, get_company_matches, get_network_graph_data ) from utils.display import ( display_candidate_profile, display_company_card, display_match_table, display_stats_overview ) from utils.visualization import create_network_graph import streamlit.components.v1 as components def configure_page(): """Configure Streamlit page settings and custom CSS.""" st.set_page_config( page_title="HRHUB - HR Matching", page_icon="🏒", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for better styling st.markdown(""" """, unsafe_allow_html=True) def render_header(): """Render application header.""" st.markdown(f'

{APP_TITLE}

', unsafe_allow_html=True) st.markdown(f'

{APP_SUBTITLE}

', unsafe_allow_html=True) # Demo mode indicator if DEMO_MODE: st.info( "🎭 **Demo Mode Active** - Displaying hardcoded sample data. " "This will be replaced with real matching when embeddings are loaded.", icon="ℹ️" ) def render_sidebar(): """Render sidebar with controls and information.""" with st.sidebar: st.image("https://via.placeholder.com/250x80/0066CC/FFFFFF?text=HRHUB", use_container_width=True) st.markdown("---") st.markdown("### βš™οΈ Settings") # Number of matches top_k = st.slider( "Number of Matches", min_value=5, max_value=20, value=DEFAULT_TOP_K, step=5, help="Select how many top companies to display" ) # Minimum score threshold min_score = st.slider( "Minimum Match Score", min_value=0.0, max_value=1.0, value=MIN_SIMILARITY_SCORE, step=0.05, help="Filter companies below this similarity score" ) st.markdown("---") # View mode selection st.markdown("### πŸ‘€ View Mode") view_mode = st.radio( "Select view:", ["πŸ“Š Overview", "πŸ“ Detailed Cards", "πŸ“ˆ Table View"], help="Choose how to display company matches" ) st.markdown("---") # Information section with st.expander("ℹ️ About HRHUB", expanded=False): st.markdown(""" **HRHUB** is a bilateral HR matching system that uses: - πŸ€– **NLP Embeddings**: Sentence transformers (384 dimensions) - πŸ“ **Cosine Similarity**: Scale-invariant matching - πŸŒ‰ **Job Postings Bridge**: Aligns candidate and company language **Key Innovation:** Companies enriched with job posting data speak the same "skills language" as candidates! """) with st.expander("πŸ“š How to Use", expanded=False): st.markdown(""" 1. **View Candidate Profile**: See the candidate's skills and background 2. **Explore Matches**: Review top company matches with scores 3. **Network Graph**: Visualize connections interactively 4. **Company Details**: Click to see full company information """) st.markdown("---") # Version info st.caption(f"Version: {VERSION}") st.caption("Β© 2024 HRHUB Team") return top_k, min_score, view_mode def render_network_section(candidate_id: int, top_k: int): """Render interactive network visualization section.""" st.markdown('
πŸ•ΈοΈ Network Visualization
', unsafe_allow_html=True) with st.spinner("Generating interactive network graph..."): # Get graph data graph_data = get_network_graph_data(candidate_id, top_k) # Create HTML graph html_content = create_network_graph( nodes=graph_data['nodes'], edges=graph_data['edges'], height="600px" ) # Display in Streamlit components.html(html_content, height=620, scrolling=False) # Graph instructions with st.expander("πŸ“– Graph Controls", expanded=False): st.markdown(""" **How to interact with the graph:** - πŸ–±οΈ **Drag nodes**: Click and drag to reposition - πŸ” **Zoom**: Scroll to zoom in/out - πŸ‘† **Pan**: Click background and drag to pan - 🎯 **Hover**: Hover over nodes and edges for details **Legend:** - 🟒 **Green circles**: Candidates - πŸ”΄ **Red squares**: Companies - **Line thickness**: Match strength (thicker = better match) """) def render_matches_section(matches, view_mode: str): """Render company matches section with different view modes.""" st.markdown('
🎯 Company Matches
', unsafe_allow_html=True) if view_mode == "πŸ“Š Overview": # Table view display_match_table(matches) elif view_mode == "πŸ“ Detailed Cards": # Card view - detailed for rank, (comp_id, score, comp_data) in enumerate(matches, 1): display_company_card(comp_data, score, rank) elif view_mode == "πŸ“ˆ Table View": # Compact table display_match_table(matches) def main(): """Main application entry point.""" # Configure page configure_page() # Render header render_header() # Render sidebar and get settings top_k, min_score, view_mode = render_sidebar() # Main content area st.markdown("---") # Load candidate data candidate_id = DEMO_CANDIDATE_ID candidate = get_candidate_data(candidate_id) # Load company matches matches = get_company_matches(candidate_id, top_k) # Filter by minimum score matches = [(cid, score, cdata) for cid, score, cdata in matches if score >= min_score] if not matches: st.warning(f"No matches found above {min_score:.0%} threshold. Try lowering the minimum score.") return # Display statistics overview display_stats_overview(candidate, matches) # Create two columns for layout col1, col2 = st.columns([1, 2]) with col1: # Candidate profile section st.markdown('
πŸ‘€ Candidate Profile
', unsafe_allow_html=True) display_candidate_profile(candidate) with col2: # Matches section render_matches_section(matches, view_mode) st.markdown("---") # Network visualization (full width) render_network_section(candidate_id, len(matches)) st.markdown("---") # Footer with instructions st.success( "βœ… **MVP Demo Ready!** This interface shows the core functionality. " "Next step: Replace mock data with real embeddings for dynamic matching.", icon="πŸŽ‰" ) # Technical info expander with st.expander("πŸ”§ Technical Details", expanded=False): st.markdown(f""" **Current Configuration:** - Embedding Dimension: {EMBEDDING_DIMENSION} - Similarity Metric: Cosine Similarity - Top K Matches: {top_k} - Minimum Score: {min_score:.0%} - Demo Mode: {'βœ… Enabled' if DEMO_MODE else '❌ Disabled'} **Data Sources:** - Candidates: 9,544 profiles - Companies: 180,000 entities - Job Postings: 700 (bridge data) **Algorithm:** 1. Text representation of candidates/companies 2. Sentence transformer embeddings (384D) 3. Cosine similarity calculation 4. Top-K ranking """) if __name__ == "__main__": main()