Your Name Claude commited on
Commit
58da20a
·
1 Parent(s): 5ed7b69

Add loading screen during AI initialization

Browse files

- Beautiful loading screen with animated avatar and progress bar
- Polls /status endpoint every 2 seconds until initialization complete
- Shows initialization progress and status messages
- Smooth fade-out animation when AI is ready
- Chat interface hidden until Gemini API is fully initialized
- Prevents user frustration from trying to chat before AI is ready

The loading screen includes:
- Floating avatar animation
- Spinning loader
- Animated progress bar
- Real-time status messages
- Gradient purple background matching brand colors

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

Files changed (3) hide show
  1. static/css/style.css +97 -0
  2. static/js/script.js +47 -13
  3. templates/index.html +21 -1
static/css/style.css CHANGED
@@ -395,3 +395,100 @@ body {
395
  .sentiment-angry {
396
  animation: angryPulse 0.5s infinite;
397
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
  .sentiment-angry {
396
  animation: angryPulse 0.5s infinite;
397
  }
398
+
399
+ /* Loading Screen Styles */
400
+ .loading-screen {
401
+ position: fixed;
402
+ top: 0;
403
+ left: 0;
404
+ width: 100%;
405
+ height: 100%;
406
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
407
+ display: flex;
408
+ justify-content: center;
409
+ align-items: center;
410
+ z-index: 9999;
411
+ animation: fadeIn 0.5s ease-in-out;
412
+ }
413
+
414
+ .loading-content {
415
+ text-align: center;
416
+ color: white;
417
+ }
418
+
419
+ .loading-avatar {
420
+ margin-bottom: 30px;
421
+ animation: float 3s ease-in-out infinite;
422
+ }
423
+
424
+ .loading-avatar .avatar {
425
+ width: 120px;
426
+ height: 120px;
427
+ margin: 0 auto;
428
+ }
429
+
430
+ .loading-content h2 {
431
+ font-size: 28px;
432
+ font-weight: 600;
433
+ margin-bottom: 20px;
434
+ }
435
+
436
+ .loading-spinner {
437
+ width: 50px;
438
+ height: 50px;
439
+ margin: 20px auto;
440
+ border: 4px solid rgba(255, 255, 255, 0.3);
441
+ border-top-color: white;
442
+ border-radius: 50%;
443
+ animation: spin 1s linear infinite;
444
+ }
445
+
446
+ #loading-status {
447
+ font-size: 16px;
448
+ opacity: 0.9;
449
+ margin-top: 20px;
450
+ min-height: 24px;
451
+ }
452
+
453
+ .loading-bar {
454
+ width: 300px;
455
+ height: 8px;
456
+ background: rgba(255, 255, 255, 0.2);
457
+ border-radius: 10px;
458
+ margin: 20px auto 0;
459
+ overflow: hidden;
460
+ }
461
+
462
+ .loading-progress {
463
+ height: 100%;
464
+ background: white;
465
+ border-radius: 10px;
466
+ width: 0%;
467
+ transition: width 0.5s ease;
468
+ animation: loadingPulse 1.5s ease-in-out infinite;
469
+ }
470
+
471
+ @keyframes spin {
472
+ to { transform: rotate(360deg); }
473
+ }
474
+
475
+ @keyframes float {
476
+ 0%, 100% { transform: translateY(0px); }
477
+ 50% { transform: translateY(-20px); }
478
+ }
479
+
480
+ @keyframes loadingPulse {
481
+ 0%, 100% { opacity: 1; }
482
+ 50% { opacity: 0.7; }
483
+ }
484
+
485
+ .loading-screen.fade-out {
486
+ animation: fadeOut 0.5s ease-in-out forwards;
487
+ }
488
+
489
+ @keyframes fadeOut {
490
+ to {
491
+ opacity: 0;
492
+ visibility: hidden;
493
+ }
494
+ }
static/js/script.js CHANGED
@@ -179,33 +179,67 @@ document.addEventListener('DOMContentLoaded', function() {
179
  curiosityBar.style.width = `${emotions.curiosity * 100}%`;
180
  }
181
 
182
- // Add initialization status check
 
183
  function checkInitializationStatus() {
184
- const statusContainer = document.getElementById('status-container');
185
-
 
 
 
 
 
 
 
 
 
186
  fetch('/status')
187
  .then(response => response.json())
188
  .then(data => {
189
  if (data.initializing) {
190
  // Still initializing
191
- showStatusMessage('Galatea AI is still initializing. You can start chatting, but responses may be delayed.', false);
192
- setTimeout(checkInitializationStatus, 3000); // Check again in 3 seconds
 
 
193
  } else if (data.is_initialized) {
194
- // Initialization complete
195
- showStatusMessage('Galatea AI is ready!', false);
196
- // Start polling for avatar updates when initialized
197
- startAvatarPolling();
 
 
 
 
 
198
  setTimeout(() => {
199
- statusContainer.style.display = 'none';
200
- }, 3000);
 
 
 
 
 
 
 
 
 
 
 
201
  } else {
202
  // Something wrong with initialization
203
- showStatusMessage('Galatea initialization is taking longer than expected. You can still chat, but with limited functionality.', true);
 
 
 
204
  }
205
  })
206
  .catch(error => {
207
  console.error('Error checking status:', error);
208
- showStatusMessage('Error checking Galatea status', true);
 
 
 
209
  });
210
  }
211
 
 
179
  curiosityBar.style.width = `${emotions.curiosity * 100}%`;
180
  }
181
 
182
+ // Add initialization status check with loading screen
183
+ let initCheckCount = 0;
184
  function checkInitializationStatus() {
185
+ const loadingScreen = document.getElementById('loading-screen');
186
+ const chatContainer = document.getElementById('chat-container');
187
+ const loadingStatus = document.getElementById('loading-status');
188
+ const loadingProgress = document.getElementById('loading-progress');
189
+
190
+ initCheckCount++;
191
+ const progress = Math.min(initCheckCount * 10, 90); // Cap at 90% until actually ready
192
+ if (loadingProgress) {
193
+ loadingProgress.style.width = `${progress}%`;
194
+ }
195
+
196
  fetch('/status')
197
  .then(response => response.json())
198
  .then(data => {
199
  if (data.initializing) {
200
  // Still initializing
201
+ if (loadingStatus) {
202
+ loadingStatus.textContent = 'Initializing AI components...';
203
+ }
204
+ setTimeout(checkInitializationStatus, 2000); // Check again in 2 seconds
205
  } else if (data.is_initialized) {
206
+ // Initialization complete!
207
+ if (loadingProgress) {
208
+ loadingProgress.style.width = '100%';
209
+ }
210
+ if (loadingStatus) {
211
+ loadingStatus.textContent = 'Ready! Welcome to Galatea AI';
212
+ }
213
+
214
+ // Hide loading screen and show chat after a brief delay
215
  setTimeout(() => {
216
+ if (loadingScreen) {
217
+ loadingScreen.classList.add('fade-out');
218
+ setTimeout(() => {
219
+ loadingScreen.style.display = 'none';
220
+ if (chatContainer) {
221
+ chatContainer.style.display = 'flex';
222
+ }
223
+ }, 500);
224
+ }
225
+
226
+ // Start polling for avatar updates when initialized
227
+ startAvatarPolling();
228
+ }, 1000);
229
  } else {
230
  // Something wrong with initialization
231
+ if (loadingStatus) {
232
+ loadingStatus.textContent = 'Initialization taking longer than expected...';
233
+ }
234
+ setTimeout(checkInitializationStatus, 3000);
235
  }
236
  })
237
  .catch(error => {
238
  console.error('Error checking status:', error);
239
+ if (loadingStatus) {
240
+ loadingStatus.textContent = 'Error connecting to server. Retrying...';
241
+ }
242
+ setTimeout(checkInitializationStatus, 3000);
243
  });
244
  }
245
 
templates/index.html CHANGED
@@ -8,7 +8,27 @@
8
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
9
  </head>
10
  <body>
11
- <div class="chat-container">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  <div class="header">
13
  <h1>Galatea AI</h1>
14
  <div class="avatar-container">
 
8
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
9
  </head>
10
  <body>
11
+ <!-- Loading Screen -->
12
+ <div id="loading-screen" class="loading-screen">
13
+ <div class="loading-content">
14
+ <div class="loading-avatar">
15
+ <div class="avatar circle">
16
+ <div class="face">
17
+ <div class="eyes"></div>
18
+ <div class="mouth"></div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+ <h2>Initializing Galatea AI</h2>
23
+ <div class="loading-spinner"></div>
24
+ <p id="loading-status">Waking up and connecting to Gemini...</p>
25
+ <div class="loading-bar">
26
+ <div class="loading-progress" id="loading-progress"></div>
27
+ </div>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="chat-container" id="chat-container" style="display: none;">
32
  <div class="header">
33
  <h1>Galatea AI</h1>
34
  <div class="avatar-container">