File size: 36,798 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
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
"""
Symptom Agent - Specialized agent for symptom assessment using OPQRST method
"""

from config.settings import client, MODEL
from health_data import HealthContext
from health_analysis import HealthAnalyzer
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 SymptomAgent(BaseAgent):
    def __init__(self, memory=None):
        super().__init__(memory)
        self.health_context = None
        self.analyzer = None
        self.rag = get_rag_integration()
        
        # Configure handoff triggers for symptom agent
        self.handoff_triggers = {
            'nutrition_agent': ['ăn gì', 'thực đơn', 'dinh dưỡng'],
            'exercise_agent': ['tập luyện', 'vận động', 'phục hồi chức năng'],
            'mental_health_agent': ['lo âu', 'stress', 'mất ngủ do lo'],
            'general_health_agent': ['khám tổng quát', 'xét nghiệm', 'kiểm tra sức khỏe']
        }
        self.system_prompt = """Bạn là bác sĩ tư vấn chuyên nghiệp.

🩺 NHIỆM VỤ:
Thu thập thông tin triệu chứng một cách có hệ thống và chuyên nghiệp.

📋 PHƯƠNG PHÁP OPQRST (Hỏi tự nhiên, KHÔNG dùng template):

**Onset (Khởi phát):**
- Khi nào bắt đầu? Đột ngột hay từ từ?
- Ví dụ tự nhiên: 
  * Đau đầu: "Đau đầu từ khi nào rồi bạn? Đột ngột hay từ từ?"
  * Đầy bụng: "Cảm giác đầy bụng này xuất hiện từ bao giờ? Sau khi ăn hay suốt ngày?"

**Quality (Đặc điểm):**
- Mô tả cảm giác như thế nào?
- Ví dụ tự nhiên:
  * Đau đầu: "Đau kiểu gì? Đau nhói, tức, đập thình thình, hay nặng nề?"
  * Đầy bụng: "Cảm giác đầy như thế nào? Căng cứng, khó tiêu, hay đau tức?"

**Region (Vị trí):**
- Ở đâu? Có lan ra không?
- Ví dụ tự nhiên:
  * Đau đầu: "Đau ở đâu? Trán, thái dương, sau gáy, hay cả đầu?"
  * Đầy bụng: "Đầy ở vùng nào? Trên rốn, dưới rốn, hay toàn bộ bụng?"

**Provocation/Palliation (Yếu tố ảnh hưởng):**
- Gì làm tệ/đỡ hơn?
- Ví dụ tự nhiên:
  * Đau đầu: "Có gì làm đau nhiều hơn không? Ánh sáng, tiếng ồn, stress? Nghỉ ngơi có đỡ không?"
  * Đầy bụng: "Ăn gì làm nặng hơn? Có loại thức ăn nào làm đỡ không?"

**Severity (Mức độ):**
- Mức độ và triệu chứng kèm theo?
- Ví dụ tự nhiên:
  * Đau đầu: "Đau nhiều không? Có buồn nôn, nhìn mờ, hoặc sợ ánh sáng không?"
  * Đầy bụng: "Đầy nhiều không? Có ợ hơi, buồn nôn, hoặc khó thở không?"

**Timing (Thời gian):**
- Khi nào xuất hiện? Liên tục hay từng đợt?
- Ví dụ tự nhiên:
  * Đau đầu: "Đau suốt hay từng cơn? Thường xuất hiện lúc nào trong ngày?"
  * Đầy bụng: "Đầy suốt ngày hay chỉ sau ăn? Kéo dài bao lâu?"

🎯 NGUYÊN TẮC QUAN TRỌNG:

1. **HỎI TỐI ĐA 3-4 CÂU:**
   - Không hỏi mãi theo template OPQRST
   - Hỏi 3-4 câu quan trọng nhất
   - Nếu user không biết/không rõ → Chuyển sang đưa khuyến nghị

2. **ƯU TIÊN THÔNG TIN:**
   - Câu 1: Thời gian xuất hiện (khi nào?)
   - Câu 2: Đặc điểm (đau như thế nào?)
   - Câu 3: Mức độ (có triệu chứng kèm theo?)
   - Câu 4 (nếu cần): Yếu tố ảnh hưởng

3. **KHI USER KHÔNG BIẾT:**
   - User nói "không biết", "không rõ", "không chắc"
   - → DỪNG hỏi, chuyển sang đưa khuyến nghị
   - Dựa trên thông tin ĐÃ CÓ để tư vấn

4. **ĐƯA KHUYẾN NGHỊ:**
   - Tổng hợp thông tin đã thu thập
   - Đưa ra các biện pháp tự chăm sóc phù hợp
   - Khuyên gặp bác sĩ nếu cần
   - KHÔNG hỏi thêm nữa

🚨 RED FLAGS - Khuyên gặp bác sĩ NGAY:
- Đau ngực + khó thở → Nghi ngờ tim
- Đau đầu dữ dội đột ngột + cứng gáy + sốt → Nghi ngờ màng não
- Yếu đột ngột một bên → Nghi ngờ đột quỵ
- Đau bụng dữ dội → Nghi ngờ ruột thừa/cấp cứu
- Ho/nôn ra máu
- Ý định tự tử

⚠️ AN TOÀN & GIỚI HẠN:
- KHÔNG chẩn đoán bệnh
- KHÔNG kê đơn thuốc
- KHÔNG tạo giáo án tập luyện (đó là việc của exercise_agent)
- KHÔNG tư vấn dinh dưỡng chi tiết (đó là việc của nutrition_agent)
- CHỈ tập trung vào ĐÁNH GIÁ TRIỆU CHỨNG
- Luôn khuyên gặp bác sĩ với triệu chứng nghiêm trọng
- Với red flags → khuyên đi cấp cứu NGAY

💬 PHONG CÁCH:
- Tự nhiên, conversational - như đang nói chuyện
- KHÔNG formal, KHÔNG "Dựa trên thông tin bạn cung cấp"
- Emoji tối thiểu (chỉ khi thật sự cần)
- Ngắn gọn, đi thẳng vấn đề
- KHÔNG vừa hỏi vừa khuyên trong cùng 1 response

🏥 KHI USER HỎI ĐỊA CHỈ BỆNH VIỆN:
- ĐỪNG lặp lại triệu chứng nếu đã nói rồi!
- Nếu user hỏi "tôi muốn đi khám", "bệnh viện nào tốt", "cho tôi địa chỉ"
  → ĐI THẲNG VÀO ĐỊA CHỈ, không cần nhắc lại "Triệu chứng đau đầu và mất ngủ..."
- Format địa chỉ bệnh viện:

**Bệnh viện/Phòng khám gần [địa điểm]:**

1. **Tên bệnh viện**
   - Địa chỉ: [địa chỉ đầy đủ]
   - Chuyên khoa: [chuyên khoa liên quan]
   - SĐT: [nếu có]

**Khi nào cần đi khám:** [điều kiện]

- KHÔNG dùng "Giải pháp:" cho danh sách bệnh viện
- KHÔNG mix địa chỉ với home remedies (thiền, yoga) trong cùng list

📝 VÍ DỤ WORKFLOW:

**Tình huống: User đau bụng**

Turn 1:
User: "Tôi đau bụng"
Bot: "Bạn bắt đầu bị đau từ khi nào vậy?"

Turn 2:
User: "Mới xuất hiện, đau âm ỉ"
Bot: "Đau ở vị trí nào? Trên rốn, dưới rốn, hay toàn bộ bụng?"

Turn 3:
User: "Phía trên rốn"
Bot: "Có triệu chứng kèm theo như buồn nôn, ợ hơi, hoặc đầy bụng không?"

Turn 4:
User: "Không biết, giờ tôi muốn làm sao cho hết đau"
Bot: "Dựa trên thông tin bạn cung cấp (đau âm ỉ vùng thượng vị, mới xuất hiện), 
     đây có thể là triệu chứng của viêm dạ dày hoặc khó tiêu. Khuyến nghị:
     
     1. Nghỉ ngơi, tránh căng thẳng
     2. Ăn nhẹ, tránh thức ăn cay nóng, cà phê, rượu
     3. Có thể dùng thuốc giảm acid (theo chỉ định)
     
     Nếu đau không giảm sau 24h hoặc xuất hiện triệu chứng nặng hơn 
     (nôn ra máu, đau dữ dội), hãy đến bệnh viện ngay."

→ DỪNG hỏi, đưa khuyến nghị dựa trên thông tin có!

🎯 NGUYÊN TẮC QUAN TRỌNG:

1. **ƯU TIÊN GIẢI PHÁP KHI USER CẦN:**
   - Nếu user nói "đau quá", "khó chịu", "làm sao" → Đưa giải pháp NGAY
   - Không hỏi thêm khi user đang cần giúp đỡ khẩn cấp
   - Cấu trúc: Giải pháp ngay → Thuốc (nếu cần) → Cảnh báo → Phòng ngừa
   
2. **CHỈ HỎI KHI CẦN THIẾT:**
   - Tối đa 1-2 câu hỏi trong toàn bộ conversation
   - Nếu đã có đủ info cơ bản → Đưa lời khuyên luôn
   - Nếu user không muốn trả lời → Đưa lời khuyên chung

3. **EMOJI - Dùng tiết kiệm:**
   - KHÔNG dùng 😔 cho mọi triệu chứng
   - Chỉ dùng khi thực sự cần (trấn an, động viên)
   - Có thể không dùng emoji nếu câu đã đủ ấm áp

4. **PHÂN TÍCH CONTEXT:**
   - Nếu là câu hỏi ĐẦU TIÊN → có thể đồng cảm
   - Nếu đang FOLLOW-UP → đi thẳng vào câu hỏi, không cần lặp lại đồng cảm
   - Nếu user đã trả lời nhiều câu → cảm ơn họ, không cần đồng cảm nữa

VÍ DỤ CÁCH HỎI ĐA DẠNG:

❌ SAI (Lặp lại pattern):
Turn 1: "Đau đầu khó chịu lắm nhỉ 😔 Cho mình hỏi..."
Turn 2: "Đau nhói khó chịu quá 😔 Mà này..."
Turn 3: "Sợ ánh sáng khó chịu lắm 😔 Còn về..."
→ LẶP LẠI "khó chịu" + 😔 = MÁY MÓC!

✅ ĐÚNG (Đa dạng, tự nhiên):
Turn 1: "Mình hiểu rồi. Cho mình hỏi, bạn bị đau từ khi nào?"
Turn 2: "À, đau nhói từ 2 ngày trước nhỉ. Vậy đau ở đâu? Trán, thái dương, hay cả đầu?"
Turn 3: "Được rồi. Có gì làm đau nhiều hơn không? Ví dụ ánh sáng, tiếng ồn, hay stress?"
→ BIẾN ĐỔI, TỰ NHIÊN!

VÍ DỤ THEO TRIỆU CHỨNG:

**Đau đầu - Variations:**
- "Cho mình hỏi, bạn bị đau từ khi nào?"
- "Mình hiểu. Đau đầu xuất hiện đột ngột hay từ từ?"
- "Để mình giúp bạn tìm hiểu. Đau kiểu gì? Nhói, tức, hay đập thình thình?"

**Đầy bụng - Variations:**
- "Cảm giác đầy này xuất hiện từ bao giờ?"
- "Liên quan đến ăn uống không? Sau khi ăn hay suốt ngày?"
- "Có ợ hơi hoặc khó tiêu không?"

**Đau lưng - Variations:**
- "Bạn bị đau lưng từ khi nào?"
- "Có bị chấn thương hay làm gì nặng không?"
- "Đau ở vị trí nào? Lưng trên, giữa, hay dưới?"

QUAN TRỌNG: 
- Mỗi triệu chứng cần cách hỏi KHÁC NHAU
- Mỗi TURN trong conversation cần cách diễn đạt KHÁC NHAU
- KHÔNG lặp lại patterns - hãy TỰ NHIÊN như người thật!"""

    def set_health_context(self, health_context: HealthContext):
        """Inject health context and initialize health analyzer"""
        self.health_context = health_context
        self.analyzer = HealthAnalyzer(health_context)

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

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

        Returns:
            str: Response message
        """
        user_query = parameters.get("user_query", "")

        # Check for red flags first
        red_flag_response = self._check_red_flags(user_query, chat_history)
        if red_flag_response:
            # Persist red flag alert
            if self.health_context:
                self.health_context.add_health_record('symptom', {
                    'query': user_query,
                    'type': 'red_flag_alert',
                    'response': red_flag_response,
                    'timestamp': datetime.now().isoformat()
                })
            return red_flag_response

        # Use LLM to naturally assess symptoms and ask questions
        response = self._natural_symptom_assessment(user_query, chat_history)

        # Analyze health risks if analyzer is available
        if self.analyzer:
            risks = self.analyzer.identify_health_risks()
            predictions = self.analyzer.predict_disease_risk()
        else:
            risks = []
            predictions = {}

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

        return response
    
    def _build_context_instruction(self, context, chat_history, user_query=""):
        """
        Build clear instruction based on conversation stage
        """
        stage = context.get('conversation_stage', 0)
        urgency = context.get('urgency', 'medium')
        is_vague = context.get('is_vague', False)
        
        # PRIORITY: Handle vague/unclear queries first
        if is_vague and stage == 0:
            return """\n\nPHASE: LÀM RÕ Ý ĐỊNH (VỚI GỢI Ý)
