cassandrasestier commited on
Commit
cfe8e58
·
verified ·
1 Parent(s): e1df558

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +83 -410
app.py CHANGED
@@ -48,432 +48,105 @@ CRISIS_NUMBERS = {
48
  "Other / Not listed": "Call your local emergency number (**112/911**) or search “suicide crisis hotline” + your country.",
49
  }
50
 
51
- # --- Rich suggestion bank (multiple varied tips per emotion) ---
52
- SUGGESTION_BANK = {
53
  "sadness": [
54
- "Give yourself permission to cry for 5 minutes, then drink a glass of water or take a warm shower.",
55
- "Write a brief self-compassion note as if to a close friend.",
56
- "Micro-walk: 10 minutes outside (or by a window), noticing three colors.",
57
- "Make a ‘just today’ list of one or two tiny doable items.",
58
- "Play a gentle song and place a hand over your heart for 60 seconds.",
 
 
 
59
  ],
60
  "fear": [
61
- "Do 4-7-8 breathing (inhale 4s, hold 7s, exhale 8s) for four cycles.",
62
- "Gentle exposure: take a 2-minute step toward the thing that worries you.",
63
- "Reframe: ‘What if this went better than expected?’ List two positive outcomes.",
64
- "Grounding 5-4-3-2-1 (five things you see down to one taste).",
65
- "If-then plan: ‘If anxiety rises, then I rest one hand on my belly and breathe for 30s.’",
 
 
 
66
  ],
67
  "joy": [
68
- "Savor it: describe three pleasant details (sounds, smells, sensations).",
69
- "Share your joy: send a one-sentence message to someone.",
70
- "Make a memory: jot a quick notewhat made this good?",
71
- "Amplify with the body: gentle stretches, deliberate smile, shoulders back for 20s.",
72
- "Create a tiny ‘capsule’ of the moment (photo or one-line journal).",
 
 
 
73
  ],
74
  "anger": [
75
- "Healthy discharge: 20 squats or 15 wall push-ups.",
76
- "STOP pause: Stop Take a breath Observe • Proceed mindfully.",
77
- "Name it precisely: ‘I’m angry because boundary X was crossed.’",
78
- "Repair plan: draft one assertive sentence (I-feel + need + request).",
79
- "Two-minute brain dump of everything irritating you, then shred the page.",
 
 
 
80
  ],
81
  "boredom": [
82
- "Five-minute rule: set a timer and just start for 5 minutes.",
83
- "Mini-novelty: watch a short intro on a new topic and note one idea.",
84
- "Habit stack: pair a useful task with music/a podcast.",
85
- "Change the environment: different room, lighting, open a window.",
86
- "Micro-challenge: tidy or sort 20 items, then stop.",
 
 
 
87
  ],
88
  "grief": [
89
- "Ritual: light a candle, name one memory, breathe for a minute.",
90
- "Write what youd say to the person/thing you’re missing.",
91
- "Allow the waves: remind yourself grief comes and goes.",
92
- "Contact one trusted person and share a memory.",
93
- "Care for the body: water, simple food, a 10-minute walk.",
 
 
 
94
  ],
95
  "love": [
96
- "Express it with a short sincere message.",
97
- "Concrete gesture: a small note or post-it of appreciation.",
98
- "Presence: 10 minutes screen-free with the person (or with yourself).",
99
- "Positive recall: reread a message/photo and list what you appreciate.",
100
- "Care gesture: prepare something simple for yourself/someone else.",
 
 
 
101
  ],
102
  "nervousness": [
103
- "Coherent breathing at ~6 breaths/minute for 60–90 seconds.",
104
- "Quick body scan: unclench jaw, drop shoulders.",
105
- "Object anchor: hold a cool/grippy object and describe it for 30s.",
106
- "Helpful question: ‘What do I need right now?’ Choose one tiny action.",
107
- "Neck stretch and wrist circles for 30s.",
 
 
 
108
  ],
109
  "curiosity": [
110
- "Form one specific question and look up exactly one reliable answer.",
111
- "Rapid prototype: try a 10-minute micro-test.",
112
- "Note three things you learned and one next question.",
113
- "Explain the idea out loud as if to a child.",
114
- "Add a playful constraint (e.g., $10 / 10 minutes).",
 
 
 
115
  ],
116
  "gratitude": [
117
- "Three gratitudes: one for you, one for someone, one for the world.",
118
- "Active thanks: send a quick thank-you message.",
119
- "Sensory gratitude: three pleasant sensations here-and-now.",
120
- "Future gratitude: ‘Tomorrow I’ll be thankful for…’",
121
- "Snap a photo-gratitude and add a one-line caption.",
122
- ],
123
- "neutral": [
124
- "60-second pause: slow nasal breathing + relax shoulders.",
125
- "Environment tune-up: water, light, posture, fresh air.",
126
- "Pick one two-minute task (dish, email, tidy spot).",
127
- "Five-minute mindful walk, paying attention to footsteps.",
128
- "One-minute stretch: back, neck, wrists.",
129
- ],
130
- }
131
-
132
- # Short quotes (optional spice)
133
- QUOTE_BANK = {
134
- "sadness": ["“This will pass too.”", "“One step at a time.”"],
135
- "fear": ["“Courage is a habit.”", "“Breathe. You can.”"],
136
- "joy": ["“Savor it.”", "“Keep a note of this moment.”"],
137
- "anger": ["“Clarity is a kind of kindness.”", "“Pause before speaking.”"],
138
- "boredom": ["“Action creates motivation.”", "“Start small.”"],
139
- "grief": ["“Love continues in other forms.”", "“Honor what was.”"],
140
- "love": ["“Thank you builds connection.”", "“Presence is love.”"],
141
- "nervousness": ["“Let the body lead the mind.”", "“One breath at a time.”"],
142
- "curiosity": ["“Test to learn.”", "“Question → tiny action.”"],
143
- "gratitude": ["“What you water grows.”", "“See the simple.”"],
144
- "neutral": ["“Return to the body.”", "“Gentle consistency.”"],
145
- }
146
-
147
- COLOR_MAP = {
148
- "joy": "#FFF9C4", "love": "#F8BBD0", "gratitude": "#FFF176",
149
- "sadness": "#BBDEFB", "grief": "#B3E5FC",
150
- "fear": "#E1BEE7", "nervousness": "#E1BEE7",
151
- "anger": "#FFCCBC", "boredom": "#E0E0E0",
152
- "neutral": "#F5F5F5",
153
- }
154
-
155
- # Map GoEmotions label -> your UI buckets
156
- GOEMO_TO_APP = {
157
- "admiration": "gratitude",
158
- "amusement": "joy",
159
- "anger": "anger",
160
- "annoyance": "anger",
161
- "approval": "gratitude",
162
- "caring": "love",
163
- "confusion": "nervousness",
164
- "curiosity": "curiosity",
165
- "desire": "joy",
166
- "disappointment": "sadness",
167
- "disapproval": "anger",
168
- "disgust": "anger",
169
- "embarrassment": "nervousness",
170
- "excitement": "joy",
171
- "fear": "fear",
172
- "gratitude": "gratitude",
173
- "grief": "grief",
174
- "joy": "joy",
175
- "love": "love",
176
- "nervousness": "nervousness",
177
- "optimism": "joy",
178
- "pride": "joy",
179
- "realization": "neutral",
180
- "relief": "gratitude",
181
- "remorse": "grief",
182
- "sadness": "sadness",
183
- "surprise": "neutral",
184
- "neutral": "neutral",
185
- }
186
-
187
- THRESHOLD = 0.30 # probability threshold for selecting labels
188
-
189
- # ---------------- SQLite helpers ----------------
190
- def get_conn():
191
- return sqlite3.connect(DB_PATH, check_same_thread=False, timeout=10)
192
-
193
- def init_db():
194
- conn = None
195
- try:
196
- conn = get_conn()
197
- c = conn.cursor()
198
- c.execute("""
199
- CREATE TABLE IF NOT EXISTS sessions(
200
- id INTEGER PRIMARY KEY AUTOINCREMENT,
201
- ts TEXT,
202
- country TEXT,
203
- user_text TEXT,
204
- main_emotion TEXT
205
- )
206
- """)
207
- conn.commit()
208
- finally:
209
- try:
210
- if conn: conn.close()
211
- except Exception:
212
- pass
213
-
214
- def log_session(country, msg, emotion):
215
- conn = None
216
- try:
217
- conn = get_conn()
218
- c = conn.cursor()
219
- c.execute(
220
- "INSERT INTO sessions(ts, country, user_text, main_emotion) VALUES(?,?,?,?)",
221
- (datetime.utcnow().isoformat(timespec="seconds"), country, msg[:500], emotion),
222
- )
223
- conn.commit()
224
- finally:
225
- try:
226
- if conn: conn.close()
227
- except Exception:
228
- pass
229
-
230
- # ---------------- Train / Load model from DATASET ONLY ----------------
231
- def load_goemotions_dataset():
232
- # "simplified" gives 'text' and 'labels' as list[int] indices
233
- ds = load_dataset("google-research-datasets/go_emotions", "simplified")
234
- label_names = ds["train"].features["labels"].feature.names
235
- return ds, label_names
236
-
237
- def _prepare_xy(split):
238
- # Each example has text and labels (list of ints)
239
- X = split["text"]
240
- y = split["labels"] # list[list[int]]
241
- return X, y
242
-
243
- def train_or_load_model():
244
- # Try cache first
245
- if os.path.isfile(MODEL_PATH):
246
- print("[MM] Loading cached classifier...")
247
- bundle = joblib.load(MODEL_PATH)
248
- if bundle.get("version") == MODEL_VERSION:
249
- return bundle["pipeline"], bundle["mlb"], bundle["label_names"]
250
- else:
251
- print("[MM] Cached model version mismatch; retraining...")
252
-
253
- print("[MM] Loading GoEmotions dataset...")
254
- ds, label_names = load_goemotions_dataset()
255
-
256
- print("[MM] Preparing data...")
257
- X_train, y_train_idx = _prepare_xy(ds["train"])
258
- X_val, y_val_idx = _prepare_xy(ds["validation"])
259
-
260
- # MultiLabelBinarizer to convert list[int] -> multi-hot
261
- mlb = MultiLabelBinarizer(classes=list(range(len(label_names))))
262
- Y_train = mlb.fit_transform(y_train_idx)
263
- Y_val = mlb.transform(y_val_idx)
264
-
265
- # Build pipeline
266
- # - TfidfVectorizer with simple English settings
267
- # - LogisticRegression (saga) in One-vs-Rest for multi-label probabilities
268
- clf = Pipeline(steps=[
269
- ("tfidf", TfidfVectorizer(
270
- lowercase=True,
271
- ngram_range=(1,2),
272
- min_df=2,
273
- max_df=0.9,
274
- strip_accents="unicode",
275
- )),
276
- ("ovr", OneVsRestClassifier(
277
- LogisticRegression(
278
- solver="saga",
279
- max_iter=1000,
280
- n_jobs=-1,
281
- class_weight="balanced",
282
- ),
283
- n_jobs=-1
284
- ))
285
- ])
286
-
287
- print("[MM] Training classifier (this happens once; cached afterward)...")
288
- clf.fit(X_train, Y_train)
289
-
290
- # Quick validation metric (macro F1 over labels present in val)
291
- Y_val_pred = clf.predict(X_val)
292
- macro_f1 = f1_score(Y_val, Y_val_pred, average="macro", zero_division=0)
293
- print(f"[MM] Validation macro F1: {macro_f1:.3f}")
294
-
295
- # Cache model
296
- joblib.dump({
297
- "version": MODEL_VERSION,
298
- "pipeline": clf,
299
- "mlb": mlb,
300
- "label_names": label_names
301
- }, MODEL_PATH)
302
- print(f"[MM] Saved classifier to {MODEL_PATH}")
303
-
304
- return clf, mlb, label_names
305
-
306
- # Train/load at startup
307
- try:
308
- CLASSIFIER, MLB, LABEL_NAMES = train_or_load_model()
309
- except Exception as e:
310
- print(f"[WARN] Failed to train/load classifier: {e}")
311
- CLASSIFIER, MLB, LABEL_NAMES = None, None, None
312
-
313
- # ---------------- Inference using ONLY the trained classifier ----------------
314
- def classify_text(text: str):
315
- """
316
- Returns list of (label_name, prob) for labels above THRESHOLD, sorted desc.
317
- """
318
- if not CLASSIFIER or not MLB or not LABEL_NAMES:
319
- return []
320
-
321
- # predict_proba returns array shape (1, n_labels)
322
- try:
323
- proba = CLASSIFIER.predict_proba([text])[0]
324
- except AttributeError:
325
- # If estimator doesn't support predict_proba (shouldn't happen with LR),
326
- # fall back to decision_function -> sigmoid
327
- from scipy.special import expit
328
- scores = CLASSIFIER.decision_function([text])[0]
329
- proba = expit(scores)
330
-
331
- idxs = [i for i, p in enumerate(proba) if p >= THRESHOLD]
332
- # Sort by probability desc
333
- idxs.sort(key=lambda i: proba[i], reverse=True)
334
- return [(LABEL_NAMES[i], float(proba[i])) for i in idxs]
335
-
336
- def detect_emotions(text: str):
337
- chosen = classify_text(text)
338
- if not chosen:
339
- return [], "neutral"
340
- # Map to app buckets and take the strongest
341
- bucket = {}
342
- for label, p in chosen:
343
- app = GOEMO_TO_APP.get(label.lower(), "neutral")
344
- bucket[app] = max(bucket.get(app, 0.0), p)
345
- main = max(bucket, key=bucket.get) if bucket else "neutral"
346
- return chosen, main
347
-
348
- # ---------------- Response composer (new) ----------------
349
- def compose_support(main_emotion: str, detected: list, is_first_msg: bool) -> str:
350
- """Build a varied reply: 2 tips + 1 reflective question + optional mini-quote."""
351
- tips = SUGGESTION_BANK.get(main_emotion, SUGGESTION_BANK["neutral"])
352
- tips = random.sample(tips, k=min(2, len(tips))) # two distinct tips
353
-
354
- question_bank = {
355
- "sadness": "What would benefit from a bit of care or softness right now?",
356
- "fear": "What would you tell a friend in the same situation?",
357
- "joy": "How could you keep a tiny trace of this moment for later?",
358
- "anger": "What boundary do you want to set calmly, and with whom?",
359
- "boredom": "What two-minute micro-task would move your day forward?",
360
- "grief": "What memory would you like to honor today?",
361
- "love": "What small expression of care could you offer (or offer yourself) now?",
362
- "nervousness": "What would help your body feel 5% safer?",
363
- "curiosity": "What’s the first specific question you want to explore?",
364
- "gratitude": "Who/what deserves a concrete thank-you today?",
365
- "neutral": "What small, simple thing could you do right away?",
366
- }
367
- q = question_bank.get(main_emotion, question_bank["neutral"])
368
-
369
- # 30% chance to add a mini quote
370
- quote = ""
371
- if random.random() < 0.30:
372
- quote_choices = QUOTE_BANK.get(main_emotion, QUOTE_BANK["neutral"])
373
- quote = f"\n\n💬 {random.choice(quote_choices)}"
374
-
375
- # Detected emotions summary (top 3)
376
- summary = ""
377
- if detected:
378
- top = ", ".join([f"{lbl} ({p:.2f})" for lbl, p in detected[:3]])
379
- summary = f"\n\nDetected: {top}"
380
-
381
- # Contextual intro on first message
382
- intro = "Thanks for sharing. 🫶 " if is_first_msg else ""
383
-
384
- return (
385
- f"{intro}• {tips[0]}\n"
386
- f"• {tips[1]}\n\n"
387
- f"🤔 {q}{quote}{summary}"
388
- )
389
-
390
- # ---------------- Chat logic (updated) ----------------
391
- def crisis_block(country):
392
- msg = CRISIS_NUMBERS.get(country, CRISIS_NUMBERS["Other / Not listed"])
393
- return (
394
- "💛 I'm really sorry you're feeling like this. You matter.\n\n"
395
- f"**If you might be in danger or thinking about harming yourself:**\n{msg}\n\n"
396
- "Please reach out to someone now. You are not alone."
397
- )
398
-
399
- def chat_step(message, history, country, save_session):
400
- if CRISIS_RE.search(message):
401
- return crisis_block(country), "#FFD6E7"
402
-
403
- if CLOSING_RE.search(message):
404
- return ("Thank you 💛 Take care of yourself. Small steps matter. 🌿", "#FFFFFF")
405
-
406
- recent = " ".join(message.split()[-100:])
407
- detected, main = detect_emotions(recent)
408
- color = COLOR_MAP.get(main, "#FFFFFF")
409
-
410
- if save_session:
411
- log_session(country, message, main)
412
-
413
- # Build a richer reply using the composer
414
- reply = compose_support(main, detected, is_first_msg=not bool(history))
415
-
416
- return reply, color
417
-
418
- # ---------------- Gradio UI ----------------
419
- init_db()
420
-
421
- custom_css = """
422
- :root, body, .gradio-container { transition: background-color 0.8s ease !important; }
423
- .typing { font-style: italic; opacity: 0.8; animation: blink 1s infinite; }
424
- @keyframes blink { 50% {opacity: 0.4;} }
425
- """
426
-
427
- with gr.Blocks(css=custom_css, title="🪞 MoodMirror+ (Dataset-only Edition)") as demo:
428
- style_injector = gr.HTML("")
429
- gr.Markdown(
430
- "### 🪞 MoodMirror+ — Emotional Support & Inspiration 🌸\n"
431
- "Powered only by the **GoEmotions dataset** (trained locally on startup).\n\n"
432
- "_Not medical advice. If you feel unsafe, please reach out for help immediately._"
433
- )
434
-
435
- with gr.Row():
436
- country = gr.Dropdown(choices=list(CRISIS_NUMBERS.keys()), value="Other / Not listed", label="Country")
437
- save_ok = gr.Checkbox(value=False, label="Save anonymized session (no personal data)")
438
-
439
- chat = gr.Chatbot(height=360)
440
- msg = gr.Textbox(placeholder="Type how you feel...", label="Your message")
441
- send = gr.Button("Send")
442
- typing = gr.Markdown("", elem_classes="typing")
443
-
444
- # Optional: dataset sample preview (for transparency)
445
- with gr.Accordion("🔎 Preview GoEmotions samples", open=False):
446
- with gr.Row():
447
- n_examples = gr.Slider(1, 10, value=5, step=1, label="Number of examples")
448
- split = gr.Dropdown(["train", "validation", "test"], value="train", label="Split")
449
- refresh = gr.Button("Show samples")
450
- table = gr.Dataframe(headers=["text", "labels"], row_count=5, wrap=True)
451
-
452
- def refresh_samples(n, split_name):
453
- try:
454
- ds = load_dataset("google-research-datasets/go_emotions", "simplified")
455
- names = ds["train"].features["labels"].feature.names
456
- rows = ds[split_name].shuffle(seed=42).select(range(min(int(n), len(ds[split_name]))))
457
- return [[t, ", ".join([names[i] for i in labs])] for t, labs in zip(rows["text"], rows["labels"])]
458
- except Exception as e:
459
- return [[f"Dataset load error: {e}", ""]]
460
-
461
- refresh.click(refresh_samples, inputs=[n_examples, split], outputs=[table])
462
-
463
- def respond(user_msg, chat_hist, country_choice, save_flag):
464
- if not user_msg or not user_msg.strip():
465
- yield chat_hist + [[user_msg, "Please share a short sentence about how you feel 🙂"]], "", "", ""
466
- return
467
- yield chat_hist, "💭 MoodMirror is thinking...", "", ""
468
- reply, color = chat_step(user_msg, chat_hist, country_choice, bool(save_flag))
469
- style_tag = f"<style>:root,body,.gradio-container{{background:{color}!important;}}</style>"
470
- yield chat_hist + [[user_msg, reply]], "", style_tag, ""
471
-
472
- send.click(respond, inputs=[msg, chat, country, save_ok],
473
- outputs=[chat, typing, style_injector, msg], queue=True)
474
- msg.submit(respond, inputs=[msg, chat, country, save_ok],
475
- outputs=[chat, typing, style_injector, msg], queue=True)
476
-
477
- if __name__ == "__main__":
478
- demo.queue()
479
- demo.launch()
 
