Strong1Mindtherapist commited on
Commit
454920c
·
verified ·
1 Parent(s): 75331fb

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +452 -0
  2. requirements.txt +6 -0
app.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from gtts import gTTS
2
+ import tempfile
3
+ import json
4
+ import datetime
5
+ import gradio as gr
6
+
7
+ # ----------------------------
8
+ # User data & existing lists
9
+ # ----------------------------
10
+ user_info = {"name": "", "age": "", "gender": "", "language": "english" , "Guardian_info": ""}
11
+ chat_history = []
12
+ journal_entries = []
13
+
14
+ calm_tips = [
15
+ "Take 3 deep breaths.", "Listen to nature.", "Stretch your body.",
16
+ "Drink water.", "Think of one good thing today.", "Close your eyes for 1 minute.",
17
+ "Write your feelings.", "Smile at yourself.", "Imagine a peaceful place.",
18
+ "Say a positive affirmation."
19
+ ]
20
+
21
+ study_tips = [
22
+ "Use Pomodoro: 25min study, 5min break", "Make a daily to-do list",
23
+ "Avoid multitasking", "Use color-coded notes", "Take 10-min exercise breaks",
24
+ "Sleep 7–9 hrs daily", "Drink water during study", "Use active recall",
25
+ "Study hardest topics first", "Test yourself often"
26
+ ]
27
+
28
+ tip_index = {"calm": 0, "study": 0}
29
+
30
+ lang_codes = {
31
+ "english": "en", "hindi": "hi", "marathi": "mr", "bengali": "bn",
32
+ "tamil": "ta", "telugu": "te", "malayalam": "ml", "spanish": "es",
33
+ "french": "fr", "german": "de"
34
+ }
35
+
36
+ # (Keep your harmful_keywords and emotions as-is — shortened here for clarity)
37
+ harmful_keywords = [
38
+ # ... (keep the full list from your original file) ...
39
+ "suicide", "kill myself", "end my life", "harm myself", "cut myself",
40
+ "want to die", "die", "jump off", "self-harm", "self-hate", "suicidal",
41
+ # etc.
42
+ ]
43
+
44
+ harmful_response = (
45
+ "⚠️ It sounds like you're going through a really tough time.\n\n"
46
+ "Please reach out to a professional:\n\n"
47
+ "🇮🇳 **India Helplines**\n"
48
+ "🧠 *Dr. Rachna Khanna Singh* – +91 99103 90559\n"
49
+ "📞 *iCall Helpline* – +91 9152987821\n"
50
+ "📞 *Vandrevala Foundation* – 1860 266 2345 or 1800 233 3330\n\n"
51
+ "🌍 **International Helplines**\n"
52
+ "📞 *Lifeline (USA)* – 988\n"
53
+ "📞 *Samaritans (UK)* – 116 123\n"
54
+ "📞 *Lifeline (Australia)* – 13 11 14\n\n"
55
+ "You are not alone. There are people who care and want to help 💚"
56
+ )
57
+
58
+ # Simplified emotions dictionary (keep your full mapping; trimmed in this view)
59
+ emotions = {
60
+ "sad": "I hear you 💙. I’m really sorry you’re feeling sad right now. Do you want to tell me what’s making you feel this way, or would you rather I just try to gently cheer you up?",
61
+ "anxiety": "It’s okay — anxiety can feel overwhelming, like your mind is running a race it didn’t sign up for. Try slowing down your breathing: inhale for 4 seconds, hold for 4, exhale for 6.",
62
+ "angry": "It’s normal to feel angry — it’s your mind’s way of telling you something feels unfair or hurtful.",
63
+ # ... keep the rest of your emotion replies ...
64
+ }
65
+
66
+ # ----------------------------
67
+ # Conversation state for Hybrid (C) memory model
68
+ # ----------------------------
69
+ conversation_state = {
70
+ "emotion": None, # e.g., "sad"
71
+ "context": None, # e.g., "school", "parents", "friend", "exam"
72
+ "followup_stage": 0, # how many follow-ups we've done for this emotion
73
+ "turns_since_set": 0 # used to expire after a small idle period if needed
74
+ }
75
+
76
+ # Keywords to detect context quickly
77
+ context_markers = {
78
+ "school": ["school", "exam", "test", "teacher", "class"],
79
+ "parents": ["parent", "mom", "dad", "parents", "home"],
80
+ "friend": ["friend", "friends", "bully", "shouted", "argument", "fight"],
81
+ "health": ["sick", "unwell", "hospital", "doctor"],
82
+ "love": ["crush", "boyfriend", "girlfriend", "heartbroken", "love"],
83
+ # add more markers as needed
84
+ }
85
+
86
+ # Follow-up templates (3 steps each, then action suggestions)
87
+ followups = {
88
+ "sad": [
89
+ "I’m really sorry you’re feeling sad. Can you tell me if this happened recently or is it been building up?",
90
+ "Thank you for sharing. How did that make you feel — more hurt, embarrassed, or something else?",
91
+ "That sounds heavy. Would you like a calming exercise, to write about it in the journal, or to talk more?"
92
+ ],
93
+ "anxiety": [
94
+ "Anxiety can be overwhelming. Is it about something specific like exams or relationships?",
95
+ "When your anxiety spikes, do you notice physical signs like a racing heart or trouble breathing?",
96
+ "Would you like to try a short breathing exercise now, or do you want to talk about what’s triggering it?"
97
+ ],
98
+ "angry": [
99
+ "Anger is a valid response. Do you want to share what caused this anger?",
100
+ "When you feel angry, what usually helps — space, talking, or doing something active?",
101
+ "Would you like ideas to safely express the anger, or would you prefer calming techniques first?"
102
+ ],
103
+ # fallback for other emotions:
104
+ "default": [
105
+ "Tell me more about that — when did you start feeling this way?",
106
+ "How strong does this feeling feel on a scale of 1 to 10?",
107
+ "Would you like a calming activity, a journal prompt, or to continue talking?"
108
+ ]
109
+ }
110
+
111
+ # Reset phrases (user indicates they are fine or want to change topic)
112
+ reset_phrases = [
113
+ "i'm fine", "i am fine", "i'm okay", "i am okay", "i feel better",
114
+ "thank you", "thanks", "that's all", "let's talk about something else",
115
+ "stop", "no", "I'm good", "im good"
116
+ ]
117
+
118
+ # ----------------------------
119
+ # Helper functions
120
+ # ----------------------------
121
+ def _contains_any(text, keywords):
122
+ text = text.lower()
123
+ for kw in keywords:
124
+ if kw in text:
125
+ return True
126
+ return False
127
+
128
+ def detect_harmful(text):
129
+ t = text.lower()
130
+ for kw in harmful_keywords:
131
+ if kw in t:
132
+ return True
133
+ return False
134
+
135
+ def detect_emotion_in_text(text):
136
+ t = text.lower()
137
+ # Prefer longer keys first (to avoid 'sad' matching inside other words) — optional improvement
138
+ sorted_keys = sorted(emotions.keys(), key=lambda x: -len(x))
139
+ for key in sorted_keys:
140
+ if key in t:
141
+ return key
142
+ return None
143
+
144
+ def detect_context_in_text(text):
145
+ t = text.lower()
146
+ for ctx, markers in context_markers.items():
147
+ for m in markers:
148
+ if m in t:
149
+ return ctx
150
+ return None
151
+
152
+ def is_reset_phrase(text):
153
+ t = text.lower()
154
+ for phrase in reset_phrases:
155
+ if phrase in t:
156
+ return True
157
+ return False
158
+
159
+ def build_empathy_reply(emotion):
160
+ # Base empathy from emotions dict, plus a gentle follow-up question from followups
161
+ base = emotions.get(emotion, "")
162
+ # Pick a gentle opener if no followups defined
163
+ return base
164
+
165
+ # ----------------------------
166
+ # Upgraded reply generator with memory, context, multi-turn flow
167
+ # ----------------------------
168
+ def generate_reply(input_text):
169
+ text = input_text.strip()
170
+ if not text:
171
+ return "Please say or type something when you are ready."
172
+
173
+ lower = text.lower()
174
+
175
+ # 1) Immediate harmful check (escalate without delay)
176
+ if detect_harmful(lower):
177
+ # Reset conversation state because we escalate
178
+ conversation_state["emotion"] = None
179
+ conversation_state["context"] = None
180
+ conversation_state["followup_stage"] = 0
181
+ conversation_state["turns_since_set"] = 0
182
+ return harmful_response
183
+
184
+ # 2) User reset intent — end current flow politely
185
+ if is_reset_phrase(lower):
186
+ conversation_state["emotion"] = None
187
+ conversation_state["context"] = None
188
+ conversation_state["followup_stage"] = 0
189
+ conversation_state["turns_since_set"] = 0
190
+ return "That's ok — we can pause here. If you'd like to talk again later, I'm right here."
191
+
192
+ # 3) Detect if user explicitly states a new emotion -> override current state
193
+ new_emotion = detect_emotion_in_text(lower)
194
+ if new_emotion and new_emotion != conversation_state["emotion"]:
195
+ # start new flow
196
+ conversation_state["emotion"] = new_emotion
197
+ conversation_state["context"] = detect_context_in_text(lower)
198
+ conversation_state["followup_stage"] = 0
199
+ conversation_state["turns_since_set"] = 0
200
+ # Compose reply: empathy + first follow-up
201
+ empathy = build_empathy_reply(new_emotion)
202
+ # get followup prompt
203
+ prompts = followups.get(new_emotion, followups["default"])
204
+ follow = prompts[0] if prompts else ""
205
+ # Combine neatly
206
+ combined = f"{empathy}\n\n{follow}"
207
+ return combined
208
+
209
+ # 4) If an emotion is already active, continue that flow
210
+ if conversation_state["emotion"]:
211
+ emotion = conversation_state["emotion"]
212
+ # Update context if we find context in this message
213
+ ctx = detect_context_in_text(lower)
214
+ if ctx:
215
+ conversation_state["context"] = ctx
216
+
217
+ # If the user provided details (short heuristic: message length > 20 or contains certain markers),
218
+ # treat this as progress and advance the follow-up stage
219
+ provided_detail = (len(lower) > 20) or any(w in lower for w in ["because", "so", "then", "after", "today", "yesterday", "last", "friend", "parents", "teacher", "exam", "test"])
220
+
221
+ stage = conversation_state["followup_stage"]
222
+ prompts = followups.get(emotion, followups["default"])
223
+
224
+ # If user asked a question (contains '?'), attempt to respond empathetically referencing emotion/context
225
+ if "?" in lower:
226
+ # Respond referencing emotion and context
227
+ ctx_text = f" about {conversation_state['context']}" if conversation_state["context"] else ""
228
+ response = f"I hear your question{ctx_text}. Let's look at that together. {emotions.get(emotion,'')}"
229
+ # do not advance stage on simple question
230
+ conversation_state["turns_since_set"] += 1
231
+ return response
232
+
233
+ if provided_detail:
234
+ # Provide a reply that references the emotion and context and then advance
235
+ ctx_text = ""
236
+ if conversation_state["context"]:
237
+ ctx_text = f" because of {conversation_state['context']}"
238
+ # Construct reflective reply
239
+ if stage < len(prompts):
240
+ response = f"I understand — it makes sense you'd feel {emotion}{ctx_text}. {prompts[stage]}"
241
+ conversation_state["followup_stage"] += 1
242
+ conversation_state["turns_since_set"] = 0
243
+ return response
244
+ else:
245
+ # Follow-ups exhausted; offer actionable choices
246
+ conversation_state["turns_since_set"] += 1
247
+ return ("You have shared a lot — would you like to: \n"
248
+ "1) Try a calming exercise now\n"
249
+ "2) Write this in your journal\n"
250
+ "3) Talk more about it\n\n"
251
+ "Type '1', '2', or '3' to choose, or tell me if you want a helpline.")
252
+ else:
253
+ # User gave a short reply — ask a clarifying / gentle follow-up without advancing too far
254
+ if stage < len(prompts):
255
+ response = prompts[stage]
256
+ # only advance if we already showed that prompt previously
257
+ conversation_state["turns_since_set"] += 1
258
+ # If we had asked the same prompt previously and user still gives short replies, advance stage
259
+ if conversation_state["turns_since_set"] > 1:
260
+ conversation_state["followup_stage"] = min(len(prompts), stage + 1)
261
+ conversation_state["turns_since_set"] = 0
262
+ return response
263
+ else:
264
+ # if stages done but no detail, ask for choice
265
+ return ("I’m listening. If it's hard to describe, choose: 1) calming exercise 2) journal 3) talk more. "
266
+ "Or say 'I'm fine' to stop.")
267
+ # 5) No active emotion and no new emotion detected -> try to detect context or ask to elaborate
268
+ ctx = detect_context_in_text(lower)
269
+ if ctx:
270
+ # Gentle probing
271
+ return f"You mentioned {ctx}. Is this making you feel upset or worried? How does it make you feel?"
272
+ # Default fallback
273
+ return "Tell me more about your day — what happened, or how are you feeling right now?"
274
+
275
+ # ----------------------------
276
+ # Chat function (uses TTS + conversation_state)
277
+ # ----------------------------
278
+ def chat_function(audio_input, text_input):
279
+ # We ignore audio_input here for text-only flow; you can add speech-to-text to use it.
280
+ user_text = (text_input or "").strip()
281
+ if not user_text:
282
+ return "Please type something.", None
283
+
284
+ reply = generate_reply(user_text)
285
+
286
+ # Save conversation to history
287
+ chat_history.append({"user": user_text, "bot": reply, "emotion": conversation_state.get("emotion"), "context": conversation_state.get("context")})
288
+
289
+ # Text-to-speech (language selection)
290
+ lang_code = lang_codes.get(user_info["language"], "en")
291
+ try:
292
+ tts = gTTS(reply, lang=lang_code)
293
+ audio_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp3")
294
+ tts.save(audio_file.name)
295
+ voice_path = audio_file.name
296
+ except Exception as e:
297
+ # If TTS fails, still return the reply and no voice
298
+ voice_path = None
299
+
300
+ return reply, voice_path
301
+
302
+ # ----------------------------
303
+ # Remaining utility functions (unchanged)
304
+ # ----------------------------
305
+ def set_personal_info(name, age, gender, language, Guardian_info):
306
+ user_info.update({"name": name, "age": age, "gender": gender, "language": language, "Guardian_info": Guardian_info,})
307
+ return gr.update(visible=True), f"✅ Welcome {name}! Preferences saved."
308
+
309
+ def show_personal_data():
310
+ today = datetime.date.today().strftime("%Y-%m-%d (%A)")
311
+ return f"📅 {today}\n👤 Name: {user_info['name']}\n🎂 Age: {user_info['age']}\n♀ Gender: {user_info['gender']}\n🌐 Language: {user_info['language']}\n Guardian_info: {user_info['Guardian_info']}"
312
+
313
+ def get_chat_history():
314
+ if not chat_history:
315
+ return "No conversations yet."
316
+ return "\n\n".join([f"You: {c['user']}\nBot: {c['bot']}" for c in chat_history])
317
+
318
+ def save_journal(entry):
319
+ journal_entries.append(entry)
320
+ with open("journal.json", "w") as f:
321
+ json.dump(journal_entries, f)
322
+ return "✅ Journal saved!"
323
+
324
+ def show_journal_history():
325
+ return "\n---\n".join(journal_entries) if journal_entries else "No journal entries yet."
326
+
327
+ def next_calm_tip():
328
+ tip = calm_tips[tip_index["calm"] % len(calm_tips)]
329
+ tip_index["calm"] += 1
330
+ return tip
331
+
332
+ def next_study_tip():
333
+ tip = study_tips[tip_index["study"] % len(study_tips)]
334
+ tip_index["study"] += 1
335
+ return tip
336
+
337
+ # ----------------------------
338
+ # Gradio UI (kept same as your original file)
339
+ # ----------------------------
340
+ with gr.Blocks() as app:
341
+ welcome_screen = gr.Column(visible=True)
342
+ full_app = gr.Tabs(visible=False)
343
+
344
+ with welcome_screen:
345
+ gr.HTML("""
346
+ <style>
347
+ #main-title {
348
+ text-align: center;
349
+ font-size: 2.5em;
350
+ }
351
+ #subtitle {
352
+ text-align: center;
353
+ font-size: 1.2em;
354
+ color: #ccc;
355
+ margin-bottom: 30px;
356
+ }
357
+ #start-btn {
358
+ background-color: #ff69b4;
359
+ color: white;
360
+ font-weight: bold;
361
+ border: none;
362
+ border-radius: 10px;
363
+ padding: 14px 45px;
364
+ font-size: 1.1em;
365
+ cursor: pointer;
366
+ display: block;
367
+ margin: 0 auto;
368
+ }
369
+ #start-btn:hover {
370
+ background-color: #ff85c1;
371
+ }
372
+ </style>
373
+ """)
374
+ gr.Markdown("<h1 id='main-title'>StrongMind Therapist 3.0</h1>")
375
+ gr.Markdown("<h3 id='subtitle'>Your peaceful space to talk, journal, and focus.</h3>")
376
+ start_button = gr.Button("🌸 Get Started", elem_id="start-btn")
377
+
378
+ def start_app():
379
+ return gr.update(visible=False), gr.update(visible=True)
380
+
381
+ start_button.click(start_app, outputs=[welcome_screen, full_app])
382
+
383
+ with full_app:
384
+ with gr.Tab("1️⃣ Personal Info"):
385
+ name = gr.Textbox(label="Name")
386
+ age = gr.Textbox(label="Age")
387
+ gender = gr.Dropdown(["Male", "Female", "Other"], label="Gender")
388
+ language = gr.Dropdown(list(lang_codes.keys()), label="Preferred Language")
389
+ Guardian_info = gr.Textbox(label="Guardian information")
390
+ btn = gr.Button("Save Info")
391
+ popup = gr.Markdown(visible=False, elem_classes="alert-box")
392
+ btn.click(set_personal_info, [name, age, gender, language,Guardian_info], [popup, popup])
393
+
394
+ with gr.Tab("2️⃣ Personal Info Data"):
395
+ show = gr.Button("Show My Info")
396
+ info_display = gr.Textbox(lines=6)
397
+ show.click(show_personal_data, outputs=info_display)
398
+
399
+ with gr.Tab("3️⃣ Chat"):
400
+ gr.Markdown("🗣️ Describe your day in one word.")
401
+ audio_input = gr.Audio(type="filepath", label="🎧 Say something")
402
+ text_input = gr.Textbox(label="⌨️ Or type here")
403
+ send = gr.Button("Send")
404
+ bot_reply = gr.Textbox(label="🧠 Therapist")
405
+ voice = gr.Audio(label="🔊 Voice Reply")
406
+ send.click(chat_function, [audio_input, text_input], [bot_reply, voice])
407
+
408
+ with gr.Tab("4️⃣ Chat History"):
409
+ show_history = gr.Button("📜 Show Chats")
410
+ chat_out = gr.Textbox(lines=20, label="History")
411
+ show_history.click(get_chat_history, outputs=chat_out)
412
+
413
+ with gr.Tab("5️⃣ Journal"):
414
+ journal_input = gr.Textbox(lines=6, label="Write your thoughts")
415
+ save = gr.Button("Save")
416
+ journal_status = gr.Textbox()
417
+ save.click(save_journal, journal_input, journal_status)
418
+
419
+ with gr.Tab("6️⃣ Journal History"):
420
+ view = gr.Button("View Past Entries")
421
+ past = gr.Textbox(lines=15, label="Previous Journals")
422
+ view.click(show_journal_history, outputs=past)
423
+
424
+ with gr.Tab("7️⃣ Calm Space"):
425
+ tip_btn = gr.Button("🌿 Give Me a Calm Tip")
426
+ calm_text = gr.Textbox()
427
+ tip_btn.click(next_calm_tip, outputs=calm_text)
428
+
429
+ with gr.Tab("8️⃣ Study Tips"):
430
+ tip_btn2 = gr.Button("📚 Study Tip")
431
+ study_text = gr.Textbox()
432
+ tip_btn2.click(next_study_tip, outputs=study_text)
433
+
434
+ with gr.Tab("9️⃣ Pomodoro"):
435
+ gr.Markdown("⏱️ Use 25 min study + 5 min break cycles.\n(For real timer, use front-end JavaScript or Android timers)")
436
+
437
+ with gr.Tab("💠 Games"):
438
+ gr.Markdown("🎮 Play from the game portal below:")
439
+ gr.HTML(
440
+ '''
441
+ <iframe
442
+ src="https://www.onlinegames.io/embed/portal/"
443
+ width="100%"
444
+ height="600"
445
+ frameborder="0"
446
+ allowfullscreen>
447
+ </iframe>
448
+ '''
449
+ )
450
+
451
+ if __name__ == "__main__":
452
+ app.launch()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ gradio==4.14.0
2
+ gtts
3
+ pydub
4
+ numpy
5
+ openai-whisper
6
+ torch