Shresthh03 commited on
Commit
bea454b
·
verified ·
1 Parent(s): c097254

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -114
app.py CHANGED
@@ -1,128 +1,216 @@
1
- # 🌸 Serenity Emotional Support Chatbot Backend (OpenAI + Flask)
2
- # This backend serves the chatbot and supports multiple voices & personalities.
 
 
3
 
4
- from flask import Flask, request, jsonify, render_template
5
- from flask_cors import CORS
6
- import openai
7
  import os
8
  import json
 
9
  from datetime import datetime
 
 
10
 
11
- # Initialize Flask
12
- app = Flask(__name__, static_folder="static", template_folder="templates")
 
 
 
 
 
 
 
 
 
 
 
13
  CORS(app)
14
 
15
- # Set your OpenAI API key from Hugging Face Secrets
16
- openai.api_key = os.getenv("OPENAI_API_KEY")
17
-
18
- # Session memory for users (temporary)
19
- user_sessions = {}
20
-
21
- # Personalities (you can extend easily)
22
- PERSONALITIES = {
23
- "serene": {
24
- "name": "Serenity",
25
- "voice": "soothing_female",
26
- "style": "calm, empathic, softly encouraging"
27
- },
28
- "deep_male": {
29
- "name": "Atlas",
30
- "voice": "deep_male",
31
- "style": "grounded, warm, thoughtful"
32
- },
33
- "gentle_female": {
34
- "name": "Luna",
35
- "voice": "gentle_female",
36
- "style": "loving, kind, nurturing"
37
- },
38
- "neutral": {
39
- "name": "Ari",
40
- "voice": "neutral_soft",
41
- "style": "balanced, conversational, friendly"
42
- }
43
- }
44
-
45
- # Helper: Create or get user session
46
- def get_session(user_id):
47
- if user_id not in user_sessions:
48
- user_sessions[user_id] = {
49
- "history": [],
50
- "last_active": datetime.now(),
51
- "personality": "serene"
52
- }
53
- return user_sessions[user_id]
54
-
55
- # --- API Routes ---
56
-
57
- @app.route("/")
58
- def home():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  return jsonify({"message": "🌸 Serenity Emotional Support Chatbot API is running!"})
60
 
 
61
  @app.route("/chat", methods=["POST"])
62
  def chat():
63
- try:
64
- data = request.get_json()
65
- user_id = data.get("user_id", "anonymous")
66
- user_message = data.get("message", "").strip()
67
- personality_key = data.get("personality", "serene")
68
-
69
- if not user_message:
70
- return jsonify({"error": "Empty message"}), 400
71
-
72
- # Load or create session
73
- session = get_session(user_id)
74
- personality = PERSONALITIES.get(personality_key, PERSONALITIES["serene"])
75
-
76
- # Add to chat history
77
- session["history"].append({"role": "user", "content": user_message})
78
-
79
- # Construct prompt
80
- prompt = f"""
81
- You are {personality['name']}, a {personality['style']} emotional support companion.
82
- You talk like a caring human friend, not a therapist.
83
- Avoid repeating phrases and vary your empathy naturally.
84
- You also can chat casually if the user seems lighthearted.
85
-
86
- Conversation so far:
87
- {json.dumps(session['history'], indent=2)}
88
-
89
- Respond gently, personally, and naturally.
90
- """
91
-
92
- # Call OpenAI API
93
- response = openai.ChatCompletion.create(
94
- model="gpt-4o-mini",
95
- messages=[{"role": "system", "content": prompt}] + session["history"],
96
- temperature=0.8,
97
- max_tokens=300,
98
- )
99
-
100
- bot_reply = response.choices[0].message.content.strip()
101
- session["history"].append({"role": "assistant", "content": bot_reply})
102
-
103
- return jsonify({
104
- "reply": bot_reply,
105
- "voice": personality["voice"],
106
- "personality": personality["name"]
107
- })
108
-
109
- except Exception as e:
110
- return jsonify({"error": str(e)}), 500
111
-
112
-
113
- @app.route("/reset_session", methods=["POST"])
114
- def reset_session():
115
- """Reset chat memory for a user."""
116
- try:
117
- data = request.get_json()
118
- user_id = data.get("user_id", "anonymous")
119
- if user_id in user_sessions:
120
- del user_sessions[user_id]
121
- return jsonify({"message": f"Session reset for {user_id}."})
122
- except Exception as e:
123
- return jsonify({"error": str(e)}), 500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
 
125
 
126
- # --- Run App ---
127
  if __name__ == "__main__":
128
- app.run(host="0.0.0.0", port=7860)
 
 
1
+ # app.py
2
+ # Minimal Serenity backend that serves index.html and a /chat endpoint.
3
+ # If OPENAI_API_KEY is set it will use OpenAI (gpt-3.5-turbo) for nicer replies;
4
+ # otherwise it uses a small local fallback so chat still works.
5
 
 
 
 
6
  import os
