luck210 commited on
Commit
9aec67d
·
verified ·
1 Parent(s): 6241c04

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +537 -111
app.py CHANGED
@@ -28,134 +28,560 @@ def get_chatbot_response(user_input: str, max_length=100):
28
  response = tokenizer.decode(chat_history_ids[:, input_ids.shape[-1]:][0], skip_special_tokens=True)
29
  return response.strip()
30
 
31
- # HTML, CSS, and JS embedded
32
  HTML_CONTENT = """
33
  <!DOCTYPE html>
34
  <html lang="en">
35
  <head>
36
  <meta charset="UTF-8">
37
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
38
- <title>Chatbot</title>
 
 
 
39
  <style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  body {
41
- font-family: Arial, sans-serif;
42
- background-color: #f0f2f5;
43
- margin: 0;
44
- padding: 20px;
45
- display: flex;
46
- justify-content: center;
47
- align-items: center;
48
- min-height: 100vh;
49
- }
50
- .container {
51
- max-width: 800px;
52
- width: 100%;
53
- padding: 2rem;
54
- background: white;
55
- border-radius: 10px;
56
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
57
- }
58
- h1 {
59
- color: #2c3e50;
60
- text-align: center;
61
- margin-bottom: 2rem;
62
- }
63
- .chat-area {
64
- max-height: 400px;
65
- overflow-y: auto;
66
- margin-bottom: 1.5rem;
67
- padding: 1rem;
68
- background: #f9f9f9;
69
- border: 2px solid #eee;
70
- border-radius: 5px;
71
- }
72
- .message {
73
- margin: 0.5rem 0;
74
- padding: 0.8rem;
75
- border-radius: 5px;
76
- }
77
- .user-message {
78
- background-color: #3498db;
79
- color: white;
80
- margin-left: 20%;
81
- text-align: right;
82
- }
83
- .bot-message {
84
- background-color: #ecf0f1;
85
- color: #2c3e50;
86
- margin-right: 20%;
87
- }
88
- .input-section {
89
- display: flex;
90
- gap: 1rem;
91
- }
92
- input[type="text"] {
93
- flex: 1;
94
- padding: 0.8rem;
95
- border: 2px solid #ddd;
96
- border-radius: 5px;
97
- font-size: 1rem;
98
- }
99
- button {
100
- padding: 0.8rem 1.5rem;
101
- background-color: #3498db;
102
- color: white;
103
- border: none;
104
- border-radius: 5px;
105
- cursor: pointer;
106
- font-size: 1rem;
107
- transition: background-color 0.3s;
108
- }
109
- button:hover {
110
- background-color: #2980b9;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  }
 
 
 
 
 
 
112
  </style>
113
  </head>
114
  <body>
115
- <div class="container">
116
- <h1>Chatbot</h1>
117
- <div class="chat-area" id="chatArea"></div>
118
- <div class="input-section">
119
- <input type="text" id="userInput" placeholder="Type your message..." onkeypress="if(event.key === 'Enter') sendMessage();">
120
- <button onclick="sendMessage()">Send</button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  </div>
 
 
122
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  <script>
124
- const chatArea = document.getElementById("chatArea");
125
- const userInput = document.getElementById("userInput");
126
-
127
- function addMessage(text, isUser = false) {
128
- const messageDiv = document.createElement("div");
129
- messageDiv.className = "message " + (isUser ? "user-message" : "bot-message");
130
- messageDiv.textContent = text;
131
- chatArea.appendChild(messageDiv);
132
- chatArea.scrollTop = chatArea.scrollHeight;
133
- }
134
-
135
- async function sendMessage() {
136
- const text = userInput.value.trim();
137
- if (!text) return;
138
-
139
- addMessage(text, true);
140
- userInput.value = "";
141
- addMessage("Thinking...");
142
-
143
- try {
144
- const response = await fetch("/chat", {
145
- method: "POST",
146
- headers: { "Content-Type": "application/json" },
147
- body: JSON.stringify({ message: text })
148
- });
149
- const data = await response.json();
150
- if (!response.ok) throw new Error(data.detail || "Chat error");
151
-
152
- chatArea.lastChild.remove();
153
- addMessage(data.response);
154
- } catch (error) {
155
- chatArea.lastChild.remove();
156
- addMessage(`Error: ${error.message}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  }
158
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  </script>
160
  </body>
161
  </html>
 
28
  response = tokenizer.decode(chat_history_ids[:, input_ids.shape[-1]:][0], skip_special_tokens=True)
29
  return response.strip()
30
 
31
+ # HTML, CSS, and JS for the frontend
32
  HTML_CONTENT = """
33
  <!DOCTYPE html>
