File size: 9,900 Bytes
eeb0f9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
"""
Context Analyzer - Understands user intent and needs
Determines what type of response is most appropriate
"""

from typing import Dict, List, Optional

class ContextAnalyzer:
    """
    Optimized Context Analyzer - Balanced between simplicity and coverage
    Handles 90% of scenarios with 50% less complexity
    """
    
    # Define patterns once as class variables (better performance)
    # Use compound patterns to reduce false positives
    URGENT_PATTERNS = [
        'đang đau', 'đau quá', 'khó chịu', 'không chịu nổi',
        'cấp cứu', 'khẩn cấp', 'gấp', 'ngay',
        'đau không thể', 'không aguanta được'  # Strong pain indicators
    ]
    
    # Context-specific urgent combinations (must have BOTH)
    URGENT_COMBINATIONS = [
        ('làm sao', ['hết đau', 'giảm đau', 'đỡ', 'ngay']),
        ('giúp tôi', ['đau', 'khó chịu', 'không chịu']),
        ('phải làm gì', ['đau', 'khó chịu', 'ngay', 'gấp']),
        ('cần gì', ['giảm đau', 'hết đau', 'cấp cứu'])
    ]
    
    INFO_PATTERNS = [
        'tại sao', 'nguyên nhân', 'có phải', 'bị gì',
        'là gì', 'thế nào', 'như thế nào'
    ]
    
    PREVENTION_PATTERNS = [
        'phòng ngừa', 'tránh', 'không bị', 'hạn chế',
        'làm sao để không', 'để khỏi'
    ]
    
    @staticmethod
    def is_vague_query(user_query: str) -> bool:
        """
        Detect if user query is too vague/ambiguous
        """
        vague_patterns = [
            'không khỏe', 'mệt', 'khó chịu', 'không ổn',
            'giúp tôi', 'cần giúp', 'phải làm sao',
            'không biết', 'chẳng hiểu', 'làm gì bây giờ'
        ]
        
        query_lower = user_query.lower()
        
        # Check if query is very short and vague
        if len(user_query.split()) <= 3:
            if any(pattern in query_lower for pattern in vague_patterns):
                return True
        
        # Check if query has no specific symptom/goal
        has_specifics = any(word in query_lower for word in [
            'đau', 'sốt', 'ho', 'buồn nôn',  # Symptoms
            'giảm cân', 'tăng cân', 'tập',  # Goals
            'ăn', 'thực đơn', 'calo'  # Nutrition
        ])
        
        if not has_specifics and any(pattern in query_lower for pattern in vague_patterns):
            return True
        
        return False
    
    @staticmethod
    def analyze_user_intent(user_query: str, chat_history: List) -> Dict:
        """
        Simplified but effective intent analysis with context awareness
        Returns only what's needed for response generation
        """
        query_lower = user_query.lower()
        
        # Check if query is too vague
        is_vague = ContextAnalyzer.is_vague_query(user_query)
        
        # Smart urgency check with context
        urgency = 'medium'  # default
        
        # Check direct urgent patterns
        if any(p in query_lower for p in ContextAnalyzer.URGENT_PATTERNS):
            urgency = 'high'
        # Check combination patterns (need both parts)
        else:
            for trigger, contexts in ContextAnalyzer.URGENT_COMBINATIONS:
                if trigger in query_lower:
                    if any(ctx in query_lower for ctx in contexts):
                        urgency = 'high'
                        break
        
        # If not urgent, check if it's informational
        if urgency != 'high' and any(p in query_lower for p in ContextAnalyzer.INFO_PATTERNS):
            urgency = 'low'
        
        # Determine primary intent (simplified)
        intent = 'general'  # default
        if urgency == 'high':
            intent = 'immediate_relief'
        elif any(p in query_lower for p in ContextAnalyzer.INFO_PATTERNS):
            intent = 'information'
        elif any(p in query_lower for p in ContextAnalyzer.PREVENTION_PATTERNS):
            intent = 'prevention'
        
        # Simple decision: solution vs education
        needs_solution = urgency in ['high', 'medium']
        needs_education = urgency == 'low' or intent in ['information', 'prevention']
        
        # Add conversation stage for compatibility
        conversation_stage = len(chat_history) if chat_history else 0
        
        return {
            'intent': intent,
            'urgency': urgency,
            'needs_solution': needs_solution,
            'needs_education': needs_education,
            'is_vague': is_vague,
            'needs_clarification': is_vague,
            'conversation_stage': conversation_stage
        }
    
    @staticmethod
    def determine_response_structure(context: Dict) -> Dict[str, any]:
        """
        Determine how to structure the response based on context
        
        Returns dict with:
        - structure: 'solution_first', 'assessment_first', 'education_first'
        - include_immediate: bool
        - include_prevention: bool
        - include_referral: bool
        """
        
        if context['urgency'] == 'high':
            return {
                'structure': 'solution_first',
                'include_immediate': True,
                'include_prevention': True,  # But after solution
                'include_referral': True,
                'tone': 'supportive_urgent'
            }
        
        elif context['intent'] == 'diagnosis':
            return {
                'structure': 'assessment_first',
                'include_immediate': False,
                'include_prevention': True,
                'include_referral': False,
                'tone': 'informative'
            }
        
        elif context['intent'] == 'prevention':
            return {
                'structure': 'education_first',
                'include_immediate': False,
                'include_prevention': True,
                'include_referral': False,
                'tone': 'educational'
            }
        
        else:  # Default balanced
            return {
                'structure': 'solution_first',
                'include_immediate': True,
                'include_prevention': True,
                'include_referral': True,
                'tone': 'balanced'
            }
    
    @staticmethod
    def format_contextual_response(
        symptom_assessment: str,
        solutions: List[str],
        preventions: List[str],
        response_structure: Dict
    ) -> str:
        """
        Format response based on context and user needs
        """
        response = ""
        
        if response_structure['structure'] == 'solution_first':
            # IMMEDIATE RELIEF FIRST
            if response_structure['include_immediate'] and solutions:
                response += "**Để giảm triệu chứng ngay, bạn có thể:**\n"
                for i, solution in enumerate(solutions[:3], 1):  # Top 3 immediate actions
                    response += f"{i}. {solution}\n"
                response += "\n"
            
            # MEDICATION OPTIONS (if urgent)
            if response_structure['tone'] == 'supportive_urgent':
                response += "**Về thuốc:**\n"
                response += "- Có thể dùng thuốc kháng acid (Maalox, Gaviscon) nếu đau do acid\n"
                response += "- Thuốc chống co thắt (Buscopan) nếu đau quặn\n"
                response += "⚠️ *Nên tham khảo dược sĩ trước khi dùng*\n\n"
            
            # WARNING SIGNS
            if response_structure['include_referral']:
                response += "**⚠️ Đi khám ngay nếu:**\n"
                response += "- Đau không giảm sau 2 giờ\n"
                response += "- Kèm sốt, nôn, tiêu chảy\n"
                response += "- Đau dữ dội tăng dần\n\n"
            
            # PREVENTION (after immediate care)
            if response_structure['include_prevention'] and preventions:
                response += "**Sau khi đỡ, để phòng tránh:**\n"
                for prevention in preventions[:3]:
                    response += f"• {prevention}\n"
        
        elif response_structure['structure'] == 'assessment_first':
            # Start with assessment/diagnosis
            response += symptom_assessment + "\n\n"
            
            # Then solutions
            if solutions:
                response += "**Cách xử lý:**\n"
                for solution in solutions:
                    response += f"• {solution}\n"
        
        elif response_structure['structure'] == 'education_first':
            # Start with education/prevention
            if preventions:
                response += "**Để phòng ngừa hiệu quả:**\n"
                for prevention in preventions:
                    response += f"• {prevention}\n"
        
        return response
    
    @staticmethod
    def should_ask_followup(context: Dict, chat_history: List) -> bool:
        """
        Determine if we should ask follow-up questions
        
        Rules:
        - Don't ask if urgency is high (give solutions first)
        - Don't ask if we already have enough info
        - Don't ask more than 2 questions total
        """
        
        # High urgency = no questions, give help
        if context['urgency'] == 'high':
            return False
        
        # Already asked 2+ questions = enough
        if chat_history and len(chat_history) >= 2:
            bot_questions = 0
            for _, bot_msg in chat_history:
                if bot_msg and '?' in bot_msg:
                    bot_questions += 1
            if bot_questions >= 2:
                return False
        
        # First interaction and not urgent = can ask 1 question
        if context['conversation_stage'] == 0:
            return True
        
        return False