Vedika commited on
Commit
24ae125
·
verified ·
1 Parent(s): fbc5947

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +180 -154
index.html CHANGED
@@ -6,15 +6,11 @@
6
  <title>CODE VED | Engineered by Divy Patel</title>
7
  <meta name="description" content="CODE VED - 202 Billion Parameter Enterprise AI System">
8
 
9
- <!-- Premium Fonts: Inter for UI, JetBrains Mono for Code -->
10
  <link rel="preconnect" href="https://fonts.googleapis.com">
11
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
13
 
14
- <!-- Light Theme Syntax Highlighting -->
15
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
16
-
17
- <!-- Required Libraries -->
18
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
19
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
20
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
@@ -36,9 +32,9 @@
36
  --border-focus: #d0d0d0;
37
 
38
  --brand-color: #1a1a1a;
39
- --brand-accent: #0066cc;
40
 
41
- --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
42
  --font-code: 'JetBrains Mono', monospace;
43
 
44
  --radius-sm: 8px;
@@ -48,11 +44,8 @@
48
 
49
  * { box-sizing: border-box; margin: 0; padding: 0; }
50
 
51
- /* BUG FIX: Changed from 100vh to 100dvh for mobile/tablet browser compatibility */
52
  html, body {
53
- height: 100%;
54
- height: 100dvh;
55
- width: 100vw;
56
  font-family: var(--font-ui); background-color: var(--bg-main); color: var(--text-primary);
57
  display: flex; overflow: hidden; -webkit-font-smoothing: antialiased;
58
  }
@@ -76,29 +69,34 @@
76
 
77
  .sidebar-header { padding: 16px; display: flex; align-items: center; justify-content: space-between; }
78
  .btn-new-chat {
79
- display: flex; align-items: center; gap: 8px; width: 100%; padding: 10px 12px;
80
- border-radius: var(--radius-sm); background: var(--bg-main); border: 1px solid var(--border-light);
81
  font-size: 14px; font-weight: 500; transition: 0.2s; box-shadow: 0 1px 2px rgba(0,0,0,0.02);
82
  }
83
- .btn-new-chat:hover { background: var(--bg-hover); }
84
 
85
  .sidebar-history { flex: 1; overflow-y: auto; padding: 10px; }
86
 
87
  .sidebar-footer {
88
  padding: 16px; border-top: 1px solid var(--border-light); display: flex; align-items: center; gap: 12px;
89
- cursor: pointer; transition: background 0.2s;
90
  }
91
- .sidebar-footer:hover { background: var(--bg-hover); }
92
  .user-avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--brand-color); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 600; flex-shrink: 0; }
93
  .user-info-box { flex: 1; overflow: hidden; }
94
  .user-name { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-primary); }
95
  .user-sub { font-size: 11px; font-weight: 500; color: var(--text-tertiary); margin-top: 2px; }
 
 
 
 
 
 
96
 
97
  /* --- MAIN WORKSPACE --- */
98
- /* BUG FIX: Ensures the main area doesn't push the input dock down */
99
  .main-area { flex: 1; display: flex; flex-direction: column; position: relative; background: var(--bg-main); transition: 0.3s; height: 100%; overflow: hidden; }
100
 
101
- .top-bar { padding: 16px 20px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--border-light); background: var(--bg-main); z-index: 10; flex-shrink: 0; }
 
102
  .btn-icon { width: 32px; height: 32px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); transition: 0.2s; }
103
  .btn-icon:hover { background: var(--bg-hover); color: var(--text-primary); }
104
  .btn-icon svg { width: 18px; height: 18px; }
@@ -106,8 +104,7 @@
106
  .model-selector { font-size: 14px; font-weight: 600; color: var(--text-secondary); display: flex; align-items: center; gap: 6px; }
107
 
108
  /* --- CHAT CONTAINER --- */
109
- /* BUG FIX: Proper flex and padding so it scrolls correctly above the input */
110
- .chat-container { flex: 1; overflow-y: auto; padding: 40px 20px 20px; display: flex; flex-direction: column; align-items: center; scroll-behavior: smooth; }
111
 
112
  .welcome-center { margin: auto; text-align: center; display: flex; flex-direction: column; align-items: center; animation: fadeIn 0.5s ease; }