34
  <html lang="en">
35
  <head>
36
  <meta charset="UTF-8">
37
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
38
+ <meta name="description" content="Vion IA: Your friendly AI chatbot powered by xAI">
39
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github-dark.min.css">
40
+ <link href='https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css' rel='stylesheet'>
41
+ <title>Vion IA | Powered by xAI</title>
42
  <style>
43
+ @import url('https://fonts.googleapis.com/css2?family=Open+Sans:wght@300;400;600;800&display=swap');
44
+ * { margin: 0; padding: 0; outline: none; box-sizing: border-box; font-family: "Open Sans", sans-serif; }
45
+ :root {
46
+ --primary-color: #0A0A0B; --secondary-color: #1A1B1E; --secondary-hover-color: #2A2B2E;
47
+ --focus-color: #242528; --focus-hover-color: #343538; --button-hover-color: #252627;
48
+ --text-color: #FFFFFF; --text-secondary-color: #A0A1A3; --heading-secondary-color: #606162;
49
+ --placeholder-color: #78797A; --accent-color: #00A3FF; --star-color: #FFFFFF;
50
+ --background-color: #000; --error-color: #FF4D4D; --success-color: #4CAF50;
51
+ }
52
+ .light_mode {
53
+ --primary-color: #E8E2F2; --secondary-color: #F0ECF8; --secondary-hover-color: #D8D0E6;
54
+ --focus-color: #F5F5F5; --focus-hover-color: #E8E8E8; --button-hover-color: #E0D8F0;
55
+ --text-color: #2A2A2A; --text-secondary-color: #4A4B4C; --heading-secondary-color: #BABBBB;
56
+ --placeholder-color: #868788; --accent-color: #7A5CFA; --star-color: #666;
57
+ --background-color: #F5F5F5; --error-color: #D32F2F; --success-color: #388E3C;
58
+ }
59
+ .starry_night {
60
+ --accent-color: #FFD700; --background-color: #1C2526; --star-color: #FFD700;
61
+ --secondary-color: #2E3B3E; --secondary-hover-color: #3E4B4E;
62
+ }
63
  body {
64
+ min-height: 100vh; display: flex; flex-direction: row; justify-content: space-between;
65
+ background: var(--background-color); position: relative; overflow-y: hidden; transition: background 0.3s ease;
66
+ }
67
+ .stars {
68
+ position: fixed; width: 100%; height: 100%;
69
+ background: url('https://www.transparenttextures.com/patterns/stardust.png');
70
+ animation: starsAnim 100s linear infinite; z-index: -1; transition: opacity 0.3s ease;
71
+ }
72
+ .light_mode .stars {
73
+ background: url('https://www.transparenttextures.com/patterns/stardust.png') rgba(245, 245, 245, 0.4);
74
+ opacity: 0.2;
75
+ }
76
+ .starry_night .stars {
77
+ background: url('https://www.transparenttextures.com/patterns/stardust.png') rgba(255, 215, 0, 0.1);
78
+ opacity: 0.8;
79
+ }
80
+ @keyframes starsAnim { from { background-position: 0 0; } to { background-position: 10000px 10000px; } }
81
+ @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } }
82
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
83
+ .sidebar {
84
+ width: 70px; height: 100vh; background: rgba(26, 27, 30, 0.95); display: flex; flex-direction: column;
85
+ align-items: center; padding: 1rem 0; position: fixed; left: 0; top: 0; transition: width 0.3s ease; z-index: 1001;
86
+ }
87
+ .sidebar:hover { width: 200px; }
88
+ .sidebar__item {
89
+ width: 100%; padding: 1rem; color: var(--text-secondary-color); text-decoration: none;
90
+ display: flex; align-items: center; gap: 1rem; transition: all 0.3s ease; position: relative;
91
+ }
92
+ .sidebar__item:hover {
93
+ background: var(--secondary-hover-color); color: var(--accent-color); padding-left: 1.5rem; transform: scale(1.05);
94
+ }
95
+ .sidebar__item i { font-size: 1.5rem; }
96
+ .sidebar__item span { display: none; font-size: 1rem; }
97
+ .sidebar:hover .sidebar__item span { display: inline; }
98
+ .light_mode .sidebar { background: rgba(240, 236, 248, 0.95); }
99
+ .starry_night .sidebar { background: rgba(46, 59, 62, 0.95); }
100
+ .tooltip {
101
+ visibility: hidden; background: var(--secondary-color); color: var(--text-color); font-size: 0.8rem;
102
+ padding: 0.5rem; border-radius: 0.3rem; position: absolute; top: -30px; left: 50%; transform: translateX(-50%);
103
+ white-space: nowrap; z-index: 1002; transition: visibility 0.2s, opacity 0.2s; opacity: 0;
104
+ }
105
+ .sidebar__item:hover .tooltip { visibility: visible; opacity: 1; }
106
+ .main-content {
107
+ flex: 1; display: flex; flex-direction: column; padding-bottom: 100px; padding-top: 2rem; margin-left: 70px;
108
+ height: 100vh; overflow: hidden;
109
+ }
110
+ .header { max-width: 900px; text-align: center; padding: 0 2rem; margin: 0 auto; }
111
+ .header__title h1 {
112
+ color: var(--text-color); font-size: 3.5rem; font-weight: 800; margin-bottom: 1rem;
113
+ text-shadow: 0 0 10px rgba(0, 163, 255, 0.5); animation: fadeIn 1s ease-in;
114
+ }
115
+ .header__title h2 {
116
+ color: var(--text-secondary-color); font-size: 1.5rem; font-weight: 400;
117
+ max-width: 600px; margin: 0 auto; text-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
118
+ transition: opacity 0.3s ease, height 0.3s ease;
119
+ }
120
+ .suggests {
121
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
122
+ margin: 2rem auto; max-width: 900px; gap: 1rem; padding: 0 2rem; transition: opacity 0.3s ease, height 0.3s ease;
123
+ animation: fadeIn 0.5s ease-in;
124
+ }
125
+ .suggests.hidden, .header__title h2.hidden {
126
+ opacity: 0; height: 0; margin: 0; overflow: hidden;
127
+ }
128
+ .suggests__item {
129
+ background: rgba(26, 27, 30, 0.9); color: var(--text-secondary-color); padding: 1.5rem;
130
+ border-radius: 0.5rem; cursor: pointer; transition: all 0.3s ease; border: 1px solid var(--focus-color);
131
+ position: relative;
132
+ }
133
+ .light_mode .suggests__item { background: rgba(240, 236, 248, 0.9); }
134
+ .starry_night .suggests__item { background: rgba(46, 59, 62, 0.9); }
135
+ .suggests__item:hover {
136
+ background: var(--secondary-hover-color); border-color: var(--accent-color); color: var(--text-color);
137
+ transform: translateY(-3px);
138
+ }
139
+ .suggests__item-icon { margin-top: 1rem; color: var(--accent-color); transition: transform 0.2s ease; }
140
+ .suggests__item:hover .suggests__item-icon { transform: scale(1.2); }
141
+ .suggests__item .tooltip {
142
+ top: -40px; left: 50%; transform: translateX(-50%);
143
+ }
144
+ .suggests__item:hover .tooltip { visibility: visible; opacity: 1; }
145
+ .prompt {
146
+ position: fixed; background: rgba(10, 10, 11, 0.9); z-index: 1000; width: calc(100% - 70px);
147
+ left: 70px; bottom: 0; padding: 1rem; border-top: 1px solid var(--secondary-color); transition: all 0.3s ease;
148
+ }
149
+ .light_mode .prompt { background: rgba(240, 236, 248, 0.9); border-top: 1px solid var(--focus-color); }
150
+ .starry_night .prompt { background: rgba(28, 37, 38, 0.9); }
151
+ .prompt__input-wrapper {
152
+ max-width: 900px; margin: 0 auto; position: relative; display: flex; align-items: center;
153
+ background: var(--secondary-color); border: 1px solid var(--focus-color); border-radius: 0.5rem;
154
+ padding: 0.2rem; transition: all 0.3s ease; animation: fadeIn 0.5s ease-in;
155
+ }
156
+ .prompt__input-wrapper:focus-within {
157
+ border-color: var(--accent-color); background: var(--focus-color); transform: scale(1.02);
158
+ }
159
+ .prompt__input-wrapper.dragover {
160
+ border: 2px dashed var(--accent-color); background: var(--focus-hover-color);
161
+ }
162
+ .prompt__form-input {
163
+ flex-grow: 1; border: none; resize: none; font-size: 1.1rem; color: var(--text-color);
164
+ padding: 0.3rem 0.5rem; background: transparent; outline: none; transition: all 0.3s ease;
165
+ }
166
+ .prompt__form-input::placeholder { color: var(--placeholder-color); transition: opacity 0.3s ease; }
167
+ .prompt__form-input:focus::placeholder { opacity: 0.5; }
168
+ .prompt__action-buttons {
169
+ display: flex; align-items: center; gap: 0.3rem; padding-right: 0.3rem; position: relative;
170
+ }
171
+ .prompt__action-buttons.advanced { display: none; }
172
+ .prompt__action-buttons.advanced.active { display: flex; }
173
+ .prompt__form-button {
174
+ background: none; border: none; color: var(--text-secondary-color); font-size: 1.3rem;
175
+ cursor: pointer; padding: 0.3rem; transition: all 0.3s ease; position: relative;
176
+ }
177
+ .prompt__form-button:hover { color: var(--accent-color); transform: scale(1.1); }
178
+ .prompt__form-button.send { font-size: 1.5rem; }
179
+ .prompt__form-button .tooltip {
180
+ top: -35px; left: 50%; transform: translateX(-50%);
181
+ }
182
+ .prompt__form-button:hover .tooltip { visibility: visible; opacity: 1; }
183
+ .prompt__disclaim {
184
+ text-align: center; color: var(--placeholder-color); font-size: 0.8rem; margin-top: 1rem;
185
+ max-width: 900px; margin-left: auto; margin-right: auto; transition: opacity 0.3s ease;
186
+ }
187
+ .chat-bar {
188
+ max-width: 900px; margin: 2rem auto; padding: 0 2rem; display: flex; flex-direction: column;
189
+ overflow-y: auto; max-height: calc(100vh - 180px); -ms-overflow-style: none; scrollbar-width: none;
190
+ }
191
+ .chat-bar::-webkit-scrollbar { display: none; }
192
+ .chat-message {
193
+ margin-bottom: 1rem; padding: 1rem; border-radius: 0.5rem; background: rgba(26, 27, 30, 0.9);
194
+ color: var(--text-color); word-wrap: break-word; animation: fadeIn 0.3s ease-in; position: relative;
195
+ }
196
+ .light_mode .chat-message { background: rgba(240, 236, 248, 0.9); }
197
+ .starry_night .chat-message { background: rgba(46, 59, 62, 0.9); }
198
+ .chat-message.user {
199
+ background: rgba(122, 92, 250, 0.2); border: 1px solid var(--accent-color); border-radius: 0.5rem;
200
+ }
201
+ .chat-message.bot { background: rgba(36, 37, 40, 0.9); }
202
+ .chat-message.user.bubble-rounded { border-radius: 1rem; }
203
+ .chat-message.user.bubble-sharp { border-radius: 0; border: 2px solid var(--accent-color); }
204
+ .chat-message.user.bubble-starry {
205
+ border-radius: 0.5rem; border: 1px dashed var(--accent-color);
206
+ background: rgba(122, 92, 250, 0.2) url('https://www.transparenttextures.com/patterns/stardust.png') repeat;
207
+ background-size: 100px 100px;
208
+ }
209
+ .chat-message.feedback::after {
210
+ content: 'Was this helpful?'; color: var(--text-secondary-color); font-size: 0.8rem; display: block;
211
+ margin-top: 0.5rem; cursor: pointer; text-decoration: underline;
212
+ }
213
+ .chat-message.feedback .feedback-options {
214
+ display: none; position: absolute; bottom: -30px; left: 1rem; gap: 0.5rem;
215
+ }
216
+ .chat-message.feedback:hover .feedback-options { display: flex; }
217
+ .feedback-options button {
218
+ background: none; border: none; color: var(--text-secondary-color); font-size: 1rem; cursor: pointer;
219
+ transition: color 0.2s ease;
220
+ }
221
+ .feedback-options button:hover { color: var(--accent-color); }
222
+ .error-message {
223
+ background: rgba(255, 77, 77, 0.2); border: 1px solid var(--error-color); color: var(--text-color);
224
+ padding: 1rem; border-radius: 0.5rem; margin-bottom: 1rem; animation: fadeIn 0.3s ease-in;
225
+ display: flex; justify-content: space-between; align-items: center;
226
+ }
227
+ .error-message button {
228
+ background: var(--error-color); color: var(--text-color); border: none; padding: 0.3rem 0.6rem;
229
+ border-radius: 0.3rem; cursor: pointer; transition: background 0.2s ease;
230
+ }
231
+ .error-message button:hover { background: var(--button-hover-color); }
232
+ .back-to-latest {
233
+ display: none; position: fixed; bottom: 100px; right: 2rem; background: var(--secondary-color);
234
+ color: var(--text-color); padding: 0.5rem 1rem; border-radius: 0.5rem; cursor: pointer;
235
+ border: 1px solid var(--accent-color); transition: all 0.3s ease; z-index: 1000;
236
+ }
237
+ .back-to-latest.visible { display: block; }
238
+ .back-to-latest:hover { background: var(--secondary-hover-color); transform: scale(1.05); }
239
+ .processing-dots {
240
+ display: none; position: absolute; right: 60px; color: var(--accent-color); font-size: 1.2rem;
241
+ }
242
+ .processing-dots.active { display: inline; animation: pulse 1.5s infinite; }
243
+ @keyframes blink {
244
+ 0% { opacity: 1; } 50% { opacity: 0.3; } 100% { opacity: 1; }
245
+ }
246
+ .processing-dots span {
247
+ animation: blink 1s infinite; animation-delay: calc(0.2s * var(--i));
248
+ }
249
+ .theme-selector {
250
+ display: none; position: fixed; top: 10px; right: 10px; background: var(--secondary-color);
251
+ border: 1px solid var(--focus-color); border-radius: 0.5rem; padding: 0.5rem; z-index: 1002;
252
  }
