Spaces:
Sleeping
Sleeping
| """ | |
| Student Output Service - Individual student JSON formatting | |
| Provides structured analysis output for single students | |
| """ | |
| import logging | |
| from typing import Dict, List, Any, Optional | |
| from datetime import datetime | |
| from dataclasses import dataclass, asdict | |
| logger = logging.getLogger(__name__) | |
| class SkillRecommendation: | |
| """Skill gap recommendation for student""" | |
| skill: str | |
| priority: str | |
| recommended_courses: List[str] | |
| certifications: List[str] | |
| class CareerPath: | |
| """Suggested career path""" | |
| role: str | |
| fit_score: float | |
| requirements_met: List[str] | |
| requirements_gap: List[str] | |
| class StudentOutputService: | |
| """ | |
| Formats individual student analysis into structured JSON | |
| """ | |
| # Grade thresholds | |
| GRADE_THRESHOLDS = [ | |
| (0.90, 'A+', 'Outstanding'), | |
| (0.80, 'A', 'Excellent'), | |
| (0.70, 'B+', 'Very Good'), | |
| (0.60, 'B', 'Good'), | |
| (0.50, 'C', 'Average'), | |
| (0.40, 'D', 'Below Average'), | |
| (0.00, 'F', 'Needs Improvement') | |
| ] | |
| def __init__(self): | |
| # Role requirements mapping | |
| self.career_requirements = { | |
| 'software_engineer': { | |
| 'required': ['python', 'sql', 'git', 'problem_solving'], | |
| 'preferred': ['cloud', 'docker', 'system_design'], | |
| 'description': 'Design, develop, and maintain software systems and applications' | |
| }, | |
| 'data_scientist': { | |
| 'required': ['python', 'sql', 'statistics', 'machine_learning'], | |
| 'preferred': ['deep_learning', 'spark', 'mlops'], | |
| 'description': 'Analyze complex data to extract insights and build predictive models' | |
| }, | |
| 'product_manager': { | |
| 'required': ['communication', 'leadership', 'analytics'], | |
| 'preferred': ['sql', 'strategic_thinking', 'stakeholder_management'], | |
| 'description': 'Define product vision and strategy, coordinate cross-functional teams' | |
| }, | |
| 'mechanical_engineer': { | |
| 'required': ['cad', 'engineering_drawing', 'manufacturing'], | |
| 'preferred': ['fea', 'cfd', 'automation'], | |
| 'description': 'Design and develop mechanical systems, components, and machinery' | |
| }, | |
| 'data_analyst': { | |
| 'required': ['sql', 'excel', 'statistics', 'visualization'], | |
| 'preferred': ['python', 'tableau', 'power_bi'], | |
| 'description': 'Transform raw data into actionable business insights and reports' | |
| }, | |
| 'full_stack_developer': { | |
| 'required': ['javascript', 'html', 'css', 'nodejs'], | |
| 'preferred': ['react', 'mongodb', 'aws'], | |
| 'description': 'Build complete web applications from frontend to backend' | |
| }, | |
| 'devops_engineer': { | |
| 'required': ['linux', 'docker', 'ci_cd', 'scripting'], | |
| 'preferred': ['kubernetes', 'terraform', 'aws'], | |
| 'description': 'Automate and streamline software development and deployment processes' | |
| }, | |
| 'business_analyst': { | |
| 'required': ['communication', 'sql', 'requirements_gathering'], | |
| 'preferred': ['powerpoint', 'stakeholder_management', 'agile'], | |
| 'description': 'Bridge the gap between business needs and technical solutions' | |
| } | |
| } | |
| def format_student_output(self, | |
| student_id: str, | |
| score_packet: Dict[str, Any], | |
| domain_analysis: Dict[str, Any] = None, | |
| raw_data: Dict[str, Any] = None) -> Dict[str, Any]: | |
| """ | |
| Format comprehensive student analysis JSON | |
| Args: | |
| student_id: Student identifier | |
| score_packet: Output from scoring endpoint | |
| domain_analysis: Output from FCT (optional) | |
| raw_data: Original student data (optional) | |
| Returns: | |
| Structured student JSON | |
| """ | |
| # Extract core scores | |
| final_score = score_packet.get('final_score', 0) | |
| grade, grade_desc = self._get_grade(final_score) | |
| # Component scores | |
| component_scores = score_packet.get('scores', {}).get('component_scores', {}) | |
| confidences = score_packet.get('scores', {}).get('confidences', {}) | |
| detailed_features = score_packet.get('detailed_features', {}) | |
| # Domain info | |
| detected_domain = ( | |
| domain_analysis.get('detected_domain') if domain_analysis | |
| else score_packet.get('domain_type', 'general') | |
| ) | |
| # Build output | |
| output = { | |
| 'student_id': student_id, | |
| 'generated_at': datetime.utcnow().isoformat() + 'Z', | |
| 'summary': { | |
| 'final_score': round(final_score, 3), | |
| 'grade': grade, | |
| 'grade_description': grade_desc, | |
| 'percentile': score_packet.get('percentile', 50), | |
| 'placement_ready': final_score >= 0.60 | |
| }, | |
| 'scores': { | |
| 'universal': { | |
| 'score': round(component_scores.get('universal', 0), 3), | |
| 'confidence': round(confidences.get('universal', 0), 3), | |
| 'features': detailed_features.get('universal', {}) | |
| }, | |
| 'personality': { | |
| 'score': round(component_scores.get('personality', 0), 3), | |
| 'confidence': round(confidences.get('personality', 0), 3), | |
| 'traits': detailed_features.get('personality', {}) | |
| }, | |
| 'text': { | |
| 'score': round(component_scores.get('text', 0), 3), | |
| 'confidence': round(confidences.get('text', 0), 3), | |
| 'aspects': detailed_features.get('text', {}) | |
| } | |
| }, | |
| 'domain_analysis': self._format_domain_analysis( | |
| detected_domain, domain_analysis, raw_data | |
| ), | |
| 'strengths': self._identify_strengths(detailed_features), | |
| 'improvement_areas': self._identify_improvements(detailed_features), | |
| 'career_suggestions': self._suggest_careers( | |
| detected_domain, detailed_features, raw_data | |
| ), | |
| 'skill_recommendations': self._recommend_skills( | |
| detected_domain, raw_data | |
| ), | |
| 'explanations': score_packet.get('explanations', {}) | |
| } | |
| # Add fidelity if available | |
| if domain_analysis and 'fidelity' in domain_analysis: | |
| output['fidelity_assessment'] = domain_analysis['fidelity'] | |
| return output | |
| def _get_grade(self, score: float) -> tuple: | |
| """Get grade and description for score""" | |
| for threshold, grade, desc in self.GRADE_THRESHOLDS: | |
| if score >= threshold: | |
| return (grade, desc) | |
| return ('F', 'Needs Improvement') | |
| def _format_domain_analysis(self, detected_domain: str, | |
| domain_analysis: Dict, | |
| raw_data: Dict) -> Dict[str, Any]: | |
| """Format domain-specific analysis""" | |
| result = { | |
| 'detected_domain': detected_domain, | |
| 'display_name': detected_domain.replace('_', ' ').title() | |
| } | |
| if domain_analysis: | |
| result['domain_confidence'] = domain_analysis.get('domain_confidence', 0) | |
| result['aspects'] = domain_analysis.get('aspects', {}) | |
| # Skill gaps from raw data | |
| if raw_data and 'skills' in raw_data: | |
| skills = raw_data.get('skills', []) | |
| if isinstance(skills, str): | |
| skills = [s.strip().lower() for s in skills.split(',')] | |
| result['current_skills'] = skills | |
| return result | |
| def _identify_strengths(self, features: Dict) -> List[Dict]: | |
| """Identify top strengths from features""" | |
| strengths = [] | |
| # Universal features | |
| universal = features.get('universal', {}) | |
| if universal.get('cgpa_norm', 0) > 0.8: | |
| strengths.append({ | |
| 'area': 'Academic Excellence', | |
| 'score': universal['cgpa_norm'], | |
| 'description': 'Strong academic performance with high CGPA' | |
| }) | |
| if universal.get('internship_exposure', 0) > 0.7: | |
| strengths.append({ | |
| 'area': 'Industry Experience', | |
| 'score': universal['internship_exposure'], | |
| 'description': 'Significant practical experience through internships' | |
| }) | |
| # Personality traits | |
| personality = features.get('personality', {}) | |
| for trait, score in personality.items(): | |
| if score > 0.75: | |
| strengths.append({ | |
| 'area': trait.title(), | |
| 'score': score, | |
| 'description': self._get_trait_description(trait, 'high') | |
| }) | |
| # Text aspects | |
| text = features.get('text', {}) | |
| if text.get('leadership_score', 0) > 0.7: | |
| strengths.append({ | |
| 'area': 'Leadership', | |
| 'score': text['leadership_score'], | |
| 'description': 'Demonstrated leadership abilities with concrete examples' | |
| }) | |
| if text.get('technical_skills', 0) > 0.7: | |
| strengths.append({ | |
| 'area': 'Technical Skills', | |
| 'score': text['technical_skills'], | |
| 'description': 'Strong technical competencies' | |
| }) | |
| # Sort by score and return top 5 | |
| strengths.sort(key=lambda x: x['score'], reverse=True) | |
| return strengths[:5] | |
| def _identify_improvements(self, features: Dict) -> List[Dict]: | |
| """Identify areas needing improvement""" | |
| improvements = [] | |
| # Universal features | |
| universal = features.get('universal', {}) | |
| if universal.get('ec_quality', 0) < 0.4: | |
| improvements.append({ | |
| 'area': 'Extracurricular Activities', | |
| 'current_score': universal.get('ec_quality', 0), | |
| 'suggestion': 'Strengthen your profile by joining technical clubs, participating in hackathons and coding competitions, or taking leadership roles in student organizations. These experiences demonstrate initiative and teamwork to recruiters.' | |
| }) | |
| if universal.get('cert_quality', 0) < 0.4: | |
| improvements.append({ | |
| 'area': 'Professional Certifications', | |
| 'current_score': universal.get('cert_quality', 0), | |
| 'suggestion': 'Boost your credentials with industry-recognized certifications like AWS Cloud Practitioner, Google Data Analytics, or Microsoft Azure Fundamentals. These demonstrate commitment to continuous learning and are valued by employers.' | |
| }) | |
| if universal.get('internship_exposure', 0) < 0.4: | |
| improvements.append({ | |
| 'area': 'Internship Experience', | |
| 'current_score': universal.get('internship_exposure', 0), | |
| 'suggestion': 'Gain practical experience through internships at startups or established companies. Apply through campus placements, LinkedIn, or platforms like Internshala and AngelList. Even short-term projects count towards industry exposure.' | |
| }) | |
| if universal.get('project_quality', 0) < 0.5: | |
| improvements.append({ | |
| 'area': 'Project Portfolio', | |
| 'current_score': universal.get('project_quality', 0), | |
| 'suggestion': 'Build impressive projects that showcase your skills. Create a GitHub portfolio with well-documented code, deploy live projects, and contribute to open-source. Quality matters more than quantity - focus on 2-3 impactful projects.' | |
| }) | |
| # Text aspects | |
| text = features.get('text', {}) | |
| if text.get('communication', 0) < 0.5: | |
| improvements.append({ | |
| 'area': 'Communication Skills', | |
| 'current_score': text.get('communication', 0), | |
| 'suggestion': 'Improve your communication by practicing technical presentations, writing detailed project documentation, and articulating your thoughts clearly. Consider joining Toastmasters or taking a business communication course.' | |
| }) | |
| if text.get('career_alignment', 0) < 0.5: | |
| improvements.append({ | |
| 'area': 'Career Clarity', | |
| 'current_score': text.get('career_alignment', 0), | |
| 'suggestion': 'Define clear career goals by researching industry roles, talking to professionals in your field of interest, and creating a 1-year and 5-year career roadmap. This clarity helps you make focused skill-building decisions.' | |
| }) | |
| # Sort by score (lowest first) | |
| improvements.sort(key=lambda x: x['current_score']) | |
| return improvements[:4] | |
| def _suggest_careers(self, domain: str, features: Dict, | |
| raw_data: Dict) -> List[Dict]: | |
| """Suggest career paths based on profile""" | |
| suggestions = [] | |
| # Get student skills | |
| skills = [] | |
| if raw_data and 'skills' in raw_data: | |
| skills_raw = raw_data.get('skills', []) | |
| if isinstance(skills_raw, str): | |
| skills = [s.strip().lower() for s in skills_raw.split(',')] | |
| else: | |
| skills = [s.lower() for s in skills_raw] | |
| # Text features for soft skills | |
| text = features.get('text', {}) | |
| for role, reqs in self.career_requirements.items(): | |
| # Calculate fit score | |
| required_met = sum(1 for r in reqs['required'] | |
| if r in skills or self._has_soft_skill(r, text)) | |
| preferred_met = sum(1 for p in reqs['preferred'] | |
| if p in skills or self._has_soft_skill(p, text)) | |
| total_reqs = len(reqs['required']) | |
| fit_score = (required_met / total_reqs) if total_reqs else 0 | |
| fit_score += (preferred_met / len(reqs['preferred'])) * 0.3 if reqs['preferred'] else 0 | |
| fit_score = min(fit_score, 1.0) | |
| if fit_score > 0.3: # Minimum threshold | |
| suggestions.append({ | |
| 'role': role.replace('_', ' ').title(), | |
| 'fit_score': round(fit_score, 2), | |
| 'requirements_met': [r for r in reqs['required'] | |
| if r in skills or self._has_soft_skill(r, text)], | |
| 'requirements_gap': [r for r in reqs['required'] | |
| if r not in skills and not self._has_soft_skill(r, text)] | |
| }) | |
| # Sort by fit score | |
| suggestions.sort(key=lambda x: x['fit_score'], reverse=True) | |
| return suggestions[:3] | |
| def _has_soft_skill(self, skill: str, text_features: Dict) -> bool: | |
| """Check if student has a soft skill based on text analysis""" | |
| skill_mapping = { | |
| 'communication': 'communication', | |
| 'leadership': 'leadership_score', | |
| 'problem_solving': 'problem_solving', | |
| 'teamwork': 'teamwork' | |
| } | |
| if skill in skill_mapping: | |
| return text_features.get(skill_mapping[skill], 0) > 0.6 | |
| return False | |
| def _recommend_skills(self, domain: str, raw_data: Dict) -> List[Dict]: | |
| """Recommend skills to acquire""" | |
| recommendations = [] | |
| # Domain-specific recommendations with enhanced courses | |
| domain_skills = { | |
| 'software_engineering': [ | |
| {'skill': 'cloud', 'courses': ['AWS Solutions Architect (Udemy)', 'Google Cloud Fundamentals (Coursera)', 'Azure Fundamentals (Microsoft Learn)'], 'certs': ['AWS Certified Cloud Practitioner', 'Google Cloud Associate']}, | |
| {'skill': 'system_design', 'courses': ['Grokking System Design (Educative)', 'System Design Primer (GitHub)', 'Designing Data-Intensive Applications (Book)'], 'certs': []}, | |
| {'skill': 'devops', 'courses': ['Docker Mastery (Udemy)', 'Kubernetes for Beginners (KodeKloud)', 'CI/CD with Jenkins (LinkedIn Learning)'], 'certs': ['Docker Certified Associate', 'CKA Kubernetes']}, | |
| {'skill': 'data_structures', 'courses': ['Data Structures & Algorithms (GeeksforGeeks)', 'LeetCode Premium', 'Cracking the Coding Interview (Book)'], 'certs': []} | |
| ], | |
| 'data_science': [ | |
| {'skill': 'deep_learning', 'courses': ['Deep Learning Specialization (Coursera - Andrew Ng)', 'Fast.ai Practical Deep Learning', 'PyTorch Fundamentals (Microsoft)'], 'certs': ['TensorFlow Developer Certificate']}, | |
| {'skill': 'mlops', 'courses': ['MLOps Specialization (Coursera)', 'Made With ML', 'Full Stack Deep Learning'], 'certs': ['Google ML Engineer', 'AWS ML Specialty']}, | |
| {'skill': 'statistics', 'courses': ['Statistics with Python (Coursera)', 'Khan Academy Statistics', 'Think Stats (Book)'], 'certs': []}, | |
| {'skill': 'sql_analytics', 'courses': ['SQL for Data Science (Coursera)', 'Mode Analytics SQL Tutorial', 'DataCamp SQL Track'], 'certs': ['Microsoft Data Analyst Associate']} | |
| ], | |
| 'mechanical_engineering': [ | |
| {'skill': 'ev_powertrain', 'courses': ['Electric Vehicle Technology (NPTEL)', 'EV Design Fundamentals (Udemy)', 'Battery Technology (Coursera)'], 'certs': ['SAE EV Certificate']}, | |
| {'skill': 'automation', 'courses': ['Industrial Automation (NPTEL)', 'PLC Programming (Udemy)', 'Industry 4.0 Fundamentals'], 'certs': ['Siemens Automation Certificate']}, | |
| {'skill': 'cfd', 'courses': ['Computational Fluid Dynamics (NPTEL)', 'ANSYS Fluent Tutorials', 'OpenFOAM Basics'], 'certs': []}, | |
| {'skill': 'additive_manufacturing', 'courses': ['3D Printing Fundamentals (Coursera)', 'Additive Manufacturing (NPTEL)'], 'certs': []} | |
| ], | |
| 'business': [ | |
| {'skill': 'data_visualization', 'courses': ['Tableau Desktop Specialist (Tableau)', 'Power BI (Microsoft Learn)', 'Data Storytelling (LinkedIn Learning)'], 'certs': ['Tableau Desktop Specialist', 'Power BI Data Analyst']}, | |
| {'skill': 'financial_modeling', 'courses': ['Financial Modeling (CFI)', 'Excel for Finance (Coursera)', 'Valuation Fundamentals'], 'certs': ['FMVA Certification']} | |
| ] | |
| } | |
| # Get current skills | |
| current_skills = [] | |
| if raw_data and 'skills' in raw_data: | |
| skills_raw = raw_data.get('skills', []) | |
| if isinstance(skills_raw, str): | |
| current_skills = [s.strip().lower() for s in skills_raw.split(',')] | |
| # Recommend missing skills | |
| domain_recs = domain_skills.get(domain, domain_skills.get('software_engineering', [])) | |
| for rec in domain_recs: | |
| if rec['skill'] not in current_skills: | |
| recommendations.append({ | |
| 'skill': rec['skill'].replace('_', ' ').title(), | |
| 'priority': 'high' if len(recommendations) < 2 else 'medium', | |
| 'recommended_courses': rec['courses'], | |
| 'certifications': rec.get('certs', []) | |
| }) | |
| return recommendations[:4] | |
| def _get_trait_description(self, trait: str, level: str) -> str: | |
| """Get description for personality trait""" | |
| descriptions = { | |
| 'openness': { | |
| 'high': 'Creative, curious, and open to new experiences', | |
| 'low': 'Practical and focused on concrete tasks' | |
| }, | |
| 'conscientiousness': { | |
| 'high': 'Organized, disciplined, and reliable', | |
| 'low': 'Flexible and adaptable to changing situations' | |
| }, | |
| 'extraversion': { | |
| 'high': 'Energetic, sociable, and thrives in team settings', | |
| 'low': 'Focused, reflective, and excels in independent work' | |
| }, | |
| 'agreeableness': { | |
| 'high': 'Cooperative, empathetic, and team-oriented', | |
| 'low': 'Independent thinker, comfortable with competition' | |
| }, | |
| 'stability': { | |
| 'high': 'Emotionally resilient and handles stress well', | |
| 'low': 'Sensitive and responsive to feedback' | |
| } | |
| } | |
| return descriptions.get(trait, {}).get(level, f"Strong {trait}") | |
| # Singleton | |
| _student_output_service: Optional[StudentOutputService] = None | |
| def get_student_output_service() -> StudentOutputService: | |
| """Get singleton student output service""" | |
| global _student_output_service | |
| if _student_output_service is None: | |
| _student_output_service = StudentOutputService() | |
| return _student_output_service | |