File size: 5,184 Bytes
3d015cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""Personality Module - Big Five Trait Scoring"""
import numpy as np
from typing import Dict, Tuple

class PersonalityModule:
    """Scores personality based on Big Five traits"""
    
    def __init__(self):
        # Map questions to traits (reversed questions need inverse scoring)
        self.trait_mapping = {
            'openness': ['p_q1', 'p_q3', 'p_q4'],
            'openness_r': ['p_q2'],  # Reversed
            'conscientiousness': ['p_q5', 'p_q7', 'p_q8'],
            'conscientiousness_r': ['p_q6'],  # Reversed
            'extraversion': ['p_q9', 'p_q11', 'p_q12'],
            'extraversion_r': ['p_q10'],  # Reversed
            'agreeableness': ['p_q13', 'p_q15', 'p_q16'],
            'agreeableness_r': ['p_q14'],  # Reversed
            'stability': ['p_q17', 'p_q19', 'p_q20'],
            'stability_r': ['p_q18']  # Reversed
        }
        
        # Weights for employability (some traits matter more)
        self.trait_weights = {
            'openness': 0.20,
            'conscientiousness': 0.30,
            'extraversion': 0.20,
            'agreeableness': 0.15,
            'stability': 0.15
        }
    
    def score(self, responses: Dict[str, int]) -> Tuple[float, float, Dict]:
        """
        Calculate personality score from 20 questions
        Returns: (score, confidence, trait_scores)
        """
        trait_scores = {}
        
        # Calculate each trait score
        for trait in ['openness', 'conscientiousness', 'extraversion', 'agreeableness', 'stability']:
            # Get normal questions
            normal_qs = self.trait_mapping[trait]
            reversed_qs = self.trait_mapping[f'{trait}_r']
            
            # Calculate average for this trait
            scores = []
            
            # Normal questions: higher = better
            for q in normal_qs:
                if q in responses:
                    scores.append((responses[q] - 1) / 4.0)  # Normalize 1-5 to 0-1
            
            # Reversed questions: lower = better
            for q in reversed_qs:
                if q in responses:
                    scores.append((5 - responses[q]) / 4.0)  # Invert and normalize
            
            if scores:
                trait_scores[trait] = np.mean(scores)
            else:
                trait_scores[trait] = 0.5  # Neutral if missing
        
        # Calculate overall personality score
        personality_score = sum(
            trait_scores[trait] * self.trait_weights[trait]
            for trait in trait_scores.keys()
        )
        
        # Calculate confidence based on question completion
        total_questions = 20
        answered_questions = len(responses)
        confidence = answered_questions / total_questions
        
        return personality_score, confidence, trait_scores
    
    def explain(self, trait_scores: Dict) -> Dict:
        """Generate explanation for personality scores"""
        explanations = {
            'top_strengths': [],
            'areas_for_growth': []
        }
        
        # Sort traits by score
        sorted_traits = sorted(trait_scores.items(), key=lambda x: x[1], reverse=True)
        
        # Top 2 strengths
        for trait, score in sorted_traits[:2]:
            if score > 0.6:
                explanations['top_strengths'].append({
                    'trait': trait.capitalize(),
                    'score': round(score, 2),
                    'description': self._get_trait_description(trait, score)
                })
        
        # Bottom 2 areas for growth
        for trait, score in sorted_traits[-2:]:
            if score < 0.5:
                explanations['areas_for_growth'].append({
                    'trait': trait.capitalize(),
                    'score': round(score, 2),
                    'description': self._get_trait_description(trait, score)
                })
        
        return explanations
    
    def _get_trait_description(self, trait: str, score: float) -> str:
        """Get description of trait"""
        descriptions = {
            'openness': {
                'high': "Highly creative, curious, and open to new experiences",
                'low': "Prefers routine and traditional approaches"
            },
            'conscientiousness': {
                'high': "Very organized, reliable, and goal-oriented",
                'low': "May benefit from improved organization and planning"
            },
            'extraversion': {
                'high': "Energetic, sociable, and thrives in team environments",
                'low': "Prefers independent work and smaller groups"
            },
            'agreeableness': {
                'high': "Cooperative, empathetic, and team-oriented",
                'low': "Independent thinker, comfortable with competition"
            },
            'stability': {
                'high': "Emotionally stable, handles stress well",
                'low': "May experience stress in high-pressure situations"
            }
        }
        
        level = 'high' if score > 0.6 else 'low'
        return descriptions.get(trait, {}).get(level, f"{trait} score: {score:.2f}")