Vedika66 commited on
Commit
33737bb
·
verified ·
1 Parent(s): 8a59918

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +80 -103
index.html CHANGED
@@ -37,8 +37,7 @@
37
  --brand-accent: #3b82f6;
38
  --brand-success: #10b981;
39
  --brand-danger: #ef4444;
40
- --brand-warning: #f59e0b;
41
- --brand-weather: #0ea5e9; /* Sky blue for weather */
42
 
43
  --font-ui: 'Inter', sans-serif;
44
  --font-code: 'JetBrains Mono', monospace;
@@ -121,13 +120,11 @@
121
  /* --- CHAT CONTAINER --- */
122
  .chat-container { flex: 1; overflow-y: auto; padding: 60px 20px 140px; display: flex; flex-direction: column; align-items: center; scroll-behavior: smooth; }
123
 
124
- /* Welcome Center Layout */
125
  .welcome-center { margin: auto; text-align: center; display: flex; flex-direction: column; align-items: center; animation: fadeIn 0.4s ease; width: 100%; justify-content: center; flex: 1; }
126
  .welcome-center img { width: 68px; height: 68px; border-radius: 18px; margin-bottom: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); object-fit: cover; }
127
  .welcome-center h1 { font-size: 24px; font-weight: 500; color: var(--text-primary); margin-bottom: 6px; letter-spacing: -0.5px; }
128
  .welcome-center p { font-size: 14px; color: var(--text-secondary); }
129
 
130
- /* Chat Messages Wrapper */
131
  #chatMessages { width: 100%; display: flex; flex-direction: column; align-items: center; }
132
 
133
  .message-wrapper { width: 100%; max-width: 780px; margin-bottom: 32px; display: flex; flex-direction: column; }
@@ -163,7 +160,7 @@
163
  .qwen-think-box[open] summary svg.arrow { transform: rotate(90deg); }