253
+ .theme-selector.active { display: block; }
254
+ .theme-selector button {
255
+ background: none; border: none; color: var(--text-color); padding: 0.3rem 0.6rem;
256
+ cursor: pointer; transition: all 0.2s ease;
257
+ }
258
+ .theme-selector button:hover { color: var(--accent-color); }
259
  </style>
260
  </head>
261
  <body>
262
+ <div class="stars"></div>
263
+ <nav class="sidebar" aria-label="Main navigation">
264
+ <a href="#" class="sidebar__item" aria-label="Home"><i class='bx bx-home'></i><span>Home</span><div class="tooltip">Go to Home</div></a>
265
+ <a href="#" class="sidebar__item" aria-label="Profile"><i class='bx bx-user'></i><span>Profile</span><div class="tooltip">View Profile</div></a>
266
+ <a href="#" class="sidebar__item" aria-label="Settings"><i class='bx bx-cog'></i><span>Settings</span><div class="tooltip">Adjust Settings</div></a>
267
+ <a href="#" class="sidebar__item" aria-label="Help"><i class='bx bx-help-circle'></i><span>Help</span><div class="tooltip">Get Help</div></a>
268
+ </nav>
269
+ <div class="theme-selector" id="themeSelector">
270
+ <button onclick="setTheme('dark')">Dark</button>
271
+ <button onclick="setTheme('light')">Light</button>
272
+ <button onclick="setTheme('starry')">Starry Night</button>
273
+ </div>
274
+ <div class="main-content">
275
+ <header class="header">
276
+ <div class="header__title">
277
+ <h1>Vion IA</h1>
278
+ <h2 id="welcome-text">Ask me anything and I'll provide helpful and truthful answers from an outside perspective on humanity.</h2>
279
+ </div>
280
+ </header>
281
+ <div class="suggests">
282
+ <div class="suggests__item"><p class="suggests__item-text">What is the meaning of life?</p><div class="suggests__item-icon"><i class='bx bx-bulb'></i></div><div class="tooltip">Explore life's purpose</div></div>
283
+ <div class="suggests__item"><p class="suggests__item-text">Explain quantum physics simply</p><div class="suggests__item-icon"><i class='bx bx-atom'></i></div><div class="tooltip">Learn about quantum physics</div></div>
284
+ <div class="suggests__item"><p class="suggests__item-text">How does the universe work?</p><div class="suggests__item-icon"><i class='bx bx-planet'></i></div><div class="tooltip">Discover the universe</div></div>
285
  </div>
