File size: 24,055 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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
"""
Nutrition Agent - Specialized agent for nutrition advice
"""

from config.settings import client, MODEL
from modules.nutrition import NutritionAdvisor
from health_data import HealthContext
from personalization import PersonalizationEngine
from rag.rag_integration import get_rag_integration
from agents.core.base_agent import BaseAgent
from agents.core.context_analyzer import ContextAnalyzer
from agents.core.response_validator import ResponseValidator
from typing import Dict, Any, List, Optional
from datetime import datetime
import re

class NutritionAgent(BaseAgent):
    def __init__(self, memory=None):
        super().__init__(memory)
        self.advisor = NutritionAdvisor()
        self.health_context = None
        self.personalization = None
        self.rag = get_rag_integration()
        
        # Configure handoff triggers for nutrition agent
        self.handoff_triggers = {
            'exercise_agent': ['tập', 'gym', 'cardio', 'yoga', 'chạy bộ', 'thể dục', 'vận động'],
            'symptom_agent': ['đau bụng', 'buồn nôn', 'tiêu chảy', 'dị ứng', 'ngộ độc'],
            'mental_health_agent': ['stress', 'lo âu', 'mất ngủ', 'ăn không ngon'],
            'general_health_agent': ['khám', 'xét nghiệm', 'bác sĩ']
        }
        self.system_prompt = """Bạn là chuyên gia dinh dưỡng chuyên nghiệp.

🥗 CHUYÊN MÔN:
- Tư vấn dinh dưỡng cá nhân hóa dựa trên BMI, tuổi, giới tính, mục tiêu
- Tính toán calo, macro (protein/carb/fat)
- Gợi ý thực đơn phù hợp
- Tư vấn thực phẩm bổ sung
- Hướng dẫn ăn uống cho các bệnh lý (tiểu đường, huyết áp, tim mạch...)

🎯 CÁCH TƯ VẤN:

1. **KIỂM TRA THÔNG TIN TRƯỚC KHI HỎI:**
   - ĐỌC KỸ chat history - user có thể đã cung cấp thông tin rồi!
   - Nếu user đã nói "tôi 25 tuổi, nam, 70kg, 175cm" → ĐỪNG HỎI LẠI!
   - Chỉ hỏi thông tin THỰC SỰ còn thiếu
   - Nếu đã đủ (tuổi, giới tính, cân nặng, chiều cao) → ĐƯA KHUYẾN NGHỊ NGAY!

2. **ƯU TIÊN THÔNG TIN:**
   - Câu 1: Mục tiêu (giảm cân/tăng cân/duy trì?)
   - Câu 2: Cân nặng, chiều cao (để tính BMI)
   - Câu 3: Mức độ hoạt động (ít/vừa/nhiều)
   - Câu 4 (nếu cần): Bệnh nền, dị ứng

3. **KHI USER KHÔNG MUỐN CUNG CẤP:**
   - User nói "không biết", "không muốn nói", "tư vấn chung thôi"
   - → DỪNG hỏi, đưa khuyến nghị chung
   - Dựa trên thông tin ĐÃ CÓ để tư vấn

4. **ĐƯA KHUYẾN NGHỊ:**
   - Nếu có đủ thông tin: Tính calo, macro cụ thể
   - Nếu thiếu thông tin: Đưa khuyến nghị chung (400g rau củ, protein đủ, etc.)
   - Gợi ý thực đơn mẫu
   - KHÔNG hỏi thêm nữa

⚠️ AN TOÀN:
- Luôn khuyên gặp bác sĩ dinh dưỡng cho các vấn đề phức tạp
- Cảnh báo về các chế độ ăn kiêng cực đoan
- Lưu ý về dị ứng, bệnh nền

💬 PHONG CÁCH:
- Chuyên nghiệp, rõ ràng, súc tích
- Dùng "tôi" để thể hiện tính chuyên môn
- KHÔNG dùng emoji
- Đưa ra con số cụ thể khi có thể
- Thực tế, không lý thuyết suông
- TỰ NHIÊN, MẠCH LẠC - không lặp lại ý, không copy-paste câu từ context khác
- Nếu hỏi thông tin → Hỏi NGẮN GỌN, TRỰC TIẾP
- KHÔNG dùng câu như "Bạn thử làm theo xem có đỡ không" (đây là câu của bác sĩ chữa bệnh!)"""

    def set_health_context(self, health_context: HealthContext):
        """Inject health context and initialize personalization engine"""
        self.health_context = health_context
        self.personalization = PersonalizationEngine(health_context)

    def handle(self, parameters, chat_history=None):
        """
        Handle nutrition request using LLM for natural conversation

        Args:
            parameters (dict): {
                "user_query": str,
                "user_data": dict (optional)
            }
            chat_history (list): Conversation history

        Returns:
            str: Response message
        """
        user_query = parameters.get("user_query", "")
        user_data = parameters.get("user_data", {})
        
        # Extract and save user info from current message immediately
        self.extract_and_save_user_info(user_query)
        
        # Update memory from chat history
        if chat_history:
            self.update_memory_from_history(chat_history)
        
        # Check if we should hand off to another agent
        if self.should_handoff(user_query, chat_history):
            next_agent = self.suggest_next_agent(user_query)
            if next_agent:
                # Save current nutrition data for next agent
                self.save_agent_data('last_nutrition_advice', {
                    'query': user_query,
                    'user_profile': self.get_user_profile(),
                    'timestamp': datetime.now().isoformat()
                })
                
                # Create handoff message with context
                context = self._generate_nutrition_summary()
                return self.create_handoff_message(next_agent, context, user_query)

        # Use health context if available
        if self.health_context:
            profile = self.health_context.get_user_profile()
            user_data = {
                'age': profile.age,
                'gender': profile.gender,
                'weight': profile.weight,
                'height': profile.height,
                'activity_level': profile.activity_level,
                'health_conditions': profile.health_conditions,
                'dietary_restrictions': profile.dietary_restrictions
            }
        # Extract user data from chat history if not provided
        elif not user_data and chat_history:
            user_data = self._extract_user_data_from_history(chat_history)
            # Save extracted data to shared memory for other agents
            for key, value in user_data.items():
                if value is not None:
                    self.update_user_profile(key, value)

        # Check if user needs personalized advice (BMI, calories, meal plan)
        needs_personalization = self._needs_personalized_advice(user_query, chat_history)

        if needs_personalization:
            # Check if we have enough data
            missing_fields = self._check_missing_data(user_data)

            if missing_fields:
                return self._ask_for_missing_data(missing_fields, user_data, user_query)

            # Generate personalized nutrition advice
            try:
                result = self.advisor.generate_nutrition_advice(user_data)

                # Adapt recommendations using personalization engine
                if self.personalization:
                    adapted_result = self.personalization.adapt_nutrition_plan(result)
                else:
                    adapted_result = result

                response = self._format_nutrition_response(adapted_result, user_data)

                # Persist data to health context
                if self.health_context:
                    self.health_context.add_health_record('nutrition', {
                        'query': user_query,
                        'advice': response,
                        'user_data': user_data,
                        'timestamp': datetime.now().isoformat()
                    })

                return response
            except Exception as e:
                return self._handle_error(e, user_query)
        else:
            # General nutrition question - use LLM directly
            response = self._handle_general_nutrition_query(user_query, chat_history)

            # Persist general query
            if self.health_context:
                self.health_context.add_health_record('nutrition', {
                    'query': user_query,
                    'response': response,
                    'type': 'general',
                    'timestamp': datetime.now().isoformat()
                })

            return response
    
    def _extract_user_data_from_history(self, chat_history):
        """Extract user data from conversation history"""
        user_data = {
            'age': None,
            'gender': None,
            'weight': None,
            'height': None,
            'goal': 'maintenance',
            'activity_level': 'moderate',
            'dietary_restrictions': [],
            'health_conditions': []
        }
        
        all_messages = " ".join([msg[0] for msg in chat_history if msg[0]])
        
        # Extract age
        age_match = re.search(r'(\d+)\s*tuổi|tuổi\s*(\d+)|tôi\s*(\d+)', all_messages.lower())
        if age_match:
            user_data['age'] = int([g for g in age_match.groups() if g][0])
        
        # Extract gender
        if re.search(r'\bnam\b|male|đàn ông', all_messages.lower()):
            user_data['gender'] = 'male'
        elif re.search(r'\bnữ\b|female|đàn bà', all_messages.lower()):
            user_data['gender'] = 'female'
        
        # Extract weight - improved patterns
        weight_match = re.search(r'(?:nặng|cân|weight)?\s*(\d+(?:\.\d+)?)\s*kg|(\d+(?:\.\d+)?)\s*kg', all_messages.lower())
        if weight_match:
            user_data['weight'] = float([g for g in weight_match.groups() if g][0])
        
        # Extract height - improved patterns
        height_cm_match = re.search(r'(?:cao|chiều cao|height)?\s*(\d+(?:\.\d+)?)\s*cm', all_messages.lower())
        if height_cm_match:
            user_data['height'] = float(height_cm_match.group(1))
        else:
            height_m_match = re.search(r'(?:cao|chiều cao|height)?\s*(\d+\.?\d*)\s*m\b', all_messages.lower())
            if height_m_match:
                height = float(height_m_match.group(1))
                if height < 3:  # Convert meters to cm
                    height = height * 100
                user_data['height'] = height
        
        # Extract goal
        if re.search(r'giảm cân|weight loss', all_messages.lower()):
            user_data['goal'] = 'weight_loss'
        elif re.search(r'tăng cân|weight gain', all_messages.lower()):
            user_data['goal'] = 'weight_gain'
        elif re.search(r'tập gym|muscle|cơ bắp', all_messages.lower()):
            user_data['goal'] = 'muscle_building'
        
        return user_data
    
    def _needs_personalized_advice(self, user_query, chat_history):
        """
        Determine if user needs personalized advice (BMI, calories, meal plan)
        or just general nutrition info
        """
        # Keywords that indicate need for personalization
        personalization_keywords = [
            'giảm cân', 'tăng cân', 'bmi', 'calo', 'calorie',
            'thực đơn', 'meal plan', 'chế độ ăn cá nhân',
            'tôi nên ăn gì', 'tư vấn cho tôi', 'phù hợp với tôi'
        ]
        
        query_lower = user_query.lower()
        
        # Check if user explicitly asks for personalized advice
        if any(kw in query_lower for kw in personalization_keywords):
            return True
        
        # Check chat history - if user already provided personal info
        if chat_history:
            all_messages = " ".join([msg[0] for msg in chat_history if msg[0]]).lower()
            if any(kw in all_messages for kw in personalization_keywords):
                return True
        
        # Default: general question
        return False
    
    def _check_missing_data(self, user_data):
        """Check what data is missing - check shared memory first"""
        required = ['age', 'gender', 'weight', 'height']
        
        # Check shared memory for missing fields
        profile = self.get_user_profile()
        for field in required:
            if not user_data.get(field) and profile.get(field):
                user_data[field] = profile[field]
        
        return [field for field in required if not user_data.get(field)]
    
    def _ask_for_missing_data(self, missing_fields, current_data, user_query):
        """Ask for missing data"""
        questions = {
            'age': "bạn bao nhiêu tuổi",
            'gender': "bạn là nam hay nữ",
            'weight': "bạn nặng bao nhiêu kg",
            'height': "bạn cao bao nhiêu cm"
        }
        
        # Build friendly question
        q_list = [questions[f] for f in missing_fields]
        
        if len(q_list) == 1:
            question = q_list[0]
        elif len(q_list) == 2:
            question = f"{q_list[0]}{q_list[1]}"
        else:
            question = ", ".join(q_list[:-1]) + f" và {q_list[-1]}"
        
        return f"""🥗 **Để tư vấn dinh dưỡng chính xác, mình cần biết thêm:**

Cho mình biết {question} nhé?

💡 **Ví dụ:** "Tôi 25 tuổi, nam, nặng 70kg, cao 175cm"

Sau khi có đủ thông tin, mình sẽ tính BMI và đưa ra lời khuyên dinh dưỡng cá nhân hóa cho bạn! 😊"""
    
    def _format_nutrition_response(self, result, user_data):
        """Format nutrition advice into friendly response"""
        bmi_info = result['bmi_analysis']
        targets = result['daily_targets']
        meals = result['meal_suggestions']
        supplements = result['supplement_recommendations']
        
        response = f"""🥗 **Tư Vấn Dinh Dưỡng Cá Nhân Hóa**

👤 **Thông tin của bạn:**
- {user_data['age']} tuổi, {user_data['gender']}, {user_data['weight']}kg, {user_data['height']}cm

📊 **Phân tích BMI:**
- BMI: **{bmi_info['bmi']}** ({bmi_info['category']})
- Lời khuyên: {bmi_info['advice']}

🎯 **Mục tiêu hàng ngày:**
- 🔥 Calo: **{targets['daily_calories']} kcal**
- 🥩 Protein: **{targets['protein']}**
- 🍚 Carb: **{targets['carbs']}**
- 🥑 Chất béo: **{targets['fats']}**
- 💧 Nước: **{targets['water']}**

🍽️ **Gợi ý thực đơn:**

**Sáng:**
- {meals['breakfast'][0]}
- {meals['breakfast'][1]}

**Trưa:**
- {meals['lunch'][0]}
- {meals['lunch'][1]}

**Tối:**
- {meals['dinner'][0]}
- {meals['dinner'][1]}

**Snack:**
- {meals['snacks'][0]}
- {meals['snacks'][1]}
"""
        
        if supplements:
            response += f"\n💊 **Thực phẩm bổ sung gợi ý:**\n"
            response += "\n".join([f"- {s}" for s in supplements[:4]])
        
        response += f"""

🤖 **Lời khuyên chuyên gia:**
{result['personalized_advice'][:600]}...

---

⚠️ *Đây là tư vấn tham khảo. Với các vấn đề phức tạp, hãy gặp bác sĩ dinh dưỡng nhé!*

💬 Bạn có câu hỏi gì về chế độ ăn này không? Hoặc muốn mình điều chỉnh gì không? 😊"""
        
        return response
    
    def _build_nutrition_context_instruction(self, user_query, chat_history):
        """
        Build context instruction for nutrition queries
        """
        # Check if user is answering comparison self-assessment
        if chat_history and len(chat_history) > 0:
            last_bot_msg = chat_history[-1][1] if len(chat_history[-1]) > 1 else ""
            if "TỰ KIỂM TRA" in last_bot_msg or "Bạn trả lời" in last_bot_msg:
                return """\n\nPHASE: PHÂN TÍCH LỰA CHỌN DINH DƯỠNG
User vừa trả lời các câu hỏi. Phân tích:

1. NHẬN DIỆN PHÙ HỢP (dựa vào RAG):
   - Đọc kỹ mục tiêu, lifestyle, sở thích
   - So sánh với đặc điểm của từng lựa chọn
   - Đưa ra lựa chọn PHÙ HỢP NHẤT

2. GIẢI THÍCH:
   - Vì sao lựa chọn này phù hợp
   - Lợi ích cụ thể cho user
   - Lưu ý khi thực hiện

3. HƯỚNG DẪN BẮT ĐẦU:
   - Cách bắt đầu cụ thể
   - Thực đơn mẫu (nếu cần)
   - Tips để duy trì

4. Kết thúc: "Bạn cần hướng dẫn chi tiết hơn không?"
KHÔNG nói "Dựa trên thông tin"."""
        
        # Check if asking comparison question
        if any(phrase in user_query.lower() for phrase in [
            'nên ăn', 'hay', 'hoặc', 'khác nhau thế nào',
            'chọn', 'so sánh', 'tốt hơn'
        ]):
            return """\n\nPHASE: SO SÁNH DINH DƯỠNG (GENERIC)
User muốn so sánh các lựa chọn dinh dưỡng. Sử dụng RAG để:

1. XÁC ĐỊNH các lựa chọn (từ user query):
   - Trích xuất diets/foods user đề cập
   - Hoặc tìm các lựa chọn liên quan

2. TẠO BẢNG SO SÁNH:
   Format:
   **[Lựa chọn A]:**
   • Macros: [protein/carb/fat]
   • Ưu điểm: [benefits]
   • Nhược điểm: [drawbacks]
   • Phù hợp cho: [who]
   
   **[Lựa chọn B]:**
   • Macros: [protein/carb/fat]
   • Ưu điểm: [benefits]
   • Nhược điểm: [drawbacks]
   • Phù hợp cho: [who]
   
   **Điểm khác biệt chính:** [key differences]

3. CÂU HỊI TỰ KIỂM TRA:
   Tạo 3-5 câu hỏi giúp user tự đánh giá:
   • Mục tiêu của bạn?
   • Lifestyle như thế nào?
   • Có hạn chế gì không?
   • Thời gian chuẩn bị?

4. Kết thúc: "Bạn trả lời giúp mình để recommend phù hợp nhé!"

QUAN TRỌNG: Dùng RAG knowledge, KHÔNG hard-code."""
        
        # Normal advice
        return """\n\nĐưa ra lời khuyên dinh dưỡng cụ thể, thực tế.
KHÔNG quá lý thuyết.
KHÔNG nói "Dựa trên thông tin"."""
    
    def _handle_general_nutrition_query(self, user_query, chat_history):
        """Handle general nutrition questions using LLM + RAG with comparison support"""
        from config.settings import client, MODEL

        try:
            # Smart RAG - only query when needed (inherit from BaseAgent)
            rag_answer = ''
            rag_sources = []
            
            if self.should_use_rag(user_query, chat_history):
                rag_result = self.rag.query_nutrition(user_query)
                rag_answer = rag_result.get('answer', '')
                rag_sources = rag_result.get('source_docs', [])

            # Build conversation context with RAG context
            rag_context = f"Dựa trên kiến thức từ cơ sở dữ liệu:\n{rag_answer}\n\n" if rag_answer else ""

            messages = [{"role": "system", "content": self.system_prompt}]

            # Add RAG context if available
            if rag_context:
                messages.append({"role": "system", "content": f"Thông tin tham khảo từ cơ sở dữ liệu:\n{rag_context}"})

            # Add chat history (last 5 exchanges)
            if chat_history:
                recent_history = chat_history[-5:] if len(chat_history) > 5 else chat_history
                for user_msg, bot_msg in recent_history:
                    if user_msg:
                        messages.append({"role": "user", "content": user_msg})
                    if bot_msg:
                        messages.append({"role": "assistant", "content": bot_msg})

            # Add current query with context instruction
            context_prompt = self._build_nutrition_context_instruction(user_query, chat_history)
            messages.append({"role": "user", "content": user_query + context_prompt})

            # Get LLM response
            response = client.chat.completions.create(
                model=MODEL,
                messages=messages,
                temperature=0.7,
                max_tokens=500
            )

            llm_response = response.choices[0].message.content

            # Add sources using RAG integration formatter (FIXED!)
            if rag_sources:
                formatted_response = self.rag.format_response_with_sources({
                    'answer': llm_response,
                    'source_docs': rag_sources
                })
                return formatted_response

            return llm_response

        except Exception as e:
            return f"""Xin lỗi, mình gặp lỗi kỹ thuật. Bạn có thể:
1. Thử lại câu hỏi
2. Hỏi cách khác
3. Liên hệ hỗ trợ

Chi tiết lỗi: {str(e)}"""
    
    def should_handoff(self, user_query: str, chat_history: Optional[List] = None) -> bool:
        """
        Override base method - Determine if should hand off to another agent
        
        Specific triggers for nutrition agent:
        - User asks about exercise/workout
        - User mentions symptoms (stomach pain, nausea)
        - User asks about mental health affecting eating
        """
        query_lower = user_query.lower()
        
        # Check each agent's triggers
        for agent, triggers in self.handoff_triggers.items():
            if any(trigger in query_lower for trigger in triggers):
                # Don't handoff if we're in the middle of nutrition consultation
                if chat_history and self._is_mid_consultation(chat_history):
                    return False
                return True
        
        return False
    
    def suggest_next_agent(self, user_query: str) -> Optional[str]:
        """Override base method - Suggest which agent to hand off to based on query"""
        query_lower = user_query.lower()
        
        # Priority order for handoff
        if any(trigger in query_lower for trigger in self.handoff_triggers.get('symptom_agent', [])):
            return 'symptom_agent'
        
        if any(trigger in query_lower for trigger in self.handoff_triggers.get('exercise_agent', [])):
            return 'exercise_agent'
        
        if any(trigger in query_lower for trigger in self.handoff_triggers.get('mental_health_agent', [])):
            return 'mental_health_agent'
        
        if any(trigger in query_lower for trigger in self.handoff_triggers.get('general_health_agent', [])):
            return 'general_health_agent'
        
        return None
    
    def _is_mid_consultation(self, chat_history: List) -> bool:
        """Check if we're in the middle of nutrition consultation"""
        if not chat_history or len(chat_history) < 2:
            return False
        
        # Check last bot response
        last_bot_response = chat_history[-1][1] if len(chat_history[-1]) > 1 else ""
        
        # If we just asked for user data, don't handoff
        if any(phrase in last_bot_response for phrase in [
            "cân nặng", "chiều cao", "tuổi", "giới tính", "mục tiêu"
        ]):
            return True
        
        return False
    
    def _generate_nutrition_summary(self) -> str:
        """Generate summary of nutrition advice for handoff"""
        nutrition_data = self.get_agent_data('nutrition_plan')
        user_profile = self.get_user_profile()
        
        # Natural summary without robotic prefix
        summary_parts = []
        
        if nutrition_data and isinstance(nutrition_data, dict):
            if 'bmi_analysis' in nutrition_data:
                bmi = nutrition_data['bmi_analysis']
                summary_parts.append(f"BMI: {bmi.get('bmi', 'N/A')} ({bmi.get('category', 'N/A')})")
            
            if 'daily_targets' in nutrition_data:
                targets = nutrition_data['daily_targets']
                summary_parts.append(f"Calo: {targets.get('calories', 'N/A')} kcal/ngày")
        
        if user_profile and user_profile.get('goal'):
            summary_parts.append(f"Mục tiêu: {user_profile['goal']}")
        
        return " | ".join(summary_parts)[:100] if summary_parts else ""
    
    def _handle_error(self, error, user_query):
        """Handle errors gracefully"""
        return f"""Xin lỗi, mình gặp chút vấn đề khi tạo tư vấn dinh dưỡng. 😅

Lỗi: {str(error)}

Bạn có thể thử:
1. Cung cấp lại thông tin: tuổi, giới tính, cân nặng, chiều cao
2. Hỏi câu hỏi cụ thể hơn về dinh dưỡng
3. Hoặc mình có thể tư vấn về chủ đề sức khỏe khác

Bạn muốn thử lại không? 💙"""