113
  .welcome-center img { width: 70px; height: 70px; border-radius: 18px; margin-bottom: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
@@ -122,6 +119,7 @@
122
  .bot-avatar img { width: 100%; height: 100%; object-fit: cover; }
123
  .bot-content { flex: 1; font-size: 15.5px; line-height: 1.6; color: var(--text-primary); min-width: 0; }
124
 
 
125
  .bot-content p { margin-bottom: 16px; }
126
  .bot-content p:last-child { margin-bottom: 0; }
127
  .bot-content strong { font-weight: 600; color: #000; }
@@ -132,9 +130,29 @@
132
  .chat-attachment { display: inline-flex; align-items: center; gap: 8px; background: #fff; border: 1px solid var(--border-light); padding: 6px 12px; border-radius: var(--radius-md); font-size: 13px; font-weight: 500; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); }
133
  .chat-img-preview { max-width: 250px; border-radius: var(--radius-md); border: 1px solid var(--border-light); margin-bottom: 10px; }
134
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  /* --- INPUT DOCK --- */
136
- /* BUG FIX: Changed from absolute position to standard flex-shrink so it never overlaps or hides */
137
- .input-dock { flex-shrink: 0; padding: 15px 20px 25px; background: var(--bg-main); border-top: 1px solid var(--border-light); display: flex; justify-content: center; z-index: 20; width: 100%; }
 
138
  .input-container { width: 100%; max-width: 760px; background: var(--bg-input); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 8px 12px; display: flex; flex-direction: column; transition: 0.2s; position: relative; }
139
  .input-container:focus-within { border-color: var(--border-focus); background: #fff; box-shadow: 0 4px 20px rgba(0,0,0,0.05); }
140
 
@@ -160,7 +178,6 @@
160
  .btn-send:disabled { background: #ccc; cursor: not-allowed; transform: none; }
161
 
162
  .hidden-input { display: none; }
163
- /* Adjusted dropdown position */
164
  .dropdown-menu { position: absolute; bottom: 100%; left: 0; margin-bottom: 10px; background: #fff; border: 1px solid var(--border-light); border-radius: var(--radius-md); padding: 6px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); display: none; flex-direction: column; gap: 2px; min-width: 180px; z-index: 100; }
165
  .dropdown-menu.active { display: flex; animation: fadeIn 0.2s; }
166
  .dropdown-item { padding: 10px 12px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 500; display: flex; align-items: center; gap: 10px; cursor: pointer; transition: 0.2s; }
@@ -188,7 +205,6 @@
188
 
189
  .auth-phase { display: none; }
190
  .auth-phase.active { display: flex; flex-direction: column; }
191
-
192
  .auth-message { font-size: 12px; color: #cc0000; text-align: center; margin-top: 10px; min-height: 18px; }
193
 
194
  /* --- WORKSPACE RIGHT PANEL --- */
@@ -221,18 +237,18 @@
221
  .typing-dot:nth-child(1) { animation-delay: -0.32s; } .typing-dot:nth-child(2) { animation-delay: -0.16s; }
222
  @keyframes typeBounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }
223
  svg { width: 100%; height: 100%; }
 
224
 
225
  @media (max-width: 900px) {
226
  .sidebar { position: absolute; left: 0; height: 100%; box-shadow: 5px 0 20px rgba(0,0,0,0.05); }
227
  .sidebar.collapsed { left: -260px; margin-left: 0; }
228
  .workspace-panel.active { width: 100%; position: absolute; top:0; left:0; height:100%; z-index: 1000; }
229
- .input-dock { padding: 10px 15px 15px; } /* Slightly tighter padding for phones */
230
  }
231
  </style>
232
  </head>
233
  <body>
234
 
235
- <!-- SIDEBAR -->
236
  <aside class="sidebar collapsed" id="sidebar">
237
  <div class="sidebar-header">
238
  <button class="btn-icon" onclick="UI.toggleSidebar()" title="Close Sidebar">
@@ -241,44 +257,44 @@
241
  <span style="font-weight: 600; font-size: 14px; letter-spacing: 0.5px;">CODE VED</span>
242
  </div>
243
  <div style="padding: 0 16px;">
244
- <button class="btn-new-chat" onclick="location.reload()">
245
  <svg style="width:16px; height:16px;" 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>
246
  New Chat
247
  </button>
248
  </div>
 
249
  <div class="sidebar-history" id="chatHistory">
250
- <!-- Sync history goes here -->
251
- </div>
252
 
253
- <!-- User Profile Area (Click to Login/Logout) -->
254
- <div class="sidebar-footer" id="profileArea" onclick="Auth.handleProfileClick()">
255
  <div class="user-avatar" id="uAv">G</div>
256
  <div class="user-info-box">
257
  <div class="user-name" id="uName">Guest Session</div>
258
- <div class="user-sub" id="uSub">Queries: 0/10</div>
259
  </div>
 
 
 
260
  </div>
261
  </aside>
262
 
263
- <!-- MAIN AREA -->
264
  <main class="main-area">
265
- <header class="top-bar">
266
  <button class="btn-icon" onclick="UI.toggleSidebar()" title="Open Menu" id="btnMenuOpen">
267
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
268
  </button>
269
  <div class="model-selector">CODE VED 202B</div>
270
- <div style="width: 32px;"></div> <!-- Spacer -->
271
- </header>
272
 
273
  <div class="chat-container" id="chatContainer">
274
  <div class="welcome-center" id="welcomeScreen">
275
  <img src="https://i.ibb.co/MyYStcGP/TIRANGA-20260613-131924-0000.png" alt="CODE VED Logo">
276
  <h1>What's your focus today?</h1>
277
- <p>Hi Divy Patel, I am ready to assist you.</p>
278
  </div>
279
  </div>
280
 
281
- <div class="input-dock">
282
  <div class="input-container">
283
  <div class="file-preview-bar" id="filePreviewBar">
284
  <img id="imgPreview" class="file-preview-icon" src="" style="display:none;">
@@ -319,7 +335,6 @@
319
  </div>
320
  </main>
321
 
322
- <!-- WORKSPACE PANEL -->
323
  <aside class="workspace-panel" id="workspacePanel">
324
  <div class="ws-header">
325
  <div class="ws-tabs">
@@ -341,7 +356,6 @@
341
  </div>
342
  </aside>
343
 
344
- <!-- SECURE AUTHENTICATION MODAL -->
345
  <div class="auth-overlay" id="authModal">
346
  <div class="auth-modal">
347
  <button class="auth-close" onclick="Auth.closeModal()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
@@ -352,7 +366,6 @@
352
  <div class="auth-tab" id="tabRegister" onclick="Auth.switchTab('register')">Register</div>
353
  </div>
354
 
355
- <!-- Login Flow -->
356
  <div id="flowLogin">
357
  <div class="auth-phase active" id="loginPhase1">
358
  <div class="auth-input-group">
@@ -369,7 +382,6 @@
369
  </div>
370
  </div>
371
 
372
- <!-- Register Flow -->
373
  <div id="flowRegister" style="display:none;">
374
  <div class="auth-phase active" id="regPhase1">
375
  <div class="auth-input-group">
@@ -395,7 +407,7 @@
395
  // --- 1. CONFIG & STATE ---
396
  const Config = {
397
  GAS_URL: "https://script.google.com/macros/s/AKfycbz5vrlB4GrfkfBVYdQ52IQweIXC1cNDwKuTUorxdAiOdSSIrH55mzJlaz9kq1Y94ot5/exec",
398
- API_ENDPOINT: "/api/chat", // Your backend endpoint
399
  LOGO: "https://i.ibb.co/MyYStcGP/TIRANGA-20260613-131924-0000.png"
400
  };
401
 
@@ -405,6 +417,7 @@
405
  guestCount: parseInt(localStorage.getItem('codeved_guest') || '0', 10),
406
  attachment: null,
407
  isProcessing: false,
 
408
  workspaces: [],
409
  currentWs: null
410
  };
@@ -427,9 +440,17 @@
427
  const el = document.getElementById('authMsg');
428
  el.innerText = msg; el.style.color = isError ? '#cc0000' : '#009900';
429
  setTimeout(() => el.innerText='', 4000);
 
 
 
 
 
 
 
430
  }
431
  };
432
 
 
433
  document.addEventListener('click', (e) => {
434
  if(!e.target.closest('.tools-left')) document.getElementById('attachMenu').classList.remove('active');
435
  });
@@ -440,34 +461,41 @@
440
  if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); Chat.handleSend(); }
441
  });
442
 