286
+ <div class="chat-bar" id="chatBar" aria-live="polite"></div>
287
+ <button class="back-to-latest" id="backToLatest">Back to Latest</button>
288
  </div>
289
+ <section class="prompt">
290
+ <form action="#" class="prompt__form" novalidate>
291
+ <div class="prompt__input-wrapper">
292
+ <input type="text" placeholder="Ask me anything..." class="prompt__form-input" id="chatInput" required aria-label="Chat input">
293
+ <div class="prompt__action-buttons basic">
294
+ <button type="button" class="prompt__form-button send" id="sendButton" aria-label="Send message"><i class='bx bx-send'></i><div class="tooltip">Send Message</div></button>
295
+ <button type="button" class="prompt__form-button" id="moreOptions" aria-label="Show more options"><i class='bx bx-dots-horizontal-rounded'></i><div class="tooltip">More Options</div></button>
296
+ </div>
297
+ <div class="prompt__action-buttons advanced" id="advancedOptions">
298
+ <label for="fileInput" class="prompt__form-button" aria-label="Upload file"><i class='bx bx-upload'></i><div class="tooltip">Upload File</div></label>
299
+ <input type="file" id="fileInput" style="display: none;" accept=".txt,.pdf,.jpg,.png">
300
+ <button type="button" class="prompt__form-button" id="deepSearchButton" aria-label="Deep search"><i class='bx bx-search'></i><div class="tooltip">Deep Search</div></button>
301
+ <button type="button" class="prompt__form-button" id="thinkButton" aria-label="Think mode"><i class='bx bx-brain'></i><div class="tooltip">Think Mode</div></button>
302
+ <button type="button" class="prompt__form-button" id="bubbleToggle" aria-label="Toggle bubble style"><i class='bx bx-chat'></i><div class="tooltip">Change Bubble Style</div></button>
303
+ <button type="button" class="prompt__form-button" id="soundToggle" aria-label="Toggle sound"><i class='bx bx-volume-full'></i><div class="tooltip">Toggle Sound</div></button>
304
+ <button type="button" class="prompt__form-button" id="themeToggler" aria-label="Toggle theme"><i class='bx bx-sun'></i><div class="tooltip">Toggle Theme</div></button>
305
+ <span class="processing-dots" id="processingDots"><span style="--i:1">.</span><span style="--i:2">.</span><span style="--i:3">.</span></span>
306
+ </div>
307
+ </div>
308
+ </form>
309
+ <p class="prompt__disclaim">Vion IA provides answers based on its training and design. It may make mistakes.</p>
310
+ </section>
311
+ <audio id="sendSound" src="https://www.soundjay.com/buttons/beep-01a.mp3"></audio>
312
+ <audio id="responseSound" src="https://www.soundjay.com/buttons/beep-02.mp3"></audio>
313
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
314
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
315
  <script>