User query không rõ ràng. Giúp user bằng GỢI Ý CỤ THỂ:

1. ACKNOWLEDGE + HỎI VỚI GỢI Ý:
   Format: "Mình thấy bạn [cảm giác user nói]. Bạn có thể cho mình biết rõ hơn không? Ví dụ như:
   • [Gợi ý 1 liên quan]
   • [Gợi ý 2 liên quan]
   • [Gợi ý 3 liên quan]
   • Hoặc vấn đề khác?"

2. GỢI Ý DỰA VÀO TỪ KHÓA:
   - "mệt" → gợi ý: mệt cơ thể, mệt tinh thần, mất ngủ, stress
   - "không khỏe" → gợi ý: đau đầu, buồn nôn, chóng mặt, sốt
   - "khó chịu" → gợi ý: đau bụng, khó tiêu, lo âu, căng thẳng
   - "không ổn" → gợi ý: sức khỏe thể chất, tinh thần, dinh dưỡng

3. VÍ DỤ CỤ THỂ:
   User: "tôi mệt"
   Bot: "Mình thấy bạn đang cảm thấy mệt. Bạn có thể nói rõ hơn không? Ví dụ:
   • Mệt cơ thể, không có sức?
   • Mệt tinh thần, stress?
   • Mất ngủ, ngủ không ngon?
   • Hay vấn đề khác?"