48
  "Other / Not listed": "Call your local emergency number (**112/911**) or search “suicide crisis hotline” + your country.",
49
  }
50
 
51
+ # --- Deep, varied emotional advice & comfort phrases ---
52
+ SUGGESTIONS = {
53
  "sadness": [
54
+ "Be gentle with yourself. Cry if you need to that’s healing, not weakness.",
55
+ "Let yourself rest. You don’t have to be productive while your heart is heavy.",
56
+ "Hold a pillow or blanket close and breathe slowly.",
57
+ "Talk to someone who feels safe, or write down what you wish someone would say to you.",
58
+ "It’s okay if today you just get through the day.",
59
+ "Take a warm shower, drink water, and do one small thing that feels kind.",
60
+ "Remember: sadness is a visitor, not your home.",
61
+ "Even quiet tears are a form of strength — you’re still here.",
62
  ],
63
  "fear": [
64
+ "Ground yourself with slow breathing feel your feet on the floor.",
65
+ "You are safe in this moment. Focus on what is real right now.",
66
+ "Courage isn’t about not being afraid; it’s choosing to keep going anyway.",
67
+ "Remind yourself: not every thought is a fact.",
68
+ "Small steps are still progress you don’t need to have the whole plan.",
69
+ "Try saying out loud: ‘I can handle this one moment at a time.’",
70
+ "Place a hand on your chest and whisper, ‘I am safe. I am present.’",
71
+ "Fear often shows up before growth — maybe something new is calling.",
72
  ],
73
  "joy": [
74
+ "Savor this your body deserves to feel good.",
75
+ "Let the joy sink in; you don’t have to rush to the next thing.",
76
+ "Share your happiness with someoneeven a smile counts.",
77
+ "Write down what’s bringing you joy today. It strengthens the memory.",
78
+ "Take a deep breath and feel gratitude for this small light moment.",
79
+ "Joy can be quiet — a cup of tea, a laugh, a calm pause.",
80
+ "Smile for no reason; your brain will thank you later.",
81
+ "Notice how joy feels in your body, and let yourself stay there for a while.",
82
  ],
83
  "anger": [
84
+ "Pause and breathe you don’t have to react right away.",
85
+ "Anger can mean something important needs attention listen kindly.",
86
+ "Take a walk or shake out the tension before speaking.",
87
+ "Write everything you want to say, then decide what actually needs saying.",
88
+ "It’s okay to be angry what matters is what you do with it.",
89
+ "Drink water and give your body a few minutes to settle.",
90
+ "Sometimes the kindest thing is to wait before responding.",
91
+ "Ask yourself: ‘What boundary of mine needs care right now?’",
92
  ],
93
  "boredom": [
94
+ "Boredom can be a doorway something in you wants to wake up.",
95
+ "Try something completely small and new: a song, a stretch, a random fact.",
96
+ "Put on music and tidy for 5 minutes — movement often sparks motivation.",
97
+ "Write a list of ‘tiny adventures’ you could do today.",
98
+ "Sometimes doing nothing is what your mind needs — rest counts.",
99
+ "Look outside for a moment — notice one color or sound you hadn’t before.",
100
+ "Ask yourself: ‘What might make me curious right now?’",
101
+ "Do one creative thing without judging it — draw, hum, doodle, move.",
102
  ],
103
  "grief": [
104
+ "Grief is love that has nowhere to go let it speak softly through you.",
105
+ "Youre allowed to miss them and still keep living.",
106
+ "Light a candle, whisper their name, and breathe.",
107
+ "Eat something, drink water caring for your body honors their memory too.",
108
+ "It’s okay to cry about the same thing more than once.",
109
+ "Talk about your loss. The pain lessens when it’s witnessed.",
110
+ "Hold an item that reminds you of love, not loss.",
111
+ "Healing doesn’t mean forgetting; it means remembering with more peace.",
112
  ],
113
  "love": [
114
+ "Tell someone you care about them — even in a small text.",
115
+ "Give love back to yourself: you deserve your own gentleness.",
116
+ "Love is quiet presence you don’t have to prove it.",
117
+ "A small act of kindness can brighten two days at once.",
118
+ "You are loved simply for being, not for doing.",
119
+ "Love often grows in silence and simple gestures.",
120
+ "Send out a silent thank-you to those who care for you.",
121
+ "Let yourself receive love — it’s not selfish to need warmth.",
122
  ],
123
  "nervousness": [
124
+ "Breathe slower than your worry your body will follow your rhythm.",
125
+ "Relax your jaw, drop your shoulders, exhale longer than you inhale.",
126
+ "You don’t have to fix every thought; let them pass like clouds.",
127
+ "Try naming five things you can see right now.",
128
+ "Anxiety is a false alarm you can remind your brain you’re safe.",
129
+ "Put both feet flat on the floor and press gently to ground yourself.",
130
+ "Write down what worries you, then cross out what you can’t control.",
131
+ "You can pause; you’re not behind. Safety starts with one breath.",
132
  ],
133
  "curiosity": [
134
+ "Follow the spark it doesn’t have to make sense yet.",
135
+ "Ask the question that feels exciting, not the one that feels safe.",
136
+ "Let yourself explore something simply because it’s interesting.",
137
+ "Learning is self-care too wonder is nourishment.",
138
+ "Take 10 minutes to google something random you love.",
139
+ "Curiosity is courage in disguise — let it lead.",
140
+ "Even small discoveries can wake up your energy.",
141
+ "Be a beginner; it’s a powerful place to start.",
142
  ],
143
  "gratitude": [
144
+ "Name three things you’re grateful for big or tiny.",
145
+ "Gratitude turns ordinary moments into something sacred.",
146
+ "Say ‘thank you’ out loud, even if just to yourself.",
147
+ "Look around and notice something that quietly supports you.",
148
+ "Each breath is a gift you didn’t have to earn.",
149
+ "Gratitude softens fear; it reminds you what’s still good.",
150
+ "Send a short thank-you message to someone right now.",
151
+ "Appreciate how far you’ve already come quietly, just for you.",
152
+ ]