Akshay Chame
π Add LinkedIn Profile Enhancer Streamlit app with all agents and dependencies
035c4af | # Profile Analysis Agent | |
| import re | |
| from typing import Dict, Any, List | |
| from collections import Counter | |
| class AnalyzerAgent: | |
| """Agent responsible for analyzing LinkedIn profiles and providing insights""" | |
| def __init__(self): | |
| self.action_words = [ | |
| 'led', 'managed', 'developed', 'created', 'implemented', 'designed', | |
| 'built', 'improved', 'increased', 'reduced', 'optimized', 'delivered', | |
| 'achieved', 'launched', 'established', 'coordinated', 'executed' | |
| ] | |
| def analyze_profile(self, profile_data: Dict[str, Any], job_description: str = "") -> Dict[str, Any]: | |
| """ | |
| Analyze a LinkedIn profile and provide comprehensive insights | |
| Args: | |
| profile_data (Dict[str, Any]): Extracted profile data | |
| job_description (str): Optional job description for matching analysis | |
| Returns: | |
| Dict[str, Any]: Analysis results with scores and recommendations | |
| """ | |
| if not profile_data: | |
| return self._empty_analysis() | |
| try: | |
| # Calculate completeness score | |
| completeness_score = self._calculate_completeness(profile_data) | |
| # Analyze keywords | |
| keyword_analysis = self._analyze_keywords(profile_data, job_description) | |
| # Assess content quality | |
| content_quality = self._assess_content_quality(profile_data) | |
| # Identify strengths and weaknesses | |
| strengths = self._identify_strengths(profile_data) | |
| weaknesses = self._identify_weaknesses(profile_data) | |
| # Calculate job match if job description provided | |
| job_match_score = 0 | |
| if job_description: | |
| job_match_score = self._calculate_job_match(profile_data, job_description) | |
| return { | |
| 'completeness_score': completeness_score, | |
| 'keyword_analysis': keyword_analysis, | |
| 'content_quality': content_quality, | |
| 'strengths': strengths, | |
| 'weaknesses': weaknesses, | |
| 'job_match_score': job_match_score, | |
| 'recommendations': self._generate_recommendations(profile_data, weaknesses), | |
| 'overall_rating': self._calculate_overall_rating(completeness_score, content_quality, job_match_score) | |
| } | |
| except Exception as e: | |
| print(f"Error in profile analysis: {str(e)}") | |
| return self._empty_analysis() | |
| def _calculate_completeness(self, profile_data: Dict[str, Any]) -> float: | |
| """Calculate profile completeness percentage""" | |
| score = 0 | |
| total_points = 10 | |
| # Basic information (2 points) | |
| if profile_data.get('name'): score += 1 | |
| if profile_data.get('headline'): score += 1 | |
| # About section (2 points) | |
| about = profile_data.get('about', '') | |
| if about and len(about) > 50: score += 1 | |
| if about and len(about) > 200: score += 1 | |
| # Experience (2 points) | |
| experience = profile_data.get('experience', []) | |
| if len(experience) >= 1: score += 1 | |
| if len(experience) >= 2: score += 1 | |
| # Education (1 point) | |
| if profile_data.get('education'): score += 1 | |
| # Skills (2 points) | |
| skills = profile_data.get('skills', []) | |
| if len(skills) >= 5: score += 1 | |
| if len(skills) >= 10: score += 1 | |
| # Location (1 point) | |
| if profile_data.get('location'): score += 1 | |
| return (score / total_points) * 100 | |
| def _analyze_keywords(self, profile_data: Dict[str, Any], job_description: str) -> Dict[str, Any]: | |
| """Analyze keywords in profile vs job description""" | |
| profile_text = self._extract_all_text(profile_data).lower() | |
| # Extract common tech keywords | |
| tech_keywords = [ | |
| 'python', 'javascript', 'react', 'node.js', 'sql', 'mongodb', | |
| 'aws', 'docker', 'kubernetes', 'git', 'agile', 'scrum' | |
| ] | |
| found_keywords = [] | |
| for keyword in tech_keywords: | |
| if keyword.lower() in profile_text: | |
| found_keywords.append(keyword) | |
| # Analyze job description keywords if provided | |
| missing_keywords = [] | |
| if job_description: | |
| job_keywords = re.findall(r'\b[a-zA-Z]{3,}\b', job_description.lower()) | |
| job_keyword_freq = Counter(job_keywords) | |
| for keyword, freq in job_keyword_freq.most_common(10): | |
| if keyword not in profile_text and len(keyword) > 3: | |
| missing_keywords.append(keyword) | |
| return { | |
| 'found_keywords': found_keywords, | |
| 'missing_keywords': missing_keywords[:5], # Top 5 missing | |
| 'keyword_density': len(found_keywords) | |
| } | |
| def _assess_content_quality(self, profile_data: Dict[str, Any]) -> Dict[str, Any]: | |
| """Assess the quality of content""" | |
| about_section = profile_data.get('about', '') | |
| headline = profile_data.get('headline', '') | |
| return { | |
| 'headline_length': len(headline), | |
| 'about_length': len(about_section), | |
| 'has_quantified_achievements': self._has_numbers(about_section), | |
| 'uses_action_words': self._has_action_words(about_section) | |
| } | |
| def _identify_strengths(self, profile_data: Dict[str, Any]) -> List[str]: | |
| """Identify profile strengths""" | |
| strengths = [] | |
| if len(profile_data.get('experience', [])) >= 3: | |
| strengths.append("Good work experience history") | |
| if len(profile_data.get('skills', [])) >= 10: | |
| strengths.append("Comprehensive skills list") | |
| if len(profile_data.get('about', '')) > 200: | |
| strengths.append("Detailed about section") | |
| return strengths | |
| def _identify_weaknesses(self, profile_data: Dict[str, Any]) -> List[str]: | |
| """Identify areas for improvement""" | |
| weaknesses = [] | |
| if not profile_data.get('about') or len(profile_data.get('about', '')) < 100: | |
| weaknesses.append("About section needs improvement") | |
| if len(profile_data.get('skills', [])) < 5: | |
| weaknesses.append("Limited skills listed") | |
| if not self._has_numbers(profile_data.get('about', '')): | |
| weaknesses.append("Lacks quantified achievements") | |
| return weaknesses | |
| def _calculate_job_match(self, profile_data: Dict[str, Any], job_description: str) -> float: | |
| """Calculate how well profile matches job description""" | |
| if not job_description: | |
| return 0 | |
| profile_text = self._extract_all_text(profile_data).lower() | |
| job_text = job_description.lower() | |
| # Extract keywords from job description | |
| job_keywords = set(re.findall(r'\b[a-zA-Z]{4,}\b', job_text)) | |
| # Count matches | |
| matches = 0 | |
| for keyword in job_keywords: | |
| if keyword in profile_text: | |
| matches += 1 | |
| return min((matches / len(job_keywords)) * 100, 100) if job_keywords else 0 | |
| def _extract_all_text(self, profile_data: Dict[str, Any]) -> str: | |
| """Extract all text from profile for analysis""" | |
| text_parts = [] | |
| # Add basic info | |
| text_parts.append(profile_data.get('headline', '')) | |
| text_parts.append(profile_data.get('about', '')) | |
| # Add experience descriptions | |
| for exp in profile_data.get('experience', []): | |
| text_parts.append(exp.get('description', '')) | |
| text_parts.append(exp.get('title', '')) | |
| # Add skills | |
| text_parts.extend(profile_data.get('skills', [])) | |
| return ' '.join(text_parts) | |
| def _has_numbers(self, text: str) -> bool: | |
| """Check if text contains numbers/metrics""" | |
| return bool(re.search(r'\d+', text)) | |
| def _has_action_words(self, text: str) -> bool: | |
| """Check if text contains action words""" | |
| text_lower = text.lower() | |
| return any(word in text_lower for word in self.action_words) | |
| def _generate_recommendations(self, profile_data: Dict[str, Any], weaknesses: List[str]) -> List[str]: | |
| """Generate specific recommendations based on analysis""" | |
| recommendations = [] | |
| for weakness in weaknesses: | |
| if "about section" in weakness.lower(): | |
| recommendations.append("Add a compelling about section with 150-300 words describing your expertise") | |
| elif "skills" in weakness.lower(): | |
| recommendations.append("Add more relevant skills to reach at least 10 skills") | |
| elif "quantified" in weakness.lower(): | |
| recommendations.append("Include specific numbers and metrics in your descriptions") | |
| return recommendations | |
| def _calculate_overall_rating(self, completeness: float, content_quality: Dict[str, Any], job_match: float) -> str: | |
| """Calculate overall profile rating""" | |
| score = completeness * 0.4 | |
| # Add content quality score | |
| if content_quality.get('has_quantified_achievements'): | |
| score += 10 | |
| if content_quality.get('uses_action_words'): | |
| score += 10 | |
| if content_quality.get('about_length', 0) > 150: | |
| score += 10 | |
| # Add job match if available | |
| if job_match > 0: | |
| score += job_match * 0.3 | |
| if score >= 80: | |
| return "Excellent" | |
| elif score >= 60: | |
| return "Good" | |
| elif score >= 40: | |
| return "Fair" | |
| else: | |
| return "Needs Improvement" | |
| def _empty_analysis(self) -> Dict[str, Any]: | |
| """Return empty analysis structure""" | |
| return { | |
| 'completeness_score': 0, | |
| 'keyword_analysis': {'found_keywords': [], 'missing_keywords': [], 'keyword_density': 0}, | |
| 'content_quality': {'headline_length': 0, 'about_length': 0, 'has_quantified_achievements': False, 'uses_action_words': False}, | |
| 'strengths': [], | |
| 'weaknesses': ['Profile data not available'], | |
| 'job_match_score': 0, | |
| 'recommendations': ['Please provide valid profile data'], | |
| 'overall_rating': 'Unknown' | |
| } | |