| |
| 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: |
| |
| completeness_score = self._calculate_completeness(profile_data) |
| |
| |
| keyword_analysis = self._analyze_keywords(profile_data, job_description) |
| |
| |
| content_quality = self._assess_content_quality(profile_data) |
| |
| |
| strengths = self._identify_strengths(profile_data) |
| weaknesses = self._identify_weaknesses(profile_data) |
| |
| |
| 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 |
| |
| |
| if profile_data.get('name'): score += 1 |
| if profile_data.get('headline'): score += 1 |
| |
| |
| about = profile_data.get('about', '') |
| if about and len(about) > 50: score += 1 |
| if about and len(about) > 200: score += 1 |
| |
| |
| experience = profile_data.get('experience', []) |
| if len(experience) >= 1: score += 1 |
| if len(experience) >= 2: score += 1 |
| |
| |
| if profile_data.get('education'): score += 1 |
| |
| |
| skills = profile_data.get('skills', []) |
| if len(skills) >= 5: score += 1 |
| if len(skills) >= 10: score += 1 |
| |
| |
| 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() |
| |
| |
| 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) |
| |
| |
| 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], |
| '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() |
| |
| |
| job_keywords = set(re.findall(r'\b[a-zA-Z]{4,}\b', job_text)) |
| |
| |
| 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 = [] |
| |
| |
| text_parts.append(profile_data.get('headline', '')) |
| text_parts.append(profile_data.get('about', '')) |
| |
| |
| for exp in profile_data.get('experience', []): |
| text_parts.append(exp.get('description', '')) |
| text_parts.append(exp.get('title', '')) |
| |
| |
| 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 |
| |
| |
| 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 |
| |
| |
| 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' |
| } |
|
|