Shresthh03 commited on
Commit
3650e12
·
verified ·
1 Parent(s): fc37241

Update it.

Browse files
Files changed (1) hide show
  1. index.html +191 -276
index.html CHANGED
@@ -1,294 +1,209 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Serenity - Emotional Support Companion</title>
7
- <style>
8
- :root {
9
- --bg: #f5f7fc;
10
- --user-bubble: #e2e6ff;
11
- --bot-bubble: #ffffff;
12
- --accent: #5b6ef5;
13
- --bot-shadow: rgba(91, 110, 245, 0.25);
14
- }
15
-
16
- body {
17
- background: var(--bg);
18
- font-family: "Inter", sans-serif;
19
- margin: 0;
20
- display: flex;
21
- flex-direction: column;
22
- height: 100vh;
23
- color: #222;
24
- transition: background 1s ease;
25
- }
26
-
27
- header {
28
- background: var(--accent);
29
- color: #fff;
30
- text-align: center;
31
- padding: 1rem;
32
- font-size: 1.4rem;
33
- font-weight: 600;
34
- letter-spacing: 0.4px;
35
- box-shadow: 0 2px 5px var(--bot-shadow);
36
- transition: background 0.5s ease;
37
- }
38
-
39
- #controls {
40
- display: flex;
41
- justify-content: space-between;
42
- align-items: center;
43
- padding: 0.5rem 1rem;
44
- background: #f0f2ff;
45
- border-bottom: 1px solid #ddd;
46
- font-size: 0.9rem;
47
- }
48
-
49
- select {
50
- border: 1px solid #ccc;
51
- border-radius: 8px;
52
- padding: 0.3rem 0.6rem;
53
- background: white;
54
- }
55
-
56
- button {
57
- background: var(--accent);
58
- color: #fff;
59
- border: none;
60
- padding: 0.6rem 1rem;
61
- border-radius: 8px;
62
- cursor: pointer;
63
- transition: background 0.3s;
64
- }
65
-
66
- button:hover {
67
- opacity: 0.9;
68
- }
69
-
70
- #chat-container {
71
- flex: 1;
72
- overflow-y: auto;
73
- padding: 1rem;
74
- display: flex;
75
- flex-direction: column;
76
- scroll-behavior: smooth;
77
- }
78
-
79
- .message {
80
- margin: 0.6rem 0;
81
- max-width: 75%;
82
- padding: 0.7rem 1rem;
83
- border-radius: 14px;
84
- line-height: 1.5;
85
- animation: fadeIn 0.35s ease;
86
- word-wrap: break-word;
87
- position: relative;
88
- }
89
-
90
- .user {
91
- align-self: flex-end;
92
- background: var(--user-bubble);
93
- border-bottom-right-radius: 4px;
94
- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
95
- }
96
-
97
- .bot {
98
- align-self: flex-start;
99
- background: var(--bot-bubble);
100
- border-bottom-left-radius: 4px;
101
- box-shadow: 0 3px 6px var(--bot-shadow);
102
- }
103
-
104
- .meta {
105
- font-size: 0.7rem;
106
- color: #777;
107
- margin-top: 0.2rem;
108
- text-align: right;
109
- }
110
-
111
- #input-container {
112
- display: flex;
113
- padding: 0.7rem;
114
- background: #fff;
115
- border-top: 1px solid #ddd;
116
- }
117
-
118
- #user-input {
119
- flex: 1;
120
- border: 1px solid #ccc;
121
- border-radius: 10px;
122
- padding: 0.6rem 0.8rem;
123
- font-size: 1rem;
124
- }
125
-
126
- /* Avatar */
127
- #avatar {
128
- width: 70px;
129
- height: 70px;
130
- border-radius: 50%;
131
- margin: 0.8rem auto 0.5rem;
132
- background: radial-gradient(circle at 30% 30%, #cdd4ff, #5b6ef5);
133
- box-shadow: 0 0 15px var(--bot-shadow);
134
- animation: breathe 4s ease-in-out infinite;
135
- }
136
-
137
- @keyframes breathe {
138
- 0%, 100% { transform: scale(1); opacity: 0.9; }
139
- 50% { transform: scale(1.07); opacity: 1; }
140
- }
141
-
142
- @keyframes fadeIn {
143
- from { opacity: 0; transform: translateY(6px); }
144
- to { opacity: 1; transform: translateY(0); }
145
- }
146
- </style>
147
  </head>
148
  <body>
