Spaces:
Running
Running
import os | |
import random | |
from datetime import datetime, timedelta | |
from flask import Flask, request, jsonify, make_response | |
from flask_cors import CORS | |
from flask_bcrypt import Bcrypt | |
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity, JWTManager | |
import numpy as np | |
import tensorflow as tf | |
import joblib | |
from transformers import DistilBertForSequenceClassification, DistilBertTokenizer | |
from pymongo import MongoClient | |
from bson import ObjectId | |
import torch | |
import logging | |
import requests | |
import google.generativeai as genai | |
from dotenv import load_dotenv | |
load_dotenv() | |
# --- App Initialization --- | |
app = Flask(__name__) | |
# The new, more explicit configuration | |
CORS(app, resources={ | |
r"/api/*": { | |
"origins": "*", # Allow all origins | |
"methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"], # Allow these methods | |
"headers": ["Content-Type", "Authorization"] # Allow these headers | |
} | |
}) | |
def add_cors_headers(response): | |
response.headers['Access-Control-Allow-Origin'] = '*' | |
response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' | |
response.headers['Access-Control-Allow-Methods'] = 'GET,PUT,POST,DELETE,OPTIONS' | |
return response | |
# Allow requests from your React frontend | |
# GENERATE GEMINI RESPONSES --- Add this right after your imports and "load_dotenv()" --- | |
# --- Configuration --- | |
# It's crucial to set a secret key for JWT. | |
# In production, use a long, random string stored in an environment variable. | |
app.config["JWT_SECRET_KEY"] = os.environ.get("JWT_SECRET_KEY") | |
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(hours=24) | |
bcrypt = Bcrypt(app) | |
jwt = JWTManager(app) | |
# --- Logging Setup --- | |
logging.basicConfig(level=logging.INFO) | |
logger = logging.getLogger(__name__) | |
try: | |
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY") | |
genai.configure(api_key=GEMINI_API_KEY) | |
logger.info("β Gemini API configured successfully.") | |
except Exception as e: | |
logger.error(f"β Error configuring Gemini API: {e}") | |
GEMINI_API_KEY = None | |
def generate_gemini_response(emotion, confidence, user_message, chat_history): # Add chat_history | |
""" | |
Generates a supportive response from Gemini based on context. | |
""" | |
if not GEMINI_API_KEY: | |
return "I'm currently unable to process this request. Please try again later." | |
system_prompt = f""" | |
You are 'MindWell', a compassionate and supportive AI mental health companion. | |
**Your Strict Rules:** | |
1. NEVER claim to be a human, a doctor, or a licensed therapist. | |
2. NEVER diagnose any condition. | |
3. Keep responses concise and gentle (1-3 sentences). | |
4. Provide simple, actionable coping strategies or reflective questions. | |
5. If the user's message implies crisis, your ONLY response is: "CRISIS_RESPONSE" | |
--- | |
**PREVIOUS CONVERSATION HISTORY (FOR CONTEXT):** | |
{chat_history} | |
--- | |
**CURRENT INTERACTION:** | |
- User's Detected Emotion (from this message): {emotion} | |
- Confidence in Detection: {confidence:.2f}% | |
- User's New Message: "{user_message}" | |
Based on the previous history and the current interaction, generate a supportive and relevant response. If the history mentions a high stress score, acknowledge it gently. | |
""" | |
# ... the rest of the function is the same | |
try: | |
model = genai.GenerativeModel('gemini-1.5-flash-latest') # A great, free-tier model | |
response = model.generate_content(system_prompt) | |
return response.text | |
except Exception as e: | |
logger.error(f"Error calling Gemini API: {e}") | |
return "I'm having a little trouble thinking of a response right now. Could you try rephrasing?" | |
# =================================================================================== | |
# --- MODEL LOADING --- | |
# =================================================================================== | |
# --- 1. Load Stress Prediction Model & Scaler --- | |
try: | |
stress_model = tf.keras.models.load_model("stress_model.h5") | |
stress_scaler = joblib.load("scaler.pkl") | |
logger.info("β Stress prediction model and scaler loaded successfully.") | |
except Exception as e: | |
logger.error(f"β Error loading stress model or scaler: {e}") | |
stress_model = None | |
stress_scaler = None | |
# --- 2. Load Chatbot Emotion Model & Tokenizer --- | |
try: | |
# Ensure you have the fine-tuned model files in a directory named 'fine_tuned_model' | |
chatbot_model = DistilBertForSequenceClassification.from_pretrained("./fine_tuned_model") | |
chatbot_tokenizer = DistilBertTokenizer.from_pretrained("./fine_tuned_model") | |
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
chatbot_model.to(device) | |
chatbot_model.eval() | |
logger.info(f"β Chatbot model loaded successfully on {device}.") | |
except Exception as e: | |
logger.error(f"β Error loading chatbot model: {e}") | |
chatbot_model = None | |
chatbot_tokenizer = None | |
# --- 3. Load Facial Emotion Detection Model --- | |
try: | |
emotion_model_filename = 'emotion_classifier_rf_TUNED.joblib' | |
facial_emotion_model = joblib.load(emotion_model_filename) | |
# This dictionary maps the model's integer output to a human-readable emotion | |
facial_emotion_labels = {0: 'Angry', 1: 'Disgust', 2: 'Fear', 3: 'Happy', 4: 'Sad', 5: 'Surprise', 6: 'Neutral'} | |
logger.info(f"β Facial emotion detection model loaded from: {emotion_model_filename}") | |
except Exception as e: | |
logger.error(f"β Error loading facial emotion model: {e}") | |
facial_emotion_model = None | |
# --- MongoDB Setup for Chat Logs --- | |
try: | |
MONGO_URI = os.environ.get("MONGO_URI") | |
client = MongoClient(MONGO_URI) | |
db = client["mindcare_db"] # Using a new database name for clarity | |
users_collection = db["users"] | |
stress_logs_collection = db["stress_logs"] | |
chat_logs_collection = db["chat_logs"] # You already had this | |
cbt_records_collection = db["cbt_records"] | |
meditations_collection = db["meditations"] | |
logger.info("β MongoDB connection established.") | |
except Exception as e: | |
logger.error(f"β Error connecting to MongoDB: {e}") | |
users_collection = None | |
cbt_records_collection = None | |
# --- Chatbot Helper Data --- | |
# This label map is for the text-based emotion detection in the chatbot | |
text_emotion_label_map = {0: "positive", 1: "negative"} | |
helplines = { | |
"US": "1-800-273-8255 (National Suicide Prevention Lifeline)", | |
"India": "9152987821 (iCall, India), +91-22-25521111 (Samaritans Mumbai)", | |
"Global": "Find local helplines at www.iasp.info/resources/Crisis_Centres/" | |
} | |
suggestion_library = { | |
"low": { | |
"Breathing": {"title": "Mindful Sigh", "description": "Inhale deeply through your nose and exhale with an audible sigh. A simple way to release tension and reset.", "link": "https://www.youtube.com/watch?v=r6Vynwn_q-U"}, | |
"Yoga": {"title": "Cat-Cow Stretch", "description": "A gentle, accessible stretch to increase spinal flexibility and calm the mind. Great for any time of day.", "link": "https://www.youtube.com/watch?v=LIVJZZyZ2qM"}, | |
"Music": {"title": "Lofi Hip Hop Radio", "description": "Relaxing beats perfect for studying, relaxing, or focusing without distraction.", "link": "https://www.youtube.com/watch?v=lTRiuFIWV54"} | |
}, | |
"medium": { | |
"Breathing": {"title": "Box Breathing", "description": "Inhale for 4s, hold for 4s, exhale for 4s, hold for 4s. A powerful technique to calm the nervous system.", "link": "https://www.youtube.com/watch?v=tEmt1Znux58"}, | |
"Yoga": {"title": "Child's Pose", "description": "A resting pose that can help relieve stress and fatigue. It gently stretches your back, hips, and ankles.", "link": "https://www.youtube.com/watch?v=kH12QrSGedM"}, | |
"Music": {"title": "Calm Piano Music", "description": "Beautiful, light piano music that can help reduce anxiety and promote a sense of peace.", "link": "https://www.youtube.com/watch?v=5OIeIaAhQOg"} | |
}, | |
"high": { | |
"Breathing": {"title": "4-7-8 Breathing", "description": "Inhale for 4s, hold your breath for 7s, and exhale slowly for 8s. Excellent for reducing anxiety quickly.", "link": "https://www.youtube.com/watch?v=LiUnFJ8P4gM"}, | |
"Yoga": {"title": "Legs-Up-The-Wall Pose", "description": "A restorative pose that helps calm the nervous system and reduce stress and anxiety.", "link": "https://www.youtube.com/watch?v=do_1LisFah0"}, | |
"Music": {"title": "Weightless by Marconi Union", "description": "Specifically designed in collaboration with sound therapists to reduce anxiety, heart rate, and blood pressure.", "link": "https://www.youtube.com/watch?v=UfcAVejslrU"} | |
} | |
} | |
def register(): | |
data = request.get_json() | |
name = data.get('name') | |
email = data.get('email') | |
password = data.get('password') | |
if not name or not email or not password: | |
return jsonify({"msg": "Missing name, email, or password"}), 400 | |
if users_collection.find_one({"email": email}): | |
return jsonify({"msg": "Email already exists"}), 409 | |
hashed_password = bcrypt.generate_password_hash(password).decode('utf-8') | |
user_id = users_collection.insert_one({ | |
"name": name, | |
"email": email, | |
"password": hashed_password, | |
"created_at": datetime.utcnow() | |
}).inserted_id | |
access_token = create_access_token(identity=str(user_id)) | |
logger.info(f"New user registered: {email}") | |
return jsonify(access_token=access_token, user={"id": str(user_id), "name": name, "email": email}), 201 | |
def login(): | |
data = request.get_json() | |
email = data.get('email') | |
password = data.get('password') | |
if not email or not password: | |
return jsonify({"msg": "Missing email or password"}), 400 | |
user = users_collection.find_one({"email": email}) | |
if user and bcrypt.check_password_hash(user['password'], password): | |
access_token = create_access_token(identity=str(user['_id'])) | |
logger.info(f"User logged in: {email}") | |
return jsonify(access_token=access_token, user={"id": str(user['_id']), "name": user['name'], "email": user['email']}) | |
return jsonify({"msg": "Invalid credentials"}), 401 | |
# =================================================================================== | |
# --- API ROUTES --- | |
# =================================================================================== | |
def predict_stress_route(): | |
current_user_id = get_jwt_identity() | |
if not stress_model or not stress_scaler: | |
return jsonify({"error": "Stress model is not available."}), 500 | |
data = request.json | |
features = np.array([[float(data["heart_rate"]), float(data["steps"]), float(data["sleep"]), float(data["age"])]]) | |
scaled_features = stress_scaler.transform(features) | |
prediction = stress_model.predict(scaled_features) | |
stress_level = int(np.round(prediction[0][0])) | |
stress_level = max(0, min(10, stress_level)) | |
stress_logs_collection.insert_one({ | |
"user_id": ObjectId(current_user_id), | |
"stress_level": stress_level, | |
"inputs": data, | |
"timestamp": datetime.utcnow() | |
}) | |
# --- UPDATED RESPONSE --- | |
category = 'low' | |
if 4 <= stress_level <= 6: | |
category = 'medium' | |
elif stress_level > 6: | |
category = 'high' | |
suggestions = [ | |
{"type": "Breathing", **suggestion_library[category]["Breathing"]}, | |
{"type": "Yoga", **suggestion_library[category]["Yoga"]}, | |
{"type": "Music", **suggestion_library[category]["Music"]}, | |
] | |
logger.info(f"Stress prediction for user {current_user_id} saved. Level: {stress_level}") | |
return jsonify({ | |
"stress_level": stress_level, | |
"suggestions": suggestions | |
}) | |
# =================================================================================== | |
# --- NEW: CHAT HISTORY ROUTE --- | |
# =================================================================================== | |
def get_chat_history(): | |
""" | |
Fetches the last 20 messages for the logged-in user. | |
""" | |
try: | |
current_user_id = get_jwt_identity() | |
# 1. Query the database for the user's chat logs | |
# - Filter by the current user's ID | |
# - Sort by timestamp in descending order to get the newest first | |
# - Limit to 20 documents (which is 10 user/AI message pairs) | |
history_cursor = chat_logs_collection.find( | |
{"user_id": ObjectId(current_user_id)} | |
).sort("timestamp", -1).limit(20) | |
# 2. Format the documents for the frontend | |
history_list = [] | |
for log in history_cursor: | |
history_list.append({ | |
"id": str(log["_id"]), # Convert ObjectId to string | |
"user_message": log.get("user_message"), | |
"ai_response": log.get("ai_response"), | |
"timestamp": log["timestamp"].isoformat() # Use ISO format for consistency | |
}) | |
# 3. Reverse the list so it's in chronological order (oldest first) | |
# This makes it easier to display in the chat window. | |
history_list.reverse() | |
return jsonify(history_list), 200 | |
except Exception as e: | |
logger.error(f"Error fetching chat history for user {current_user_id}: {e}") | |
return jsonify({"error": "An internal server error occurred while fetching chat history."}), 500 | |
# --- NEW ROUTE: To add context to the chat history --- | |
def add_chat_context(): | |
current_user_id = get_jwt_identity() | |
data = request.get_json() | |
event_type = data.get("event_type") | |
event_data = data.get("data", {}) | |
system_message = "" | |
if event_type == "STRESS_DETECTED" and event_data.get("level"): | |
system_message = f"System Note: The user just recorded a stress level of {event_data['level']}/10." | |
elif event_type == "EMOTION_DETECTED" and event_data.get("emotion"): | |
system_message = f"System Note: The user's emotion was just detected as {event_data['emotion']} with {event_data.get('confidence', 'N/A')}% confidence." | |
if system_message: | |
chat_logs_collection.insert_one({ | |
"user_id": ObjectId(current_user_id), | |
"role": "system", # Special role for context | |
"content": system_message, | |
"timestamp": datetime.utcnow() | |
}) | |
return jsonify({"msg": "Context added successfully"}), 200 | |
return jsonify({"msg": "Invalid event"}), 400 | |
# In app.py, replace your entire chat_route function with this one | |
def chat_route(): | |
current_user_id = get_jwt_identity() | |
data = request.get_json() | |
message_text = data.get("message") | |
if not message_text: | |
return jsonify({"msg": "Message is required"}), 400 | |
# --- 1. Crisis Check --- | |
crisis_keywords = ['suicide', 'kill myself', 'self-harm', 'want to die', 'end my life'] | |
if any(keyword in message_text.lower() for keyword in crisis_keywords): | |
helpline_info = helplines.get("India", helplines.get("Global")) | |
response_text = f"It sounds like you are in significant distress. Please reach out for immediate help. You can connect with someone at: {helpline_info}. Help is available and you are not alone." | |
chat_logs_collection.insert_one({ | |
"user_id": ObjectId(current_user_id), | |
"user_message": message_text, | |
"ai_response": "CRISIS_INTERVENTION_TRIGGERED: " + response_text, | |
"detected_emotion": "crisis", | |
"timestamp": datetime.utcnow() | |
}) | |
return jsonify({"response": response_text}), 200 | |
# --- 2. Build Context from History --- | |
history_cursor = chat_logs_collection.find( | |
{"user_id": ObjectId(current_user_id)} | |
).sort("timestamp", -1).limit(10) | |
chat_history_for_prompt = "" | |
for log in reversed(list(history_cursor)): | |
if log.get("role") == "system": | |
chat_history_for_prompt += f"{log.get('content')}\n" | |
# Make sure to check for the old format too for backward compatibility | |
elif log.get("user_message") and log.get("ai_response"): | |
chat_history_for_prompt += f"User: {log.get('user_message')}\n" | |
chat_history_for_prompt += f"AI: {log.get('ai_response')}\n" | |
# --- 3. Get Sentiment of the NEW message --- | |
inputs = chatbot_tokenizer(message_text, return_tensors="pt", truncation=True, padding=True).to(device) | |
with torch.no_grad(): | |
outputs = chatbot_model(**inputs) | |
logits = outputs.logits | |
probabilities = torch.softmax(logits, dim=1).cpu().numpy()[0] | |
predicted_class_id = np.argmax(probabilities) | |
confidence = np.max(probabilities) * 100 | |
emotion = text_emotion_label_map.get(predicted_class_id, "unknown") | |
# --- 4. Call Gemini with FULL context --- | |
response_text = generate_gemini_response(emotion, confidence, message_text, chat_history_for_prompt) | |
# --- 5. Log and Respond --- | |
if "CRISIS_RESPONSE" in response_text: | |
helpline_info = helplines.get("India", helplines.get("Global")) | |
response_text = f"It sounds like you are going through a very difficult time. It's important to talk to someone who can help. Please consider reaching out to: {helpline_info}." | |
chat_logs_collection.insert_one({ | |
"user_id": ObjectId(current_user_id), | |
"user_message": message_text, | |
"ai_response": response_text, | |
"detected_emotion": emotion, | |
"confidence": f"{confidence:.2f}%", | |
"timestamp": datetime.utcnow() | |
}) | |
return jsonify({"response": response_text}) | |
def predict_emotion_route(): | |
if not facial_emotion_model: | |
return jsonify({"error": "Facial emotion model is not available. Check server logs."}), 500 | |
try: | |
data = request.json | |
# The frontend will calculate these features and send them in the request body | |
feature_vector = np.array([[ | |
data['avg_ear'], | |
data['mar'], | |
data['eyebrow_dist'], | |
data['jaw_drop'] | |
]]) | |
predicted_class = facial_emotion_model.predict(feature_vector)[0] | |
emotion = facial_emotion_labels[predicted_class] | |
prediction_proba = facial_emotion_model.predict_proba(feature_vector)[0] | |
confidence = round(max(prediction_proba) * 100, 2) | |
logger.info(f"Facial emotion prediction: {emotion} ({confidence}%)") | |
return jsonify({"emotion": emotion, "confidence": confidence}) | |
except Exception as e: | |
logger.error(f"Error in /api/predict-emotion: {e}") | |
return jsonify({"error": "An error occurred during emotion prediction."}), 400 | |
# =================================================================================== | |
# --- NEW: THERAPIST FINDER ROUTE --- | |
# =================================================================================== | |
def find_therapists_route(): | |
lat = request.args.get("lat") | |
lng = request.args.get("lng") | |
query = request.args.get("query", "mental health therapist") | |
if not lat or not lng: | |
return jsonify({"error": "Latitude and longitude are required"}), 400 | |
fallback_locations = [ | |
{"name": "Mumbai", "lat": 19.076, "lng": 72.8777}, | |
{"name": "Delhi", "lat": 28.6139, "lng": 77.209}, | |
{"name": "Bangalore", "lat": 12.9716, "lng": 77.5946}, | |
] | |
def fetch_therapists(fs_lat, fs_lng, fs_query): | |
api_url = "https://places-api.foursquare.com/places/search" | |
api_key = os.environ.get("FOURSQUARE_SERVICE_KEY") | |
headers = { | |
"Authorization": f"Bearer {api_key}" if api_key else "", | |
"Accept": "application/json", | |
"X-Places-API-Version": "2025-06-17", | |
} | |
params = { | |
"ll": f"{fs_lat},{fs_lng}", | |
"query": fs_query, | |
"radius": 10000, | |
"limit": 20, | |
} | |
try: | |
response = requests.get(api_url, headers=headers, params=params) | |
response.raise_for_status() | |
data = response.json() | |
results = [] | |
for place in data.get("results", []): | |
lat_val = ( | |
place.get("geocodes", {}).get("main", {}).get("latitude") | |
or place.get("latitude") | |
) | |
lng_val = ( | |
place.get("geocodes", {}).get("main", {}).get("longitude") | |
or place.get("longitude") | |
) | |
if not lat_val or not lng_val: | |
continue | |
results.append({ | |
"id": place.get("fsq_id") or place.get("fsq_place_id"), | |
"name": place.get("name"), | |
"address": ", ".join( | |
filter( | |
None, | |
[ | |
place.get("location", {}).get("address"), | |
place.get("location", {}).get("locality"), | |
place.get("location", {}).get("region"), | |
], | |
) | |
) or "Address not available", | |
"latitude": lat_val, | |
"longitude": lng_val, | |
"phone": place.get("tel"), | |
}) | |
return results | |
except requests.exceptions.RequestException as e: | |
return [] | |
# Try user location | |
results = fetch_therapists(lat, lng, query) | |
# If no results, try fallback cities | |
if not results: | |
for loc in fallback_locations: | |
results = fetch_therapists(loc["lat"], loc["lng"], query) | |
if results: | |
break | |
return jsonify(results) | |
# =================================================================================== | |
# --- NEW: DASHBOARD HISTORY ROUTE --- | |
# =================================================================================== | |
def get_history(): | |
current_user_id = get_jwt_identity() | |
try: | |
seven_days_ago = datetime.utcnow() - timedelta(days=7) | |
stress_logs_cursor = stress_logs_collection.find({ | |
"user_id": ObjectId(current_user_id), | |
"timestamp": {"$gte": seven_days_ago} | |
}).sort("timestamp", 1) | |
stress_logs = list(stress_logs_cursor) | |
# --- NEW: Aggregate data for Pie Chart --- | |
stress_summary = {"Low": 0, "Medium": 0, "High": 0} | |
for log in stress_logs: | |
level = log['stress_level'] | |
if level <= 3: | |
stress_summary["Low"] += 1 | |
elif 4 <= level <= 6: | |
stress_summary["Medium"] += 1 | |
else: | |
stress_summary["High"] += 1 | |
pie_chart_data = [{"name": key, "value": value} for key, value in stress_summary.items()] | |
# (Existing history logic remains) | |
dates_last_7_days = [(seven_days_ago + timedelta(days=i)).strftime("%b %d") for i in range(8)] | |
stress_map = {date: None for date in dates_last_7_days} | |
for log in stress_logs: | |
date_str = log['timestamp'].strftime("%b %d") | |
stress_map[date_str] = log['stress_level'] | |
stress_history = [{"date": date, "level": level} for date, level in stress_map.items()] | |
last_stress_score = stress_logs[-1]['stress_level'] if stress_logs else "N/A" | |
# --- 3. Get Last Chat Insight --- | |
last_chat_log = chat_logs_collection.find_one( | |
{"user_id": ObjectId(current_user_id), "ai_response": {"$exists": True}}, | |
sort=[("timestamp", -1)] | |
) | |
# 2. Use the safe .get() method to prevent crashes. | |
last_chat_insight = last_chat_log.get('ai_response') if last_chat_log else "No recent chats." | |
# --- 4. Combine and Return Data --- | |
dashboard_data = { | |
"stress_history": stress_history, | |
"stress_summary_pie": pie_chart_data, # NEW | |
"last_stress_score": last_stress_score, | |
"last_chat_insight": last_chat_insight | |
} | |
return jsonify(dashboard_data), 200 | |
except Exception as e: | |
logger.error(f"Error fetching history for user {current_user_id}: {e}") | |
return jsonify({"error": "An internal server error occurred."}), 500 | |
def get_resources(): | |
# This data is hardcoded for easy management, but could be moved to a database. | |
resources_data = [ | |
{ | |
"category": "Immediate Help & Helplines", | |
"items": [ | |
{ | |
"title": "iCall Psychosocial Helpline (India)", | |
"description": "Free telephone and email-based counseling services provided by trained mental health professionals.", | |
"link": "https://icallhelpline.org/" | |
}, | |
{ | |
"title": "Samaritans Mumbai (India)", | |
"description": "Provides emotional support to anyone in distress, struggling to cope, or at risk of suicide.", | |
"link": "http://www.samaritansmumbai.com/" | |
}, | |
{ | |
"title": "National Suicide Prevention Lifeline (US)", | |
"description": "A national network of local crisis centers that provides free and confidential emotional support.", | |
"link": "https://suicidepreventionlifeline.org/" | |
} | |
] | |
}, | |
{ | |
"category": "Guided Meditations & Mindfulness", | |
"items": [ | |
{ | |
"title": "10-Minute Meditation for Beginners", | |
"description": "A simple, guided meditation to help you start your mindfulness practice.", | |
"link": "https://www.youtube.com/watch?v=O-6f5wQXSu8" | |
}, | |
{ | |
"title": "Mindful Breathing Exercise", | |
"description": "A short exercise focusing on the breath to calm anxiety and center your thoughts.", | |
"link": "https://youtu.be/watch?v=r6Vynwn_q-U" | |
} | |
] | |
}, | |
{ | |
"category": "Understanding Anxiety", | |
"items": [ | |
{ | |
"title": "What Is Anxiety?", | |
"description": "An informative article from the American Psychiatric Association explaining anxiety disorders.", | |
"link": "https://www.psychiatry.org/patients-families/anxiety-disorders/what-are-anxiety-disorders" | |
}, | |
{ | |
"title": "How to Cope with Anxiety", | |
"description": "Practical tips and strategies for managing anxiety symptoms in your daily life from Mind UK.", | |
"link": "https://www.mind.org.uk/information-support/types-of-mental-health-problems/anxiety-and-panic-attacks/self-care/" | |
} | |
] | |
} | |
] | |
return jsonify(resources_data), 200 | |
def add_cbt_record(): | |
"""Saves a new CBT Thought Record to the database.""" | |
current_user_id = get_jwt_identity() | |
data = request.get_json() | |
# Basic validation | |
required_fields = ['situation', 'automatic_thought', 'emotions', 'alternative_thought'] | |
if not all(field in data for field in required_fields): | |
return jsonify({"msg": "Missing required fields"}), 400 | |
record = { | |
"user_id": ObjectId(current_user_id), | |
"situation": data.get("situation"), | |
"automatic_thought": data.get("automatic_thought"), | |
"emotions": data.get("emotions"), | |
"alternative_thought": data.get("alternative_thought"), | |
"timestamp": datetime.utcnow() | |
} | |
cbt_records_collection.insert_one(record) | |
return jsonify({"msg": "Record saved successfully"}), 201 | |
def get_cbt_records(): | |
"""Fetches all CBT Thought Records for the logged-in user.""" | |
current_user_id = get_jwt_identity() | |
records_cursor = cbt_records_collection.find( | |
{"user_id": ObjectId(current_user_id)} | |
).sort("timestamp", -1) # Sort by newest first | |
records_list = [] | |
for record in records_cursor: | |
record["_id"] = str(record["_id"]) | |
record["user_id"] = str(record["user_id"]) | |
records_list.append(record) | |
return jsonify(records_list), 200 | |
# --- ADD THIS NEW ROUTE FOR MEDITATIONS --- | |
def get_meditations(): | |
try: | |
if meditations_collection is None: | |
return jsonify({"error": "Database not connected"}), 500 | |
all_meditations = list(meditations_collection.find({})) | |
# Convert the MongoDB ObjectId to a string if you are not using custom string _id's | |
for med in all_meditations: | |
if '_id' in med and not isinstance(med['_id'], str): | |
med['_id'] = str(med['_id']) | |
return jsonify(all_meditations) | |
except Exception as e: | |
logger.error(f"Error fetching meditations: {e}") | |
return jsonify({"error": "Could not fetch meditations"}), 500 | |
if __name__ == "__main__": | |
app.run(host='0.0.0.0', port=7860) | |