Spaces:
Running
Running
Vedika commited on
Update index.html
Browse files- 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',
|
| 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:
|
| 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 |
-
|
| 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:
|
|
|
|
| 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 |
-
|
| 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 |
-
|
| 137 |
-
.input-dock {
|
|
|
|
| 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; }
|
| 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="
|
| 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 |
-
<
|
| 251 |
-
</div>
|
| 252 |
|
| 253 |
-
<
|
| 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"
|
| 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> <
|
| 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
|
| 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",
|
| 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
|
| 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 |
-
|
| 452 |
-
|
| 453 |
-
|
|
|
|
| 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 |
-
|
| 463 |
-
if(
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 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 |
-
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
}
|
| 538 |
-
} catch
|
| 539 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 540 |
}
|
| 541 |
-
|
| 542 |
}
|
| 543 |
};
|
| 544 |
|
| 545 |
-
// --- 4. FILE HANDLING
|
| 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 |
-
//
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
|
| 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 |
-
//
|
| 754 |
if(!State.user) {
|
| 755 |
-
if(State.guestCount >= 10) {
|
| 756 |
-
|
| 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('
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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 |
|