149
- <header>🪷 Serenity Your Emotional Support Companion</header>
150
-
151
- <div id="controls">
152
- <div>
153
- <label for="voice-profile">Personality: </label>
154
- <select id="voice-profile">
 
 
 
 
 
 
155
  <option value="neutral">Neutral</option>
156
- <option value="calm_male">Calm Male</option>
157
- <option value="deep_male">Deep Male</option>
158
- <option value="soothing_male">Soothing Male</option>
159
- <option value="gentle_female">Gentle Female</option>
160
- <option value="feminine_female">Feminine Female</option>
161
- <option value="deep_female">Deep Female</option>
162
- <option value="soothing_female">Soothing Female</option>
163
  </select>
 
 
164
  </div>
165
- <button id="reset">Reset Chat</button>
166
  </div>
167
 
168
- <div id="avatar"></div>
 
 
169
 
170
- <div id="chat-container"></div>
171
-
172
- <div id="input-container">
173
- <input id="user-input" type="text" placeholder="Type your message..." />
174
- <button id="send">Send</button>
175
  </div>
176
-
177
- <script>
178
- const chatContainer = document.getElementById("chat-container");
179
- const input = document.getElementById("user-input");
180
- const sendBtn = document.getElementById("send");
181
- const voiceSelect = document.getElementById("voice-profile");
182
- const resetBtn = document.getElementById("reset");
183
- const avatar = document.getElementById("avatar");
184
- const header = document.querySelector("header");
185
-
186
- let session = localStorage.getItem("session_id");
187
- if (!session) {
188
- session = "sess_" + Math.random().toString(36).substring(2, 10);
189
- localStorage.setItem("session_id", session);
190
- }
191
-
192
- // Color palette per personality
193
- const themes = {
194
- neutral: ["#f5f7fc", "#5b6ef5", "rgba(91,110,245,0.25)"],
195
- calm_male: ["#eaf7ff", "#4b84e6", "rgba(75,132,230,0.25)"],
196
- deep_male: ["#f5f5f5", "#2a3b8e", "rgba(42,59,142,0.25)"],
197
- soothing_male: ["#f3f8ff", "#5aa4c8", "rgba(90,164,200,0.25)"],
198
- gentle_female: ["#fff6f8", "#f27ba3", "rgba(242,123,163,0.25)"],
199
- feminine_female: ["#fef5fc", "#d35dc4", "rgba(211,93,196,0.25)"],
200
- deep_female: ["#faf4ff", "#8b5fc7", "rgba(139,95,199,0.25)"],
201
- soothing_female: ["#f4fbfa", "#4db6ac", "rgba(77,182,172,0.25)"],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  };
203
-
204
- function applyTheme(personality) {
205
- const [bg, accent, shadow] = themes[personality] || themes["neutral"];
206
- document.documentElement.style.setProperty("--bg", bg);
207
- document.documentElement.style.setProperty("--accent", accent);
208
- document.documentElement.style.setProperty("--bot-shadow", shadow);
209
- avatar.style.background = `radial-gradient(circle at 30% 30%, #fff, ${accent})`;
210
- header.style.background = accent;
211
- }
212
-
213
- voiceSelect.addEventListener("change", () => {
214
- applyTheme(voiceSelect.value);
215
- });
216
-
217
- async function appendMessage(sender, text, emotion, intent) {
218
- const div = document.createElement("div");
219
- div.classList.add("message", sender);
220
- div.textContent = text;
221
- chatContainer.appendChild(div);
222
- if (emotion || intent) {
223
- const meta = document.createElement("div");
224
- meta.classList.add("meta");
225
- meta.textContent = `(${intent || "..."}, ${emotion || "..."})`;
226
- div.appendChild(meta);
227
- }
228
- chatContainer.scrollTop = chatContainer.scrollHeight;
229
- }
230
-
231
- async function sendMessage() {
232
- const text = input.value.trim();
233
- if (!text) return;
234
- appendMessage("user", text);
235
- input.value = "";
236
- avatar.style.animation = "breathe 2s infinite ease-in-out";
237
-
238
- const body = {
239
- session: session,
240
- message: text,
241
- personality: voiceSelect.value
242
- };
243
-
244
- try {
245
- const res = await fetch("/chat", {
246
- method: "POST",
247
- headers: { "Content-Type": "application/json" },
248
- body: JSON.stringify(body)
249
- });
250
- const data = await res.json();
251
- appendMessage("bot", data.reply, data.emotion, data.intent);
252
- } catch (err) {
253
- appendMessage("bot", "Sorry, I had trouble connecting. Please try again.");
254
- } finally {
255
- avatar.style.animation = "breathe 4s infinite ease-in-out";
256
- }
257
- }
258
-
259
- async function initChat() {
260
  const res = await fetch("/chat", {
261
  method: "POST",
262
- headers: { "Content-Type": "application/json" },
263
- body: JSON.stringify({ session, init: true, personality: voiceSelect.value })
264
  });
265
- const data = await res.json();
266
- appendMessage("bot", data.reply, data.emotion, data.intent);
267
- }
268
-
269
- async function resetChat() {
270
- await fetch("/reset_session", {
271
- method: "POST",
272
- headers: { "Content-Type": "application/json" },
273
- body: JSON.stringify({ session })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  });
275
- localStorage.removeItem("session_id");
276
- session = "sess_" + Math.random().toString(36).substring(2, 10);
277
- localStorage.setItem("session_id", session);
278
- chatContainer.innerHTML = "";
279
- appendMessage("bot", "🔄 Chat reset. Let's start fresh!");
280
- initChat();
281
- }
282
-
283
- sendBtn.addEventListener("click", sendMessage);
284
- input.addEventListener("keypress", (e) => {
285
- if (e.key === "Enter") sendMessage();
286
- });
287
- resetBtn.addEventListener("click", resetChat);
288
-
289
- // Initialize
290
- applyTheme(voiceSelect.value);
291
- initChat();
292
- </script>
293
  </body>