7
  import json
8
+ import random
9
  from datetime import datetime
10
+ from flask import Flask, request, jsonify, send_from_directory
11
+ from flask_cors import CORS
12
 
13
+ # Optional OpenAI usage
14
+ try:
15
+ import openai
16
+ OPENAI_PRESENT = True
17
+ OPENAI_KEY = os.getenv("OPENAI_API_KEY")
18
+ if OPENAI_KEY:
19
+ openai.api_key = OPENAI_KEY
20
+ else:
21
+ OPENAI_PRESENT = False
22
+ except Exception:
23
+ OPENAI_PRESENT = False
24
+
25
+ app = Flask(__name__, static_folder=".", static_url_path="/")
26
  CORS(app)
27
 
28
+ # Simple memory (session -> data) kept in memory + optionally saved to file
29
+ MEM_FILE = "memory.json"
30
+ try:
31
+ if os.path.exists(MEM_FILE):
32
+ with open(MEM_FILE, "r", encoding="utf-8") as f:
33
+ MEMORY = json.load(f)
34
+ else:
35
+ MEMORY = {}
36
+ except Exception:
37
+ MEMORY = {}
38
+
39
+ def save_memory():
40
+ try:
41
+ with open(MEM_FILE, "w", encoding="utf-8") as f:
42
+ json.dump(MEMORY, f, indent=2, ensure_ascii=False)
43
+ except Exception:
44
+ pass
45
+
46
+ # Simple emotion heuristic (fallback)
47
+ def simple_emotion(text: str) -> str:
48
+ t = text.lower()
49
+ if any(w in t for w in ["happy","great","good","awesome","yay","joy"]): return "happy"
50
+ if any(w in t for w in ["sad","down","depress","lonely","cry"]): return "sad"
51
+ if any(w in t for w in ["angry","mad","furious"]): return "angry"
52
+ if any(w in t for w in ["scared","afraid","anxious","panic","worried"]): return "worried"
53
+ if any(w in t for w in ["calm","fine","okay","ok","relaxed"]): return "calm"
54
+ if any(w in t for w in ["motivate","motivation","guidance","inspire"]): return "motivated"
55
+ return "neutral"
56
+
57
+ # Basic fallback reply generator (when OpenAI not available)
58
+ def fallback_reply(user_text: str, persona: str, name: str = None) -> str:
59
+ greetings = [
60
+ "Thanks for sharing I'm here with you.",
61
+ "I hear you. Tell me more if you'd like.",
62
+ "That matters. Would you like to say more about it?"
63
+ ]
64
+ casual = [
65
+ "Haha, nice! What's new with you?",
66
+ "I’m here — how’s your day going?",
67
+ "That sounds fun — tell me more!"
68
+ ]
69
+ motivate = [
70
+ "You’ve got this — small steps add up.",
71
+ "Take one small step today; it can make a difference.",
72
+ "I believe in you. What is one tiny thing you can try now?"
73
+ ]
74
+ # choose style based on keywords
75
+ txt = user_text.lower()
76
+ if any(k in txt for k in ["motivate","motivation","guidance","inspire","quote"]):
77
+ return random.choice(motivate)
78
+ if any(k in txt for k in ["hi","hello","hey","how are you","sup","what's up"]):
79
+ return random.choice(casual)
80
+ # emotional catch
81
+ if any(k in txt for k in ["sad","depress","lonely","upset","not good","terrible","bad"]):
82
+ return random.choice(greetings)
83
+ return random.choice(greetings)
84
+
85
+ # Serve the frontend (IMPORTANT: this serves index.html at root)
86
+ @app.route("/", methods=["GET"])
87
+ def index():
88
+ # Serve index.html from same directory
89
+ return send_from_directory(".", "index.html")
90
+
91
+ # Optional small status endpoint (not the app root)
92
+ @app.route("/status", methods=["GET"])
93
+ def status():
94
  return jsonify({"message": "🌸 Serenity Emotional Support Chatbot API is running!"})
95
 
96
+ # Main chat endpoint
97
  @app.route("/chat", methods=["POST"])
98
  def chat():
