Spaces:
Runtime error
Runtime error
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
|