Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import requests | |
| from datetime import datetime | |
| from flask import Flask, request, jsonify, send_from_directory | |
| from transformers import pipeline | |
| from openai import OpenAI | |
| app = Flask(__name__) | |
| # Load emotion model | |
| emotion_model = pipeline( | |
| "text-classification", | |
| model="j-hartmann/emotion-english-distilroberta-base" | |
| ) | |
| # Ensure user data file | |
| USER_FILE = "user_data.json" | |
| if not os.path.exists(USER_FILE): | |
| with open(USER_FILE, "w") as f: | |
| json.dump({ | |
| "name": None, | |
| "age": None, | |
| "mood": None, | |
| "last_interaction": None, | |
| "missed_days": 0, | |
| "mode": "emotional_support", | |
| "conversation_history": [] | |
| }, f) | |
| def load_user(): | |
| with open(USER_FILE, "r") as f: | |
| return json.load(f) | |
| def save_user(data): | |
| with open(USER_FILE, "w") as f: | |
| json.dump(data, f) | |
| # Safe OpenAI client initialization | |
| def get_client(): | |
| api_key = os.getenv("OPENAI_API_KEY") | |
| if not api_key or api_key.strip() == "": | |
| raise ValueError("OpenAI API key is missing or empty. Please set OPENAI_API_KEY in Hugging Face Secrets.") | |
| return OpenAI(api_key=api_key) | |
| # Model priority list for fallbacks | |
| MODEL_LIST = ["gpt-4o-mini", "gpt-3.5-turbo", "gpt-3.5-turbo-16k"] | |
| # Helpline numbers | |
| HELPLINES = { | |
| "US": "National Suicide Prevention Lifeline: 988", | |
| "UK": "Samaritans: 116 123", | |
| "IN": "AASRA: 91-9820466726", | |
| "CA": "Canada Suicide Prevention Service: 988", | |
| "AU": "Lifeline: 13 11 14", | |
| "default": "Please contact your local crisis helpline immediately." | |
| } | |
| def get_country_from_ip(ip): | |
| try: | |
| response = requests.get(f"http://ipapi.co/{ip}/country/") | |
| if response.status_code == 200: | |
| return response.text.upper() | |
| except: | |
| pass | |
| return "default" | |
| def detect_self_harm(message): | |
| keywords = ["suicide", "kill myself", "end my life", "self harm", "hurt myself"] | |
| return any(word in message.lower() for word in keywords) | |
| def chat(): | |
| try: | |
| data = request.get_json() | |
| message = data.get("message", "").strip() | |
| if not message: | |
| return jsonify({"reply": "Please enter a message.", "emotion": "neutral"}), 400 | |
| mode = data.get("mode", "emotional_support") | |
| user_ip = request.remote_addr | |
| user = load_user() | |
| now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
| user["last_interaction"] = now | |
| user["mode"] = mode | |
| user["conversation_history"].append({"role": "user", "content": message, "timestamp": now}) | |
| # Emotion detection | |
| emotion = emotion_model(message)[0]["label"] | |
| user["mood"] = emotion | |
| # Self-harm check | |
| if detect_self_harm(message): | |
| country = get_country_from_ip(user_ip) | |
| helpline = HELPLINES.get(country, HELPLINES["default"]) | |
| reply = ( | |
| f"I'm really concerned about what you shared. Please reach out right now — " | |
| f"you're not alone. Here's someone you can call: {helpline}" | |
| ) | |
| user["conversation_history"].append({"role": "assistant", "content": reply, "timestamp": now}) | |
| save_user(user) | |
| return jsonify({"reply": reply, "emotion": emotion}) | |
| # Build context for chat | |
| history = user["conversation_history"][-10:] | |
| messages = [ | |
| {"role": "system", "content": ( | |
| f"You are Serenity — an empathetic, emotionally intelligent best friend. " | |
| f"Be warm, caring, supportive, and human-like. Respond briefly (1–2 sentences), " | |
| f"showing love, empathy, and curiosity. Never sound robotic or repetitive. " | |
| f"Current mood: {emotion}. Mode: {mode}." | |
| )} | |
| ] + history | |
| # Try models in priority order | |
| client = get_client() | |
| reply = None | |
| for model in MODEL_LIST: | |
| try: | |
| response = client.chat.completions.create( | |
| model=model, | |
| messages=messages, | |
| temperature=0.8 | |
| ) | |
| reply = response.choices[0].message.content.strip() | |
| print(f"✅ Used model: {model}") | |
| break # Success, stop trying other models | |
| except Exception as e: | |
| error_str = str(e).lower() | |
| if "rate_limit" in error_str or "429" in error_str or "quota" in error_str: | |
| print(f"⚠️ Rate limit on {model}, trying next model...") | |
| continue # Try next model | |
| else: | |
| # Non-rate-limit error, re-raise | |
| raise e | |
| if reply is None: | |
| # All models failed | |
| reply = "All models are currently rate-limited. Please try again later or check your OpenAI account." | |
| user["conversation_history"].append({"role": "assistant", "content": reply, "timestamp": now}) | |
| save_user(user) | |
| return jsonify({"reply": reply, "emotion": emotion}) | |
| except ValueError as e: | |
| print(f"❌ API Key Error: {e}") | |
| return jsonify({ | |
| "reply": "API key is missing or invalid. Please check your Hugging Face Secrets and ensure it's a valid OpenAI key.", | |
| "emotion": "neutral" | |
| }), 500 | |
| except Exception as e: | |
| print(f"❌ Chat error: {e}") | |
| return jsonify({ | |
| "reply": "Something went wrong (e.g., network issue). Try again later.", | |
| "emotion": "neutral" | |
| }), 500 | |
| def index(): | |
| return send_from_directory(".", "index.html") | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0", port=7860) |