Spaces:
Sleeping
Sleeping
Update it.
Browse files- index.html +116 -38
index.html
CHANGED
|
@@ -5,62 +5,116 @@
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
<title>Serenity - Emotional Support Companion</title>
|
| 7 |
<style>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
body {
|
| 9 |
-
background:
|
| 10 |
font-family: "Inter", sans-serif;
|
| 11 |
margin: 0;
|
| 12 |
-
padding: 0;
|
| 13 |
display: flex;
|
| 14 |
flex-direction: column;
|
| 15 |
height: 100vh;
|
| 16 |
color: #222;
|
|
|
|
| 17 |
}
|
|
|
|
| 18 |
header {
|
| 19 |
-
background:
|
| 20 |
color: #fff;
|
| 21 |
text-align: center;
|
| 22 |
padding: 1rem;
|
| 23 |
-
font-size: 1.
|
| 24 |
font-weight: 600;
|
| 25 |
-
letter-spacing: 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
#chat-container {
|
| 28 |
flex: 1;
|
| 29 |
overflow-y: auto;
|
| 30 |
padding: 1rem;
|
| 31 |
display: flex;
|
| 32 |
flex-direction: column;
|
|
|
|
| 33 |
}
|
|
|
|
| 34 |
.message {
|
| 35 |
margin: 0.6rem 0;
|
| 36 |
max-width: 75%;
|
| 37 |
padding: 0.7rem 1rem;
|
| 38 |
-
border-radius:
|
| 39 |
line-height: 1.5;
|
| 40 |
-
animation: fadeIn 0.
|
| 41 |
word-wrap: break-word;
|
|
|
|
| 42 |
}
|
|
|
|
| 43 |
.user {
|
| 44 |
align-self: flex-end;
|
| 45 |
-
background:
|
|
|
|
|
|
|
| 46 |
}
|
|
|
|
| 47 |
.bot {
|
| 48 |
align-self: flex-start;
|
| 49 |
-
background:
|
| 50 |
-
border:
|
|
|
|
| 51 |
}
|
|
|
|
| 52 |
.meta {
|
| 53 |
font-size: 0.7rem;
|
| 54 |
color: #777;
|
| 55 |
margin-top: 0.2rem;
|
| 56 |
text-align: right;
|
| 57 |
}
|
|
|
|
| 58 |
#input-container {
|
| 59 |
display: flex;
|
| 60 |
padding: 0.7rem;
|
| 61 |
background: #fff;
|
| 62 |
border-top: 1px solid #ddd;
|
| 63 |
}
|
|
|
|
| 64 |
#user-input {
|
| 65 |
flex: 1;
|
| 66 |
border: 1px solid #ccc;
|
|
@@ -68,33 +122,23 @@
|
|
| 68 |
padding: 0.6rem 0.8rem;
|
| 69 |
font-size: 1rem;
|
| 70 |
}
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
button:hover {
|
| 82 |
-
background: #4d5fe3;
|
| 83 |
-
}
|
| 84 |
-
#controls {
|
| 85 |
-
display: flex;
|
| 86 |
-
justify-content: space-between;
|
| 87 |
-
align-items: center;
|
| 88 |
-
padding: 0.5rem 1rem;
|
| 89 |
-
background: #f0f2ff;
|
| 90 |
-
border-bottom: 1px solid #ddd;
|
| 91 |
-
font-size: 0.9rem;
|
| 92 |
}
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
}
|
|
|
|
| 98 |
@keyframes fadeIn {
|
| 99 |
from { opacity: 0; transform: translateY(6px); }
|
| 100 |
to { opacity: 1; transform: translateY(0); }
|
|
@@ -106,9 +150,9 @@
|
|
| 106 |
|
| 107 |
<div id="controls">
|
| 108 |
<div>
|
| 109 |
-
<label for="voice-profile">
|
| 110 |
<select id="voice-profile">
|
| 111 |
-
<option value="neutral">Neutral
|
| 112 |
<option value="calm_male">Calm Male</option>
|
| 113 |
<option value="deep_male">Deep Male</option>
|
| 114 |
<option value="soothing_male">Soothing Male</option>
|
|
@@ -121,6 +165,8 @@
|
|
| 121 |
<button id="reset">Reset Chat</button>
|
| 122 |
</div>
|
| 123 |
|
|
|
|
|
|
|
| 124 |
<div id="chat-container"></div>
|
| 125 |
|
| 126 |
<div id="input-container">
|
|
@@ -134,6 +180,8 @@
|
|
| 134 |
const sendBtn = document.getElementById("send");
|
| 135 |
const voiceSelect = document.getElementById("voice-profile");
|
| 136 |
const resetBtn = document.getElementById("reset");
|
|
|
|
|
|
|
| 137 |
|
| 138 |
let session = localStorage.getItem("session_id");
|
| 139 |
if (!session) {
|
|
@@ -141,6 +189,31 @@
|
|
| 141 |
localStorage.setItem("session_id", session);
|
| 142 |
}
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
async function appendMessage(sender, text, emotion, intent) {
|
| 145 |
const div = document.createElement("div");
|
| 146 |
div.classList.add("message", sender);
|
|
@@ -160,6 +233,7 @@
|
|
| 160 |
if (!text) return;
|
| 161 |
appendMessage("user", text);
|
| 162 |
input.value = "";
|
|
|
|
| 163 |
|
| 164 |
const body = {
|
| 165 |
session: session,
|
|
@@ -177,6 +251,8 @@
|
|
| 177 |
appendMessage("bot", data.reply, data.emotion, data.intent);
|
| 178 |
} catch (err) {
|
| 179 |
appendMessage("bot", "Sorry, I had trouble connecting. Please try again.");
|
|
|
|
|
|
|
| 180 |
}
|
| 181 |
}
|
| 182 |
|
|
@@ -184,7 +260,7 @@
|
|
| 184 |
const res = await fetch("/chat", {
|
| 185 |
method: "POST",
|
| 186 |
headers: { "Content-Type": "application/json" },
|
| 187 |
-
body: JSON.stringify({ session
|
| 188 |
});
|
| 189 |
const data = await res.json();
|
| 190 |
appendMessage("bot", data.reply, data.emotion, data.intent);
|
|
@@ -210,6 +286,8 @@
|
|
| 210 |
});
|
| 211 |
resetBtn.addEventListener("click", resetChat);
|
| 212 |
|
|
|
|
|
|
|
| 213 |
initChat();
|
| 214 |
</script>
|
| 215 |
</body>
|
|
|
|
| 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;
|
|
|
|
| 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); }
|
|
|
|
| 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>
|
|
|
|
| 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">
|
|
|
|
| 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) {
|
|
|
|
| 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);
|
|
|
|
| 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,
|
|
|
|
| 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 |
|
|
|
|
| 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);
|
|
|
|
| 286 |
});
|
| 287 |
resetBtn.addEventListener("click", resetChat);
|
| 288 |
|
| 289 |
+
// Initialize
|
| 290 |
+
applyTheme(voiceSelect.value);
|
| 291 |
initChat();
|
| 292 |
</script>
|
| 293 |
</body>
|