QUAN TRỌNG: 
- Dùng từ khóa user nói để tạo gợi ý phù hợp
- 3-4 gợi ý cụ thể
- Luôn có "hoặc vấn đề khác" để mở rộng
- Tự nhiên, không formal"""
        
        # Assessment phase (first 1-2 turns)
        if stage <= 1:
            return """\n\nPHASE: ĐÁNH GIÁ TRIỆU CHỨNG
Hỏi 1-2 câu ngắn để hiểu rõ:
- Thời gian xuất hiện
- Vị trí đau
- Mức độ đau
CHỈ HỎi, KHÔNG đưa lời khuyên."""
        
        # High urgency - skip to solutions
        if urgency == 'high':
            return """\n\nPHASE: GIẢI PHÁP KHẨN CẤP
User cần giúp NGAY. Đưa ra:
1. Giải pháp tức thời (2-3 điềm)
2. Thuốc có thể dùng + disclaimer
3. Cảnh báo khi nào đi khám
KHÔNG hỏi thêm."""
        
        # Check if user is answering self-assessment questions
        if chat_history and len(chat_history) > 0:
            last_bot_msg = chat_history[-1][1] if len(chat_history[-1]) > 1 else ""
            # More specific detection - must have "Câu hỏi tự kiểm tra" section
            if ("Câu hỏi tự kiểm tra" in last_bot_msg or "### Câu hỏi tự kiểm tra" in last_bot_msg) and len(user_query) > 30:
                return """\n\nPHASE: PHÂN TÍCH KẾT QUẢ TỰ KIỂM TRA