443
- // --- 3. AUTHENTICATION (DATABASE LINK) ---
444
  const Auth = {
445
  init: () => {
446
  const uAv = document.getElementById('uAv');
447
  const uName = document.getElementById('uName');
448
  const uSub = document.getElementById('uSub');
 
 
449
 
450
  if (State.user) {
451
- uAv.innerText = (State.name ? State.name.charAt(0) : State.user.charAt(0)).toUpperCase();
452
- uName.innerText = State.name || State.user.split('@')[0];
453
- uSub.innerText = "Authenticated User";
 
454
  uSub.style.color = "#009900";
 
 
 
 
 
 
455
  } else {
456
  uAv.innerText = "G";
457
  uName.innerText = "Guest Session";
458
  uSub.innerText = `Queries: ${State.guestCount}/10`;
459
  uSub.style.color = "var(--text-tertiary)";
 
 
460
  }
461
  },
462
- handleProfileClick: () => {
463
- if(State.user) {
464
- if(confirm("Do you want to securely logout?")) {
465
- localStorage.removeItem('codeved_user');
466
- localStorage.removeItem('codeved_name');
467
- location.reload();
468
- }
469
- } else {
470
- Auth.openModal();
471
  }
472
  },
473
  openModal: () => document.getElementById('authModal').style.display = 'flex',
@@ -478,18 +506,10 @@
478
  document.getElementById('flowLogin').style.display = 'none';
479
  document.getElementById('flowRegister').style.display = 'none';
480
 
481
- if(tab === 'login') {
482
- document.getElementById('tabLogin').classList.add('active');
483
- document.getElementById('flowLogin').style.display = 'block';
484
- } else {
485
- document.getElementById('tabRegister').classList.add('active');
486
- document.getElementById('flowRegister').style.display = 'block';
487
- }
488
- },
489
- switchPhase: (from, to) => {
490
- document.getElementById(from).classList.remove('active');
491
- document.getElementById(to).classList.add('active');
492
  },
 
493
  process: async (action) => {
494
  let payload = { action: action };
495
  let btnId = '';
@@ -516,11 +536,7 @@
516
  btn.disabled = true; btn.innerText = "Processing...";
517
 
518
  try {
519
- const res = await fetch(Config.GAS_URL, {
520
- method: 'POST', mode: 'cors',
521
- headers: { 'Content-Type': 'text/plain;charset=utf-8' },
522
- body: JSON.stringify(payload)
523
- });
524
  const data = await res.json();
525
 
526
  if (data.status === 'success') {
@@ -532,17 +548,49 @@
532
  if(payload.name) localStorage.setItem('codeved_name', payload.name);
533
  location.reload();
534
  }
535
- } else {
536
- UI.showAuthMsg(data.message);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
  }
538
- } catch (e) {
539
- UI.showAuthMsg("Database connection error. Please try again.");
 
 
 
 
 
 
 
 
 
 
540
  }
541
- btn.disabled = false; btn.innerText = originalText;
542
  }
543
  };
544
 
545
- // --- 4. FILE HANDLING (Sanitized) ---
546
  const FileSys = {
547
  process: async (input, type) => {
548
  document.getElementById('attachMenu').classList.remove('active');
@@ -586,10 +634,7 @@
586
  } else {
587
  r.onload = (e) => {
588
  let data = e.target.result;
589
- // Safe HTML sanitization
590
- if(file.name.endsWith('.html')) {
591
- data = data.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "\n[SCRIPT SANITIZED]\n");
592
- }
593
  State.attachment = { type: 'text', data: data, name: file.name };
594
  };
595
  r.readAsText(file);
@@ -615,93 +660,54 @@
615
  Speech.rec.onstart = () => { Speech.isRec = true; document.getElementById('btnStt').classList.add('recording'); };
616
  Speech.rec.onresult = (e) => {
617
  let trans = '';
618
- for (let i = e.resultIndex; i < e.results.length; ++i) {
619
- if (e.results[i].isFinal) trans += e.results[i][0].transcript;
620
- }
621
- if (trans) {
622
- const input = document.getElementById('mainInput');
623
- input.value += (input.value ? ' ' : '') + trans;
624
- UI.autoGrow(input);
625
- }
626
  };
627
  Speech.rec.onerror = () => Speech.stop();
628
  Speech.rec.onend = () => Speech.stop();
629
  },
630
- toggle: () => {
631
- if (!Speech.rec) Speech.init();
632
- if (Speech.isRec) Speech.stop();
633
- else { try { Speech.rec.start(); } catch(e) {} }
634
- },
635
- stop: () => {
636
- if(Speech.rec) Speech.rec.stop();
637
- Speech.isRec = false;
638
- document.getElementById('btnStt').classList.remove('recording');
639
- }
640
  };
641
 
642
  // --- 6. WORKSPACE PRO MAX ---
