File size: 4,916 Bytes
b482b16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268baab
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
"""
Input handler for processing and validating user messages.
Handles numeric inputs, validation, and interpretation.
"""
import re
from src.rag.utilclasses import ConversationState
from src.utils.logging import get_logger

logger = get_logger("input_handler")


class InputHandler:
    """Handles input validation and interpretation"""
    
    @staticmethod
    def validate_and_normalize(message: str) -> str:
        """
        Normalize and validate user input.
        
        Args:
            message: Raw user input
            
        Returns:
            Normalized message
        """
        if not message:
            return ""
        
        # Strip whitespace
        normalized = message.strip()
        
        # Handle empty or very short inputs
        if len(normalized) < 1:
            return ""
        
        return normalized
    
    @staticmethod
    def is_numeric_input(message: str) -> bool:
        """
        Check if message is a standalone number.
        
        Args:
            message: User input
            
        Returns:
            True if message is just a number
        """
        normalized = message.strip()
        # Check if it's just digits (possibly with decimal)
        return bool(re.match(r'^\d+(\.\d+)?$', normalized))
    
    @staticmethod
    def interpret_numeric_input(
        message: str, 
        conversation_history: list
    ) -> str:
        """
        Interpret standalone numeric input based on conversation context.
        
        Args:
            message: Numeric input (e.g., "5")
            conversation_history: Recent conversation messages (LangChain message objects)
            
        Returns:
            Interpreted message (e.g., "I have 5 years of experience")
        """
        number = message.strip()
        
        # Look at recent messages for context
        recent_context = ""
        if len(conversation_history) > 0:
            # Get last bot message
            # Import here to avoid circular dependency
            from langchain_core.messages import AIMessage
            
            for msg in reversed(conversation_history):
                # Handle LangChain message objects
                if isinstance(msg, AIMessage):
                    recent_context = msg.content.lower() if hasattr(msg, 'content') else ""
                    break
                # Handle dictionary format (for backward compatibility)
                elif isinstance(msg, dict) and msg.get("role") == "assistant":
                    recent_context = msg.get("content", "").lower()
                    break
        
        # Interpret based on context keywords
        if any(keyword in recent_context for keyword in [
            "experience", "years", "worked", "arbeits", "erfahrung", "jahre"
        ]):
            logger.info(f"Interpreting numeric input '{number}' as years of experience")
            return f"I have {number} years of work experience"
        
        elif any(keyword in recent_context for keyword in [
            "age", "old", "alter", "jahre alt"
        ]):
            logger.info(f"Interpreting numeric input '{number}' as age")
            return f"I am {number} years old"
        
        elif any(keyword in recent_context for keyword in [
            "qualification", "degree", "bachelor", "master", "qualifikation"
        ]):
            logger.info(f"Interpreting numeric input '{number}' as qualification level")
            # Interpret as degree type
            level_map = {
                "1": "I have a Bachelor's degree",
                "2": "I have a Master's degree",
                "3": "I have an MBA",
                "4": "I have a doctorate/PhD"
            }
            return level_map.get(number, f"My qualification level is {number}")
        
        # Default: assume years of experience (most common)
        logger.info(f"Interpreting numeric input '{number}' as years of experience (default)")
        return f"I have {number} years of work experience"
    
    @staticmethod
    def process_input(
        message: str,
        conversation_history: list
    ) -> tuple[str, bool]:
        """
        Process user input with validation and interpretation.
        
        Args:
            message: Raw user input
            conversation_history: Recent messages for context
            
        Returns:
            Tuple of (processed_message, is_valid)
        """
        # Normalize
        normalized = InputHandler.validate_and_normalize(message)
        
        if not normalized:
            return "", False
        
        # Check if numeric
        if InputHandler.is_numeric_input(normalized):
            interpreted = InputHandler.interpret_numeric_input(
                normalized, 
                conversation_history
            )
            return interpreted, True
        
        return normalized, True