99
+ """
100
+ Expected JSON:
101
+ {
102
+ "session": "optional-session-id",
103
+ "message": "user text",
104
+ "personality": "calm" (optional)
105
+ }
106
+ Response JSON:
107
+ {
108
+ "reply": "...",
109
+ "emotion": "sad|happy|calm|... ",
110
+ "voice": "calm_male" (suggested voice key for frontend)
111
+ }
112
+ """
113
+ data = request.get_json(force=True) or {}
114
+ session = data.get("session") or request.remote_addr or "default"
115
+ text = (data.get("message") or "").strip()
116
+ personality = (data.get("personality") or "calm").lower()
117
+
118
+ if not text:
119
+ return jsonify({"reply":"Please send a message.", "emotion":"neutral", "voice":"neutral"})
120
+
121
+ # initialize session data
122
+ slot = MEMORY.get(session, {"name": None, "age": None, "last_mood": None, "history": []})
123
+ # optional: try to detect a name
124
+ if not slot.get("name"):
125
+ # very naive name detection
126
+ if text.lower().startswith("i am ") or text.lower().startswith("i'm "):
127
+ name = text.split()[2:3]
128
+ if name:
129
+ slot["name"] = name[0].capitalize()
130
+
131
+ # Use OpenAI if available
132
+ reply_text = None
133
+ emotion_label = None
134
+ voice_key = "neutral"
135
+
136
+ if OPENAI_PRESENT:
137
+ try:
138
+ # Compose a short system prompt that balances support + casual + knowledge
139
+ persona_text = {
140
+ "calm": "You are calm, gentle, and concise.",
141
+ "friendly": "You are warm, friendly and playful when appropriate.",
142
+ "motivational": "You are upbeat, encouraging, motivational.",
143
+ "spiritual": "You are nurturing, mindful, non-denominational.",
144
+ "neutral": "You are neutral, clear, and friendly."
145
+ }.get(personality, "You are calm and supportive.")
146
+
147
+ system_msg = (
148
+ f"You are Serenity, an empathetic emotional-support assistant. {persona_text} "
149
+ "Do not act like a therapist. If the user asks factual questions, answer clearly and then check in emotionally. "
150
+ "Vary phrasing; avoid repeating the same canned sentences."
151
+ )
152
+
153
+ # ask OpenAI to both classify emotion and reply in a friendly supportive tone
154
+ # We'll call chat completion twice cheaply: classify then reply (keeps prompt simpler)
155
+ classify_prompt = (
156
+ "Classify the primary emotion from the short user message. "
157
+ "Respond with one word from: happy, sad, angry, worried, calm, neutral, motivated, fearful, love.\n\n"
158
+ f"Message: {text}"
159
+ )
160
+ classification = openai.ChatCompletion.create(
161
+ model="gpt-3.5-turbo",
162
+ messages=[{"role":"system","content":"You are a concise classifier."},
163
+ {"role":"user","content":classify_prompt}],
164
+ temperature=0.0,
165
+ max_tokens=6
166
+ )
167
+ emotion_label = (classification.choices[0].message.content.strip().split()[0].lower())[:20]
168
+ except Exception:
169
+ # fallback classification
170
+ emotion_label = simple_emotion(text)
171
+
172
+ try:
173
+ # Now produce a reply using the persona/system prompt
174
+ user_msg_for_ai = f"User: {text}"
175
+ ai_resp = openai.ChatCompletion.create(
176
+ model="gpt-3.5-turbo",
177
+ messages=[
178
+ {"role":"system","content":system_msg},
179
+ {"role":"user","content":user_msg_for_ai}
180
+ ],
181
+ temperature=0.8,
182
+ max_tokens=250
183
+ )
184
+ reply_text = ai_resp.choices[0].message.content.strip()
185
+ except Exception as e:
186
+ # fallback to simple reply if OpenAI fails
187
+ reply_text = fallback_reply(text, personality, slot.get("name"))
188
+ if not emotion_label:
189
+ emotion_label = simple_emotion(text)
190
+ else:
191
+ # OpenAI not available — fallback behavior
192
+ emotion_label = simple_emotion(text)
193
+ reply_text = fallback_reply(text, personality, slot.get("name"))
194
+
195
+ # choose a voice key suggestion for frontend to map to browser voices
196
+ voice_map = {
197
+ "calm": "calm_male",
198
+ "friendly": "friendly_female",
199
+ "motivational": "deep_male",
200
+ "spiritual": "soothing_female",
201
+ "neutral": "neutral"
202
+ }
203
+ voice_key = voice_map.get(personality, "neutral")
204
+
205
+ # update memory
206
+ slot["last_mood"] = emotion_label
207
+ slot.setdefault("history", []).append({"user": text, "bot": reply_text, "ts": datetime.utcnow().isoformat()})
208
+ slot["history"] = slot["history"][-50:]
209
+ MEMORY[session] = slot
210
+ save_memory()
211
 
212
+ return jsonify({"reply": reply_text, "emotion": emotion_label, "voice": voice_key})
213
 
 
214
  if __name__ == "__main__":
215
+ port = int(os.getenv("PORT", 7860))
216
+ app.run(host="0.0.0.0", port=port)