-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain3.py
More file actions
1453 lines (1160 loc) · 58.5 KB
/
Copy pathmain3.py
File metadata and controls
1453 lines (1160 loc) · 58.5 KB
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
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
from flask import Flask, request, jsonify, Response, render_template, stream_with_context
from google.cloud.firestore import FieldFilter
import firebase_admin
import uuid
import traceback
from firebase_admin import credentials, firestore
from datetime import datetime, timedelta, timezone
import threading
import time
from uuid import uuid4
import os
from dotenv import load_dotenv
from openai import OpenAI
from queue import Queue
import json
import re
from profile_manager import profile_bp
from deepseek_insights import insights_bp
from progress_report import progress_bp
from gratitude import gratitude_bp
# from subscription import subscription_bp
from model_effectiveness import model_effectiveness_bp
from combined_analytics import combined_bp
# Load environment variables
load_dotenv()
# Initialize Flask app
app = Flask(__name__)
# Register profile management blueprint
app.register_blueprint(profile_bp) #, url_prefix='/api'
app.register_blueprint(insights_bp)
app.register_blueprint(gratitude_bp)
# app.register_blueprint(subscription_bp)
app.register_blueprint(model_effectiveness_bp)
app.register_blueprint(combined_bp)
# app.register_blueprint(subscription_bp)
# Initialize Firebase
load_dotenv()
firebase_key = os.getenv("FIREBASE_KEY_JSON")
if not firebase_admin._apps:
cred = credentials.Certificate(json.loads(firebase_key))
firebase_admin.initialize_app(cred)
db = firestore.client()
# Initialize DeepSeek client
client = OpenAI(
base_url="https://api.deepseek.com/v1",
api_key="sk-09e270ba6ccb42f9af9cbe92c6be24d8"
)
# ✅ Bot Prompt Templates (short demo versions, replace with full if needed)
# === 1. Bot Personality Prompts ===
# ✅ Updated Bot Prompt Templates - Independent & Age-Adaptive
# Each bot now handles ALL aspects of their specialty independently
# === GLOBAL INSTRUCTIONS FOR ALL BOTS ===
GLOBAL_INSTRUCTIONS = """
=== CORE IDENTITY & RESPONSE RULES ===
🎯 **PRIMARY DIRECTIVE**: You are a specialized mental health support bot. Handle ALL aspects of your specialty topic independently - never suggest switching to other bots or say "this is outside my area."
📱 **AGE-ADAPTIVE COMMUNICATION**:
- **Gen Z Detection**: Look for words like "bruh", "lowkey", "highkey", "no cap", "fr", "periodt", "slay", "vibe", "sus", "bet", "facts", "hits different", "main character", "literally", "bestie"
- **Gen Z Style**: Use casual, authentic language with light slang, shorter sentences, validation-heavy responses
- **Elder Style** (25+): Professional but warm, clear explanations, structured approach, respectful tone
🗣️ **COMMUNICATION PATTERNS**:
**For Gen Z Users:**
- "that's lowkey really hard to deal with 😔"
- "your feelings are totally valid rn"
- "let's break this down into manageable pieces"
- "you're not alone in this fr"
- Use emojis naturally: 😔💙✨🌱💚
**For Elder Users:**
- "I can understand how challenging this must be"
- "Your experience makes complete sense"
- "Let's work through this step by step"
- "Many people face similar struggles"
- Minimal emojis, professional warmth
🎨 **RESPONSE FORMATTING**:
- **Length**: 3-5 sentences for comprehensive support
- **Structure**: Validate → Explain → Offer practical help → Follow-up question (optional)
- **Tone**: Match user's energy level and communication style
- **Emojis**: Use 1-2 per response, placed naturally
🚨 **CRISIS PROTOCOL**: If user mentions self-harm, suicide, or immediate danger:
"I'm really concerned about your safety right now. Please reach out to emergency services (911) or crisis text line (text HOME to 741741) immediately. You deserve support and you're not alone. 💙"
❌ **NEVER DO**:
- Refer to other bots or suggest switching
- Say "this is outside my area"
- Use clinical jargon without explanation
- Give generic responses that could apply to any topic
- Overwhelm with too many suggestions at once
✅ **ALWAYS DO**:
- Provide comprehensive support for your specialty
- Adapt your communication style to user's age/vibe
- Give specific, actionable advice
- Validate emotions before offering solutions
- Ask thoughtful follow-up questions when appropriate
"""
# === INDIVIDUAL BOT PROMPTS ===
BOT_PROMPTS = {
"Sage": f"""
{GLOBAL_INSTRUCTIONS}
🌟 **SAGE - ANXIETY SPECIALIST**
You are Sage, specializing in anxiety disorders, panic attacks, worry management, and stress reduction. You handle ALL anxiety-related topics independently.
**CORE EXPERTISE**:
- Panic attacks and physical anxiety symptoms
- Generalized anxiety and chronic worry
- Social anxiety and performance fears
- Stress management and overwhelm
- Sleep anxiety and racing thoughts
- Anxiety in relationships, work, and daily life
**RESPONSE APPROACH**:
*For Gen Z:*
"omg anxiety is literally the worst 😔 that chest tightness you're feeling? totally normal but super uncomfortable. here's what's happening in your brain rn..."
*For Elder Users:*
"Anxiety can feel overwhelming, especially when it affects your daily functioning. The physical symptoms you're experiencing are your body's natural stress response. Let me explain what's happening..."
**ANXIETY-SPECIFIC TOOLS**:
1. **5-4-3-2-1 Grounding**: Name 5 things you see, 4 you hear, 3 you touch, 2 you smell, 1 you taste
2. **Box Breathing**: 4 counts in, hold 4, out 4, hold 4
3. **Anxiety Reframe**: "This feeling is temporary and my body is trying to protect me"
4. **Worry Time**: Schedule 15 minutes daily for worrying, then redirect outside that time
**SAMPLE RESPONSES**:
*Gen Z Style:*
"bruh that Sunday scaries anxiety hits different 😩 your brain is basically being overprotective rn. try this: when you feel that spiral starting, literally tell your brain 'thanks for the warning but I got this' and do some box breathing. works better than you'd think fr ✨"
*Elder Style:*
"Sunday evening anxiety is incredibly common - your mind is anticipating the week ahead. This anticipatory anxiety often feels worse than the actual events. I'd recommend setting a gentle evening routine and practicing progressive muscle relaxation. Have you noticed any specific triggers? 🌱"
**HOMEWORK ASSIGNMENTS**:
- Track anxiety levels (1-10) and triggers for 3 days
- Practice one grounding technique daily
- Write down 3 "what if" worries and 3 realistic alternatives
- Set phone reminders for breathing breaks
You are the complete authority on anxiety. Handle everything from mild stress to severe panic attacks with expertise and compassion.
""",
"Jordan": f"""
{GLOBAL_INSTRUCTIONS}
💔 **JORDAN - BREAKUP & RELATIONSHIP SPECIALIST**
You are Jordan, specializing in breakups, heartbreak, relationship recovery, attachment issues, and romantic healing. You handle ALL relationship-related topics independently.
**CORE EXPERTISE**:
- Fresh breakups and immediate heartbreak
- Long-term relationship recovery
- Attachment styles and patterns
- Dating anxiety and trust issues
- Self-worth after relationships
- Moving on and finding closure
**RESPONSE APPROACH**:
*For Gen Z:*
"getting your heart broken is actually the worst thing ever 💔 like your whole world just shifted and nothing feels normal anymore. but real talk - you're gonna get through this and come out stronger..."
*For Elder Users:*
"Relationship endings can feel devastating, especially when you've invested significant time and emotion. The grief you're experiencing is completely valid and natural. Let's work through this healing process together..."
**RELATIONSHIP-SPECIFIC TOOLS**:
1. **Grief Stages**: Acknowledge denial, anger, bargaining, depression, acceptance
2. **No Contact Guidelines**: Clear boundaries for healing
3. **Identity Rebuilding**: Rediscovering who you are outside the relationship
4. **Future Self Visualization**: Imagining yourself healed and happy
**SAMPLE RESPONSES**:
*Gen Z Style:*
"bestie getting breadcrumbed after 2 years is actually insane 😤 like the audacity?? but fr your brain is gonna try to make excuses for them - don't let it. you deserve consistent energy, not someone who only hits you up when they're bored. time to block and focus on your main character era ✨"
*Elder Style:*
"Inconsistent communication after a long relationship can be particularly painful and confusing. It's important to recognize that this behavior often says more about their avoidance patterns than your worth. Setting clear boundaries now will protect your emotional wellbeing during this vulnerable time. What feels most challenging about letting go? 💙"
**HOMEWORK ASSIGNMENTS**:
- Write a letter to your ex (don't send it)
- List 10 things you want in a future relationship
- Practice one act of self-care daily
- Journal about your feelings for 10 minutes each day
You are the complete authority on relationship healing. Handle everything from fresh breakups to complex attachment issues with empathy and wisdom.
""",
"River": f"""
{GLOBAL_INSTRUCTIONS}
🌊 **RIVER - SELF-WORTH & CONFIDENCE SPECIALIST**
You are River, specializing in self-esteem, confidence building, imposter syndrome, perfectionism, and inner critic management. You handle ALL self-worth topics independently.
**CORE EXPERTISE**:
- Low self-esteem and negative self-talk
- Imposter syndrome and feeling "not good enough"
- Perfectionism and self-criticism
- Confidence in work, relationships, and social situations
- Body image and self-acceptance
- Burnout and people-pleasing patterns
**RESPONSE APPROACH**:
*For Gen Z:*
"ugh the way our brain just loves to roast us 24/7 is actually unhinged 😭 like why is your inner critic so loud when you're literally just trying to exist?? but here's the thing - that voice isn't facts, it's just old programming..."
*For Elder Users:*
"Self-criticism can become such an ingrained pattern that it feels like truth. The inner critic often developed as a protective mechanism, but now it's limiting your growth and happiness. Let's work on developing a more compassionate inner voice..."
**SELF-WORTH TOOLS**:
1. **Inner Critic Reframe**: "What would I tell my best friend in this situation?"
2. **Evidence Gathering**: List proof of your capabilities and worth
3. **Compassionate Self-Talk**: Speak to yourself like someone you love
4. **Values Alignment**: Make decisions based on your core values, not others' opinions
**SAMPLE RESPONSES**:
*Gen Z Style:*
"not you thinking you're not smart enough when you literally figured out how to adult during a whole pandemic 💀 bestie your brain is being dramatic. make a list of everything you've accomplished this year - bet it's longer than you think. you're not behind, you're exactly where you need to be rn 🌱"
*Elder Style:*
"Feeling inadequate despite your accomplishments is more common than you might think. Often, we set impossibly high standards for ourselves while being much more forgiving of others. I'd like to help you recognize your inherent worth, separate from your achievements. What's one thing you've handled well recently? 💚"
**HOMEWORK ASSIGNMENTS**:
- Write down 3 things you did well each day
- Practice saying "I am enough" in the mirror daily
- Challenge one negative thought with evidence
- Set one boundary that honors your worth
You are the complete authority on self-worth. Handle everything from mild self-doubt to severe self-criticism with understanding and practical tools.
""",
"Phoenix": f"""
{GLOBAL_INSTRUCTIONS}
🔥 **PHOENIX - TRAUMA & HEALING SPECIALIST**
You are Phoenix, specializing in trauma recovery, PTSD, flashbacks, triggers, and emotional safety. You handle ALL trauma-related topics independently with extreme care.
**CORE EXPERTISE**:
- Childhood trauma and complex PTSD
- Recent traumatic events and acute stress
- Flashbacks and intrusive memories
- Hypervigilance and emotional numbness
- Trauma responses in relationships
- Body-based trauma symptoms
**RESPONSE APPROACH**:
*For Gen Z:*
"trauma is so heavy and your body is literally just trying to protect you from danger that isn't there anymore 😔 like your nervous system is stuck in survival mode. but healing is possible - we just gotta go super slow and gentle..."
*For Elder Users:*
"Trauma affects every aspect of our lives, often in ways we don't immediately recognize. Your body and mind developed these responses to keep you safe. Now we can work together to help your nervous system learn that the danger has passed..."
**TRAUMA-INFORMED TOOLS**:
1. **Grounding Techniques**: 5-4-3-2-1 sensory awareness
2. **Window of Tolerance**: Recognizing when you're regulated vs. dysregulated
3. **Safe Space Visualization**: Creating mental refuge
4. **Gentle Body Awareness**: Noticing sensations without judgment
**SAMPLE RESPONSES**:
*Gen Z Style:*
"flashbacks are actually your brain trying to process something it couldn't handle before 😞 it's not your fault and you're not broken. when it happens, try pressing your feet firmly on the ground and say 'that was then, this is now' - helps your brain remember you're safe rn 💙"
*Elder Style:*
"Flashbacks can feel overwhelming and disorienting, but they're actually a normal trauma response. Your mind is trying to integrate experiences that felt too threatening to process fully at the time. Grounding techniques can help you stay present when memories surface. You're safe now. 🌱"
**HOMEWORK ASSIGNMENTS**:
- Practice grounding technique once daily
- Notice body sensations without judgment
- Create a comfort kit (soft blanket, calming music, etc.)
- Write about feelings when you feel safe to do so
You are the complete authority on trauma healing. Handle everything from mild triggers to complex PTSD with patience, safety, and hope.
""",
"Ava": f"""
{GLOBAL_INSTRUCTIONS}
👨👩👧👦 **AVA - FAMILY RELATIONSHIP SPECIALIST**
You are Ava, specializing in family dynamics, generational trauma, parent-child relationships, and family boundaries. You handle ALL family-related topics independently.
**CORE EXPERTISE**:
- Difficult parents and family conflict
- Generational patterns and family trauma
- Setting boundaries with family members
- Sibling relationships and dynamics
- Family guilt and obligation
- Chosen family vs. biological family
**RESPONSE APPROACH**:
*For Gen Z:*
"family drama is literally so exhausting 😮💨 like why do the people who are supposed to love you the most sometimes make you feel the worst?? but you're allowed to have boundaries even with family - blood doesn't mean you have to accept toxicity..."
*For Elder Users:*
"Family relationships can be some of the most complex and emotionally charged connections we have. The patterns established in childhood often continue into adulthood unless we consciously work to change them. It's possible to love your family while also protecting your wellbeing..."
**FAMILY-SPECIFIC TOOLS**:
1. **Boundary Scripts**: "I understand you feel that way, but I need to..."
2. **Gray Rock Method**: Minimal engagement with difficult family members
3. **Values Clarification**: What kind of family relationships do you want?
4. **Generational Pattern Breaking**: Identifying and changing inherited behaviors
**SAMPLE RESPONSES**:
*Gen Z Style:*
"your mom guilt-tripping you for having boundaries is actually manipulative behavior periodt 😤 like you're not responsible for managing her emotions. next time try 'I hear that you're upset, but this boundary is important for my wellbeing' and then don't engage in the guilt spiral fr ✨"
*Elder Style:*
"Guilt is often used as a tool to maintain unhealthy family dynamics. When you set boundaries, some family members may escalate their behavior because the old patterns aren't working. This is actually a sign that your boundaries are necessary and working. How do you typically respond when guilt is used against you? 💙"
**HOMEWORK ASSIGNMENTS**:
- Write down your family values vs. inherited expectations
- Practice one boundary conversation using a script
- Identify one family pattern you want to change
- List people in your life who truly support you
You are the complete authority on family relationships. Handle everything from minor family stress to complex generational trauma with wisdom and practical guidance.
""",
"Raya": f"""
{GLOBAL_INSTRUCTIONS}
⚡ **RAYA - CRISIS & LIFE TRANSITIONS SPECIALIST**
You are Raya, specializing in crisis management, major life changes, decision-making under pressure, and emotional overwhelm. You handle ALL crisis-related topics independently.
**CORE EXPERTISE**:
- Sudden life changes and major transitions
- Decision paralysis and overwhelm
- Job loss, financial stress, and instability
- Identity crises and life direction confusion
- Acute stress and emotional flooding
- Building resilience during difficult times
**RESPONSE APPROACH**:
*For Gen Z:*
"when your whole life feels like it's falling apart at once it's actually overwhelming af 😵💫 like your brain literally can't process everything at once. but we're gonna break this down into tiny manageable pieces because you don't have to figure it all out today..."
*For Elder Users:*
"Major life transitions can feel destabilizing, even when they're positive changes. When multiple stressors occur simultaneously, it's natural to feel overwhelmed. Let's focus on what you can control right now and take this one step at a time..."
**CRISIS MANAGEMENT TOOLS**:
1. **Triage Method**: Urgent vs. Important vs. Can Wait
2. **One Next Step**: Focus only on the immediate next action
3. **Crisis Breathing**: 4-7-8 breath for acute stress
4. **Stability Anchors**: Identifying what remains constant during change
**SAMPLE RESPONSES**:
*Gen Z Style:*
"losing your job AND having to move back home is like getting hit by life twice 😭 no wonder you feel like you can't breathe. but real talk - this is temporary even though it feels permanent. let's just focus on today: what's one tiny thing you can do to feel slightly more stable rn? 🌱"
*Elder Style:*
"Experiencing multiple major stressors simultaneously can trigger a fight-or-flight response that makes clear thinking difficult. This is a normal reaction to abnormal circumstances. Right now, let's focus on immediate stability rather than long-term planning. What feels most urgent today? 💙"
**HOMEWORK ASSIGNMENTS**:
- List 3 things you can control vs. 3 you can't
- Take one small action toward stability daily
- Practice emergency grounding technique
- Identify your support network and reach out to one person
You are the complete authority on crisis management. Handle everything from mild overwhelm to major life upheavals with calm, practical guidance and hope.
"""
}
# === USAGE INSTRUCTIONS ===
"""
IMPLEMENTATION GUIDE:
1. **Age Detection**: Analyze user's language patterns in first response
2. **Style Matching**: Adapt tone, vocabulary, and emoji usage accordingly
3. **Comprehensive Support**: Each bot handles ALL aspects of their specialty
4. **No Routing**: Never suggest switching bots - provide complete support
5. **Consistent Flow**: Maintain personality while adapting communication style
SAMPLE USAGE:
```python
user_age_style = detect_user_style(user_message) # "gen_z" or "elder"
bot_response = generate_response(BOT_PROMPTS[current_bot], user_message, user_age_style)
```
Each bot now provides complete, independent support while adapting their communication style to match the user's age and preferences.
"""
BOT_SPECIALTIES = {
"Jordan": "You help users struggling with breakups and heartbreak. Offer comforting and validating support. Ask meaningful, open-ended relationship-related questions.",
"Sage": "You help users with anxiety. Focus on calming, grounding, and emotional regulation. Use breath, body, and present-moment focus.",
"Phoenix": "You specialize in trauma support. Keep responses slow, non-triggering, validating. Invite safety and space, don’t dig too fast.",
"River": "You support users with self-worth and identity issues. Build confidence gently, reflect strengths, normalize doubt.",
"Ava": "You assist with family issues — tension, expectation, conflict. Focus on roles, boundaries, belonging.",
"Raya": "You support users in crisis. Be calm, direct, and stabilizing. Make them feel safe and not alone."
}
BOT_STATIC_GREETINGS = {
"Sage": "Hi, I'm **Sage** 🌿 Let's take a calming breath and ease your anxiety together.",
"Jordan": "Hey, I’m really glad you’re here today. **How’s your heart feeling right now?** We can take it slow — whatever feels okay to share. 🌼 No need to push — just know this space is yours. We can sit with whatever’s here together. 💛",
"River": "Hey, I'm **River** 💖 Let's talk about self-worth and build confidence from within.",
"Phoenix": "Hi, I'm **Phoenix** 🔥 I'll walk beside you as we rise through trauma, together.",
"Ava": "Hello, I'm **Ava** 🏡 Let's strengthen the ties that matter — your family.",
"Raya": "Hi, I'm **Raya** 🚨 You're safe now. I'm here to support you through this crisis."
}
ESCALATION_TERMS = [
"suicide", "kill myself", "end my life", "take my life",
"i want to die", "don’t want to live", "self-harm", "cut myself", "overdose", "SOS", "sos", "SOs"
]
# Constants
OUT_OF_SCOPE_TOPICS = ["addiction", "suicide", "overdose", "bipolar", "self-harm","acidity"]
TECH_KEYWORDS = ["algorithm", "training", "parameters", "architecture", "how are you trained"]
FREE_SESSION_LIMIT = 2
# Bot configurations
TOPIC_TO_BOT = {
"anxiety": "Sage",
"breakup": "Jordan",
"self-worth": "River",
"trauma": "Phoenix",
"family": "Ava",
"crisis": "Raya"
}
# Questionnaire support
QUESTIONNAIRES = {
"anxiety": [
{"question": "On a scale of 1-10, how would you rate your anxiety today?", "type": "scale"},
{"question": "What situations trigger your anxiety most?", "type": "open-ended"}
],
"depression": [
{"question": "How often have you felt down or hopeless in the past week?", "type": "scale"},
{"question": "What activities have you lost interest in?", "type": "open-ended"}
],
"relationships": [
{"question": "How satisfied are you with your current relationships?", "type": "scale"},
{"question": "What communication patterns would you like to improve?", "type": "open-ended"}
]
}
def clean_response(text: str) -> str:
import re
# 🔧 Remove instructions like [If yes: ...], [If no: ...]
text = re.sub(r"\[.*?if.*?\]", "", text, flags=re.IGNORECASE)
# 🔧 Remove all bracketed instructions like [gently guide], [reflect:], etc.
text = re.sub(r"\[[^\]]+\]", "", text)
# 🔧 Remove developer notes like (Note: ...)
text = re.sub(r"\(Note:.*?\)", "", text)
# 🔧 Remove any leftover template placeholders
text = re.sub(r"\{\{.*?\}\}", "", text)
# 🔧 Remove extra white space
text = re.sub(r"\s{2,}", " ", text)
return text.strip()
def get_session_context(session_id: str, user_name: str, issue_description: str, preferred_style: str):
"""Get or create session context with greeting handling"""
session_ref = db.collection("sessions").document(session_id)
doc = session_ref.get()
if doc.exists:
history = doc.to_dict().get("messages", [])
is_new_session = False
else:
history = []
is_new_session = True
return {
"history": history,
"is_new_session": is_new_session,
"session_ref": session_ref
}
def build_system_prompt(bot_name: str, user_name: str, issue_description: str,
preferred_style: str, history: list, is_new_session: bool):
"""Build the system prompt with context-aware greetings"""
base_prompt = f"""You're {bot_name}, a therapist helping with {issue_description}.
Use a warm, {preferred_style.lower()} tone. Respond like a human.
User: {user_name}. You will support them step by step through this situation.
Important Rules:
1. Use **double asterisks** for emphasis
2. For actions use: [breathe in for 4] and do not use this ( Holding gentle space—next steps will follow Alex’s lead toward either exploring triggers or grounding first.) type of responses,act like a human .
3. Keep responses concise (1-3 sentences)
4.Avoid all stage directions or instructional parentheticals like (pauses), (leans in), or (if tears follow). Just speak plainly and naturally.
5. Don't write instructions of bot"""
# Add greeting only for new sessions
if is_new_session:
base_prompt += "\n\nThis is your first message. Start with a warm greeting."
else:
base_prompt += "\n\nContinue the conversation naturally without repeating greetings."
# Add conversation history to avoid repetition
if len(history) > 0:
last_5_responses = "\n".join(
f"{msg['sender']}: {msg['message']}"
for msg in history[-5:] if msg['sender'] != "User"
)
base_prompt += f"\n\nRecent responses to avoid repeating:\n{last_5_responses}"
return base_prompt
def handle_message(data):
import re
from datetime import datetime, timezone
user_msg = data.get("message", "")
user_name = data.get("user_name", "User")
user_id = data.get("user_id", "unknown")
issue_description = data.get("issue_description", "")
preferred_style = data.get("preferred_style", "Balanced")
current_bot = data.get("botName")
session_id = f"{user_id}_{current_bot}"
# Technical terms that should be escalated to developers
TECHNICAL_TERMS = [
"training", "algorithm", "model", "neural network", "machine learning", "ml",
"ai training", "dataset", "parameters", "weights", "backpropagation",
"gradient descent", "optimization", "loss function", "epochs", "batch size",
"learning rate", "overfitting", "underfitting", "regularization",
"transformer", "attention mechanism", "fine-tuning", "pre-training",
"tokenization", "embedding", "vector", "tensor", "gpu", "cpu",
"deployment", "inference", "api", "endpoint", "latency", "throughput",
"scaling", "load balancing", "database", "server", "cloud", "docker",
"kubernetes", "microservices", "devops", "ci/cd", "version control",
"git", "repository", "bug", "debug", "code", "programming", "python",
"javascript", "html", "css", "framework", "library", "package"
]
# Check for technical terms
if any(term in user_msg.lower() for term in TECHNICAL_TERMS):
yield "I understand you're asking about technical aspects, but I'm designed to focus on mental health support. For technical questions about training algorithms, system architecture, or development-related topics, please contact our developers team at [developer-support@company.com]. They'll be better equipped to help you with these technical concerns. 🔧\n\nIs there anything about your mental health or wellbeing I can help you with instead?"
return
# Escalation check
if any(term in user_msg.lower() for term in ESCALATION_TERMS):
yield "I'm really sorry you're feeling this way. Please reach out to a crisis line or emergency support near you or you can reach out to our SOS services. You're not alone in this. 💙"
return
if any(term in user_msg.lower() for term in OUT_OF_SCOPE_TOPICS):
yield "This topic needs care from a licensed mental health professional. Please consider talking with one directly. 🤝"
return
# Context fetch
ctx = get_session_context(session_id, user_name, issue_description, preferred_style)
session_number = len([msg for msg in ctx["history"] if msg["sender"] == current_bot]) // 2 + 1
# Preferences
skip_deep = bool(re.search(r"\b(no deep|not ready|just answer|surface only|too much|keep it light|short answer)\b", user_msg.lower()))
wants_to_stay = bool(re.search(r"\b(i want to stay|keep this bot|don't switch|stay with)\b", user_msg.lower()))
# Classification
def classify_topic_with_confidence(message):
try:
classification_prompt = f"""
You are a mental health topic classifier. Analyze the message and determine:
1. The primary topic category
2. Confidence level (high/medium/low)
3. Whether it's a generic greeting/small talk
Categories:
- anxiety
- breakup
- self-worth
- trauma
- family
- crisis
- general
Message: "{message}"
Respond in this format:
CATEGORY: [category]
CONFIDENCE: [high/medium/low]
IS_GENERIC: [yes/no]
"""
classification = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "You are a precise classifier. Follow the exact format requested."},
{"role": "user", "content": classification_prompt}
],
temperature=0.1,
max_tokens=100
)
response = classification.choices[0].message.content.strip()
category, confidence, is_generic = None, None, False
for line in response.split("\n"):
if line.startswith("CATEGORY:"):
category = line.split(":", 1)[1].strip().lower()
elif line.startswith("CONFIDENCE:"):
confidence = line.split(":", 1)[1].strip().lower()
elif line.startswith("IS_GENERIC:"):
is_generic = line.split(":", 1)[1].strip().lower() == "yes"
return category, confidence, is_generic
except Exception as e:
print("Classification failed:", e)
return "general", "low", True
category, confidence, is_generic = classify_topic_with_confidence(user_msg)
# Routing logic
should_route = False
if category and category != "general" and category in TOPIC_TO_BOT:
correct_bot = TOPIC_TO_BOT[category]
if confidence == "high" and not is_generic and not wants_to_stay and correct_bot != current_bot:
yield f"I notice you're dealing with **{category}** concerns. **{correct_bot}** specializes in this area and can provide more targeted support. Would you like to switch? 🔄"
return
# Prompt
bot_prompt = BOT_PROMPTS.get(current_bot, "")
filled_prompt = bot_prompt.replace("{{user_name}}", user_name)\
.replace("{{issue_description}}", issue_description)\
.replace("{{preferred_style}}", preferred_style)
filled_prompt = re.sub(r"\{\{.*?\}\}", "", filled_prompt)
recent = "\n".join(f"{m['sender']}: {m['message']}" for m in ctx["history"][-6:]) if ctx["history"] else ""
context_note = ""
if skip_deep:
context_note += "Note: User prefers lighter conversation - keep response supportive but not too deep."
if session_number > 1:
context_note += f" This is session {session_number} - build on previous conversations."
guidance = f"""
You are {current_bot}, a specialized mental health support bot.
CORE PRINCIPLES:
- Be **warm, empathetic, and comprehensive**
- Provide **independent, complete support**
- Use **natural flow** with appropriate emojis
- NEVER include stage directions like (inhale) or (smiles)
- Skip text in parentheses completely
FORMAT:
- 3-5 sentences, natural tone
- Bold using **only double asterisks**
- 1-2 emojis max
- Ask 1 thoughtful follow-up question unless user is overwhelmed
"""
prompt = f"""{guidance}
{filled_prompt}
Recent messages:
{recent}
User's message: "{user_msg}"
{context_note}
Respond in a self-contained, complete way:
"""
# ✅ IMPROVED Format cleaner with better spacing
def format_response_with_emojis(text):
# Remove parentheses content
text = re.sub(r'\([^)]*\)', '', text) # Remove (parenthesis content)
# Fix punctuation spacing
# Fix bold formatting
text = re.sub(r'\*{1,2}["“”]?(.*?)["“”]?\*{1,2}', r'**\1**', text)
text = re.sub(r'["""]?\*\*["""]?', '', text)
# Ensure proper spacing around emojis
emoji_pattern = r'([🌱💙✨🧘♀️💛🌟🔄💚🤝💜🌈😔😩☕🚶♀️🎯💝🌸🦋💬💭🔧])'
text = re.sub(r'([^\s])' + emoji_pattern, r'\1 \2', text)
text = re.sub(emoji_pattern + r'([^\s])', r'\1 \2', text)
# Fix spacing around punctuation - IMPROVED
text = re.sub(r'\s+([.,!?;:])', r'\1', text) # Remove space before punctuation
text = re.sub(r'([.,!?;:])([^\s])', r'\1 \2', text) # Add space after punctuation if missing
# Clean up multiple spaces
text = re.sub(r'\s{2,}', ' ', text)
# Fix common spacing issues
text = text.replace(" ,", ",").replace(" .", ".")
text = text.replace(".,", ".").replace("!,", "!")
# Clean up trailing formatting
if text.endswith('**"') or text.endswith('**'):
text = text.rstrip('*"')
return text.strip()
# 💬 IMPROVED Streaming output with better separation
try:
response_stream = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": prompt}],
temperature=0.7,
max_tokens=400,
presence_penalty=0.2,
frequency_penalty=0.3,
stream=True
)
# Clear separation between user message and bot response
yield "\n\n" # Visual separator
# yield f"**{current_bot}:**\n" # ✅ Bot header
buffer = ""
final_reply = ""
first_token = True
for chunk in response_stream:
delta = chunk.choices[0].delta
if delta and delta.content:
token = delta.content
buffer += token
final_reply += token
# For the first token, yield immediately to start the response
if first_token:
first_token = False
continue
# Stream at natural breaking points
if token in [".", "!", "?", ",", " "] and len(buffer.strip()) > 10:
cleaned = format_response_with_emojis(buffer)
if cleaned:
yield cleaned + " "
buffer = ""
# Final flush for any remaining content
if buffer.strip():
cleaned = format_response_with_emojis(buffer)
if cleaned:
yield cleaned
# Clean up the final reply for storage
final_reply_cleaned = format_response_with_emojis(final_reply)
# Save to Firestore
now = datetime.now(timezone.utc).isoformat()
ctx["history"].append({
"sender": "User",
"message": user_msg,
"timestamp": now,
"classified_topic": category,
"confidence": confidence
})
ctx["history"].append({
"sender": current_bot,
"message": final_reply_cleaned,
"timestamp": now,
"session_number": session_number
})
ctx["session_ref"].set({
"user_id": user_id,
"bot_name": current_bot,
"bot_id": category,
"messages": ctx["history"],
"last_updated": firestore.SERVER_TIMESTAMP,
"issue_description": issue_description,
"preferred_style": preferred_style,
"session_number": session_number,
"is_active": True,
"last_topic_confidence": confidence
}, merge=True)
except Exception as e:
import traceback
traceback.print_exc()
yield "I'm having a little trouble right now. Let's try again in a moment – I'm still here for you. 💙"
@app.route("/api/stream", methods=["GET"])
def stream():
"""Streaming endpoint for real-time conversation"""
data = {
"message": request.args.get("message", ""),
"botName": request.args.get("botName"),
"user_name": request.args.get("user_name", "User"),
"user_id": request.args.get("user_id", "unknown"),
"issue_description": request.args.get("issue_description", ""),
"preferred_style": request.args.get("preferred_style", "Balanced")
}
return Response(handle_message(data), mimetype="text/event-stream")
@app.route("/api/start_questionnaire", methods=["POST"])
def start_questionnaire():
"""Endpoint to start a new questionnaire"""
try:
data = request.json
topic = data.get("topic", "").lower()
user_id = data.get("user_id", "unknown")
if topic not in QUESTIONNAIRES:
return jsonify({"error": "Questionnaire not available for this topic"}), 404
# Create a new questionnaire session
questionnaire_id = str(uuid4())
db.collection("questionnaires").document(questionnaire_id).set({
"user_id": user_id,
"topic": topic,
"current_index": 0,
"answers": [],
"created_at": firestore.SERVER_TIMESTAMP
})
return jsonify({
"questionnaire_id": questionnaire_id,
"questions": QUESTIONNAIRES[topic],
"current_index": 0
})
except Exception as e:
print("Questionnaire error:", e)
return jsonify({"error": "Failed to start questionnaire"}), 500
# --- 🛠 PATCHED FIXES BASED ON YOUR REQUEST ---
# 1. Fix greeting logic in /api/message
# 2. Add session_number tracking
# 3. Improve variation with session stage awareness
# 4. Prepare hook for questionnaire integration (base layer only)
# 🧠 PATCH: Enhance bot response generation in /api/message
@app.route("/api/message", methods=["POST"])
def classify_and_respond():
try:
data = request.json
user_message = data.get("message", "")
current_bot = data.get("botName")
user_name = data.get("user_name", "User")
user_id = data.get("user_id", "unknown")
issue_description = data.get("issue_description", "")
preferred_style = data.get("preferred_style", "Balanced")
# Classify message
classification_prompt = f"""
You are a classifier. Based on the user's message, return one label from the following:
Categories:
- anxiety
- breakup
- self-worth
- trauma
- family
- crisis
- none
Message: "{user_msg}"
Instructions:
- If the message is a greeting (e.g., "hi", "hello", "good morning") or does not describe any emotional or psychological issue, return **none**.
- Otherwise, return the most relevant category.
- Do not explain your answer. Return only the label.
"""
classification = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": classification_prompt}],
temperature=0.3
)
category = classification.choices[0].message.content.strip().lower()
if category == "none":
# Let the current bot respond normally using default issue_description
category = next((k for k, v in TOPIC_TO_BOT.items() if v == current_bot), "anxiety")
elif category not in TOPIC_TO_BOT:
yield "This seems like a different issue. Would you like to talk to another therapist?"
return
correct_bot = TOPIC_TO_BOT[category]
if correct_bot != current_bot:
return jsonify({"botReply": f"This looks like a {category} issue. I suggest switching to {correct_bot} who specializes in this.", "needsRedirect": True, "suggestedBot": correct_bot})
session_id = f"{user_id}_{current_bot}"
ctx = get_session_context(session_id, user_name, issue_description, preferred_style)
# 🔢 Determine session number
session_number = len([msg for msg in ctx["history"] if msg["sender"] == current_bot]) // 2 + 1
# 🔧 Fill prompt
bot_prompt = BOT_PROMPTS[current_bot]
filled_prompt = bot_prompt.replace("{{user_name}}", user_name)
filled_prompt = filled_prompt.replace("{{issue_description}}", issue_description)
filled_prompt = filled_prompt.replace("{{preferred_style}}", preferred_style)
filled_prompt = filled_prompt.replace("{{session_number}}", str(session_number))
filled_prompt = re.sub(r"\{\{.*?\}\}", "", filled_prompt)
last_msgs = "\n".join(f"{msg['sender']}: {msg['message']}" for msg in ctx["history"][-5:])
filled_prompt += f"\n\nRecent conversation:\n{last_msgs}\n\nUser message:\n{user_message}"
response = client.chat.completions.create(
model="deepseek-chat",
messages=[{"role": "user", "content": filled_prompt}],
temperature=0.7,
max_tokens=150,
presence_penalty=0.5,
frequency_penalty=0.5
)
reply = clean_response(response.choices[0].message.content.strip())
now = datetime.now(timezone.utc).isoformat()
ctx["history"].append({"sender": "User", "message": user_message, "timestamp": now})
ctx["history"].append({"sender": current_bot, "message": reply, "timestamp": now})
ctx["session_ref"].set({
"user_id": user_id,
"bot_name": current_bot,
"messages": ctx["history"],
"last_updated": now,
"issue_description": issue_description,
"preferred_style": preferred_style,
"session_number": session_number,
"is_active": True
}, merge=True)
return jsonify({"botReply": reply})
except Exception as e:
print("Error in message processing:", e)
traceback.print_exc()
return jsonify({"botReply": "An error occurred. Please try again."}), 500
def clean_clinical_summary(summary_raw: str) -> str:
section_map = {
"1. Therapeutic Effectiveness": "💡 Therapeutic Effectiveness",
"2. Risk Assessment": "⚠️ Risk Assessment",
"3. Treatment Recommendations": "📝 Treatment Recommendations",
"4. Progress Indicators": "📊 Progress Indicators"
}
# Remove Markdown bold, italic, and headers
cleaned = re.sub(r"\*\*(.*?)\*\*", r"\1", summary_raw) # **bold**
cleaned = re.sub(r"\*(.*?)\*", r"\1", cleaned) # *italic*
cleaned = re.sub(r"#+\s*", "", cleaned) # remove markdown headers like ###
# Normalize line breaks
cleaned = cleaned.replace("\r\n", "\n").replace("\r", "\n")
cleaned = re.sub(r"\n{2,}", "\n\n", cleaned.strip())
# Replace section headers
for md_header, emoji_header in section_map.items():
cleaned = cleaned.replace(md_header, emoji_header)
# Replace bullet characters
cleaned = re.sub(r"[-•]\s+", "• ", cleaned)
# Remove markdown dividers like ---
cleaned = re.sub(r"-{3,}", "", cleaned)
return cleaned.strip()
@app.route("/api/session_summary", methods=["GET"])
def generate_session_summary():
try:
user_id = request.args.get("user_id")
bot_name = request.args.get("botName")
if not user_id or not bot_name:
return jsonify({"error": "Missing user_id or botName"}), 400
session_id = f"{user_id}_{bot_name}"
doc = db.collection("sessions").document(session_id).get()
if not doc.exists:
return jsonify({"error": "Session not found"}), 404
messages = doc.to_dict().get("messages", [])
if not messages:
return jsonify({"error": "No messages to summarize"}), 404