Subhakanta156 commited on
Commit
3a34fab
·
verified ·
1 Parent(s): b3c9dfb

Update fronted/index.html

Browse files
Files changed (1) hide show
  1. frontend/index.html +551 -551
frontend/index.html CHANGED
@@ -1,552 +1,552 @@
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>Odisha Disaster Chatbot</title>
7
-
8
- <!-- Tailwind CDN -->
9
- <script src="https://cdn.tailwindcss.com"></script>
10
-
11
- <!-- Vanta.js for 3D animated background -->
12
- <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
13
- <script src="https://cdn.jsdelivr.net/npm/vanta/dist/vanta.net.min.js"></script>
14
-
15
- <!-- FontAwesome for icons -->
16
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
17
-
18
- <!-- Marked.js for Markdown -->
19
- <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
20
-
21
- <!-- Google Fonts -->
22
- <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
23
-
24
- <style>
25
- * { font-family: 'Poppins', sans-serif; }
26
-
27
- /* Glass morph styles */
28
- .glassmorphism {
29
- backdrop-filter: blur(16px) saturate(180%);
30
- background: rgba(255, 255, 255, 0.15);
31
- border: 1px solid rgba(255, 255, 255, 0.2);
32
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
33
- }
34
-
35
- .dark-mode .glassmorphism {
36
- background: rgba(15, 23, 42, 0.4);
37
- border: 1px solid rgba(255, 255, 255, 0.1);
38
- }
39
-
40
- /* Chat container */
41
- .chat-container {
42
- backdrop-filter: blur(20px) saturate(180%);
43
- background: rgba(255, 255, 255, 0.25);
44
- border: 2px solid rgba(255, 255, 255, 0.3);
45
- box-shadow: 0 12px 48px rgba(76, 175, 80, 0.15);
46
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
47
- }
48
-
49
- .dark-mode .chat-container {
50
- background: rgba(15, 23, 42, 0.5);
51
- border: 2px solid rgba(76, 175, 80, 0.3);
52
- box-shadow: 0 12px 48px rgba(76, 175, 80, 0.25);
53
- }
54
-
55
- .chat-container:hover {
56
- transform: translateY(-5px);
57
- box-shadow: 0 16px 56px rgba(76, 175, 80, 0.3);
58
- }
59
-
60
- /* Chatbox */
61
- .chatbox {
62
- backdrop-filter: blur(12px);
63
- background: rgba(255, 255, 255, 0.1);
64
- border-radius: 16px;
65
- padding: 16px;
66
- overflow-y: auto;
67
- scrollbar-width: thin;
68
- scrollbar-color: rgba(76, 175, 80, 0.5) transparent;
69
- }
70
-
71
- .chatbox::-webkit-scrollbar { width: 6px; }
72
- .chatbox::-webkit-scrollbar-track { background: transparent; }
73
- .chatbox::-webkit-scrollbar-thumb {
74
- background: rgba(76, 175, 80, 0.5);
75
- border-radius: 10px;
76
- transition: all 0.3s;
77
- }
78
- .chatbox::-webkit-scrollbar-thumb:hover { background: rgba(76, 175, 80, 0.8); }
79
-
80
- /* Messages with slide-in animation */
81
- @keyframes slideInLeft {
82
- from { opacity: 0; transform: translateX(-30px); }
83
- to { opacity: 1; transform: translateX(0); }
84
- }
85
-
86
- @keyframes slideInRight {
87
- from { opacity: 0; transform: translateX(30px); }
88
- to { opacity: 1; transform: translateX(0); }
89
- }
90
-
91
- @keyframes messageGlow {
92
- 0%, 100% { box-shadow: 0 0 10px rgba(76, 175, 80, 0.3); }
93
- 50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.6); }
94
- }
95
-
96
- .message {
97
- padding: 12px 16px;
98
- margin: 8px 0;
99
- border-radius: 16px;
100
- max-width: 85%;
101
- word-wrap: break-word;
102
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
103
- position: relative;
104
- overflow: hidden;
105
- }
106
-
107
- .message::before {
108
- content: '';
109
- position: absolute;
110
- top: 0;
111
- left: -100%;
112
- width: 100%;
113
- height: 100%;
114
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
115
- transition: left 0.5s;
116
- }
117
-
118
- .message:hover::before {
119
- left: 100%;
120
- }
121
-
122
- .message.user {
123
- background: linear-gradient(135deg, rgba(76, 175, 80, 0.4), rgba(56, 142, 60, 0.5));
124
- align-self: flex-end;
125
- margin-left: auto;
126
- animation: slideInRight 0.4s ease-out;
127
- border: 1px solid rgba(76, 175, 80, 0.4);
128
- }
129
-
130
- .message.bot {
131
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.15));
132
- align-self: flex-start;
133
- animation: slideInLeft 0.4s ease-out;
134
- border: 1px solid rgba(255, 255, 255, 0.3);
135
- }
136
-
137
- .dark-mode .message.bot {
138
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.08));
139
- }
140
-
141
- .message:hover {
142
- transform: translateY(-2px) scale(1.02);
143
- box-shadow: 0 6px 20px rgba(76, 175, 80, 0.3);
144
- }
145
-
146
- /* Typing indicator */
147
- @keyframes bounce {
148
- 0%, 80%, 100% { transform: translateY(0); }
149
- 40% { transform: translateY(-10px); }
150
- }
151
-
152
- .typing-indicator {
153
- display: none;
154
- padding: 12px 16px;
155
- background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.15));
156
- border-radius: 16px;
157
- max-width: 80px;
158
- animation: slideInLeft 0.4s ease-out;
159
- border: 1px solid rgba(255, 255, 255, 0.3);
160
- }
161
-
162
- .typing-indicator.active { display: flex; gap: 6px; align-items: center; }
163
-
164
- .typing-dot {
165
- width: 8px;
166
- height: 8px;
167
- background: #4caf50;
168
- border-radius: 50%;
169
- animation: bounce 1.4s infinite ease-in-out both;
170
- }
171
-
172
- .typing-dot:nth-child(1) { animation-delay: -0.32s; }
173
- .typing-dot:nth-child(2) { animation-delay: -0.16s; }
174
-
175
- /* Theme colors */
176
- .dark-mode {
177
- background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
178
- color: white;
179
- }
180
-
181
- .light-mode {
182
- background: linear-gradient(135deg, #e0f2f1 0%, #b2dfdb 100%);
183
- color: #111827;
184
- }
185
-
186
- /* Toggle button with glow effect */
187
- @keyframes pulseGlow {
188
- 0%, 100% { box-shadow: 0 0 10px rgba(76, 175, 80, 0.4); }
189
- 50% { box-shadow: 0 0 25px rgba(76, 175, 80, 0.7); }
190
- }
191
-
192
- .toggle-btn {
193
- cursor: pointer;
194
- padding: 10px 20px;
195
- border-radius: 50px;
196
- background: rgba(76, 175, 80, 0.3);
197
- backdrop-filter: blur(12px);
198
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
199
- border: 2px solid rgba(76, 175, 80, 0.4);
200
- font-weight: 500;
201
- }
202
-
203
- .toggle-btn:hover {
204
- background: rgba(76, 175, 80, 0.5);
205
- transform: translateY(-3px) scale(1.05);
206
- animation: pulseGlow 1.5s infinite;
207
- }
208
-
209
- .toggle-btn:active {
210
- transform: translateY(0) scale(0.98);
211
- }
212
-
213
- /* Send button animation */
214
- .send-btn {
215
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
216
- position: relative;
217
- overflow: hidden;
218
- }
219
-
220
- .send-btn::before {
221
- content: '';
222
- position: absolute;
223
- top: 50%;
224
- left: 50%;
225
- width: 0;
226
- height: 0;
227
- border-radius: 50%;
228
- background: rgba(255, 255, 255, 0.3);
229
- transform: translate(-50%, -50%);
230
- transition: width 0.6s, height 0.6s;
231
- }
232
-
233
- .send-btn:hover::before {
234
- width: 300px;
235
- height: 300px;
236
- }
237
-
238
- .send-btn:hover {
239
- transform: translateY(-2px);
240
- box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
241
- }
242
-
243
- .send-btn:active {
244
- transform: translateY(0);
245
- }
246
-
247
- /* Input field with glow focus */
248
- .chat-input {
249
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
250
- }
251
-
252
- .chat-input:focus {
253
- outline: none;
254
- box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.3);
255
- transform: scale(1.01);
256
- }
257
-
258
- /* About section animations */
259
- @keyframes fadeInUp {
260
- from { opacity: 0; transform: translateY(30px); }
261
- to { opacity: 1; transform: translateY(0); }
262
- }
263
-
264
- .about-section {
265
- backdrop-filter: blur(20px) saturate(180%);
266
- background: rgba(255, 255, 255, 0.2);
267
- border: 2px solid rgba(255, 255, 255, 0.3);
268
- animation: fadeInUp 0.8s ease-out 0.3s both;
269
- }
270
-
271
- .dark-mode .about-section {
272
- background: rgba(15, 23, 42, 0.5);
273
- border: 2px solid rgba(76, 175, 80, 0.3);
274
- }
275
-
276
- .profile-img {
277
- transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
278
- border: 3px solid rgba(76, 175, 80, 0.5);
279
- }
280
-
281
- .profile-img:hover {
282
- transform: scale(1.1) rotate(5deg);
283
- box-shadow: 0 12px 40px rgba(76, 175, 80, 0.5);
284
- border-color: #4caf50;
285
- }
286
-
287
- /* Social icons */
288
- .social-icon {
289
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
290
- display: inline-block;
291
- }
292
-
293
- .social-icon:hover {
294
- transform: translateY(-5px) rotate(360deg) scale(1.2);
295
- color: #4caf50;
296
- }
297
-
298
- /* Header title animation */
299
- @keyframes titleGlow {
300
- 0%, 100% { text-shadow: 0 0 10px rgba(76, 175, 80, 0.5); }
301
- 50% { text-shadow: 0 0 20px rgba(76, 175, 80, 0.8), 0 0 30px rgba(76, 175, 80, 0.6); }
302
- }
303
-
304
- .chat-title {
305
- animation: titleGlow 3s infinite ease-in-out;
306
- font-weight: 700;
307
- background: linear-gradient(135deg, #4caf50, #66bb6a);
308
- -webkit-background-clip: text;
309
- -webkit-text-fill-color: transparent;
310
- background-clip: text;
311
- }
312
-
313
- /* Skill badges */
314
- .skill-badge {
315
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
316
- background: rgba(76, 175, 80, 0.2);
317
- backdrop-filter: blur(8px);
318
- border: 1px solid rgba(76, 175, 80, 0.3);
319
- }
320
-
321
- .skill-badge:hover {
322
- background: rgba(76, 175, 80, 0.4);
323
- transform: translateY(-3px) scale(1.05);
324
- box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
325
- }
326
-
327
- /* Loading animation */
328
- @keyframes spin {
329
- from { transform: rotate(0deg); }
330
- to { transform: rotate(360deg); }
331
- }
332
-
333
- .loading-icon {
334
- animation: spin 1s linear infinite;
335
- }
336
- </style>
337
- </head>
338
- <body class="light-mode flex flex-col items-center justify-start min-h-screen p-4 transition-all duration-500">
339
-
340
- <!-- 3D Background -->
341
- <div id="vanta-bg" class="fixed top-0 left-0 w-full h-full -z-10"></div>
342
-
343
- <!-- Header with toggle -->
344
- <div class="w-full max-w-4xl flex justify-between items-center mb-6">
345
- <div class="flex items-center gap-3">
346
- <i class="fas fa-shield-alt text-3xl" style="color: #4caf50;"></i>
347
- <h1 class="text-2xl font-bold">Odisha Disaster Assistant</h1>
348
- </div>
349
- <div class="toggle-btn" onclick="toggleTheme()">
350
- <i class="fas fa-moon" id="theme-icon"></i> <span id="theme-text">Dark Mode</span>
351
- </div>
352
- </div>
353
-
354
- <!-- Chat Container -->
355
- <div class="chat-container flex flex-col w-full max-w-2xl p-6 rounded-2xl mb-8">
356
- <h2 class="chat-title text-3xl font-bold mb-4 text-center">AI Disaster Chatbot</h2>
357
- <p class="text-center mb-4 opacity-80">Get real-time disaster information and emergency assistance</p>
358
-
359
- <div id="chatbox" class="chatbox flex-1 h-96 overflow-y-auto mb-4 flex flex-col">
360
- <div class="message bot">
361
- <strong>🤖 Assistant:</strong> Hello! I'm your Odisha Disaster Assistant. How can I help you stay safe today?
362
- </div>
363
- </div>
364
-
365
- <div class="typing-indicator" id="typingIndicator">
366
- <div class="typing-dot"></div>
367
- <div class="typing-dot"></div>
368
- <div class="typing-dot"></div>
369
- </div>
370
-
371
- <div class="flex gap-2">
372
- <input
373
- type="text"
374
- id="query"
375
- class="chat-input flex-1 p-3 rounded-xl border-none focus:outline-none bg-white bg-opacity-70 dark:bg-gray-800 dark:bg-opacity-70"
376
- placeholder="Ask about disasters, safety measures, emergency contacts..."
377
- >
378
- <button onclick="askBot()" class="send-btn px-6 py-3 rounded-xl bg-green-600 text-white font-semibold hover:bg-green-500 transition relative z-10">
379
- <i class="fas fa-paper-plane mr-2"></i>Send
380
- </button>
381
- </div>
382
- </div>
383
-
384
- <!-- About Section -->
385
- <div class="about-section flex flex-col items-center p-6 max-w-2xl w-full rounded-2xl glassmorphism shadow-lg mb-8">
386
- <img src="https://avatars.githubusercontent.com/u/000000?v=4" class="profile-img w-32 h-32 rounded-full mb-4 shadow-xl" alt="Profile">
387
- <h3 class="text-2xl font-bold mb-2">Subhakanta Rath</h3>
388
- <p class="text-center mb-4 opacity-90 max-w-lg">Aspiring Data Engineer | AI & ML Enthusiast | Full Stack Developer | Building intelligent solutions for disaster management and public safety</p>
389
-
390
- <div class="flex flex-wrap gap-3 mb-4 justify-center">
391
- <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
392
- <i class="fas fa-code mr-1"></i> Python
393
- </span>
394
- <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
395
- <i class="fas fa-robot mr-1"></i> Machine Learning
396
- </span>
397
- <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
398
- <i class="fas fa-database mr-1"></i> Data Engineering
399
- </span>
400
- <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
401
- <i class="fas fa-globe mr-1"></i> Full Stack
402
- </span>
403
- </div>
404
-
405
- <div class="flex space-x-6 mt-2">
406
- <a href="#" class="social-icon text-2xl"><i class="fab fa-github"></i></a>
407
- <a href="#" class="social-icon text-2xl"><i class="fab fa-linkedin"></i></a>
408
- <a href="#" class="social-icon text-2xl"><i class="fab fa-twitter"></i></a>
409
- <a href="#" class="social-icon text-2xl"><i class="fab fa-instagram"></i></a>
410
- </div>
411
- </div>
412
-
413
- <!-- Footer -->
414
- <footer class="w-full text-center text-sm opacity-70 py-4">
415
- <p>© 2025 Subhakanta Rath. All rights reserved. | Built with ❤️ for Odisha</p>
416
- </footer>
417
-
418
- <script>
419
- // Initialize Vanta 3D background
420
- let vantaEffect;
421
- function initVanta() {
422
- if (vantaEffect) vantaEffect.destroy();
423
-
424
- const isDark = document.body.classList.contains('dark-mode');
425
-
426
- vantaEffect = VANTA.NET({
427
- el: "#vanta-bg",
428
- mouseControls: true,
429
- touchControls: true,
430
- gyroControls: false,
431
- minHeight: 200.00,
432
- minWidth: 200.00,
433
- scale: 1.0,
434
- scaleMobile: 1.0,
435
- color: isDark ? 0x4caf50 : 0x66bb6a,
436
- backgroundColor: isDark ? 0x0f172a : 0xe0f2f1,
437
- points: 10.0,
438
- maxDistance: 25.0,
439
- spacing: 15.0
440
- });
441
- }
442
-
443
- // Initialize on load
444
- window.addEventListener('load', initVanta);
445
-
446
- // Chatbot functionality
447
- async function askBot() {
448
- let q = document.getElementById("query");
449
- let query = q.value.trim();
450
- if(!query) return;
451
-
452
- addMessage(query, "user");
453
- q.value = "";
454
-
455
- showTypingIndicator();
456
-
457
- try {
458
- let res = await fetch("/api/chat", {
459
- method: "POST",
460
- headers: {"Content-Type": "application/json"},
461
- body: JSON.stringify({query})
462
- });
463
- let data = await res.json();
464
- hideTypingIndicator();
465
- addMessage(data.answer, "bot");
466
- } catch(e) {
467
- hideTypingIndicator();
468
- // Fallback responses for demo
469
- setTimeout(() => {
470
- const response = generateResponse(query);
471
- addMessage(response, "bot");
472
- }, 1000);
473
- }
474
- }
475
-
476
- function generateResponse(query) {
477
- const q = query.toLowerCase();
478
- if (q.includes('cyclone') || q.includes('storm')) {
479
- return `**🌪️ Cyclone Safety Guidelines:**\n\n✓ Stay indoors away from windows\n✓ Stock emergency supplies (water, food, medicines)\n✓ Keep battery-powered radio for updates\n✓ Follow evacuation orders immediately\n\n📞 **Emergency Helpline:** 1077`;
480
- } else if (q.includes('flood')) {
481
- return `**🌊 Flood Safety Measures:**\n\n✓ Move to higher ground immediately\n✓ Avoid walking/driving through water\n✓ Keep important documents waterproof\n✓ Turn off electricity and gas\n\n📞 **Flood Helpline:** 1070`;
482
- } else if (q.includes('earthquake')) {
483
- return `**⚡ Earthquake Safety:**\n\n✓ DROP, COVER, and HOLD ON\n✓ Stay away from windows and heavy objects\n✓ If outdoors, move to open areas\n✓ Don't use elevators\n\n📞 **Emergency:** 108`;
484
- } else if (q.includes('emergency') || q.includes('contact') || q.includes('help')) {
485
- return `**📞 Emergency Contacts:**\n\n🚨 Police: **100**\n🚒 Fire: **101**\n🚑 Ambulance: **108**\n⚠️ Disaster Helpline: **112**\n🏛️ State Control Room: **1077**\n👩 Women Helpline: **1091**`;
486
- } else {
487
- return `I can help you with:\n\n• Cyclone & storm safety\n• Flood preparedness\n• Earthquake guidelines\n• Emergency contacts\n• Weather alerts\n• Evacuation procedures\n\nWhat would you like to know?`;
488
- }
489
- }
490
-
491
- function addMessage(text, sender) {
492
- let box = document.getElementById("chatbox");
493
- let msg = document.createElement("div");
494
- msg.className = "message " + sender;
495
-
496
- const prefix = sender === 'user' ? '<strong>👤 You:</strong> ' : '<strong>🤖 Assistant:</strong> ';
497
- msg.innerHTML = prefix + marked.parse(text);
498
-
499
- box.appendChild(msg);
500
- box.scrollTop = box.scrollHeight;
501
- }
502
-
503
- function showTypingIndicator() {
504
- document.getElementById('typingIndicator').classList.add('active');
505
- let box = document.getElementById("chatbox");
506
- box.scrollTop = box.scrollHeight;
507
- }
508
-
509
- function hideTypingIndicator() {
510
- document.getElementById('typingIndicator').classList.remove('active');
511
- }
512
-
513
- // Enter key support
514
- document.getElementById("query").addEventListener("keydown", e => {
515
- if(e.key === "Enter") askBot();
516
- });
517
-
518
- // Dark/Light Mode Toggle with animation
519
- function toggleTheme() {
520
- const body = document.body;
521
- const icon = document.getElementById('theme-icon');
522
- const text = document.getElementById('theme-text');
523
-
524
- body.classList.toggle("dark-mode");
525
- body.classList.toggle("light-mode");
526
-
527
- if (body.classList.contains('dark-mode')) {
528
- icon.className = 'fas fa-sun';
529
- text.textContent = 'Light Mode';
530
- } else {
531
- icon.className = 'fas fa-moon';
532
- text.textContent = 'Dark Mode';
533
- }
534
-
535
- // Reinitialize Vanta with new colors
536
- initVanta();
537
- }
538
-
539
- // Add welcome animation
540
- window.addEventListener('load', () => {
541
- document.querySelector('.chat-container').style.opacity = '0';
542
- document.querySelector('.chat-container').style.transform = 'translateY(20px)';
543
-
544
- setTimeout(() => {
545
- document.querySelector('.chat-container').style.transition = 'all 0.6s ease-out';
546
- document.querySelector('.chat-container').style.opacity = '1';
547
- document.querySelector('.chat-container').style.transform = 'translateY(0)';
548
- }, 100);
549
- });
550
- </script>
551
- </body>
552
  </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.0">
6
+ <title>Odisha Disaster Chatbot</title>
7
+
8
+ <!-- Tailwind CDN -->
9
+ <script src="https://cdn.tailwindcss.com"></script>
10
+
11
+ <!-- Vanta.js for 3D animated background -->
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
13
+ <script src="https://cdn.jsdelivr.net/npm/vanta/dist/vanta.net.min.js"></script>
14
+
15
+ <!-- FontAwesome for icons -->
16
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
17
+
18
+ <!-- Marked.js for Markdown -->
19
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
20
+
21
+ <!-- Google Fonts -->
22
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap" rel="stylesheet">
23
+
24
+ <style>
25
+ * { font-family: 'Poppins', sans-serif; }
26
+
27
+ /* Glass morph styles */
28
+ .glassmorphism {
29
+ backdrop-filter: blur(16px) saturate(180%);
30
+ background: rgba(255, 255, 255, 0.15);
31
+ border: 1px solid rgba(255, 255, 255, 0.2);
32
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
33
+ }
34
+
35
+ .dark-mode .glassmorphism {
36
+ background: rgba(15, 23, 42, 0.4);
37
+ border: 1px solid rgba(255, 255, 255, 0.1);
38
+ }
39
+
40
+ /* Chat container */
41
+ .chat-container {
42
+ backdrop-filter: blur(20px) saturate(180%);
43
+ background: rgba(255, 255, 255, 0.25);
44
+ border: 2px solid rgba(255, 255, 255, 0.3);
45
+ box-shadow: 0 12px 48px rgba(76, 175, 80, 0.15);
46
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
47
+ }
48
+
49
+ .dark-mode .chat-container {
50
+ background: rgba(15, 23, 42, 0.5);
51
+ border: 2px solid rgba(76, 175, 80, 0.3);
52
+ box-shadow: 0 12px 48px rgba(76, 175, 80, 0.25);
53
+ }
54
+
55
+ .chat-container:hover {
56
+ transform: translateY(-5px);
57
+ box-shadow: 0 16px 56px rgba(76, 175, 80, 0.3);
58
+ }
59
+
60
+ /* Chatbox */
61
+ .chatbox {
62
+ backdrop-filter: blur(12px);
63
+ background: rgba(255, 255, 255, 0.1);
64
+ border-radius: 16px;
65
+ padding: 16px;
66
+ overflow-y: auto;
67
+ scrollbar-width: thin;
68
+ scrollbar-color: rgba(76, 175, 80, 0.5) transparent;
69
+ }
70
+
71
+ .chatbox::-webkit-scrollbar { width: 6px; }
72
+ .chatbox::-webkit-scrollbar-track { background: transparent; }
73
+ .chatbox::-webkit-scrollbar-thumb {
74
+ background: rgba(76, 175, 80, 0.5);
75
+ border-radius: 10px;
76
+ transition: all 0.3s;
77
+ }
78
+ .chatbox::-webkit-scrollbar-thumb:hover { background: rgba(76, 175, 80, 0.8); }
79
+
80
+ /* Messages with slide-in animation */
81
+ @keyframes slideInLeft {
82
+ from { opacity: 0; transform: translateX(-30px); }
83
+ to { opacity: 1; transform: translateX(0); }
84
+ }
85
+
86
+ @keyframes slideInRight {
87
+ from { opacity: 0; transform: translateX(30px); }
88
+ to { opacity: 1; transform: translateX(0); }
89
+ }
90
+
91
+ @keyframes messageGlow {
92
+ 0%, 100% { box-shadow: 0 0 10px rgba(76, 175, 80, 0.3); }
93
+ 50% { box-shadow: 0 0 20px rgba(76, 175, 80, 0.6); }
94
+ }
95
+
96
+ .message {
97
+ padding: 12px 16px;
98
+ margin: 8px 0;
99
+ border-radius: 16px;
100
+ max-width: 85%;
101
+ word-wrap: break-word;
102
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
103
+ position: relative;
104
+ overflow: hidden;
105
+ }
106
+
107
+ .message::before {
108
+ content: '';
109
+ position: absolute;
110
+ top: 0;
111
+ left: -100%;
112
+ width: 100%;
113
+ height: 100%;
114
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
115
+ transition: left 0.5s;
116
+ }
117
+
118
+ .message:hover::before {
119
+ left: 100%;
120
+ }
121
+
122
+ .message.user {
123
+ background: linear-gradient(135deg, rgba(76, 175, 80, 0.4), rgba(56, 142, 60, 0.5));
124
+ align-self: flex-end;
125
+ margin-left: auto;
126
+ animation: slideInRight 0.4s ease-out;
127
+ border: 1px solid rgba(76, 175, 80, 0.4);
128
+ }
129
+
130
+ .message.bot {
131
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.15));
132
+ align-self: flex-start;
133
+ animation: slideInLeft 0.4s ease-out;
134
+ border: 1px solid rgba(255, 255, 255, 0.3);
135
+ }
136
+
137
+ .dark-mode .message.bot {
138
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.08));
139
+ }
140
+
141
+ .message:hover {
142
+ transform: translateY(-2px) scale(1.02);
143
+ box-shadow: 0 6px 20px rgba(76, 175, 80, 0.3);
144
+ }
145
+
146
+ /* Typing indicator */
147
+ @keyframes bounce {
148
+ 0%, 80%, 100% { transform: translateY(0); }
149
+ 40% { transform: translateY(-10px); }
150
+ }
151
+
152
+ .typing-indicator {
153
+ display: none;
154
+ padding: 12px 16px;
155
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.15));
156
+ border-radius: 16px;
157
+ max-width: 80px;
158
+ animation: slideInLeft 0.4s ease-out;
159
+ border: 1px solid rgba(255, 255, 255, 0.3);
160
+ }
161
+
162
+ .typing-indicator.active { display: flex; gap: 6px; align-items: center; }
163
+
164
+ .typing-dot {
165
+ width: 8px;
166
+ height: 8px;
167
+ background: #4caf50;
168
+ border-radius: 50%;
169
+ animation: bounce 1.4s infinite ease-in-out both;
170
+ }
171
+
172
+ .typing-dot:nth-child(1) { animation-delay: -0.32s; }
173
+ .typing-dot:nth-child(2) { animation-delay: -0.16s; }
174
+
175
+ /* Theme colors */
176
+ .dark-mode {
177
+ background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
178
+ color: white;
179
+ }
180
+
181
+ .light-mode {
182
+ background: linear-gradient(135deg, #e0f2f1 0%, #b2dfdb 100%);
183
+ color: #111827;
184
+ }
185
+
186
+ /* Toggle button with glow effect */
187
+ @keyframes pulseGlow {
188
+ 0%, 100% { box-shadow: 0 0 10px rgba(76, 175, 80, 0.4); }
189
+ 50% { box-shadow: 0 0 25px rgba(76, 175, 80, 0.7); }
190
+ }
191
+
192
+ .toggle-btn {
193
+ cursor: pointer;
194
+ padding: 10px 20px;
195
+ border-radius: 50px;
196
+ background: rgba(76, 175, 80, 0.3);
197
+ backdrop-filter: blur(12px);
198
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
199
+ border: 2px solid rgba(76, 175, 80, 0.4);
200
+ font-weight: 500;
201
+ }
202
+
203
+ .toggle-btn:hover {
204
+ background: rgba(76, 175, 80, 0.5);
205
+ transform: translateY(-3px) scale(1.05);
206
+ animation: pulseGlow 1.5s infinite;
207
+ }
208
+
209
+ .toggle-btn:active {
210
+ transform: translateY(0) scale(0.98);
211
+ }
212
+
213
+ /* Send button animation */
214
+ .send-btn {
215
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
216
+ position: relative;
217
+ overflow: hidden;
218
+ }
219
+
220
+ .send-btn::before {
221
+ content: '';
222
+ position: absolute;
223
+ top: 50%;
224
+ left: 50%;
225
+ width: 0;
226
+ height: 0;
227
+ border-radius: 50%;
228
+ background: rgba(255, 255, 255, 0.3);
229
+ transform: translate(-50%, -50%);
230
+ transition: width 0.6s, height 0.6s;
231
+ }
232
+
233
+ .send-btn:hover::before {
234
+ width: 300px;
235
+ height: 300px;
236
+ }
237
+
238
+ .send-btn:hover {
239
+ transform: translateY(-2px);
240
+ box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
241
+ }
242
+
243
+ .send-btn:active {
244
+ transform: translateY(0);
245
+ }
246
+
247
+ /* Input field with glow focus */
248
+ .chat-input {
249
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
250
+ }
251
+
252
+ .chat-input:focus {
253
+ outline: none;
254
+ box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.3);
255
+ transform: scale(1.01);
256
+ }
257
+
258
+ /* About section animations */
259
+ @keyframes fadeInUp {
260
+ from { opacity: 0; transform: translateY(30px); }
261
+ to { opacity: 1; transform: translateY(0); }
262
+ }
263
+
264
+ .about-section {
265
+ backdrop-filter: blur(20px) saturate(180%);
266
+ background: rgba(255, 255, 255, 0.2);
267
+ border: 2px solid rgba(255, 255, 255, 0.3);
268
+ animation: fadeInUp 0.8s ease-out 0.3s both;
269
+ }
270
+
271
+ .dark-mode .about-section {
272
+ background: rgba(15, 23, 42, 0.5);
273
+ border: 2px solid rgba(76, 175, 80, 0.3);
274
+ }
275
+
276
+ .profile-img {
277
+ transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
278
+ border: 3px solid rgba(76, 175, 80, 0.5);
279
+ }
280
+
281
+ .profile-img:hover {
282
+ transform: scale(1.1) rotate(5deg);
283
+ box-shadow: 0 12px 40px rgba(76, 175, 80, 0.5);
284
+ border-color: #4caf50;
285
+ }
286
+
287
+ /* Social icons */
288
+ .social-icon {
289
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
290
+ display: inline-block;
291
+ }
292
+
293
+ .social-icon:hover {
294
+ transform: translateY(-5px) rotate(360deg) scale(1.2);
295
+ color: #4caf50;
296
+ }
297
+
298
+ /* Header title animation */
299
+ @keyframes titleGlow {
300
+ 0%, 100% { text-shadow: 0 0 10px rgba(76, 175, 80, 0.5); }
301
+ 50% { text-shadow: 0 0 20px rgba(76, 175, 80, 0.8), 0 0 30px rgba(76, 175, 80, 0.6); }
302
+ }
303
+
304
+ .chat-title {
305
+ animation: titleGlow 3s infinite ease-in-out;
306
+ font-weight: 700;
307
+ background: linear-gradient(135deg, #4caf50, #66bb6a);
308
+ -webkit-background-clip: text;
309
+ -webkit-text-fill-color: transparent;
310
+ background-clip: text;
311
+ }
312
+
313
+ /* Skill badges */
314
+ .skill-badge {
315
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
316
+ background: rgba(76, 175, 80, 0.2);
317
+ backdrop-filter: blur(8px);
318
+ border: 1px solid rgba(76, 175, 80, 0.3);
319
+ }
320
+
321
+ .skill-badge:hover {
322
+ background: rgba(76, 175, 80, 0.4);
323
+ transform: translateY(-3px) scale(1.05);
324
+ box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
325
+ }
326
+
327
+ /* Loading animation */
328
+ @keyframes spin {
329
+ from { transform: rotate(0deg); }
330
+ to { transform: rotate(360deg); }
331
+ }
332
+
333
+ .loading-icon {
334
+ animation: spin 1s linear infinite;
335
+ }
336
+ </style>
337
+ </head>
338
+ <body class="light-mode flex flex-col items-center justify-start min-h-screen p-4 transition-all duration-500">
339
+
340
+ <!-- 3D Background -->
341
+ <div id="vanta-bg" class="fixed top-0 left-0 w-full h-full -z-10"></div>
342
+
343
+ <!-- Header with toggle -->
344
+ <div class="w-full max-w-4xl flex justify-between items-center mb-6">
345
+ <div class="flex items-center gap-3">
346
+ <i class="fas fa-shield-alt text-3xl" style="color: #4caf50;"></i>
347
+ <h1 class="text-2xl font-bold">Odisha Disaster Assistant</h1>
348
+ </div>
349
+ <div class="toggle-btn" onclick="toggleTheme()">
350
+ <i class="fas fa-moon" id="theme-icon"></i> <span id="theme-text">Dark Mode</span>
351
+ </div>
352
+ </div>
353
+
354
+ <!-- Chat Container -->
355
+ <div class="chat-container flex flex-col w-full max-w-2xl p-6 rounded-2xl mb-8">
356
+ <h2 class="chat-title text-3xl font-bold mb-4 text-center">AI Disaster Chatbot</h2>
357
+ <p class="text-center mb-4 opacity-80">Get real-time disaster information and emergency assistance</p>
358
+
359
+ <div id="chatbox" class="chatbox flex-1 h-96 overflow-y-auto mb-4 flex flex-col">
360
+ <div class="message bot">
361
+ <strong>🤖 Assistant:</strong> Hello! I'm your Odisha Disaster Assistant. How can I help you stay safe today?
362
+ </div>
363
+ </div>
364
+
365
+ <div class="typing-indicator" id="typingIndicator">
366
+ <div class="typing-dot"></div>
367
+ <div class="typing-dot"></div>
368
+ <div class="typing-dot"></div>
369
+ </div>
370
+
371
+ <div class="flex gap-2">
372
+ <input
373
+ type="text"
374
+ id="query"
375
+ class="chat-input flex-1 p-3 rounded-xl border-none focus:outline-none bg-white bg-opacity-70 dark:bg-gray-800 dark:bg-opacity-70"
376
+ placeholder="Ask about disasters, safety measures, emergency contacts..."
377
+ >
378
+ <button onclick="askBot()" class="send-btn px-6 py-3 rounded-xl bg-green-600 text-white font-semibold hover:bg-green-500 transition relative z-10">
379
+ <i class="fas fa-paper-plane mr-2"></i>Send
380
+ </button>
381
+ </div>
382
+ </div>
383
+
384
+ <!-- About Section -->
385
+ <div class="about-section flex flex-col items-center p-6 max-w-2xl w-full rounded-2xl glassmorphism shadow-lg mb-8">
386
+ <img src="https://avatars.githubusercontent.com/u/000000?v=4" class="profile-img w-32 h-32 rounded-full mb-4 shadow-xl" alt="Profile">
387
+ <h3 class="text-2xl font-bold mb-2">Subhakanta Rath</h3>
388
+ <p class="text-center mb-4 opacity-90 max-w-lg">Aspiring Data Engineer | AI & ML Enthusiast | Full Stack Developer | Building intelligent solutions for disaster management and public safety</p>
389
+
390
+ <div class="flex flex-wrap gap-3 mb-4 justify-center">
391
+ <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
392
+ <i class="fas fa-code mr-1"></i> Python
393
+ </span>
394
+ <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
395
+ <i class="fas fa-robot mr-1"></i> Machine Learning
396
+ </span>
397
+ <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
398
+ <i class="fas fa-database mr-1"></i> Data Engineering
399
+ </span>
400
+ <span class="skill-badge px-4 py-2 rounded-full text-sm font-medium">
401
+ <i class="fas fa-globe mr-1"></i> Full Stack
402
+ </span>
403
+ </div>
404
+
405
+ <div class="flex space-x-6 mt-2">
406
+ <a href="https://github.com/subhakanta156" class="social-icon text-2xl" target="_blank" title="GitHub"><i class="fab fa-github"></i></a>
407
+ <a href="https://www.linkedin.com/in/subhakanta-rath-0b45b0326/" class="social-icon text-2xl" target="_blank" title="linkedin"><i class="fab fa-linkedin"></i></a>
408
+ <a href="#" class="social-icon text-2xl"><i class="fab fa-twitter"></i></a>
409
+ <a href="#" class="social-icon text-2xl"><i class="fab fa-instagram"></i></a>
410
+ </div>
411
+ </div>
412
+
413
+ <!-- Footer -->
414
+ <footer class="w-full text-center text-sm opacity-70 py-4">
415
+ <p>© 2025 Subhakanta Rath. All rights reserved. | Built with ❤️ for Odisha</p>
416
+ </footer>
417
+
418
+ <script>
419
+ // Initialize Vanta 3D background
420
+ let vantaEffect;
421
+ function initVanta() {
422
+ if (vantaEffect) vantaEffect.destroy();
423
+
424
+ const isDark = document.body.classList.contains('dark-mode');
425
+
426
+ vantaEffect = VANTA.NET({
427
+ el: "#vanta-bg",
428
+ mouseControls: true,
429
+ touchControls: true,
430
+ gyroControls: false,
431
+ minHeight: 200.00,
432
+ minWidth: 200.00,
433
+ scale: 1.0,
434
+ scaleMobile: 1.0,
435
+ color: isDark ? 0x4caf50 : 0x66bb6a,
436
+ backgroundColor: isDark ? 0x0f172a : 0xe0f2f1,
437
+ points: 10.0,
438
+ maxDistance: 25.0,
439
+ spacing: 15.0
440
+ });
441
+ }
442
+
443
+ // Initialize on load
444
+ window.addEventListener('load', initVanta);
445
+
446
+ // Chatbot functionality
447
+ async function askBot() {
448
+ let q = document.getElementById("query");
449
+ let query = q.value.trim();
450
+ if(!query) return;
451
+
452
+ addMessage(query, "user");
453
+ q.value = "";
454
+
455
+ showTypingIndicator();
456
+
457
+ try {
458
+ let res = await fetch("/api/chat", {
459
+ method: "POST",
460
+ headers: {"Content-Type": "application/json"},
461
+ body: JSON.stringify({query})
462
+ });
463
+ let data = await res.json();
464
+ hideTypingIndicator();
465
+ addMessage(data.answer, "bot");
466
+ } catch(e) {
467
+ hideTypingIndicator();
468
+ // Fallback responses for demo
469
+ setTimeout(() => {
470
+ const response = generateResponse(query);
471
+ addMessage(response, "bot");
472
+ }, 1000);
473
+ }
474
+ }
475
+
476
+ function generateResponse(query) {
477
+ const q = query.toLowerCase();
478
+ if (q.includes('cyclone') || q.includes('storm')) {
479
+ return `**🌪️ Cyclone Safety Guidelines:**\n\n✓ Stay indoors away from windows\n✓ Stock emergency supplies (water, food, medicines)\n✓ Keep battery-powered radio for updates\n✓ Follow evacuation orders immediately\n\n📞 **Emergency Helpline:** 1077`;
480
+ } else if (q.includes('flood')) {
481
+ return `**🌊 Flood Safety Measures:**\n\n✓ Move to higher ground immediately\n✓ Avoid walking/driving through water\n✓ Keep important documents waterproof\n✓ Turn off electricity and gas\n\n📞 **Flood Helpline:** 1070`;
482
+ } else if (q.includes('earthquake')) {
483
+ return `**⚡ Earthquake Safety:**\n\n✓ DROP, COVER, and HOLD ON\n✓ Stay away from windows and heavy objects\n✓ If outdoors, move to open areas\n✓ Don't use elevators\n\n📞 **Emergency:** 108`;
484
+ } else if (q.includes('emergency') || q.includes('contact') || q.includes('help')) {
485
+ return `**📞 Emergency Contacts:**\n\n🚨 Police: **100**\n🚒 Fire: **101**\n🚑 Ambulance: **108**\n⚠️ Disaster Helpline: **112**\n🏛️ State Control Room: **1077**\n👩 Women Helpline: **1091**`;
486
+ } else {
487
+ return `I can help you with:\n\n• Cyclone & storm safety\n• Flood preparedness\n• Earthquake guidelines\n• Emergency contacts\n• Weather alerts\n• Evacuation procedures\n\nWhat would you like to know?`;
488
+ }
489
+ }
490
+
491
+ function addMessage(text, sender) {
492
+ let box = document.getElementById("chatbox");
493
+ let msg = document.createElement("div");
494
+ msg.className = "message " + sender;
495
+
496
+ const prefix = sender === 'user' ? '<strong>👤 You:</strong> ' : '<strong>🤖 Assistant:</strong> ';
497
+ msg.innerHTML = prefix + marked.parse(text);
498
+
499
+ box.appendChild(msg);
500
+ box.scrollTop = box.scrollHeight;
501
+ }
502
+
503
+ function showTypingIndicator() {
504
+ document.getElementById('typingIndicator').classList.add('active');
505
+ let box = document.getElementById("chatbox");
506
+ box.scrollTop = box.scrollHeight;
507
+ }
508
+
509
+ function hideTypingIndicator() {
510
+ document.getElementById('typingIndicator').classList.remove('active');
511
+ }
512
+
513
+ // Enter key support
514
+ document.getElementById("query").addEventListener("keydown", e => {
515
+ if(e.key === "Enter") askBot();
516
+ });
517
+
518
+ // Dark/Light Mode Toggle with animation
519
+ function toggleTheme() {
520
+ const body = document.body;
521
+ const icon = document.getElementById('theme-icon');
522
+ const text = document.getElementById('theme-text');
523
+
524
+ body.classList.toggle("dark-mode");
525
+ body.classList.toggle("light-mode");
526
+
527
+ if (body.classList.contains('dark-mode')) {
528
+ icon.className = 'fas fa-sun';
529
+ text.textContent = 'Light Mode';
530
+ } else {
531
+ icon.className = 'fas fa-moon';
532
+ text.textContent = 'Dark Mode';
533
+ }
534
+
535
+ // Reinitialize Vanta with new colors
536
+ initVanta();
537
+ }
538
+
539
+ // Add welcome animation
540
+ window.addEventListener('load', () => {
541
+ document.querySelector('.chat-container').style.opacity = '0';
542
+ document.querySelector('.chat-container').style.transform = 'translateY(20px)';
543
+
544
+ setTimeout(() => {
545
+ document.querySelector('.chat-container').style.transition = 'all 0.6s ease-out';
546
+ document.querySelector('.chat-container').style.opacity = '1';
547
+ document.querySelector('.chat-container').style.transform = 'translateY(0)';
548
+ }, 100);
549
+ });
550
+ </script>
551
+ </body>
552
  </html>