294
- </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
6
+ <title>Serenity Emotional Support</title>
7
+ <style>
8
+ :root {
9
+ --accent: #5b6ef5;
10
+ --bg: linear-gradient(135deg,#eef6ff,#fff6f8);
11
+ }
12
+ body{ margin:0; font-family:Inter,system-ui,-apple-system,Segoe UI,Roboto,"Helvetica Neue"; background:var(--bg); transition:background 1s;}
13
+ header{ background:var(--accent); color:white; padding:14px; text-align:center; font-weight:700; box-shadow:0 4px 18px rgba(20,20,60,0.08);}
14
+ .container{ max-width:960px; margin:18px auto; padding:18px; display:flex; gap:18px; align-items:flex-start; justify-content:center;}
15
+ .left{ width:220px; display:flex; flex-direction:column; align-items:center; gap:12px;}
16
+ .avatar{ width:140px; height:140px; border-radius:50%; background: radial-gradient(circle at 35% 30%, #fff, #7fb3ff); box-shadow: 0 10px 30px rgba(80,110,255,0.12); animation:breathe 4s ease-in-out infinite;}
17
+ @keyframes breathe{0%,100%{transform:scale(1);opacity:0.9}50%{transform:scale(1.08);opacity:1}}
18
+ .controls{ display:flex; flex-direction:column; gap:8px; align-items:center;}
19
+ .select,button,input{ padding:8px 10px; border-radius:10px; border:1px solid rgba(10,10,30,0.06); }
20
+ .main{ flex:1; display:flex; flex-direction:column; gap:10px;}
21
+ .chat{ height:520px; background:rgba(255,255,255,0.9); border-radius:12px; padding:18px; overflow:auto; box-shadow: 0 8px 30px rgba(10,20,40,0.06);}
22
+ .bubble{ max-width:72%; padding:12px 14px; border-radius:14px; margin:10px 0; line-height:1.35;}
23
+ .bubble.user{ margin-left:auto; background:linear-gradient(135deg,#e6f0ff,#d7e9ff); text-align:right;}
24
+ .bubble.bot{ margin-right:auto; background:linear-gradient(135deg,#fff7f9,#fff1f7); text-align:left;}
25
+ .typing{ font-style:italic; color:#64748b; margin-bottom:6px;}
26
+ .inputRow{ display:flex; gap:8px; align-items:center;}
27
+ .inputRow input{ flex:1; padding:12px 14px; border-radius:12px; border:1px solid rgba(10,10,30,0.06);}
28
+ .inputRow button{ padding:10px 14px; border-radius:10px; border:none; cursor:pointer; background:var(--accent); color:white;}
29
+ @media(max-width:900px){ .container{ flex-direction:column; padding:10px;} .avatar{ width:90px; height:90px;} .chat{ height:360px; } }
30
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  </head>
32
  <body>
33
+ <header>🌷 Serenity Your Emotional Support Companion</header>
34
+
35
+ <div class="container">
36
+ <div class="left">
37
+ <div id="orb" class="avatar" aria-hidden="true"></div>
38
+ <div class="controls">
39
+ <label>Personality</label>
40
+ <select id="personality" class="select">
41
+ <option value="calm">Calm</option>
42
+ <option value="friendly">Friendly</option>
43
+ <option value="deep">Deep</option>
44
+ <option value="spiritual">Spiritual</option>
45
  <option value="neutral">Neutral</option>
 
 
 
 
 
 
 
46
  </select>
47
+ <button id="switchAvatar" class="select">Switch Avatar</button>
48
+ <button id="resetBtn" class="select">Reset Chat</button>
49
  </div>
 
50
  </div>
51
 
52
+ <div class="main">
53
+ <div id="chat" class="chat" role="log" aria-live="polite"></div>
54
+ <div id="typing" class="typing" style="display:none">Serenity is thinking…</div>
55
 
56
+ <div class="inputRow">
57
+ <input id="input" placeholder="Type your message..." />
58
+ <button id="sendBtn">Send</button>
59
+ </div>
 
60
  </div>
61
+ </div>
62
+
63
+ <script>
64
+ // Session
65
+ let session = localStorage.getItem("serenity_session");
66
+ if(!session){ session = "s_" + Math.random().toString(36).slice(2,12); localStorage.setItem("serenity_session", session); }
67
+
68
+ const chat = document.getElementById("chat");
69
+ const input = document.getElementById("input");
70
+ const sendBtn = document.getElementById("sendBtn");
71
+ const personalitySelect = document.getElementById("personality");
72
+ const typing = document.getElementById("typing");
73
+ const orb = document.getElementById("orb");
74
+ const resetBtn = document.getElementById("resetBtn");
75
+ const switchAvatar = document.getElementById("switchAvatar");
76
+
77
+ let orbStyle = 0; // 0 = orb, 1 = humanoid (not implemented large differences here)
78
+
79
+ // Append bubble helpers
80
+ function appendBubble(who, text, meta){
81
+ const d = document.createElement("div");
82
+ d.className = "bubble " + (who === "user" ? "user" : "bot");
83
+ d.innerHTML = `<strong>${who === "user" ? "You" : "Serenity"}:</strong> ${text}`;
84
+ if(meta){
85
+ const m = document.createElement("div");
86
+ m.style.fontSize = "12px"; m.style.color="#6b7280"; m.style.marginTop="6px";
87
+ m.textContent = `(${meta.intent || "..."}, ${meta.emotion || "..."})`;
88
+ d.appendChild(m);
89
+ }
90
+ chat.appendChild(d);
91
+ chat.scrollTop = chat.scrollHeight;
92
+ }
93
+
94
+ function showTyping(){ typing.style.display = "block"; orb.style.transform = "scale(1.06)"; }
95
+ function hideTyping(){ typing.style.display = "none"; orb.style.transform = ""; }
96
+
97
+ // speech synthesis (browser)
98
+ function speak(text){
99
+ if(!("speechSynthesis" in window)) return;
100
+ const utter = new SpeechSynthesisUtterance(text);
101
+ // simple mapping: choose a voice by matching label; fallback to first
102
+ const voices = speechSynthesis.getVoices();
103
+ const persona = personalitySelect.value || "neutral";
104
+ // heuristics to pick a voice
105
+ let chosen = null;
106
+ if(persona === "calm") chosen = voices.find(v=>/male|man|david|john|alex/i.test(v.name));
107
+ if(persona === "friendly") chosen = voices.find(v=>/female|zira|susan|sarah|victoria/i.test(v.name));
108
+ if(!chosen) chosen = voices.find(v=>v.lang && v.lang.startsWith("en")) || voices[0];
109
+ if(chosen) utter.voice = chosen;
110
+ // tune pitch & rate by persona
111
+ const map = {
112
+ calm: {pitch:0.85, rate:0.95},
113
+ friendly: {pitch:1.15, rate:1.0},
114
+ deep: {pitch:0.75, rate:0.9},
115
+ spiritual: {pitch:1.0, rate:0.95},
116
+ neutral: {pitch:1.0, rate:1.0}
117
  };
118
+ const cfg = map[persona] || map["neutral"];
119
+ utter.pitch = cfg.pitch; utter.rate = cfg.rate;
120
+ window.speechSynthesis.cancel();
121
+ window.speechSynthesis.speak(utter);
122
+ // show slight breathing while speaking
123
+ orb.style.animationDuration = "2s";
124
+ utter.onend = ()=> { orb.style.animationDuration = "4s"; }
125
+ }
126
+
127
+ // send to backend
128
+ async function sendText(msg){
129
+ if(!msg) return;
130
+ appendBubble("user", msg);
131
+ input.value = "";
132
+ showTyping();
133
+ try{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  const res = await fetch("/chat", {
135
  method: "POST",
136
+ headers: {"Content-Type":"application/json"},
137
+ body: JSON.stringify({ session, message: msg, personality: personalitySelect.value })
138
  });
139
+ const j = await res.json();
140
+ hideTyping();
141
+ const reply = j.reply || j.response || j.message || j.text || j.reply_text || j.reply;
142
+ const emotion = j.emotion || j.intent || "neutral";
143
+ const intent = j.intent || "unknown";
144
+ // fallback keys compatibility
145
+ const payloadText = reply || (j.response || "");
146
+ appendBubble("bot", payloadText, { emotion: j.emotion, intent: j.intent });
147
+ // speak via browser TTS
148
+ speak(payloadText);
149
+ // soft background by emotion
150
+ const mapBg = {
151
+ joy: "linear-gradient(135deg,#fff9c4,#ffecb3)",
152
+ sadness: "linear-gradient(135deg,#a7c7e7,#d4f1f4)",
153
+ anger: "linear-gradient(135deg,#ffb3b3,#ff6666)",
154
+ love: "linear-gradient(135deg,#ffc1cc,#ffb6c1)",
155
+ fear: "linear-gradient(135deg,#c8d8e4,#a7bed3)",
156
+ crisis: "linear-gradient(135deg,#ffe6e6,#fff1f0)",
157
+ neutral: "linear-gradient(135deg,#eef6ff,#fff6f8)"
158
+ };
159
+ document.body.style.background = mapBg[(j.emotion || "neutral")] || mapBg["neutral"];
160
+ }catch(e){
161
+ hideTyping();
162
+ appendBubble("bot", "Sorry — I couldn't connect right now. Please try again.");
163
+ }
164
+ }
165
+
166
+ // UI events
167
+ sendBtn.addEventListener("click", ()=> sendText(input.value.trim()));
168
+ input.addEventListener("keydown", (e)=>{ if(e.key === "Enter") sendText(input.value.trim()); });
169
+ personalitySelect.addEventListener("change", ()=> {
170
+ // slight theme shift on persona change
171
+ const p = personalitySelect.value;
172
+ if(p === "calm") orb.style.background = "radial-gradient(circle, #fff, #7fb3ff)";
173
+ if(p === "friendly") orb.style.background = "radial-gradient(circle, #fff, #f7a6c2)";
174
+ if(p === "deep") orb.style.background = "radial-gradient(circle, #fff, #9fa8da)";
175
+ if(p === "spiritual") orb.style.background = "radial-gradient(circle, #fff, #a3e9c4)";
176
+ });
177
+
178
+ resetBtn.addEventListener("click", async ()=>{
179
+ chat.innerHTML = "";
180
+ await fetch("/reset_session", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({session})}).catch(()=>{});
181
+ appendBubble("bot", "🔄 Chat reset. I’m here. How are you feeling today?");
182
+ });
183
+
184
+ switchAvatar.addEventListener("click", ()=>{
185
+ orbStyle = 1 - orbStyle;
186
+ if(orbStyle === 0){ orb.style.borderRadius = "50%"; orb.style.width = "140px"; orb.style.height = "140px"; }
187
+ else { orb.style.borderRadius = "18px"; orb.style.width = "120px"; orb.style.height = "160px"; }
188
+ });
189
+
190
+ // initial greeting (init)
191
+ (async function init(){
192
+ try{
193
+ const res = await fetch("/chat", {
194
+ method:"POST",
195
+ headers: {"Content-Type":"application/json"},
196
+ body: JSON.stringify({session, init:true})
197
  });
198
+ const j = await res.json();
199
+ const initial = j.reply || j.response || "Hey I'm Serenity. What's your name?";
200
+ appendBubble("bot", initial, {emotion:j.emotion, intent:j.intent});
201
+ // speak welcome
202
+ speak(initial);
203
+ }catch(e){
204
+ appendBubble("bot", "Hey — I’m Serenity. How are you feeling today?");
205
+ }
206
+ })();
207
+ </script>
 
 
 
 
 
 
 
 
208
  </body>
209
+ </html>