Roger Surf
feat: add heatmap + bilateral fairness visualization + mathematical proof section
96a706d
| """ | |
| HRHUB V2.1 - Display Utilities | |
| All display functions for candidate and company profiles, matches, and stats | |
| """ | |
| import streamlit as st | |
| import pandas as pd | |
| def display_candidate_profile(candidate): | |
| """ | |
| Display candidate profile card with all relevant information. | |
| Args: | |
| candidate: pandas Series with candidate data | |
| """ | |
| # Career Objective | |
| if 'career_objective' in candidate and candidate['career_objective']: | |
| with st.expander("π― Career Objective", expanded=True): | |
| st.write(candidate['career_objective']) | |
| # Skills & Expertise | |
| if 'skills' in candidate and candidate['skills']: | |
| with st.expander("π οΈ Skills & Expertise", expanded=True): | |
| skills_text = candidate['skills'] | |
| if isinstance(skills_text, str): | |
| # Try to split into badges if comma-separated | |
| if ',' in skills_text: | |
| skills_list = [s.strip() for s in skills_text.split(',')[:15]] # Limit to 15 | |
| # Display as badges in columns | |
| cols = st.columns(3) | |
| for idx, skill in enumerate(skills_list): | |
| with cols[idx % 3]: | |
| st.markdown(f"**`{skill}`**") | |
| else: | |
| st.write(skills_text[:300] + ('...' if len(skills_text) > 300 else '')) | |
| # Education | |
| if 'education' in candidate and candidate['education']: | |
| with st.expander("π Education", expanded=False): | |
| st.write(candidate['education']) | |
| # Work Experience | |
| if 'experience' in candidate and candidate['experience']: | |
| with st.expander("πΌ Work Experience", expanded=False): | |
| exp_text = candidate['experience'] | |
| if isinstance(exp_text, str): | |
| st.write(exp_text[:400] + ('...' if len(exp_text) > 400 else '')) | |
| # Additional info box | |
| st.info("π‘ **Profile enriched** with job posting vocabulary for semantic matching") | |
| def display_company_card(company_data, score, rank): | |
| """ | |
| Display company match card with score and details. | |
| Args: | |
| company_data: pandas Series with company data | |
| score: float similarity score | |
| rank: int rank position | |
| """ | |
| # Determine match quality | |
| if score >= 0.7: | |
| quality = "π₯ Excellent Match" | |
| color = "green" | |
| elif score >= 0.6: | |
| quality = "β¨ Very Good Match" | |
| color = "blue" | |
| else: | |
| quality = "β Good Match" | |
| color = "orange" | |
| # Get company name | |
| company_name = company_data.get('name', f'Company {rank}') | |
| company_id = company_data.name if hasattr(company_data, 'name') else rank | |
| # Card expander | |
| with st.expander(f"#{rank} - {company_name} - {score:.1%}", expanded=(rank <= 3)): | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| st.markdown(f"**Company:** {company_name}") | |
| st.markdown(f"**Match Score:** {score:.1%}") | |
| # Industry | |
| if 'industry' in company_data and company_data['industry']: | |
| st.markdown(f"**Industry:** {company_data['industry']}") | |
| # Description/About | |
| if 'description' in company_data and company_data['description']: | |
| desc = company_data['description'] | |
| if isinstance(desc, str) and len(desc) > 0: | |
| st.markdown("**About:**") | |
| st.write(desc[:250] + ('...' if len(desc) > 250 else '')) | |
| # Job postings indicator | |
| if 'has_job_postings' in company_data: | |
| if company_data['has_job_postings']: | |
| st.caption("β Direct job posting data") | |
| else: | |
| st.caption("π Collaborative filtering") | |
| with col2: | |
| # Match quality badge | |
| if color == "green": | |
| st.success(quality) | |
| elif color == "blue": | |
| st.info(quality) | |
| else: | |
| st.warning(quality) | |
| # Company ID | |
| st.caption(f"ID: {company_id}") | |
| def display_match_table(matches): | |
| """ | |
| Display matches in table format. | |
| Args: | |
| matches: list of tuples (company_id, score, company_data) | |
| """ | |
| if len(matches) == 0: | |
| st.warning("No matches to display") | |
| return | |
| # Build table data | |
| table_data = [] | |
| for rank, (comp_id, score, comp_data) in enumerate(matches, 1): | |
| company_name = comp_data.get('name', f'Company {comp_id}') | |
| industry = comp_data.get('industry', 'N/A') | |
| # Match quality | |
| if score >= 0.7: | |
| quality = "π₯ Excellent" | |
| elif score >= 0.6: | |
| quality = "β¨ Very Good" | |
| else: | |
| quality = "β Good" | |
| table_data.append({ | |
| 'Rank': f'#{rank}', | |
| 'Company': company_name, | |
| 'Industry': industry, | |
| 'Score': f'{score:.1%}', | |
| 'Quality': quality | |
| }) | |
| # Display as dataframe | |
| df = pd.DataFrame(table_data) | |
| st.dataframe(df, use_container_width=True, hide_index=True) | |
| # Add info tip | |
| st.info("π‘ **Tip:** Scores above 0.6 indicate strong semantic alignment between your skills and company requirements!") | |
| def display_stats_overview(candidate, matches): | |
| """ | |
| Display statistics overview for candidate matching. | |
| Args: | |
| candidate: pandas Series with candidate data | |
| matches: list of tuples (company_id, score, company_data) | |
| """ | |
| if len(matches) == 0: | |
| st.warning("No matches to display statistics") | |
| return | |
| # Calculate stats | |
| total_matches = len(matches) | |
| avg_score = sum(score for _, score, _ in matches) / total_matches | |
| excellent_matches = sum(1 for _, score, _ in matches if score >= 0.7) | |
| best_score = max(score for _, score, _ in matches) | |
| # Display metrics | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric( | |
| "π Total Matches", | |
| total_matches, | |
| help="Number of companies above minimum threshold" | |
| ) | |
| with col2: | |
| st.metric( | |
| "π Average Score", | |
| f"{avg_score:.1%}", | |
| help="Mean similarity score across all matches" | |
| ) | |
| with col3: | |
| st.metric( | |
| "π₯ Excellent Matches", | |
| excellent_matches, | |
| help="Companies with score β₯ 70%" | |
| ) | |
| with col4: | |
| st.metric( | |
| "π― Best Match", | |
| f"{best_score:.1%}", | |
| help="Highest similarity score achieved" | |
| ) | |
| def display_candidate_card_basic(candidate_data, candidate_id, score, rank): | |
| """ | |
| Display basic candidate card for company view. | |
| Args: | |
| candidate_data: pandas Series with candidate data | |
| candidate_id: int candidate ID | |
| score: float similarity score | |
| rank: int rank position | |
| """ | |
| # Determine match quality | |
| if score >= 0.7: | |
| quality = "π₯ Excellent" | |
| color = "green" | |
| elif score >= 0.6: | |
| quality = "β¨ Very Good" | |
| color = "blue" | |
| else: | |
| quality = "β Good" | |
| color = "orange" | |
| # Card expander | |
| with st.expander(f"#{rank} - Candidate {candidate_id} - {score:.1%}", expanded=(rank <= 3)): | |
| col1, col2 = st.columns([2, 1]) | |
| with col1: | |
| st.markdown(f"**Candidate ID:** {candidate_id}") | |
| st.markdown(f"**Match Score:** {score:.1%}") | |
| # Career objective | |
| if 'career_objective' in candidate_data and candidate_data['career_objective']: | |
| obj = candidate_data['career_objective'] | |
| if isinstance(obj, str) and len(obj) > 0: | |
| st.markdown("**Career Objective:**") | |
| st.write(obj[:200] + ('...' if len(obj) > 200 else '')) | |
| # Skills | |
| if 'skills' in candidate_data and candidate_data['skills']: | |
| skills = candidate_data['skills'] | |
| if isinstance(skills, str) and len(skills) > 0: | |
| st.markdown("**Skills:**") | |
| # Show first few skills as badges | |
| if ',' in skills: | |
| skills_list = [s.strip() for s in skills.split(',')[:8]] | |
| st.markdown(' β’ '.join(skills_list)) | |
| else: | |
| st.write(skills[:200] + ('...' if len(skills) > 200 else '')) | |
| # Experience | |
| if 'experience' in candidate_data and candidate_data['experience']: | |
| exp = candidate_data['experience'] | |
| if isinstance(exp, str) and len(exp) > 0: | |
| st.markdown("**Experience:**") | |
| st.write(exp[:150] + ('...' if len(exp) > 150 else '')) | |
| with col2: | |
| # Match quality badge | |
| if color == "green": | |
| st.success(quality) | |
| elif color == "blue": | |
| st.info(quality) | |
| else: | |
| st.warning(quality) | |
| def display_company_profile_basic(company_data, company_id): | |
| """ | |
| Display basic company profile card. | |
| Args: | |
| company_data: pandas Series with company data | |
| company_id: int company ID | |
| """ | |
| st.markdown(f"**Company ID:** {company_id}") | |
| # Name | |
| if 'name' in company_data and company_data['name']: | |
| st.markdown(f"**Name:** {company_data['name']}") | |
| # Industry | |
| if 'industry' in company_data and company_data['industry']: | |
| st.markdown(f"**Industry:** {company_data['industry']}") | |
| # Description | |
| if 'description' in company_data and company_data['description']: | |
| desc = company_data['description'] | |
| if isinstance(desc, str) and len(desc) > 0: | |
| with st.expander("π Company Description", expanded=False): | |
| st.write(desc[:500] + ('...' if len(desc) > 500 else '')) | |
| # Job posting status | |
| has_postings = company_data.get('has_job_postings', True) | |
| st.markdown("---") | |
| if has_postings: | |
| st.success("β **Has job postings** (direct semantic data)") | |
| else: | |
| st.info("π **Collaborative filtering** (skills inherited from similar companies)") | |
| st.caption("π‘ Company profile enriched with job posting vocabulary") | |
| def display_match_table_candidates(matches): | |
| """ | |
| Display candidate matches in table format (for company view). | |
| Args: | |
| matches: list of tuples (candidate_id, score, candidate_data) | |
| """ | |
| if len(matches) == 0: | |
| st.warning("No matches to display") | |
| return | |
| # Build table data | |
| table_data = [] | |
| for rank, (cand_id, score, cand_data) in enumerate(matches, 1): | |
| # Match quality | |
| if score >= 0.7: | |
| quality = "π₯ Excellent" | |
| elif score >= 0.6: | |
| quality = "β¨ Very Good" | |
| else: | |
| quality = "β Good" | |
| # Get some candidate info | |
| skills_preview = "" | |
| if 'skills' in cand_data and cand_data['skills']: | |
| skills = cand_data['skills'] | |
| if isinstance(skills, str) and len(skills) > 0: | |
| if ',' in skills: | |
| skills_list = [s.strip() for s in skills.split(',')[:3]] | |
| skills_preview = ', '.join(skills_list) + '...' | |
| else: | |
| skills_preview = skills[:50] + ('...' if len(skills) > 50 else '') | |
| table_data.append({ | |
| 'Rank': f'#{rank}', | |
| 'Candidate ID': cand_id, | |
| 'Skills Preview': skills_preview if skills_preview else 'N/A', | |
| 'Score': f'{score:.1%}', | |
| 'Quality': quality | |
| }) | |
| # Display as dataframe | |
| df = pd.DataFrame(table_data) | |
| st.dataframe(df, use_container_width=True, hide_index=True) | |
| # Add info tip | |
| st.info("π‘ **Tip:** Scores above 0.6 indicate strong alignment between candidate skills and company requirements!") | |
| def display_stats_overview_company(company, matches): | |
| """ | |
| Display statistics overview for company matching (company view). | |
| Args: | |
| company: pandas Series with company data | |
| matches: list of tuples (candidate_id, score, candidate_data) | |
| """ | |
| if len(matches) == 0: | |
| st.warning("No matches to display statistics") | |
| return | |
| # Calculate stats | |
| total_matches = len(matches) | |
| avg_score = sum(score for _, score, _ in matches) / total_matches | |
| excellent_matches = sum(1 for _, score, _ in matches if score >= 0.7) | |
| best_score = max(score for _, score, _ in matches) | |
| # Display metrics | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric( | |
| "π Total Candidates", | |
| total_matches, | |
| help="Number of candidates above minimum threshold" | |
| ) | |
| with col2: | |
| st.metric( | |
| "π Average Score", | |
| f"{avg_score:.1%}", | |
| help="Mean similarity score across all candidates" | |
| ) | |
| with col3: | |
| st.metric( | |
| "π₯ Excellent Matches", | |
| excellent_matches, | |
| help="Candidates with score β₯ 70%" | |
| ) | |
| with col4: | |
| st.metric( | |
| "π― Best Match", | |
| f"{best_score:.1%}", | |
| help="Highest similarity score achieved" | |
| ) | |