643
  const Workspace = {
644
  open: (id) => {
645
- State.currentWs = id;
646
- const d = State.workspaces[id];
647
- const b = document.getElementById('wsCodeBlock');
648
- b.className = `hljs language-${d.lang || 'plaintext'}`;
649
- b.textContent = d.code;
650
- hljs.highlightElement(b);
651
-
652
  document.getElementById('workspacePanel').classList.add('active');
653
  if(window.innerWidth <= 900) { document.getElementById('sidebar').classList.add('collapsed'); }
654
  Workspace.switchTab('code');
655
  },
656
  close: () => document.getElementById('workspacePanel').classList.remove('active'),
657
  switchTab: (tab) => {
658
- document.getElementById('tabCode').classList.remove('active');
659
- document.getElementById('tabPreview').classList.remove('active');
660
  if(tab === 'code') {
661
- document.getElementById('tabCode').classList.add('active');
662
- document.getElementById('wsCodeView').style.display = 'block';
663
- document.getElementById('wsPreviewView').style.display = 'none';
664
  } else {
665
- document.getElementById('tabPreview').classList.add('active');
666
- document.getElementById('wsCodeView').style.display = 'none';
667
- document.getElementById('wsPreviewView').style.display = 'flex';
668
  Workspace.run();
669
  }
670
  },
671
- copy: () => {
672
- if(State.currentWs !== null) {
673
- navigator.clipboard.writeText(State.workspaces[State.currentWs].code).then(() => alert('Code Copied!'));
674
- }
675
- },
676
  run: async () => {
677
  if (State.currentWs === null) return;
678
- const d = State.workspaces[State.currentWs];
679
- const lang = (d.lang || '').toLowerCase();
680
- const view = document.getElementById('wsPreviewView');
681
 
682
  if (['html', 'xml', 'javascript', 'js', 'css'].includes(lang)) {
683
  let html = d.code;
684
  if(lang === 'javascript' || lang === 'js') html = `<script>${d.code}<\/script>`;
685
  if(lang === 'css') html = `<style>${d.code}</style><div style="padding:20px;font-family:sans-serif;">CSS Applied. Add HTML to test.</div>`;
686
-
687
- const iframe = document.createElement('iframe');
688
- iframe.style.width = '100%'; iframe.style.height = '100%'; iframe.style.border = 'none';
689
- view.innerHTML = ''; view.appendChild(iframe);
690
- iframe.contentWindow.document.open(); iframe.contentWindow.document.write(html); iframe.contentWindow.document.close();
691
  return;
692
  }
693
-
694
  view.innerHTML = '<div class="ws-console" style="color:var(--brand-accent);">Compiling code...</div>';
695
- const pMap = {'python':'python', 'py':'python', 'c':'c', 'cpp':'c++', 'java':'java'};
696
- const rLang = pMap[lang];
697
-
698
  if(!rLang) { view.innerHTML = `<div class="ws-console" style="color:#cc0000;">Live Preview not supported for ${lang}.</div>`; return; }
699
 
700
  try {
701
- const res = await fetch('https://emkc.org/api/v2/piston/execute', {
702
- method: 'POST', headers: { 'Content-Type': 'application/json' },
703
- body: JSON.stringify({ language: rLang, version: "*", files: [{ content: d.code }] })
704
- });
705
  const data = await res.json();
706
  let out = (data.compile?.output || "") + "\n" + (data.run?.output || "") + "\n" + (data.run?.stderr || "");
707
  view.innerHTML = `<div class="ws-console">${UI.escape(out.trim() || "[Execution Finished]")}</div>`;
@@ -711,8 +717,7 @@
711
 
712
  const MDRenderer = new marked.Renderer();
713
  MDRenderer.code = function(code, lang) {
714
- const id = State.workspaces.length;
715
- State.workspaces.push({code: code, lang: lang});
716
  const highlighted = hljs.highlightAuto(code).value;
717
  return `
718
  <div style="margin: 16px 0;">
@@ -727,7 +732,7 @@
727
  };
728
  marked.use({ renderer: MDRenderer });
729
 
730
- // --- 7. CHAT ENGINE ---
731
  const Chat = {
732
  renderUser: (txt, attachUI) => {
733
  const c = document.getElementById('chatContainer');
@@ -744,32 +749,37 @@
744
  c.appendChild(w); UI.scrollToBottom();
745
  return w.querySelector('.bot-content');
746
  },
 
 
 
 
 
 
 
 
 
 
 
747
  handleSend: async () => {
748
  if(State.isProcessing) return;
749
  const input = document.getElementById('mainInput');
750
  const text = input.value.trim();
751
  if(!text && !State.attachment) return;
752
 
753
- // GUEST LIMIT LOGIC
754
  if(!State.user) {
755
- if(State.guestCount >= 10) {
756
- Auth.openModal();
757
- UI.showAuthMsg("Guest limit reached. Secure Login required.", true);
758
- return;
759
- }
760
- State.guestCount++;
761
- localStorage.setItem('codeved_guest', State.guestCount);
762
  document.getElementById('uSub').innerText = `Queries: ${State.guestCount}/10`;
763
  }
764
 
765
- State.isProcessing = true;
766
- document.getElementById('btnSend').disabled = true;
767
- input.value = ''; input.style.height = 'auto';
768
- document.getElementById('welcomeScreen').style.display = 'none';
769
 
770
  let payloadStr = text;
771
  let attachUI = '';
772
  let mediaArray = [];
 
773
 
774
  if(State.attachment) {
775
  if(State.attachment.type === 'text') {
@@ -782,9 +792,15 @@
782
  }
783
 
784
  Chat.renderUser(text || '[Attached Media]', attachUI);
 
785
  FileSys.discard();
786
 
787
  const botContent = Chat.renderBot();
 
 
 
 
 
788
 
789
  try {
790
  const res = await fetch(Config.API_ENDPOINT, {
@@ -792,7 +808,7 @@
792
  body: JSON.stringify({
793
  message: payloadStr, attachments: mediaArray,
794
  system_prompt: "You are CODE VED, a highly intelligent system engineered by Divy Patel. Speak purely in English.",
795
- history: []
796
  })
797
  });
798
 
@@ -817,14 +833,25 @@
817
  if(json.choices && json.choices[0].delta.content) fullText += json.choices[0].delta.content;
818
  else if (json.response) fullText += json.response;
819
 
820
- botContent.innerHTML = marked.parse(fullText.replace(/<think>[\s\S]*?<\/think>/gi, ''));
 
 
 
 
 
 
 
821
  UI.scrollToBottom();
822
  } catch(e){}
823
  }
824
  }
825
  }
 
 
 
 
826
  } catch(e) {
827
- botContent.innerHTML = `<span style="color:#cc0000; font-weight:500;">Connection Offline. Backend database is currently unreachable.</span>`;
828
  } finally {
829
  State.isProcessing = false;
830
  document.getElementById('btnSend').disabled = false;
@@ -835,7 +862,6 @@
835
 
836
  window.onload = () => {
837
  Auth.init();
838
- // Ensures sidebar layout doesn't break chat input
839
  if(window.innerWidth > 900) { document.getElementById('btnMenuOpen').style.display = 'none'; document.getElementById('sidebar').classList.remove('collapsed'); }
840
  };
841
 
 
6
  <title>CODE VED | Engineered by Divy Patel</title>
7
  <meta name="description" content="CODE VED - 202 Billion Parameter Enterprise AI System">
8
 
 
9
  <link rel="preconnect" href="https://fonts.googleapis.com">
10
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
12
 
 
13
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css">
 
 
14
  <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
15
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script>
16
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
 
32
  --border-focus: #d0d0d0;
33
 
34
  --brand-color: #1a1a1a;
35
+ --brand-accent: #0066cc; /* Tool Calling Color */
36
 
37
+ --font-ui: 'Inter', sans-serif;
38
  --font-code: 'JetBrains Mono', monospace;
39
 
40
  --radius-sm: 8px;
 
44
 
45
  * { box-sizing: border-box; margin: 0; padding: 0; }
46
 
 
47
  html, body {
48
+ height: 100%; height: 100dvh; width: 100vw;
 
 
49
  font-family: var(--font-ui); background-color: var(--bg-main); color: var(--text-primary);
50
  display: flex; overflow: hidden; -webkit-font-smoothing: antialiased;
51
  }
 
69
 
70
  .sidebar-header { padding: 16px; display: flex; align-items: center; justify-content: space-between; }
71
  .btn-new-chat {
72
+ display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; padding: 10px 12px;
73
+ border-radius: var(--radius-sm); background: #fff; border: 1px solid var(--border-light);
74
  font-size: 14px; font-weight: 500; transition: 0.2s; box-shadow: 0 1px 2px rgba(0,0,0,0.02);
75
  }
76
+ .btn-new-chat:hover { background: var(--bg-hover); color: #000; border-color: #ccc; }
77
 
78
  .sidebar-history { flex: 1; overflow-y: auto; padding: 10px; }
79
 
80
  .sidebar-footer {
81
  padding: 16px; border-top: 1px solid var(--border-light); display: flex; align-items: center; gap: 12px;
82
+ transition: background 0.2s;
83
  }
 
84
  .user-avatar { width: 34px; height: 34px; border-radius: 50%; background: var(--brand-color); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 600; flex-shrink: 0; }
85
  .user-info-box { flex: 1; overflow: hidden; }
86
  .user-name { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-primary); }
87
  .user-sub { font-size: 11px; font-weight: 500; color: var(--text-tertiary); margin-top: 2px; }
88
+
89
+ .btn-power {
90
+ width: 32px; height: 32px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center;
91
+ color: var(--text-secondary); transition: 0.2s; cursor: pointer; border: 1px solid transparent;
92
+ }
93
+ .btn-power:hover { background: #ffe6e6; color: #cc0000; border-color: #ffcccc; }
94
 
95
  /* --- MAIN WORKSPACE --- */
 
96
  .main-area { flex: 1; display: flex; flex-direction: column; position: relative; background: var(--bg-main); transition: 0.3s; height: 100%; overflow: hidden; }
97
 
98
+ .top-bar { padding: 12px 20px; display: flex; align-items: center; justify-content: space-between; background: var(--bg-main); z-index: 10; flex-shrink: 0; border-bottom: 1px solid transparent; transition: border 0.3s; }
99
+ .top-bar.scrolled { border-bottom: 1px solid var(--border-light); }
100
  .btn-icon { width: 32px; height: 32px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); transition: 0.2s; }
101
  .btn-icon:hover { background: var(--bg-hover); color: var(--text-primary); }
102
  .btn-icon svg { width: 18px; height: 18px; }
 
104
  .model-selector { font-size: 14px; font-weight: 600; color: var(--text-secondary); display: flex; align-items: center; gap: 6px; }
105
 
106
  /* --- CHAT CONTAINER --- */
107
+ .chat-container { flex: 1; overflow-y: auto; padding: 20px 20px 40px; display: flex; flex-direction: column; align-items: center; scroll-behavior: smooth; }
 
108
 
109
  .welcome-center { margin: auto; text-align: center; display: flex; flex-direction: column; align-items: center; animation: fadeIn 0.5s ease; }
110
  .welcome-center img { width: 70px; height: 70px; border-radius: 18px; margin-bottom: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
 
119
  .bot-avatar img { width: 100%; height: 100%; object-fit: cover; }
120
  .bot-content { flex: 1; font-size: 15.5px; line-height: 1.6; color: var(--text-primary); min-width: 0; }
121
 
122
+ /* Markdown Styling */
123
  .bot-content p { margin-bottom: 16px; }
124
  .bot-content p:last-child { margin-bottom: 0; }
125
  .bot-content strong { font-weight: 600; color: #000; }
 
130
  .chat-attachment { display: inline-flex; align-items: center; gap: 8px; background: #fff; border: 1px solid var(--border-light); padding: 6px 12px; border-radius: var(--radius-md); font-size: 13px; font-weight: 500; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.05); }
131
  .chat-img-preview { max-width: 250px; border-radius: var(--radius-md); border: 1px solid var(--border-light); margin-bottom: 10px; }
132
 
133
+ /* --- GOOGLE SEARCH TOOL CALLING UI --- */
134
+ .tool-indicator {
135
+ display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 500;
136
+ color: var(--brand-accent); background: rgba(0, 102, 204, 0.05); padding: 8px 14px;
137
+ border-radius: var(--radius-sm); margin-bottom: 16px; border: 1px solid rgba(0, 102, 204, 0.2);
138
+ transition: 0.3s;
139
+ }
140
+ .tool-indicator.active {
141
+ animation: pulseGlow 2s infinite alternate;
142
+ }
143
+ .tool-indicator svg { width: 16px; height: 16px; }
144
+ .tool-indicator.active svg { animation: spin 2s linear infinite; }
145
+
146
+ @keyframes pulseGlow {
147
+ 0% { box-shadow: 0 0 0 rgba(0, 102, 204, 0); border-color: rgba(0, 102, 204, 0.2); }
148
+ 100% { box-shadow: 0 0 12px rgba(0, 102, 204, 0.3); border-color: rgba(0, 102, 204, 0.5); }
149
+ }
150
+ @keyframes spin { 100% { transform: rotate(360deg); } }
151
+
152
  /* --- INPUT DOCK --- */
153
+ .input-dock { flex-shrink: 0; padding: 15px 20px 25px; background: var(--bg-main); border-top: 1px solid transparent; display: flex; justify-content: center; z-index: 20; width: 100%; transition: border 0.3s; }
154
+ .input-dock.scrolled { border-top: 1px solid var(--border-light); }
155
+
156
  .input-container { width: 100%; max-width: 760px; background: var(--bg-input); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 8px 12px; display: flex; flex-direction: column; transition: 0.2s; position: relative; }
157
  .input-container:focus-within { border-color: var(--border-focus); background: #fff; box-shadow: 0 4px 20px rgba(0,0,0,0.05); }
158
 
 
178
  .btn-send:disabled { background: #ccc; cursor: not-allowed; transform: none; }
179
 
180
  .hidden-input { display: none; }
 
181
  .dropdown-menu { position: absolute; bottom: 100%; left: 0; margin-bottom: 10px; background: #fff; border: 1px solid var(--border-light); border-radius: var(--radius-md); padding: 6px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); display: none; flex-direction: column; gap: 2px; min-width: 180px; z-index: 100; }
182
  .dropdown-menu.active { display: flex; animation: fadeIn 0.2s; }
183
  .dropdown-item { padding: 10px 12px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 500; display: flex; align-items: center; gap: 10px; cursor: pointer; transition: 0.2s; }
 
205
 
206
  .auth-phase { display: none; }
207
  .auth-phase.active { display: flex; flex-direction: column; }
 
208
  .auth-message { font-size: 12px; color: #cc0000; text-align: center; margin-top: 10px; min-height: 18px; }
209
 
210
  /* --- WORKSPACE RIGHT PANEL --- */
 
237
  .typing-dot:nth-child(1) { animation-delay: -0.32s; } .typing-dot:nth-child(2) { animation-delay: -0.16s; }
238
  @keyframes typeBounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } }
239
  svg { width: 100%; height: 100%; }
240
+ .sys-msg { padding: 40px; text-align: center; color: var(--text-secondary); font-size: 14px; }
241
 
242
  @media (max-width: 900px) {
243
  .sidebar { position: absolute; left: 0; height: 100%; box-shadow: 5px 0 20px rgba(0,0,0,0.05); }
244
  .sidebar.collapsed { left: -260px; margin-left: 0; }
245
  .workspace-panel.active { width: 100%; position: absolute; top:0; left:0; height:100%; z-index: 1000; }
246
+ .input-dock { padding: 10px 15px 15px; }
247
  }
248
  </style>
249
  </head>
250
  <body>
251
 
 
252
  <aside class="sidebar collapsed" id="sidebar">
253
  <div class="sidebar-header">
254
  <button class="btn-icon" onclick="UI.toggleSidebar()" title="Close Sidebar">
 
257
  <span style="font-weight: 600; font-size: 14px; letter-spacing: 0.5px;">CODE VED</span>
258
  </div>
259
  <div style="padding: 0 16px;">
260
+ <button class="btn-new-chat" onclick="HistoryManager.clearHistory()">
261
  <svg style="width:16px; height:16px;" 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>
262
  New Chat
263
  </button>
264
  </div>
265
+
266
  <div class="sidebar-history" id="chatHistory">
267
+ </div>
 
268
 
269
+ <div class="sidebar-footer" id="profileArea">
 
270
  <div class="user-avatar" id="uAv">G</div>
271
  <div class="user-info-box">
272
  <div class="user-name" id="uName">Guest Session</div>
273
+ <div class="user-sub" id="uSub" onclick="Auth.openModal()" style="cursor:pointer; color:var(--brand-accent);">Login Required</div>
274
  </div>
275
+ <button class="btn-power" id="btnLogout" onclick="Auth.handleLogout()" title="Logout" style="display:none;">
276
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18.36 6.64a9 9 0 1 1-12.73 0"></path><line x1="12" y1="2" x2="12" y2="12"></line></svg>
277
+ </button>
278
  </div>
279
  </aside>
280
 
 
281
  <main class="main-area">
282
+ <header class="top-bar" id="topBar">
283
  <button class="btn-icon" onclick="UI.toggleSidebar()" title="Open Menu" id="btnMenuOpen">
284
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>
285
  </button>
286
  <div class="model-selector">CODE VED 202B</div>
287
+ <div style="width: 32px;"></div> </header>
 
288
 
289
  <div class="chat-container" id="chatContainer">
290
  <div class="welcome-center" id="welcomeScreen">
291
  <img src="https://i.ibb.co/MyYStcGP/TIRANGA-20260613-131924-0000.png" alt="CODE VED Logo">
292
  <h1>What's your focus today?</h1>
293
+ <p id="welcomeGreeting">Hi there, I am ready to assist you.</p>
294
  </div>
295
  </div>
296
 
297
+ <div class="input-dock" id="inputDock">
298
  <div class="input-container">
299
  <div class="file-preview-bar" id="filePreviewBar">
300
  <img id="imgPreview" class="file-preview-icon" src="" style="display:none;">
 
335
  </div>
336
  </main>
337
 
 
338
  <aside class="workspace-panel" id="workspacePanel">
339
  <div class="ws-header">
340
  <div class="ws-tabs">
 
356
  </div>
357
  </aside>
358
 
 
359
  <div class="auth-overlay" id="authModal">
360
  <div class="auth-modal">
361
  <button class="auth-close" onclick="Auth.closeModal()"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
 
366
  <div class="auth-tab" id="tabRegister" onclick="Auth.switchTab('register')">Register</div>
367
  </div>
368
 
 
369
  <div id="flowLogin">
370
  <div class="auth-phase active" id="loginPhase1">
371
  <div class="auth-input-group">
 
382
  </div>
383
  </div>
384
 
 
385
  <div id="flowRegister" style="display:none;">
386
  <div class="auth-phase active" id="regPhase1">
387
  <div class="auth-input-group">
 
407
  // --- 1. CONFIG & STATE ---
408
  const Config = {
409
  GAS_URL: "https://script.google.com/macros/s/AKfycbz5vrlB4GrfkfBVYdQ52IQweIXC1cNDwKuTUorxdAiOdSSIrH55mzJlaz9kq1Y94ot5/exec",
410
+ API_ENDPOINT: "/api/chat",
411
  LOGO: "https://i.ibb.co/MyYStcGP/TIRANGA-20260613-131924-0000.png"
412
  };
413
 
 
417
  guestCount: parseInt(localStorage.getItem('codeved_guest') || '0', 10),
418
  attachment: null,
419
  isProcessing: false,
420
+ history: [],
421
  workspaces: [],
422
  currentWs: null
423
  };
 
440
  const el = document.getElementById('authMsg');
441
  el.innerText = msg; el.style.color = isError ? '#cc0000' : '#009900';
442
  setTimeout(() => el.innerText='', 4000);
443
+ },
444
+ handleScrollEvents: () => {
445
+ const c = document.getElementById('chatContainer');
446
+ const topBar = document.getElementById('topBar');
447
+ const dock = document.getElementById('inputDock');
448
+ if (c.scrollTop > 10) topBar.classList.add('scrolled'); else topBar.classList.remove('scrolled');
449
+ if (c.scrollHeight - c.scrollTop - c.clientHeight > 10) dock.classList.add('scrolled'); else dock.classList.remove('scrolled');
450
  }
451
  };
452
 
453
+ document.getElementById('chatContainer').addEventListener('scroll', UI.handleScrollEvents);
454
  document.addEventListener('click', (e) => {
455
  if(!e.target.closest('.tools-left')) document.getElementById('attachMenu').classList.remove('active');
456
  });
 
461
  if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); Chat.handleSend(); }
462
  });
463
 
464
+ // --- 3. AUTHENTICATION & HISTORY DB (RESTORED) ---
465
  const Auth = {
466
  init: () => {
467
  const uAv = document.getElementById('uAv');
468
  const uName = document.getElementById('uName');
469
  const uSub = document.getElementById('uSub');
470
+ const btnLogout = document.getElementById('btnLogout');
471
+ const greeting = document.getElementById('welcomeGreeting');
472
 
473
  if (State.user) {
474
+ const dispName = State.name || State.user.split('@')[0];
475
+ uAv.innerText = dispName.charAt(0).toUpperCase();
476
+ uName.innerText = dispName;
477
+ uSub.innerText = "Authenticated";
478
  uSub.style.color = "#009900";
479
+ uSub.onclick = null;
480
+ uSub.style.cursor = 'default';
481
+ btnLogout.style.display = 'flex';
482
+ greeting.innerText = `Hi ${dispName}, I am ready to assist you.`;
483
+
484
+ HistoryManager.sync(); // Load History on Boot
485
  } else {
486
  uAv.innerText = "G";
487
  uName.innerText = "Guest Session";
488
  uSub.innerText = `Queries: ${State.guestCount}/10`;
489
  uSub.style.color = "var(--text-tertiary)";
490
+ btnLogout.style.display = 'none';
491
+ greeting.innerText = `Hi there, I am ready to assist you.`;
492
  }
493
  },
494
+ handleLogout: () => {
495
+ if(confirm("Are you sure you want to log out?")) {
496
+ localStorage.removeItem('codeved_user');
497
+ localStorage.removeItem('codeved_name');
498
+ location.reload();
 
 
 
 
499
  }
500
  },
501
  openModal: () => document.getElementById('authModal').style.display = 'flex',
 
506
  document.getElementById('flowLogin').style.display = 'none';
507
  document.getElementById('flowRegister').style.display = 'none';
508
 
509
+ if(tab === 'login') { document.getElementById('tabLogin').classList.add('active'); document.getElementById('flowLogin').style.display = 'block'; }
510
+ else { document.getElementById('tabRegister').classList.add('active'); document.getElementById('flowRegister').style.display = 'block'; }
 
 
 
 
 
 
 
 
 
511
  },
512
+ switchPhase: (from, to) => { document.getElementById(from).classList.remove('active'); document.getElementById(to).classList.add('active'); },
513
  process: async (action) => {
514
  let payload = { action: action };
515
  let btnId = '';
 
536
  btn.disabled = true; btn.innerText = "Processing...";
537
 
538
  try {
539
+ const res = await fetch(Config.GAS_URL, { method: 'POST', mode: 'cors', headers: { 'Content-Type': 'text/plain;charset=utf-8' }, body: JSON.stringify(payload) });
 
 
 
 
540
  const data = await res.json();
541
 
542
  if (data.status === 'success') {
 
548
  if(payload.name) localStorage.setItem('codeved_name', payload.name);
549
  location.reload();
550
  }
551
+ } else { UI.showAuthMsg(data.message); }
552
+ } catch (e) { UI.showAuthMsg("Database connection error. Please try again."); }
553
+
554
+ btn.disabled = false; btn.innerText = originalText;
555
+ }
556
+ };
557
+
558
+ const HistoryManager = {
559
+ sync: async () => {
560
+ if(!State.user) return;
561
+ try {
562
+ const res = await fetch(Config.GAS_URL, { method: 'POST', body: JSON.stringify({action: "get_history", email: State.user})});
563
+ const data = await res.json();
564
+ if(data.status === 'success' && data.historyJSON !== "[]") {
565
+ State.history = JSON.parse(data.historyJSON);
566
+ document.getElementById('welcomeScreen').style.display = 'none';
567
+ State.history.forEach(msg => {
568
+ if(msg.role === 'user') Chat.renderUser(msg.content, '');
569
+ else {
570
+ const botNode = Chat.renderBot();
571
+ botNode.innerHTML = marked.parse(msg.content.replace(/<think>[\s\S]*?<\/think>/gi, ''));
572
+ }
573
+ });
574
+ setTimeout(UI.scrollToBottom, 200);
575
  }
576
+ } catch(e) { console.warn("History sync failed."); }
577
+ },
578
+ save: () => {
579
+ if(!State.user) return;
580
+ fetch(Config.GAS_URL, {
581
+ method: 'POST', body: JSON.stringify({action: "save_history", email: State.user, historyJSON: JSON.stringify(State.history)})
582
+ }).catch(e=>{});
583
+ },
584
+ clearHistory: async () => {
585
+ if(State.user) {
586
+ document.getElementById('chatContainer').innerHTML = '<div class="sys-msg">Clearing Memory Workspace...</div>';
587
+ try { await fetch(Config.GAS_URL, { method: 'POST', body: JSON.stringify({action: "delete_history", email: State.user}) }); } catch(e){}
588
  }
589
+ location.reload();
590
  }
591
  };
592
 
593
+ // --- 4. FILE HANDLING ---
594
  const FileSys = {
595
  process: async (input, type) => {
596
  document.getElementById('attachMenu').classList.remove('active');
 
634
  } else {
635
  r.onload = (e) => {
636
  let data = e.target.result;
637
+ if(file.name.endsWith('.html')) { data = data.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "\n[SCRIPT SANITIZED]\n"); }
 
 
 
638
  State.attachment = { type: 'text', data: data, name: file.name };
639
  };
640
  r.readAsText(file);
 
660
  Speech.rec.onstart = () => { Speech.isRec = true; document.getElementById('btnStt').classList.add('recording'); };
661
  Speech.rec.onresult = (e) => {
662
  let trans = '';
663
+ for (let i = e.resultIndex; i < e.results.length; ++i) { if (e.results[i].isFinal) trans += e.results[i][0].transcript; }
664
+ if (trans) { const input = document.getElementById('mainInput'); input.value += (input.value ? ' ' : '') + trans; UI.autoGrow(input); }
 
 
 
 
 
 
665
  };
666
  Speech.rec.onerror = () => Speech.stop();
667
  Speech.rec.onend = () => Speech.stop();
668
  },
669
+ toggle: () => { if (!Speech.rec) Speech.init(); if (Speech.isRec) Speech.stop(); else { try { Speech.rec.start(); } catch(e) {} } },
670
+ stop: () => { if(Speech.rec) Speech.rec.stop(); Speech.isRec = false; document.getElementById('btnStt').classList.remove('recording'); }
 
 
 
 
 
 
 
 
671
  };
672
 
673
  // --- 6. WORKSPACE PRO MAX ---
674
  const Workspace = {
675
  open: (id) => {
676
+ State.currentWs = id; const d = State.workspaces[id]; const b = document.getElementById('wsCodeBlock');
677
+ b.className = `hljs language-${d.lang || 'plaintext'}`; b.textContent = d.code; hljs.highlightElement(b);
 
 
 
 
 
678
  document.getElementById('workspacePanel').classList.add('active');
679
  if(window.innerWidth <= 900) { document.getElementById('sidebar').classList.add('collapsed'); }
680
  Workspace.switchTab('code');
681
  },
682
  close: () => document.getElementById('workspacePanel').classList.remove('active'),
683
  switchTab: (tab) => {
684
+ document.getElementById('tabCode').classList.remove('active'); document.getElementById('tabPreview').classList.remove('active');
 
685
  if(tab === 'code') {
686
+ document.getElementById('tabCode').classList.add('active'); document.getElementById('wsCodeView').style.display = 'block'; document.getElementById('wsPreviewView').style.display = 'none';
 
 
687
  } else {
688
+ document.getElementById('tabPreview').classList.add('active'); document.getElementById('wsCodeView').style.display = 'none'; document.getElementById('wsPreviewView').style.display = 'flex';
 
 
689
  Workspace.run();
690
  }
691
  },
692
+ copy: () => { if(State.currentWs !== null) { navigator.clipboard.writeText(State.workspaces[State.currentWs].code).then(() => alert('Code Copied!')); } },
 
 
 
 
693
  run: async () => {
694
  if (State.currentWs === null) return;
695
+ const d = State.workspaces[State.currentWs]; const lang = (d.lang || '').toLowerCase(); const view = document.getElementById('wsPreviewView');
 
 
696
 
697
  if (['html', 'xml', 'javascript', 'js', 'css'].includes(lang)) {
698
  let html = d.code;
699
  if(lang === 'javascript' || lang === 'js') html = `<script>${d.code}<\/script>`;
700
  if(lang === 'css') html = `<style>${d.code}</style><div style="padding:20px;font-family:sans-serif;">CSS Applied. Add HTML to test.</div>`;
701
+ const iframe = document.createElement('iframe'); iframe.style.width = '100%'; iframe.style.height = '100%'; iframe.style.border = 'none';
702
+ view.innerHTML = ''; view.appendChild(iframe); iframe.contentWindow.document.open(); iframe.contentWindow.document.write(html); iframe.contentWindow.document.close();
 
 
 
703
  return;
704
  }
 
705
  view.innerHTML = '<div class="ws-console" style="color:var(--brand-accent);">Compiling code...</div>';
706
+ const pMap = {'python':'python', 'py':'python', 'c':'c', 'cpp':'c++', 'java':'java'}; const rLang = pMap[lang];
 
 
707
  if(!rLang) { view.innerHTML = `<div class="ws-console" style="color:#cc0000;">Live Preview not supported for ${lang}.</div>`; return; }
708
 
709
  try {
710
+ const res = await fetch('https://emkc.org/api/v2/piston/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ language: rLang, version: "*", files: [{ content: d.code }] }) });
 
 
 
711
  const data = await res.json();
712
  let out = (data.compile?.output || "") + "\n" + (data.run?.output || "") + "\n" + (data.run?.stderr || "");
713
  view.innerHTML = `<div class="ws-console">${UI.escape(out.trim() || "[Execution Finished]")}</div>`;
 
717
 
718
  const MDRenderer = new marked.Renderer();
719
  MDRenderer.code = function(code, lang) {
720
+ const id = State.workspaces.length; State.workspaces.push({code: code, lang: lang});
 
721
  const highlighted = hljs.highlightAuto(code).value;
722
  return `
723
  <div style="margin: 16px 0;">
 
732
  };
733
  marked.use({ renderer: MDRenderer });
734
 
735
+ // --- 7. CHAT ENGINE (WITH TOOL CALLING UI) ---
736
  const Chat = {
737
  renderUser: (txt, attachUI) => {
738
  const c = document.getElementById('chatContainer');
 
749
  c.appendChild(w); UI.scrollToBottom();
750
  return w.querySelector('.bot-content');
751
  },
752
+
753
+ getToolHTML: (isActive) => {
754
+ return `
755
+ <div class="tool-indicator ${isActive ? 'active' : ''}">
756
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
757
+ <circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line>
758
+ </svg>
759
+ ${isActive ? 'Searching on Google Search...' : 'Searched on Google Search'}
760
+ </div><br>`;
761
+ },
762
+
763
  handleSend: async () => {
764
  if(State.isProcessing) return;
765
  const input = document.getElementById('mainInput');
766
  const text = input.value.trim();
767
  if(!text && !State.attachment) return;
768
 
769
+ // Guest Validation
770
  if(!State.user) {
771
+ if(State.guestCount >= 10) { Auth.openModal(); UI.showAuthMsg("Guest limit reached. Secure Login required.", true); return; }
772
+ State.guestCount++; localStorage.setItem('codeved_guest', State.guestCount);
 
 
 
 
 
773
  document.getElementById('uSub').innerText = `Queries: ${State.guestCount}/10`;
774
  }
775
 
776
+ State.isProcessing = true; document.getElementById('btnSend').disabled = true;
777
+ input.value = ''; input.style.height = 'auto'; document.getElementById('welcomeScreen').style.display = 'none';
 
 
778
 
779
  let payloadStr = text;
780
  let attachUI = '';
781
  let mediaArray = [];
782
+ let isSearching = text.toLowerCase().startsWith('/search'); // TOOL TRIGGER
783
 
784
  if(State.attachment) {
785
  if(State.attachment.type === 'text') {
 
792
  }
793
 
794
  Chat.renderUser(text || '[Attached Media]', attachUI);
795
+ State.history.push({ role: 'user', content: payloadStr });
796
  FileSys.discard();
797
 
798
  const botContent = Chat.renderBot();
799
+
800
+ // Show glowing tool UI immediately if it's a search
801
+ if (isSearching) {
802
+ botContent.innerHTML = Chat.getToolHTML(true) + `<div class="typing-indicator"><div class="typing-dot"></div><div class="typing-dot"></div></div>`;
803
+ }
804
 
805
  try {
806
  const res = await fetch(Config.API_ENDPOINT, {
 
808
  body: JSON.stringify({
809
  message: payloadStr, attachments: mediaArray,
810
  system_prompt: "You are CODE VED, a highly intelligent system engineered by Divy Patel. Speak purely in English.",
811
+ history: State.history
812
  })
813
  });
814
 
 
833
  if(json.choices && json.choices[0].delta.content) fullText += json.choices[0].delta.content;
834
  else if (json.response) fullText += json.response;
835
 
836
+ // Parse Markdown, Stop Tool animation if it was active
837
+ let finalHtml = marked.parse(fullText.replace(/<think>[\s\S]*?<\/think>/gi, ''));
838
+ if(isSearching) {
839
+ botContent.innerHTML = Chat.getToolHTML(false) + finalHtml;
840
+ } else {
841
+ botContent.innerHTML = finalHtml;
842
+ }
843
+
844
  UI.scrollToBottom();
845
  } catch(e){}
846
  }
847
  }
848
  }
849
+
850
+ State.history.push({ role: 'assistant', content: fullText });
851
+ HistoryManager.save();
852
+
853
  } catch(e) {
854
+ botContent.innerHTML = `<span style="color:#cc0000; font-weight:500;">Connection Offline. Backend is unreachable.</span>`;
855
  } finally {
856
  State.isProcessing = false;
857
  document.getElementById('btnSend').disabled = false;
 
862
 
863
  window.onload = () => {
864
  Auth.init();
 
865
  if(window.innerWidth > 900) { document.getElementById('btnMenuOpen').style.display = 'none'; document.getElementById('sidebar').classList.remove('collapsed'); }
866
  };
867