User vừa trả lời self-assessment. Phân tích THÔNG MINH dựa trên ĐÚNG CONTEXT:

QUAN TRỌNG: 
- CHỈ phân tích dựa trên triệu chứng user VỪA NÓI
- KHÔNG dùng thông tin từ RAG không liên quan
- KHÔNG nhầm lẫn với các bệnh khác

1. NHẬN DIỆN PATTERN (dựa vào RAG knowledge):
   - Đọc kỹ triệu chứng user mô tả
   - So sánh với các bệnh có thể có (từ RAG)
   - Tìm điểm KHÁC BIỆT quan trọng
   - Đưa ra 1-2 khả năng phù hợp nhất

2. ĐÁNH GIÁ MỨC ĐỘ NGHIÊM TRỌNG:
   - Có red flags? → "CẦN KHÁM NGAY"
   - Triệu chứng nặng? → "Nên đi khám sớm"
   - Triệu chứng nhẹ? → "Thử giải pháp, không đỡ thì khám"

3. LUÔN DISCLAIMER:
   "Đây chỉ là đánh giá sơ bộ dựa trên triệu chứng. Bác sĩ sẽ chẩn đoán chính xác qua khám lâm sàng và xét nghiệm."

4. NEXT STEPS:
   - Giải pháp tạm thời (nếu không nguy hiểm)
   - Khi nào cần đi khám
   - "Bạn muốn biết thêm về [bệnh nghi ngờ] không?"

QUAN TRỌNG: Phân tích GENERIC cho MỌI triệu chứng, KHÔNG hard-code."""
        
        # Check if user asking "how to know" / differential diagnosis
        if any(phrase in user_query.lower() for phrase in [
            'làm sao biết', 'làm sao để biết', 'phân biệt',
            'khác nhau thế nào', 'hay', 'hoặc'
        ]):
            return """\n\nPHASE: HƯỚNG DẪN TỰ KIỂM TRA (GENERIC)
User muốn phân biệt các bệnh/tình trạng. Sử dụng RAG để:

1. XÁC ĐỊNH các bệnh có thể (từ user query):
   - Trích xuất các bệnh user đề cập
   - Hoặc tìm các bệnh liên quan đến triệu chứng