316
+ // Initialize state
317
+ let soundEnabled = localStorage.getItem('soundEnabled') !== 'false';
318
+ let messageHistory = [];
319
+ let currentBubbleIndex = 0;
320
+ const bubbleStyles = ['bubble-rounded', 'bubble-sharp', 'bubble-starry'];
321
+ const chatBar = document.getElementById('chatBar');
322
+ const inputField = document.getElementById('chatInput');
323
+ const suggests = document.querySelector('.suggests');
324
+ const welcomeText = document.getElementById('welcome-text');
325
+ const processingDots = document.getElementById('processingDots');
326
+ const sendButton = document.getElementById('sendButton');
327
+ const backToLatest = document.getElementById('backToLatest');
328
+ const themeToggler = document.getElementById('themeToggler');
329
+ const soundToggle = document.getElementById('soundToggle');
330
+ const advancedOptions = document.getElementById('advancedOptions');
331
+ const moreOptions = document.getElementById('moreOptions');
332
+ const themeSelector = document.getElementById('themeSelector');
333
+
334
+ // Personalized greeting
335
+ function setGreeting() {
336
+ const hour = new Date().getHours();
337
+ const greeting = hour < 12 ? 'Good morning!' : hour < 18 ? 'Good afternoon!' : 'Good evening!';
338
+ const returning = localStorage.getItem('visited');
339
+ welcomeText.textContent = returning ? `Welcome back! ${greeting}` : `${greeting} Ask me anything!`;
340
+ localStorage.setItem('visited', 'true');
341
+ }
342
+ setGreeting();
343
+
344
+ // Theme management
345
+ function setTheme(theme) {
346
+ document.body.classList.remove('light_mode', 'starry_night');
347
+ if (theme === 'light') document.body.classList.add('light_mode');
348
+ if (theme === 'starry') document.body.classList.add('starry_night');
349
+ themeToggler.innerHTML = theme === 'light' ? "<i class='bx bx-moon'></i>" : "<i class='bx bx-sun'></i>";
350
+ localStorage.setItem('theme', theme);
351
+ themeSelector.classList.remove('active');
352
+ }
353
+ const savedTheme = localStorage.getItem('theme') || 'dark';
354
+ setTheme(savedTheme);
355
+
356
+ // Toggle theme selector
357
+ themeToggler.addEventListener('click', () => {
358
+ themeSelector.classList.toggle('active');
359
+ });
360
+
361
+ // Sound toggle
362
+ soundToggle.innerHTML = soundEnabled ? "<i class='bx bx-volume-full'></i>" : "<i class='bx bx-volume-mute'></i>";
363
+ soundToggle.addEventListener('click', () => {
364
+ soundEnabled = !soundEnabled;
365
+ localStorage.setItem('soundEnabled', soundEnabled);
366
+ soundToggle.innerHTML = soundEnabled ? "<i class='bx bx-volume-full'></i>" : "<i class='bx bx-volume-mute'></i>";
367
+ });
368
+
369
+ // Progressive disclosure
370
+ moreOptions.addEventListener('click', () => {
371
+ advancedOptions.classList.toggle('active');
372
+ moreOptions.style.transform = advancedOptions.classList.contains('active') ? 'rotate(90deg)' : 'rotate(0)';
373
+ });
374
+
375
+ // Bubble customization
376
+ document.getElementById('bubbleToggle').addEventListener('click', () => {
377
+ currentBubbleIndex = (currentBubbleIndex + 1) % bubbleStyles.length;
378
+ applyBubbleStyle();
379
+ });
380
+
381
+ function applyBubbleStyle() {
382
+ const userMessages = document.querySelectorAll('.chat-message.user');
383
+ userMessages.forEach(msg => {
384
+ bubbleStyles.forEach(style => msg.classList.remove(style));
385
+ msg.classList.add(bubbleStyles[currentBubbleIndex]);
386
+ });
387
+ }
388
+
389
+ // Add message with feedback option
390
+ function addMessage(content, isUser = false, isError = false) {
391
+ if (isError) {
392
+ const errorDiv = document.createElement('div');
393
+ errorDiv.classList.add('error-message');
394
+ errorDiv.innerHTML = `${content} <button onclick="retryLastMessage()">Retry</button>`;
395
+ chatBar.appendChild(errorDiv);
396
+ } else {
397
+ const messageDiv = document.createElement('div');
398
+ messageDiv.classList.add('chat-message', isUser ? 'user' : 'bot');
399
+ if (isUser) messageDiv.classList.add(bubbleStyles[currentBubbleIndex]);
400
+ if (!isUser) messageDiv.classList.add('feedback');
401
+ messageDiv.textContent = content;
402
+ if (!isUser) {
403
+ const feedbackDiv = document.createElement('div');
404
+ feedbackDiv.classList.add('feedback-options');
405
+ feedbackDiv.innerHTML = `
406
+ <button onclick="handleFeedback('up')" aria-label="Thumbs up"><i class='bx bx-thumbs-up'></i></button>
407
+ <button onclick="handleFeedback('down')" aria-label="Thumbs down"><i class='bx bx-thumbs-down'></i></button>
408
+ `;
409
+ messageDiv.appendChild(feedbackDiv);
410
+ }
411
+ chatBar.appendChild(messageDiv);
412
+ messageHistory.push({ content, isUser });
413
+ }
414
+ if (chatBar.scrollTop + chatBar.clientHeight >= chatBar.scrollHeight - 100) {
415
+ chatBar.scrollTop = chatBar.scrollHeight;
416
  }
417
  }