164
  .qwen-think-content { padding: 14px; border-top: 1px solid var(--border-light); font-size: 13.5px; color: var(--text-secondary); font-style: italic; background: #fff; line-height: 1.6; }
165
 
166
- /* --- ✨ SEARCH & LOCATION ANIMATIONS --- */
167
  .action-status {
168
  display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px;
169
  background: var(--bg-sidebar); border-radius: 12px; font-size: 13px; font-weight: 500;
@@ -174,7 +171,7 @@
174
  .flicker-text { animation: pulseOpacity 1.2s infinite alternate; }
175
 
176
  @keyframes pulseOpacity {
177
- 0% { opacity: 0.4; }
178
  100% { opacity: 1; }
179
  }
180
 
@@ -226,8 +223,7 @@
226
  .tool-btn:hover { background: var(--bg-sidebar); color: var(--text-primary); }
227
 
228
  /* 🎨 DYNAMIC COLORS */
229
- .tool-btn.active-gps { color: var(--brand-accent); background: #eff6ff; }
230
- .tool-btn.active-weather { color: var(--brand-weather); background: #e0f2fe; }
231
 
232
  .tool-btn.active-think-low { color: var(--brand-danger); background: #fee2e2; }
233
  .tool-btn.active-think-medium { color: var(--brand-warning); background: #fef3c7; }
@@ -319,10 +315,7 @@
319
  <svg style="width:14px; height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
320
  New Workspace
321
  </button>
322
-
323
- <div class="sidebar-history" id="chatHistory">
324
- <!-- Threads will load here dynamically -->
325
- </div>
326
 
327
  <div class="sidebar-footer">
328
  <div class="user-avatar" id="uAv">G</div>
@@ -338,20 +331,19 @@
338
 
339
  <main class="main-area">
340
  <div class="chat-container" id="chatContainer">
341
- <!-- 🌟 FIXED WELCOME SCREEN LAYOUT -->
342
  <div class="welcome-center" id="welcomeScreen">
343
  <img src="https://i.ibb.co/MyYStcGP/TIRANGA-20260613-131924-0000.png" alt="CODE VED Logo">
344
  <h1>CODE VED</h1>
345
  <p id="welcomeGreeting">Engineered by Divy Patel</p>
346
  </div>
347
 
348
- <div id="chatMessages" style="width: 100%; display: flex; flex-direction: column; align-items: center;">
349
- <!-- Chat bubbles load here so they don't overwrite the welcome screen div -->
350
- </div>
351
  </div>
352
 
353
  <div class="input-dock" id="inputDock">
354
- <!-- Status Toast -->
355
  <div class="loc-toast" id="locStatus"></div>
356
 
357
  <div class="input-container">
@@ -379,14 +371,14 @@
379
  <input type="file" id="docUpload" class="hidden-input" accept=".pdf,.txt,.docx,.html,.js,.py,.css,.cpp,.c,.json,.md" onchange="FileSys.process(this, 'document')">
380
  </div>
381
 
382
- <!-- Location (GPS) -->
383
- <button class="tool-btn" id="btnLoc" onclick="LocationManager.toggle()" title="Find Location">
384
- <svg style="width:18px;height:18px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="3"></circle></svg>
385
  </button>
386
 
387
- <!-- 🌤️ LIVE WEATHER (No Backend Changes Needed!) -->
388
- <button class="tool-btn" id="btnWeather" onclick="WeatherManager.toggle()" title="Live Weather">
389
- <svg style="width:18px;height:18px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path></svg>
390
  </button>
391
 
392
  <!-- Thinking Effort Menu -->
@@ -413,7 +405,7 @@
413
  </div>
414
  </main>
415
 
416
- <!-- WORKSPACE PANEL -->
417
  <aside class="workspace-panel" id="workspacePanel">
418
  <div class="ws-header">
419
  <div class="ws-tabs">
@@ -491,9 +483,9 @@
491
  currentWs: null,
492
  abortController: null,
493
  location: null,
 
494
  thinkingMode: false,
495
  thinkingEffort: "medium",
496
- weatherContext: null, // 🌤️ Added for Frontend Weather Injection
497
  lastUserMessage: null,
498
  currentThreadId: null,
499
  currentTitle: null
@@ -533,7 +525,7 @@
533
  document.getElementById('btnLogout').style.display = 'flex';
534
  document.getElementById('welcomeGreeting').innerText = `Ready, ${dispName}.`;
535
  },
536
- // 🌟 Centralized Welcome Screen Logic
537
  updateWelcomeScreen: () => {
538
  const ws = document.getElementById('welcomeScreen');
539
  if(State.history.length === 0) {
@@ -606,11 +598,8 @@
606
  else if (action === 'login_send_otp') Auth.switchPhase('loginPhase1', 'loginPhase2');
607
  else {
608
  localStorage.setItem('codeved_user', payload.email);
609
- if(data.user && data.user.name) {
610
- localStorage.setItem('codeved_name', data.user.name);
611
- } else if (payload.name) {
612
- localStorage.setItem('codeved_name', payload.name);
613
- }
614
  location.reload();
615
  }
616
  } else { UI.showAuthMsg(data.message); }
@@ -656,21 +645,19 @@
656
  if(!State.user || State.isProcessing) return;
657
  State.currentThreadId = threadId;
658
 
659
- // Clear current messages, keep welcome screen div
660
- document.getElementById('chatMessages').innerHTML = '';
661
- UI.updateWelcomeScreen();
662
 
663
  try {
664
  const res = await fetch(Config.GAS_URL, { method: 'POST', body: JSON.stringify({action: "get_chat", email: State.user, threadId: threadId})});
665
  const data = await res.json();
666
  if(data.status === 'success') {
667
  State.history = JSON.parse(data.historyJSON || "[]");
668
-
669
- UI.updateWelcomeScreen(); // Hide it since history has items
670
 
671
  State.history.forEach(msg => {
672
  if(msg.role === 'user') {
673
  let dispText = msg.content;
 
674
  if(dispText.includes('---END DATA---')) dispText = dispText.split('User: ')[1] || '[Attached File]';
675
  Chat.renderUser(dispText);
676
  } else {
@@ -690,9 +677,8 @@
690
  State.currentTitle = null;
691
  State.history = [];
692
 
693
- // Clean the chat area perfectly
694
  document.getElementById('chatMessages').innerHTML = '';
695
- UI.updateWelcomeScreen(); // Shows welcome screen since history is empty!
696
 
697
  HistoryManager.syncAllChats();
698
  if(window.innerWidth <= 900) UI.toggleSidebar();
@@ -703,6 +689,7 @@
703
  State.currentThreadId = "thr_" + Date.now();
704
  const firstUser = State.history.find(m => m.role === 'user');
705
  let rawText = firstUser ? firstUser.content : "New Workspace";
 
706
  if(rawText.includes('---END DATA---')) rawText = rawText.split('User: ')[1] || "Document Analysis";
707
  State.currentTitle = rawText.substring(0, 25) + (rawText.length > 25 ? '...' : '');
708
  }
@@ -731,14 +718,15 @@
731
  }
732
  };
733
 
734
- // --- 4. GPS, WEATHER & THINKING MANAGERS ---
735
- const LocationManager = {
736
  toggle: () => {
737
- const btn = document.getElementById('btnLoc');
738
  const status = document.getElementById('locStatus');
739
- if(State.location) {
740
  State.location = null;
741
- btn.classList.remove('active-gps');
 
742
  status.style.display = 'none';
743
  } else {
744
  if(navigator.geolocation) {
@@ -746,65 +734,33 @@
746
  status.style.display = 'flex';
747
  status.innerHTML = `<svg style="width:14px;height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="3"></circle></svg> <span class="flicker-text">Finding your exact location...</span>`;
748
 
749
- navigator.geolocation.getCurrentPosition(
750
- pos => {
751
- State.location = { lat: pos.coords.latitude, lng: pos.coords.longitude };
752
- btn.style.color = '';
753
- btn.classList.add('active-gps');
754
- status.innerHTML = `<span style="color:var(--brand-success);">Location found & attached.</span>`;
755
- setTimeout(() => status.style.display = 'none', 3000);
756
- },
757
- err => {
758
- btn.style.color = '';
759
- status.innerHTML = `<span style="color:var(--brand-danger);">Location access denied.</span>`;
760
- setTimeout(() => status.style.display = 'none', 3000);
761
- }
762
- );
763
- } else { alert("GPS not supported."); }
764
- }
765
- }
766
- };
767
-
768
- // 🌤️ CLIENT-SIDE WEATHER MANAGER (No Backend Reconstruction Needed!)
769
- const WeatherManager = {
770
- toggle: async () => {
771
- const btn = document.getElementById('btnWeather');
772
- const status = document.getElementById('locStatus');
773
- if(State.weatherContext) {
774
- State.weatherContext = null;
775
- btn.classList.remove('active-weather');
776
- status.style.display = 'none';
777
- } else {
778
- if(navigator.geolocation) {
779
- btn.style.color = 'var(--brand-accent)';
780
- status.style.display = 'flex';
781
- status.innerHTML = `<span class="flicker-text">Fetching real-time weather...</span>`;
782
-
783
- navigator.geolocation.getCurrentPosition(async pos => {
784
  try {
785
- const lat = pos.coords.latitude;
786
- const lon = pos.coords.longitude;
787
- // Using free open-meteo API (no key needed)
788
- const res = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${lat}&longitude=${lon}&current_weather=true`);
789
  const data = await res.json();
790
  const w = data.current_weather;
 
791
 
792
- State.weatherContext = `Local Weather Status: ${w.temperature}°C, Wind Speed: ${w.windspeed} km/h.`;
793
  btn.style.color = '';
794
- btn.classList.add('active-weather');
795
- status.innerHTML = `<span style="color:var(--brand-success);">Live weather attached!</span>`;
796
  setTimeout(() => status.style.display = 'none', 3000);
797
- } catch(e) {
798
- btn.style.color = '';
799
- status.innerHTML = `<span style="color:var(--brand-danger);">Weather fetch failed.</span>`;
 
800
  setTimeout(() => status.style.display = 'none', 3000);
801
  }
802
- }, err => {
803
- btn.style.color = '';
804
- status.innerHTML = `<span style="color:var(--brand-danger);">Please allow GPS for weather access.</span>`;
805
  setTimeout(() => status.style.display = 'none', 3000);
806
  });
807
- } else { alert("Geolocation not supported."); }
808
  }
809
  }
810
  };
@@ -830,7 +786,7 @@
830
  }
831
  };
832
 
833
- // --- 5. FILE HANDLING ---
834
  const FileSys = {
835
  process: async (input, type) => {
836
  document.getElementById('attachMenu').classList.remove('active');
@@ -847,7 +803,25 @@
847
  r.onload = (e) => { State.attachment = { type: 'text', data: e.target.result, name: file.name }; }; r.readAsText(file);
848
  }
849
  input.value = '';
850
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
851
  };
852
 
853
  // --- 6. WORKSPACE ---
@@ -917,16 +891,16 @@
917
  };
918
  marked.use({ renderer: MDRenderer });
919
 
920
- // --- 7. CHAT ENGINE ---
921
  const Chat = {
922
  renderUser: (txt, attachUI = '') => {
923
- const c = document.getElementById('chatMessages'); // Appending to chatMessages now
924
  const w = document.createElement('div'); w.className = 'message-wrapper';
925
  w.innerHTML = `<div class="user-message">${attachUI}${txt ? UI.escape(txt) : ''}</div>`;
926
  c.appendChild(w); UI.scrollToBottom();
927
  },
928
  renderBot: (msgId) => {
929
- const c = document.getElementById('chatMessages'); // Appending to chatMessages now
930
  const w = document.createElement('div'); w.className = 'message-wrapper';
931
 
932
  const copyIcon = `<svg style="width:14px;height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
@@ -1038,7 +1012,6 @@
1038
  State.lastUserMessage = text;
1039
  input.value = ''; input.style.height = 'auto';
1040
 
1041
- // Hide Welcome Screen on first chat
1042
  UI.updateWelcomeScreen();
1043
 
1044
  const searchTriggers = ["search", "latest", "news", "near", "restaurant", "shop", "distance", "time", "आसपास", "दूरी", "दुकान"];
@@ -1058,14 +1031,16 @@
1058
  }
1059
  }
1060
 
1061
- // 🌤️ Inject Weather Context into Backend Prompt
 
1062
  if(State.weatherContext) {
1063
- payloadStr += `\n\n[SYSTEM REAL-TIME WEATHER: ${State.weatherContext}]`;
1064
  }
1065
 
1066
  if(!isRetry) {
 
1067
  Chat.renderUser(text, attachUI);
1068
- State.history.push({ role: 'user', content: payloadStr });
1069
  }
1070
 
1071
  FileSys.discard();
@@ -1079,7 +1054,7 @@
1079
  const res = await fetch(Config.API_ENDPOINT, {
1080
  method: 'POST', headers: {'Content-Type': 'application/json'},
1081
  body: JSON.stringify({
1082
- message: payloadStr,
1083
  attachments: mediaArray,
1084
  is_search: isSearching,
1085
  location: State.location,
@@ -1111,7 +1086,9 @@
1111
  if(json.choices && json.choices[0].delta.content) fullText += json.choices[0].delta.content;
1112
  Chat.parseAndRender(fullText, isSearching, true, botObj.contentDiv);
1113
  UI.scrollToBottom();
1114
- } catch(e){}
 
 
1115
  }
1116
  }
1117
  }
 
37
  --brand-accent: #3b82f6;
38
  --brand-success: #10b981;
39
  --brand-danger: #ef4444;
40
+ --brand-warning: #eab308; /* Yellow */
 
41
 
42
  --font-ui: 'Inter', sans-serif;
43
  --font-code: 'JetBrains Mono', monospace;
 
120
  /* --- CHAT CONTAINER --- */
121
  .chat-container { flex: 1; overflow-y: auto; padding: 60px 20px 140px; display: flex; flex-direction: column; align-items: center; scroll-behavior: smooth; }
122
 
 
123
  .welcome-center { margin: auto; text-align: center; display: flex; flex-direction: column; align-items: center; animation: fadeIn 0.4s ease; width: 100%; justify-content: center; flex: 1; }
124
  .welcome-center img { width: 68px; height: 68px; border-radius: 18px; margin-bottom: 20px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); object-fit: cover; }
125
  .welcome-center h1 { font-size: 24px; font-weight: 500; color: var(--text-primary); margin-bottom: 6px; letter-spacing: -0.5px; }
126
  .welcome-center p { font-size: 14px; color: var(--text-secondary); }
127
 
 
128
  #chatMessages { width: 100%; display: flex; flex-direction: column; align-items: center; }
129
 
130
  .message-wrapper { width: 100%; max-width: 780px; margin-bottom: 32px; display: flex; flex-direction: column; }
 
160
  .qwen-think-box[open] summary svg.arrow { transform: rotate(90deg); }
161
  .qwen-think-content { padding: 14px; border-top: 1px solid var(--border-light); font-size: 13.5px; color: var(--text-secondary); font-style: italic; background: #fff; line-height: 1.6; }
162
 
163
+ /* --- ✨ SEARCH & LOCATION ANIMATIONS (NO SPINNING, ONLY FLICKER) --- */
164
  .action-status {
165
  display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px;
166
  background: var(--bg-sidebar); border-radius: 12px; font-size: 13px; font-weight: 500;
 
171
  .flicker-text { animation: pulseOpacity 1.2s infinite alternate; }
172
 
173
  @keyframes pulseOpacity {
174
+ 0% { opacity: 0.3; }
175
  100% { opacity: 1; }
176
  }
177
 
 
223
  .tool-btn:hover { background: var(--bg-sidebar); color: var(--text-primary); }
224
 
225
  /* 🎨 DYNAMIC COLORS */
226
+ .tool-btn.active-env { color: var(--brand-accent); background: #eff6ff; }
 
227
 
228
  .tool-btn.active-think-low { color: var(--brand-danger); background: #fee2e2; }
229
  .tool-btn.active-think-medium { color: var(--brand-warning); background: #fef3c7; }
 
315
  <svg style="width:14px; height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
316
  New Workspace
317
  </button>
318
+ <div class="sidebar-history" id="chatHistory"></div>
 
 
 
319
 
320
  <div class="sidebar-footer">
321
  <div class="user-avatar" id="uAv">G</div>
 
331
 
332
  <main class="main-area">
333
  <div class="chat-container" id="chatContainer">
334
+ <!-- 🌟 STATIC WELCOME SCREEN -->
335
  <div class="welcome-center" id="welcomeScreen">
336
  <img src="https://i.ibb.co/MyYStcGP/TIRANGA-20260613-131924-0000.png" alt="CODE VED Logo">
337
  <h1>CODE VED</h1>
338
  <p id="welcomeGreeting">Engineered by Divy Patel</p>
339
  </div>
340
 
341
+ <!-- 💬 ALL MESSAGES GO HERE -->
342
+ <div id="chatMessages"></div>
 
343
  </div>
344
 
345
  <div class="input-dock" id="inputDock">
346
+ <!-- 🌍 Environment Status Toast -->
347
  <div class="loc-toast" id="locStatus"></div>
348
 
349
  <div class="input-container">
 
371
  <input type="file" id="docUpload" class="hidden-input" accept=".pdf,.txt,.docx,.html,.js,.py,.css,.cpp,.c,.json,.md" onchange="FileSys.process(this, 'document')">
372
  </div>
373
 
374
+ <!-- Voice Typing -->
375
+ <button class="tool-btn" id="btnStt" onclick="Speech.toggle()" title="Voice Typing">
376
+ <svg style="width:18px;height:18px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" y1="19" x2="12" y2="23"></line><line x1="8" y1="23" x2="16" y2="23"></line></svg>
377
  </button>
378
 
379
+ <!-- 🌍 UNIFIED ENVIRONMENT (Location + Weather) -->
380
+ <button class="tool-btn" id="btnEnv" onclick="EnvironmentManager.toggle()" title="Environment (Location & Weather)">
381
+ <svg style="width:18px;height:18px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg>
382
  </button>
383
 
384
  <!-- Thinking Effort Menu -->
 
405
  </div>
406
  </main>
407
 
408
+ <!-- WORKSPACE PANEL (RESTORED & FUNCTIONAL) -->
409
  <aside class="workspace-panel" id="workspacePanel">
410
  <div class="ws-header">
411
  <div class="ws-tabs">
 
483
  currentWs: null,
484
  abortController: null,
485
  location: null,
486
+ weatherContext: null, // Unified Environment Context
487
  thinkingMode: false,
488
  thinkingEffort: "medium",
 
489
  lastUserMessage: null,
490
  currentThreadId: null,
491
  currentTitle: null
 
525
  document.getElementById('btnLogout').style.display = 'flex';
526
  document.getElementById('welcomeGreeting').innerText = `Ready, ${dispName}.`;
527
  },
528
+ // 🌟 Permanent Welcome Screen Fix
529
  updateWelcomeScreen: () => {
530
  const ws = document.getElementById('welcomeScreen');
531
  if(State.history.length === 0) {
 
598
  else if (action === 'login_send_otp') Auth.switchPhase('loginPhase1', 'loginPhase2');
599
  else {
600
  localStorage.setItem('codeved_user', payload.email);
601
+ if(data.user && data.user.name) localStorage.setItem('codeved_name', data.user.name);
602
+ else if (payload.name) localStorage.setItem('codeved_name', payload.name);
 
 
 
603
  location.reload();
604
  }
605
  } else { UI.showAuthMsg(data.message); }
 
645
  if(!State.user || State.isProcessing) return;
646
  State.currentThreadId = threadId;
647
 
648
+ document.getElementById('chatMessages').innerHTML = ''; // Clear chat area
 
 
649
 
650
  try {
651
  const res = await fetch(Config.GAS_URL, { method: 'POST', body: JSON.stringify({action: "get_chat", email: State.user, threadId: threadId})});
652
  const data = await res.json();
653
  if(data.status === 'success') {
654
  State.history = JSON.parse(data.historyJSON || "[]");
655
+ UI.updateWelcomeScreen();
 
656
 
657
  State.history.forEach(msg => {
658
  if(msg.role === 'user') {
659
  let dispText = msg.content;
660
+ if(dispText.includes('[SYSTEM REAL-TIME WEATHER:')) dispText = dispText.split('\n\n[SYSTEM REAL-TIME WEATHER:')[0];
661
  if(dispText.includes('---END DATA---')) dispText = dispText.split('User: ')[1] || '[Attached File]';
662
  Chat.renderUser(dispText);
663
  } else {
 
677
  State.currentTitle = null;
678
  State.history = [];
679
 
 
680
  document.getElementById('chatMessages').innerHTML = '';
681
+ UI.updateWelcomeScreen();
682
 
683
  HistoryManager.syncAllChats();
684
  if(window.innerWidth <= 900) UI.toggleSidebar();
 
689
  State.currentThreadId = "thr_" + Date.now();
690
  const firstUser = State.history.find(m => m.role === 'user');
691
  let rawText = firstUser ? firstUser.content : "New Workspace";
692
+ if(rawText.includes('[SYSTEM REAL-TIME WEATHER:')) rawText = rawText.split('\n\n[SYSTEM REAL-TIME WEATHER:')[0];
693
  if(rawText.includes('---END DATA---')) rawText = rawText.split('User: ')[1] || "Document Analysis";
694
  State.currentTitle = rawText.substring(0, 25) + (rawText.length > 25 ? '...' : '');
695
  }
 
718
  }
719
  };
720
 
721
+ // --- 4. 🌍 UNIFIED ENVIRONMENT MANAGER (GPS + WEATHER) ---
722
+ const EnvironmentManager = {
723
  toggle: () => {
724
+ const btn = document.getElementById('btnEnv');
725
  const status = document.getElementById('locStatus');
726
+ if(State.location || State.weatherContext) {
727
  State.location = null;
728
+ State.weatherContext = null;
729
+ btn.classList.remove('active-env');
730
  status.style.display = 'none';
731
  } else {
732
  if(navigator.geolocation) {
 
734
  status.style.display = 'flex';
735
  status.innerHTML = `<svg style="width:14px;height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="3"></circle></svg> <span class="flicker-text">Finding your exact location...</span>`;
736
 
737
+ navigator.geolocation.getCurrentPosition(async pos => {
738
+ State.location = { lat: pos.coords.latitude, lng: pos.coords.longitude };
739
+ status.innerHTML = `<svg style="width:14px;height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"></path></svg> <span class="flicker-text">Fetching real-time weather...</span>`;
740
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
741
  try {
742
+ // Direct API call for Live Weather!
743
+ const res = await fetch(`https://api.open-meteo.com/v1/forecast?latitude=${State.location.lat}&longitude=${State.location.lng}&current_weather=true`);
 
 
744
  const data = await res.json();
745
  const w = data.current_weather;
746
+ State.weatherContext = `Temperature: ${w.temperature}°C, Wind Speed: ${w.windspeed} km/h`;
747
 
 
748
  btn.style.color = '';
749
+ btn.classList.add('active-env');
750
+ status.innerHTML = `<span style="color:var(--brand-success);">Location & Weather active!</span>`;
751
  setTimeout(() => status.style.display = 'none', 3000);
752
+ } catch (e) {
753
+ btn.style.color = '';
754
+ btn.classList.add('active-env');
755
+ status.innerHTML = `<span style="color:var(--brand-warning);">Location found, weather failed.</span>`;
756
  setTimeout(() => status.style.display = 'none', 3000);
757
  }
758
+ }, err => {
759
+ btn.style.color = '';
760
+ status.innerHTML = `<span style="color:var(--brand-danger);">Location access denied.</span>`;
761
  setTimeout(() => status.style.display = 'none', 3000);
762
  });
763
+ } else { alert("GPS not supported."); }
764
  }
765
  }
766
  };
 
786
  }
787
  };
788
 
789
+ // --- 5. FILE HANDLING & VOICE ---
790
  const FileSys = {
791
  process: async (input, type) => {
792
  document.getElementById('attachMenu').classList.remove('active');
 
803
  r.onload = (e) => { State.attachment = { type: 'text', data: e.target.result, name: file.name }; }; r.readAsText(file);
804
  }
805
  input.value = '';
806
+ },
807
+ discard: () => { State.attachment = null; document.getElementById('filePreviewBar').classList.remove('active'); }
808
+ };
809
+
810
+ const Speech = {
811
+ rec: null, isRec: false,
812
+ init: () => {
813
+ const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
814
+ if (!SR) return alert("Speech Recognition not supported.");
815
+ Speech.rec = new SR(); Speech.rec.continuous = false; Speech.rec.interimResults = true; Speech.rec.lang = 'en-US';
816
+ Speech.rec.onstart = () => { Speech.isRec = true; document.getElementById('btnStt').classList.add('recording'); };
817
+ Speech.rec.onresult = (e) => {
818
+ let trans = ''; for (let i = e.resultIndex; i < e.results.length; ++i) { if (e.results[i].isFinal) trans += e.results[i][0].transcript; }
819
+ if (trans) { const input = document.getElementById('mainInput'); input.value += (input.value ? ' ' : '') + trans; UI.autoGrow(input); }
820
+ };
821
+ Speech.rec.onerror = () => Speech.stop(); Speech.rec.onend = () => Speech.stop();
822
+ },
823
+ toggle: () => { if (!Speech.rec) Speech.init(); if (Speech.isRec) Speech.stop(); else { try { Speech.rec.start(); } catch(e) {} } },
824
+ stop: () => { if(Speech.rec) Speech.rec.stop(); Speech.isRec = false; document.getElementById('btnStt').classList.remove('recording'); }
825
  };
826
 
827
  // --- 6. WORKSPACE ---
 
891
  };
892
  marked.use({ renderer: MDRenderer });
893
 
894
+ // --- 7. CHAT ENGINE (ROCK SOLID) ---
895
  const Chat = {
896
  renderUser: (txt, attachUI = '') => {
897
+ const c = document.getElementById('chatMessages'); // Hardbound rendering
898
  const w = document.createElement('div'); w.className = 'message-wrapper';
899
  w.innerHTML = `<div class="user-message">${attachUI}${txt ? UI.escape(txt) : ''}</div>`;
900
  c.appendChild(w); UI.scrollToBottom();
901
  },
902
  renderBot: (msgId) => {
903
+ const c = document.getElementById('chatMessages');
904
  const w = document.createElement('div'); w.className = 'message-wrapper';
905
 
906
  const copyIcon = `<svg style="width:14px;height:14px;" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`;
 
1012
  State.lastUserMessage = text;
1013
  input.value = ''; input.style.height = 'auto';
1014
 
 
1015
  UI.updateWelcomeScreen();
1016
 
1017
  const searchTriggers = ["search", "latest", "news", "near", "restaurant", "shop", "distance", "time", "आसपास", "दूरी", "दुकान"];
 
1031
  }
1032
  }
1033
 
1034
+ // 🌤️ Inject Weather Context Safely
1035
+ let systemInjectedPayload = payloadStr;
1036
  if(State.weatherContext) {
1037
+ systemInjectedPayload += `\n\n[SYSTEM REAL-TIME WEATHER: ${State.weatherContext}]`;
1038
  }
1039
 
1040
  if(!isRetry) {
1041
+ // Only show the user's text on screen, NOT the system tags
1042
  Chat.renderUser(text, attachUI);
1043
+ State.history.push({ role: 'user', content: systemInjectedPayload });
1044
  }
1045
 
1046
  FileSys.discard();
 
1054
  const res = await fetch(Config.API_ENDPOINT, {
1055
  method: 'POST', headers: {'Content-Type': 'application/json'},
1056
  body: JSON.stringify({
1057
+ message: systemInjectedPayload,
1058
  attachments: mediaArray,
1059
  is_search: isSearching,
1060
  location: State.location,
 
1086
  if(json.choices && json.choices[0].delta.content) fullText += json.choices[0].delta.content;
1087
  Chat.parseAndRender(fullText, isSearching, true, botObj.contentDiv);
1088
  UI.scrollToBottom();
1089
+ } catch(e){
1090
+ // Safe parsing: Ignore incomplete chunks during stream
1091
+ }
1092
  }
1093
  }
1094
  }