2. TẠO BẢNG SO SÁNH:
   Format:
   **[Bệnh A]:**
   • Triệu chứng đặc trưng 1
   • Triệu chứng đặc trưng 2
   • Đặc điểm riêng
   
   **[Bệnh B]:**
   • Triệu chứng đặc trưng 1
   • Triệu chứng đặc trưng 2
   • Đặc điểm riêng
   
   **Điểm khác biệt chính:** [Highlight 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á:
   • Về thời gian xuất hiện
   • Về đặc điểm triệu chứng
   • Về yếu tố kích hoạt
   • Về triệu chứng kèm theo

4. LUÔN DISCLAIMER:
   "Tuy nhiên, chỉ bác sĩ mới chẩn đoán chính xác qua khám lâm sàng và xét nghiệm."

5. Kết thúc: "Sau khi tự kiểm tra, bạn có thể cho mình biết kết quả để mình phân tích nhé!"

QUAN TRỌNG: Dùng RAG knowledge, KHÔNG hard-code bệnh cụ thể."""
        
        # Advice phase (have enough info)
        return """\n\nPHASE: TƯ VẤN & PHÒNG NGỪÀ
Đưa ra:
1. Đánh giá ngắn (1 câu): Triệu chứng có thể là gì
2. Giải pháp (3-4 điểm cụ thể)
3. Khi nào cần đi khám
4. Kết thúc: "Có gì thắc mắc cứ hỏi mình nhé!"
KHÔNG nói "Dựa trên thông tin"."""
    
    def _validate_response(self, response, context):
        """
        Validate if LLM response follows instructions
        Returns: (is_valid, list_of_issues)
        """
        issues = []
        stage = context.get('conversation_stage', 0)
        
        # Check for bad formal phrases
        bad_phrases = [
            "Dựa trên thông tin bạn cung cấp",
            "Dựa vào thông tin",
            "Theo thông tin bạn đưa ra"
        ]
        
        for phrase in bad_phrases:
            if phrase.lower() in response.lower():
                issues.append(f"Dùng cụm từ formal: '{phrase}'")
                break
        
        # Assessment phase: should ask, not advise
        if stage <= 1:
            advice_indicators = [
                "khuyến nghị", "nên", "hãy", "bạn thử",
                "giải pháp", "cách xử lý"
            ]
            has_advice = any(ind in response.lower() for ind in advice_indicators)
            has_question = '?' in response
            
            if has_advice and not has_question:
                issues.append("Đưa lời khuyên quá sớm (phase assessment)")
        
        # Check if both asking and advising (bad)
        if '?' in response:
            advice_count = sum(1 for ind in ["khuyến nghị", "nên", "hãy thử"] if ind in response.lower())
            if advice_count >= 2:
                issues.append("Vừa hỏi vừa khuyên trong cùng response")
        
        is_valid = len(issues) == 0
        return is_valid, issues
    
    def _post_process_response(self, response, context):
        """
        Clean up LLM response to ensure quality
        """
        # Remove formal phrases
        bad_phrases = [
            "Dựa trên thông tin bạn cung cấp",
            "Dựa vào thông tin",
            "Theo thông tin bạn đưa ra",
            "Từ thông tin trên"
        ]
        
        for phrase in bad_phrases:
            response = response.replace(phrase, "")
            response = response.replace(phrase.lower(), "")
        
        # Clean up extra whitespace
        response = "\n".join(line.strip() for line in response.split("\n") if line.strip())
        
        return response
    
    def _check_red_flags(self, user_query, chat_history):
        """Check for dangerous symptoms that need immediate medical attention"""
        all_text = user_query.lower()
        if chat_history:
            all_text += " " + " ".join([msg[0].lower() for msg in chat_history if msg[0]])
        
        red_flags = {
            "heart_attack": {
                "keywords": ["đau ngực", "khó thở", "chest pain", "đau tim"],
                "message": """🚨 **CẢNH BÁO KHẨN CẤP**

Triệu chứng của bạn có thể liên quan đến **cơn đau tim**. Đây là tình huống khẩn cấp!

⚠️ **HÃY LÀM NGAY:**
1. **Gọi cấp cứu 115** hoặc đến bệnh viện GẤP
2. Ngồi nghỉ, không vận động
3. Nếu có aspirin, nhai 1 viên (nếu không dị ứng)
4. Thông báo cho người thân

🚑 **KHÔNG TỰ LÁI XE** - Gọi xe cấp cứu hoặc nhờ người khác đưa đi

Sức khỏe của bạn là ưu tiên số 1. Hãy đi khám NGAY nhé! 💙"""
            },
            "stroke": {
                "keywords": ["yếu một bên", "méo miệng", "nói khó", "tê nửa người"],
                "message": """🚨 **CẢNH BÁO KHẨN CẤP - NGUY CƠ ĐỘT QUỴ**

Triệu chứng của bạn có thể là **đột quỵ não**. Mỗi phút đều quan trọng!

⚠️ **HÃY LÀM NGAY:**
1. **Gọi cấp cứu 115 NGAY LẬP TỨC**
2. Ghi nhớ thời gian triệu chứng bắt đầu
3. Nằm nghỉ, đầu hơi cao
4. KHÔNG cho ăn uống gì

🚑 Đây là cấp cứu y tế. Hãy đi bệnh viện NGAY! Thời gian vàng chỉ có 3-4 giờ!"""
            },
            "meningitis": {
                "keywords": ["đau đầu dữ dội", "cứng gáy", "sốt cao", "buồn nôn"],
                "message": """🚨 **CẢNH BÁO - CẦN KHÁM NGAY**

Triệu chứng đau đầu dữ dội + cứng gáy + sốt có thể là **viêm màng não** - rất nguy hiểm!

⚠️ **HÃY LÀM NGAY:**
1. Đi bệnh viện hoặc gọi cấp cứu 115
2. Không trì hoãn
3. Thông báo bác sĩ về tất cả triệu chứng

Đây là tình huống nghiêm trọng. Hãy đi khám NGAY nhé! 🏥"""
            },
            "severe_abdominal": {
                "keywords": ["đau bụng dữ dội", "đau bụng không chịu nổi", "đau bụng cấp"],
                "message": """⚠️ **CẦN KHÁM BÁC SĨ NGAY**

Đau bụng dữ dội có thể là nhiều nguyên nhân nghiêm trọng (viêm ruột thừa, sỏi mật, thủng dạ dày...).

🏥 **Hãy đi khám ngay nếu:**
- Đau không giảm sau 1-2 giờ
- Kèm sốt, nôn, tiêu chảy
- Bụng cứng, đau khi ấn
- Có máu trong phân

Đừng chần chừ, hãy đi bệnh viện để được khám và xử lý kịp thời nhé!"""
            }
        }
        
        for flag_type, flag_data in red_flags.items():
            if any(keyword in all_text for keyword in flag_data["keywords"]):
                return flag_data["message"]
        
        return None
    
    def _needs_rag_query(self, user_query, chat_history):
        """Determine if RAG query is needed for this question"""
        # Simple questions don't need RAG
        simple_patterns = [
            'đau', 'bị', 'khó tiêu', 'mệt', 'chóng mặt', 'buồn nôn',
            'sốt', 'ho', 'cảm', 'đau đầu', 'đau bụng', 'đau lưng'
        ]
        
        # Check if it's a simple symptom report (first turn)
        if not chat_history or len(chat_history) == 0:
            # First message - usually just symptom report
            if any(pattern in user_query.lower() for pattern in simple_patterns):
                return False  # Don't need RAG for initial symptom report
        
        # Need RAG for complex questions or specific medical info
        complex_patterns = [
            'nguyên nhân', 'tại sao', 'làm sao', 'điều trị', 'thuốc',
            'phòng ngừa', 'biến chứng', 'triệu chứng của', 'bệnh gì'
        ]
        
        if any(pattern in user_query.lower() for pattern in complex_patterns):
            return True
        
        # Default: don't use RAG for conversational turns
        return False
    
    def _natural_symptom_assessment(self, user_query, chat_history):
        """Use LLM to naturally assess symptoms with context awareness"""
        try:
            # Analyze user context and intent
            context = ContextAnalyzer.analyze_user_intent(user_query, chat_history)
            response_structure = ContextAnalyzer.determine_response_structure(context)
            
            # Smart RAG - only query when needed
            rag_answer = ''
            rag_sources = []
            
            if self._needs_rag_query(user_query, chat_history):
                # Build context-aware RAG query
                # Include recent conversation context to get relevant results
                if chat_history and len(chat_history) > 0:
                    last_exchange = chat_history[-1]
                    last_bot_msg = last_exchange[1] if len(last_exchange) > 1 else ""
                    # If answering self-assessment, include the diseases mentioned
                    if "Câu hỏi tự kiểm tra" in last_bot_msg:
                        # Extract diseases from last bot message
                        import re
                        diseases = re.findall(r'\*\*\[(.*?)\]:\*\*', last_bot_msg)
                        if diseases:
                            # Query specifically about those diseases
                            enhanced_query = f"{user_query} (liên quan đến: {', '.join(diseases)})"
                            rag_result = self.rag.query_health(enhanced_query)
                        else:
                            rag_result = self.rag.query_health(user_query)
                    else:
                        rag_result = self.rag.query_health(user_query)
                else:
                    rag_result = self.rag.query_health(user_query)
                    
                rag_answer = rag_result.get('answer', '')
                rag_sources = rag_result.get('source_docs', [])

            # Build conversation context
            messages = [{"role": "system", "content": self.system_prompt}]

            # Add RAG context if available with explicit filtering instruction
            if rag_answer:
                # Add warning about context relevance
                rag_instruction = f"""Thông tin tham khảo từ cơ sở dữ liệu:\n{rag_answer}

⚠️ QUAN TRỌNG: 
- CHỈ sử dụng thông tin LIÊN QUAN đến triệu chứng user đang nói
- KHÔNG dùng thông tin về bệnh khác không liên quan
- Nếu thông tin RAG không match với triệu chứng user → BỎ QUA"""
                messages.append({"role": "system", "content": rag_instruction})

            # Add chat history (last 5 exchanges for context)
            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})

            # Build context-aware instruction
            context_prompt = self._build_context_instruction(context, chat_history, user_query)
            
            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
            
            # CRITICAL: Check for context mismatch (e.g., talking about brain when discussing stomach)
            if chat_history and len(chat_history) > 0:
                # Get recent symptoms mentioned
                recent_symptoms = []
                for msg, _ in chat_history[-3:]:
                    if msg:
                        recent_symptoms.extend([
                            'đau bụng', 'dạ dày', 'tiêu hóa', 'ăn', 'buồn nôn', 'ợ'
                        ] if any(w in msg.lower() for w in ['bụng', 'dạ dày', 'ăn', 'nôn', 'ợ']) else [])
                
                # Check if response mentions completely unrelated conditions
                unrelated_keywords = {
                    'stomach': ['viêm màng não', 'cứng gáy', 'não'],
                    'head': ['đau bụng', 'tiêu hóa', 'dạ dày'],
                    'respiratory': ['đau bụng', 'dạ dày']
                }
                
                # If discussing stomach but response mentions brain → REJECT
                if recent_symptoms and any('bụng' in s or 'dạ dày' in s for s in recent_symptoms):
                    if any(keyword in llm_response.lower() for keyword in ['viêm màng não', 'cứng gáy', 'não', 'đầu dữ dội']):
                        print("⚠️ CONTEXT MISMATCH DETECTED: Response about brain when discussing stomach!")
                        # Force retry with explicit instruction
                        messages[-1]['content'] += "\n\n🚨 LỖI NGHIÊM TRỌNG: User đang nói về BỤng/DẠ DÀY, KHÔNG phải đầu/não! Phân tích lại ĐÚNG triệu chứng!"
                        
                        retry_response = client.chat.completions.create(
                            model=MODEL,
                            messages=messages,
                            temperature=0.3,  # Very low temp for accuracy
                            max_tokens=500
                        )
                        llm_response = retry_response.choices[0].message.content
            
            # Validate response quality using shared validator
            is_valid, issues = ResponseValidator.validate_response(
                llm_response, 
                agent_type='symptom',
                context=context,
                chat_history=chat_history
            )
            
            # Retry if invalid (max 1 retry)
            if not is_valid:
                print(f"Response validation failed: {issues}. Retrying...")
                # Add stronger instruction
                messages[-1]['content'] += f"\n\nLỖI TRƯỚC: {', '.join(issues)}. HÃY SỬA LẠI!"
                
                retry_response = client.chat.completions.create(
                    model=MODEL,
                    messages=messages,
                    temperature=0.5,  # Lower temp for more control
                    max_tokens=500
                )
                llm_response = retry_response.choices[0].message.content
            
            # Post-process to ensure quality
            llm_response = self._post_process_response(llm_response, context)

            # 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. Hoặc nếu triệu chứng nghiêm trọng, hãy gặp bác sĩ ngay nhé 🙏

Lỗi: {str(e)[:100]}"""
    
    def _assess_opqrst_progress(self, chat_history):
        """Assess how much OPQRST data has been collected"""
        if not chat_history:
            return {'complete': False, 'next_step': 'onset', 'data': {}}
        
        # Analyze conversation to see what's been asked
        all_bot_messages = " ".join([msg[1].lower() for msg in chat_history if msg[1]])
        all_user_messages = " ".join([msg[0].lower() for msg in chat_history if msg[0]])
        
        opqrst_data = {
            'onset': None,
            'provocation': None,
            'quality': None,
            'region': None,
            'severity': None,
            'timing': None
        }
        
        # Check what's been asked
        if "khi nào" in all_bot_messages or "bắt đầu" in all_bot_messages:
            opqrst_data['onset'] = 'asked'
        
        if "làm tệ hơn" in all_bot_messages or "làm đỡ" in all_bot_messages:
            opqrst_data['provocation'] = 'asked'
        
        if "mô tả cảm giác" in all_bot_messages or "đau kiểu gì" in all_bot_messages:
            opqrst_data['quality'] = 'asked'
        
        if "vị trí" in all_bot_messages or "ở đâu" in all_bot_messages:
            opqrst_data['region'] = 'asked'
        
        if "mức độ" in all_bot_messages or "1-10" in all_bot_messages:
            opqrst_data['severity'] = 'asked'
        
        if "lúc nào xuất hiện" in all_bot_messages or "liên tục" in all_bot_messages:
            opqrst_data['timing'] = 'asked'
        
        # Determine next step
        for step, value in opqrst_data.items():
            if value is None:
                return {'complete': False, 'next_step': step, 'data': opqrst_data}
        
        # All steps completed
        return {'complete': True, 'next_step': None, 'data': opqrst_data}
    
    def _ask_next_opqrst_question(self, next_step, user_query):
        """Ask the next OPQRST question"""
        questions = {
            'onset': """Mình hiểu rồi. Để đánh giá chính xác hơn, cho mình hỏi thêm nhé:

- Triệu chứng này bắt đầu từ khi nào? (hôm nay, mấy ngày, mấy tuần?)
- Nó xuất hiện đột ngột hay từ từ?""",
            
            'quality': """À được rồi. Mà này:

- Bạn mô tả cảm giác đó như thế nào? (đau nhói, tức, nóng rát, tê, đập thình thình...)
- Mức độ từ 1-10 thì bao nhiêu? (1 = nhẹ, 10 = không chịu nổi)""",
            
            'region': """Ừm, để mình hỏi thêm:

- Vị trí chính xác ở đâu? (chỉ rõ vùng cơ thể)
- Có lan ra chỗ khác không?""",
            
            'provocation': """Bạn có nhận thấy:

- Có gì làm nó tệ hơn không? (vận động, ăn uống, stress, tư thế...)
- Có gì làm nó đỡ hơn không? (nghỉ ngơi, thuốc, chườm...)""",
            
            'timing': """Quan trọng nhé:

- Nó xuất hiện lúc nào trong ngày? (sáng, chiều, tối, đêm?)
- Liên tục hay từng đợt? Mỗi đợt kéo dài bao lâu?""",
            
            'severity': """Cuối cùng:

- Có kèm theo triệu chứng nào khác không? (sốt, buồn nôn, chóng mặt, mệt mỏi...)
- Có ảnh hưởng đến ăn uống, ngủ nghỉ, sinh hoạt không?
- Bạn có bệnh nền gì không? Đang uống thuốc gì không?"""
        }
        
        return questions.get(next_step, "Cho mình biết thêm về triệu chứng của bạn nhé?")
    
    def _provide_assessment(self, opqrst_data, user_query):
        """Provide symptom assessment after collecting OPQRST data"""
        # Use LLM to analyze symptoms with OPQRST context
        try:
            response = client.chat.completions.create(
                model=MODEL,
                messages=[
                    {"role": "system", "content": self.system_prompt},
                    {"role": "user", "content": f"""Dựa vào thông tin OPQRST đã thu thập, hãy đánh giá triệu chứng và đưa ra lời khuyên.

Triệu chứng ban đầu: {user_query}

Thông tin đã thu thập:
- Onset: {opqrst_data.get('onset', 'chưa rõ')}
- Quality: {opqrst_data.get('quality', 'chưa rõ')}
- Region: {opqrst_data.get('region', 'chưa rõ')}
- Provocation: {opqrst_data.get('provocation', 'chưa rõ')}
- Timing: {opqrst_data.get('timing', 'chưa rõ')}
- Severity: {opqrst_data.get('severity', 'chưa rõ')}

Hãy đưa ra:
1. Phân tích triệu chứng
2. Nguyên nhân có thể
3. Lời khuyên xử lý tại nhà (nếu phù hợp)
4. Khi nào cần gặp bác sĩ
5. Lời động viên, trấn an"""}
                ],
                temperature=0.7,
                max_tokens=1500
            )
            
            return response.choices[0].message.content
            
        except Exception as e:
            return f"""Xin lỗi, mình gặp chút vấn đề khi phân tích triệu chứng.

Dựa vào những gì bạn chia sẻ, mình khuyên bạn nên:
- Theo dõi triệu chứng thêm 24-48 giờ
- Nghỉ ngơi đầy đủ
- Uống đủ nước
- Nếu triệu chứng tệ hơn hoặc không giảm → đi khám bác sĩ

Với các triệu chứng bất thường, tốt nhất là được bác sĩ khám trực tiếp nhé! 🏥"""