418
+
419
+ // Handle feedback (placeholder)
420
+ function handleFeedback(type) {
421
+ console.log(`Feedback: ${type}`);
422
+ alert(`Thanks for your feedback! (${type === 'up' ? 'Thumbs up' : 'Thumbs down'})`);
423
+ }
424
+
425
+ // Retry last message
426
+ function retryLastMessage() {
427
+ const lastUserMessage = messageHistory.filter(m => m.isUser).slice(-1)[0];
428
+ if (lastUserMessage) sendMessage(lastUserMessage.content);
429
+ }
430
+
431
+ // Input events
432
+ inputField.addEventListener('input', () => {
433
+ const input = inputField.value.trim();
434
+ suggests.classList.toggle('hidden', input.length > 0);
435
+ welcomeText.classList.toggle('hidden', input.length > 0);
436
+ inputField.setCustomValidity(input.length < 3 && input.length > 0 ? 'Please enter at least 3 characters.' : '');
437
+ });
438
+
439
+ inputField.addEventListener('focus', () => {
440
+ inputField.parentElement.style.boxShadow = `0 0 5px var(--accent-color)`;
441
+ });
442
+
443
+ inputField.addEventListener('blur', () => {
444
+ inputField.parentElement.style.boxShadow = 'none';
445
+ });
446
+
447
+ inputField.addEventListener('keydown', (e) => {
448
+ if (e.key === 'Enter' && !e.shiftKey) {
449
+ e.preventDefault();
450
+ sendMessage();
451
+ } else if (e.ctrlKey && e.key === 'Enter') {
452
+ alert('Toggling advanced mode (placeholder)');
453
+ }
454
+ });
455
+
456
+ // Drag and drop
457
+ const inputWrapper = document.querySelector('.prompt__input-wrapper');
458
+ inputWrapper.addEventListener('dragover', (e) => {
459
+ e.preventDefault();
460
+ inputWrapper.classList.add('dragover');
461
+ });
462
+ inputWrapper.addEventListener('dragleave', () => {
463
+ inputWrapper.classList.remove('dragover');
464
+ });
465
+ inputWrapper.addEventListener('drop', (e) => {
466
+ e.preventDefault();
467
+ inputWrapper.classList.remove('dragover');
468
+ const file = e.dataTransfer.files[0];
469
+ if (file) alert(`File dropped: ${file.name} (Processing to be implemented)`);
470
+ });
471
+
472
+ // Suggestion interactions
473
+ document.querySelectorAll('.suggests__item').forEach(item => {
474
+ item.addEventListener('click', () => {
475
+ inputField.value = item.querySelector('.suggests__item-text').textContent;
476
+ suggests.classList.add('hidden');
477
+ welcomeText.classList.add('hidden');
478
+ inputField.focus();
479
+ });
480
+ item.addEventListener('dblclick', () => {
481
+ alert(`Pinned suggestion: ${item.querySelector('.suggests__item-text').textContent} (Placeholder)`);
482
+ });
483
+ });
484
+
485
+ // Scroll handling
486
+ chatBar.addEventListener('scroll', () => {
487
+ const isScrolledUp = chatBar.scrollTop < chatBar.scrollHeight - chatBar.clientHeight - 100;
488
+ backToLatest.classList.toggle('visible', isScrolledUp);
489
+ if (chatBar.scrollTop < 100 && messageHistory.length > 10) {
490
+ loadMoreMessages();
491
+ }
492
+ });
493
+
494
+ backToLatest.addEventListener('click', () => {
495
+ chatBar.scrollTop = chatBar.scrollHeight;
496
+ });
497
+
498
+ // Placeholder for loading more messages
499
+ function loadMoreMessages() {
500
+ console.log('Loading more messages (placeholder)');
501
+ }
502
+
503
+ // Send message
504
+ function sendMessage(input = inputField.value.trim()) {
505
+ if (!input) {
506
+ addMessage('Oops, please type something to ask!', false, true);
507
+ return;
508
+ }
509
+ if (input.length < 3) {
510
+ addMessage('Your query is too short—try adding more details!', false, true);
511
+ return;
512
+ }
513
+
514
+ sendButton.disabled = true;
515
+ processingDots.classList.add('active');
516
+ addMessage(input, true);
517
+ inputField.value = '';
518
+ if (soundEnabled) document.getElementById('sendSound').play();
519
+
520
+ fetch('/chat', {
521
+ method: 'POST',
522
+ headers: { 'Content-Type': 'application/json' },
523
+ body: JSON.stringify({ message: input })
524
+ })
525
+ .then(res => res.json())
526
+ .then(data => {
527
+ if (data.response) {
528
+ addMessage(data.response);
529
+ suggests.classList.add('hidden');
530
+ if (soundEnabled) document.getElementById('responseSound').play();
531
+ } else {
532
+ addMessage(data.detail || 'Something went wrong! Please try again.', false, true);
533
+ }
534
+ })
535
+ .catch(error => {
536
+ addMessage('Failed to process the query! Please check your connection.', false, true);
537
+ })
538
+ .finally(() => {
539
+ sendButton.disabled = false;
540
+ processingDots.classList.remove('active');
541
+ });
542
+ }
543
+
544
+ sendButton.addEventListener('click', () => sendMessage());
545
+
546
+ // Placeholder button actions
547
+ document.getElementById('deepSearchButton').addEventListener('click', () => {
548
+ alert('Initiating DeepSearch... (Functionality to be implemented)');
549
+ });
550
+ document.getElementById('thinkButton').addEventListener('click', () => {
551
+ alert('Activating Think mode... (Functionality to be implemented)');
552
+ });
553
+ document.getElementById('fileInput').addEventListener('change', (e) => {
554
+ const file = e.target.files[0];
555
+ if (file) alert(`File selected: ${file.name} (Processing to be implemented)`);
556
+ });
557
+
558
+ // Responsive adjustments
559
+ window.addEventListener('resize', () => {
560
+ const width = window.innerWidth;
561
+ chatBar.style.maxHeight = width < 768 ? 'calc(100vh - 200px)' : 'calc(100vh - 180px)';
562
+ });
563
+
564
+ // Starry background effects
565
+ document.addEventListener('mousemove', (e) => {
566
+ let x = e.clientX / window.innerWidth;
567
+ let y = e.clientY / window.innerHeight;
568
+ document.querySelector('.stars').style.transform = `translate(${x * 50}px, ${y * 50}px)`;
569
+ });
570
+ window.addEventListener('scroll', () => {
571
+ const scrollPosition = window.scrollY;
572
+ const stars = document.querySelector('.stars');
573
+ stars.style.animationDuration = `${100 - scrollPosition / 10}s`;
574
+ });
575
+
576
+ // Accessibility: Focus management
577
+ document.querySelectorAll('.prompt__form-button, .suggests__item').forEach(el => {
578
+ el.addEventListener('keydown', (e) => {
579
+ if (e.key === 'Enter' || e.key === ' ') {
580
+ e.preventDefault();
581
+ el.click();
582
+ }
583
+ });
584
+ });
585
  </script>
586
  </body>
587
  </html>