Spaces:
Running
Running
Vedika commited on
Update index.html
Browse files- index.html +186 -355
index.html
CHANGED
|
@@ -1,4 +1,3 @@
|
|
| 1 |
-
|
| 2 |
<!DOCTYPE html>
|
| 3 |
<html lang="en" dir="ltr">
|
| 4 |
<head>
|
|
@@ -12,7 +11,7 @@
|
|
| 12 |
<title>Arjun 2.O - Professional Advanced AI</title>
|
| 13 |
|
| 14 |
<!-- =========================================================================================
|
| 15 |
-
EXTERNAL RESOURCES, FONTS & LIBRARIES (बाहरी स्रोत)
|
| 16 |
========================================================================================= -->
|
| 17 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 18 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
@@ -30,14 +29,14 @@
|
|
| 30 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
|
| 31 |
|
| 32 |
<!-- =========================================================================================
|
| 33 |
-
MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग)
|
| 34 |
========================================================================================= -->
|
| 35 |
<style>
|
| 36 |
/* ---------------------------------------------------------------------------------------
|
| 37 |
-
A. CSS VARIABLES, DESIGN TOKENS & BRANDING
|
| 38 |
--------------------------------------------------------------------------------------- */
|
| 39 |
:root {
|
| 40 |
-
/* Brand Identity: Saffron, White, Green (Tiranga
|
| 41 |
--brand-saffron: #FF9933;
|
| 42 |
--brand-saffron-light: rgba(255, 153, 51, 0.12);
|
| 43 |
--brand-saffron-dark: #e68a2e;
|
|
@@ -65,12 +64,11 @@
|
|
| 65 |
--text-tertiary: #9ca3af;
|
| 66 |
--text-inverse: #ffffff;
|
| 67 |
--text-error: #ef4444;
|
| 68 |
-
--text-success: #10b981;
|
| 69 |
|
| 70 |
/* Borders & Dividers */
|
| 71 |
--border-light: rgba(0, 0, 0, 0.08);
|
| 72 |
--border-medium: rgba(0, 0, 0, 0.15);
|
| 73 |
-
--border-focus: rgba(255, 153, 51, 0.
|
| 74 |
|
| 75 |
/* Shadows & Elevation */
|
| 76 |
--shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
|
|
@@ -78,7 +76,6 @@
|
|
| 78 |
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
|
| 79 |
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
|
| 80 |
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
|
| 81 |
-
--shadow-float: 0 25px 50px -12px rgba(0,0,0,0.15);
|
| 82 |
--shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06);
|
| 83 |
|
| 84 |
/* Font Families */
|
|
@@ -99,7 +96,7 @@
|
|
| 99 |
--ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
| 100 |
--ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
| 101 |
|
| 102 |
-
/* Z-Indices
|
| 103 |
--z-ambient: -1;
|
| 104 |
--z-base: 1;
|
| 105 |
--z-header: 10;
|
|
@@ -110,7 +107,6 @@
|
|
| 110 |
--z-modal: 5000;
|
| 111 |
--z-toast: 9000;
|
| 112 |
--z-live: 9999;
|
| 113 |
-
--z-offline: 10000;
|
| 114 |
}
|
| 115 |
|
| 116 |
/* ---------------------------------------------------------------------------------------
|
|
@@ -120,6 +116,7 @@
|
|
| 120 |
box-sizing: border-box;
|
| 121 |
margin: 0;
|
| 122 |
padding: 0;
|
|
|
|
| 123 |
-webkit-tap-highlight-color: transparent !important;
|
| 124 |
-webkit-touch-callout: none !important;
|
| 125 |
}
|
|
@@ -138,9 +135,8 @@
|
|
| 138 |
-moz-osx-font-smoothing: grayscale;
|
| 139 |
}
|
| 140 |
|
| 141 |
-
/*
|
| 142 |
-
*:focus
|
| 143 |
-
*:focus { outline: none; }
|
| 144 |
|
| 145 |
button, input, textarea, select {
|
| 146 |
font-family: inherit;
|
|
@@ -150,27 +146,19 @@
|
|
| 150 |
}
|
| 151 |
|
| 152 |
button { cursor: pointer; user-select: none; }
|
| 153 |
-
button:disabled { cursor: not-allowed; opacity: 0.6; }
|
| 154 |
a { color: inherit; text-decoration: none; }
|
| 155 |
img { max-width: 100%; height: auto; display: block; }
|
| 156 |
svg { flex-shrink: 0; }
|
| 157 |
|
| 158 |
-
/*
|
| 159 |
-
::-webkit-scrollbar { width:
|
| 160 |
::-webkit-scrollbar-track { background: transparent; }
|
| 161 |
-
::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.
|
| 162 |
-
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.
|
| 163 |
|
| 164 |
/* ---------------------------------------------------------------------------------------
|
| 165 |
-
C.
|
| 166 |
--------------------------------------------------------------------------------------- */
|
| 167 |
-
.network-offline-banner {
|
| 168 |
-
position: fixed; top: 0; left: 0; right: 0; background: var(--text-error); color: white;
|
| 169 |
-
text-align: center; padding: 8px; font-size: 14px; font-weight: 700; z-index: var(--z-offline);
|
| 170 |
-
transform: translateY(-100%); transition: transform var(--ease-spring); display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: var(--shadow-md);
|
| 171 |
-
}
|
| 172 |
-
.network-offline-banner.active { transform: translateY(0); }
|
| 173 |
-
|
| 174 |
.ambient-environment {
|
| 175 |
position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
|
| 176 |
background: linear-gradient(135deg, var(--brand-saffron-light) 0%, var(--bg-primary) 50%, var(--brand-green-light) 100%);
|
|
@@ -197,25 +185,21 @@
|
|
| 197 |
}
|
| 198 |
|
| 199 |
/* ---------------------------------------------------------------------------------------
|
| 200 |
-
D.
|
| 201 |
--------------------------------------------------------------------------------------- */
|
| 202 |
.toast-wrapper {
|
| 203 |
position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
|
| 204 |
z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px;
|
| 205 |
-
pointer-events: none; width: 90%; max-width:
|
| 206 |
}
|
| 207 |
.toast-notification {
|
| 208 |
-
background:
|
| 209 |
border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl);
|
| 210 |
animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards;
|
| 211 |
-
display: flex; align-items: center; gap:
|
| 212 |
-
|
| 213 |
}
|
| 214 |
-
.toast-notification
|
| 215 |
-
.toast-notification.success { background: rgba(16, 185, 129, 0.95); border-color: rgba(255,255,255,0.2); }
|
| 216 |
-
.toast-notification svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--brand-saffron); }
|
| 217 |
-
.toast-notification.error svg, .toast-notification.success svg { color: white; }
|
| 218 |
-
|
| 219 |
@keyframes toastSlideIn { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
| 220 |
@keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
|
| 221 |
|
|
@@ -230,22 +214,22 @@
|
|
| 230 |
}
|
| 231 |
.startup-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
|
| 232 |
|
| 233 |
-
.startup-logo-container { position: relative; margin-bottom: 32px; animation: popIn var(--ease-spring) 0.
|
| 234 |
.startup-logo-container img { width: 140px; height: 140px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 4px solid var(--bg-primary); position: relative; z-index: 2; }
|
| 235 |
.startup-logo-glow { position: absolute; inset: -20px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(30px); opacity: 0.4; border-radius: var(--radius-full); z-index: 1; animation: pulseGlow 3s infinite alternate; }
|
| 236 |
|
| 237 |
@keyframes pulseGlow { from { opacity: 0.3; transform: scale(0.95); } to { opacity: 0.6; transform: scale(1.05); } }
|
| 238 |
-
@keyframes popIn {
|
| 239 |
|
| 240 |
-
.startup-title { font-family: var(--font-sans); font-size: 2.
|
| 241 |
-
.startup-desc { font-size: 1.
|
| 242 |
|
| 243 |
-
.btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: 1.125rem; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 10px 25px rgba(0,0,0,0.15); animation: slideUp var(--ease-smooth) 0.
|
| 244 |
.btn-startup-launch::before { content: ''; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); transform: skewX(-20deg); transition: 0.5s; }
|
| 245 |
.btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); }
|
| 246 |
.btn-startup-launch:hover::before { left: 150%; }
|
| 247 |
|
| 248 |
-
@keyframes slideUp { from { opacity: 0; transform: translateY(
|
| 249 |
|
| 250 |
/* ---------------------------------------------------------------------------------------
|
| 251 |
F. CORE APPLICATION LAYOUT & SIDEBAR
|
|
@@ -257,11 +241,11 @@
|
|
| 257 |
.sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
|
| 258 |
|
| 259 |
.brand-identity { display: flex; align-items: center; gap: 14px; text-decoration: none; }
|
| 260 |
-
.brand-identity img { width:
|
| 261 |
-
.brand-identity:hover img { transform: scale(1.08) rotate(-
|
| 262 |
.brand-typography { display: flex; flex-direction: column; }
|
| 263 |
.brand-name { font-family: var(--font-sans); font-weight: 900; font-size: 20px; color: var(--text-primary); letter-spacing: -0.5px; line-height: 1.1; }
|
| 264 |
-
.brand-edition { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; background: linear-gradient(90deg, var(--brand-saffron
|
| 265 |
|
| 266 |
.btn-mobile-close { display: none; background: rgba(0,0,0,0.05); border: none; width: 36px; height: 36px; border-radius: 50%; color: var(--text-primary); cursor: pointer; align-items: center; justify-content: center; transition: var(--ease-fast); }
|
| 267 |
.btn-mobile-close:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
|
|
@@ -280,7 +264,7 @@
|
|
| 280 |
.user-details { flex: 1; overflow: hidden; }
|
| 281 |
.user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
| 282 |
.user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
|
| 283 |
-
.user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow:
|
| 284 |
.btn-system-logout { background: rgba(239, 68, 68, 0.08); color: var(--text-error); border: none; width: 38px; height: 38px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-fast); }
|
| 285 |
.btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
|
| 286 |
|
|
@@ -301,14 +285,13 @@
|
|
| 301 |
--------------------------------------------------------------------------------------- */
|
| 302 |
.main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; }
|
| 303 |
|
| 304 |
-
.chat-top-bar { padding:
|
| 305 |
.top-bar-left { display: flex; align-items: center; gap: 16px; }
|
| 306 |
.btn-hamburger { display: none; background: var(--bg-primary); border: 1px solid var(--border-light); cursor: pointer; color: var(--text-primary); width: 42px; height: 42px; border-radius: var(--radius-sm); align-items: center; justify-content: center; box-shadow: var(--shadow-sm); transition: var(--ease-fast); }
|
| 307 |
.btn-hamburger:hover { background: var(--bg-secondary); }
|
| 308 |
|
| 309 |
-
.system-status-pill { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 700; color: var(--text-primary); padding: 8px 18px; background: var(--bg-secondary); border-radius: var(--radius-full); border: 1px solid var(--border-light);
|
| 310 |
-
.pulse-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 0 3px rgba(19, 136, 8, 0.2); animation: statusPulse 2s infinite;
|
| 311 |
-
.system-status-pill.offline .pulse-dot { background: var(--text-error); box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2); animation: none; }
|
| 312 |
@keyframes statusPulse { 0% { box-shadow: 0 0 0 0 rgba(19,136,8,0.4); } 70% { box-shadow: 0 0 0 6px rgba(19,136,8,0); } 100% { box-shadow: 0 0 0 0 rgba(19,136,8,0); } }
|
| 313 |
|
| 314 |
/* DYNAMIC LIVE MODE ACTIVATOR */
|
|
@@ -326,12 +309,11 @@
|
|
| 326 |
.hero-avatar-wrapper img { width: 100px; height: 100px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 3px solid var(--bg-primary); position: relative; z-index: 2; }
|
| 327 |
.hero-avatar-glow { position: absolute; inset: -12px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(25px); opacity: 0.35; border-radius: 40px; z-index: 1; animation: rotateGlow 10s linear infinite;}
|
| 328 |
@keyframes rotateGlow { 100% { transform: rotate(360deg); } }
|
| 329 |
-
@keyframes slideUpFade { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } }
|
| 330 |
|
| 331 |
-
.hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary);
|
| 332 |
.hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; }
|
| 333 |
|
| 334 |
-
/* GUEST BADGE LIMIT DISPLAY */
|
| 335 |
.guest-warning-badge { font-size: 13px; font-weight: 700; color: var(--text-error); background: #fee2e2; padding: 10px 20px; border-radius: var(--radius-full); margin-bottom: 32px; display: none; align-items: center; gap: 8px; border: 1px solid #fca5a5; box-shadow: var(--shadow-sm); }
|
| 336 |
.guest-warning-badge svg { width: 18px; height: 18px; }
|
| 337 |
|
|
@@ -347,8 +329,8 @@
|
|
| 347 |
/* ---------------------------------------------------------------------------------------
|
| 348 |
H. CHAT MESSAGE BUBBLES & PREVIEWS
|
| 349 |
--------------------------------------------------------------------------------------- */
|
| 350 |
-
.chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.
|
| 351 |
-
@keyframes messagePopIn { from { opacity: 0; transform: translateY(
|
| 352 |
.chat-message-row.user-msg { flex-direction: row-reverse; align-self: flex-end; }
|
| 353 |
.chat-message-row.bot-msg { align-self: flex-start; }
|
| 354 |
|
|
@@ -364,8 +346,7 @@
|
|
| 364 |
.file-badge svg { width: 12px; height: 12px; }
|
| 365 |
|
| 366 |
/* In-Bubble File Previews */
|
| 367 |
-
.chat-in-bubble-img { max-width: 320px; max-height: 320px; border-radius: var(--radius-md); object-fit: cover; border: 2px solid rgba(255,255,255,0.2); box-shadow: var(--shadow-md); margin-bottom: 12px;
|
| 368 |
-
.chat-in-bubble-img:hover { transform: scale(1.02); }
|
| 369 |
.chat-file-card { display: flex; align-items: center; gap: 14px; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); padding: 12px 18px; border-radius: var(--radius-md); margin-bottom: 12px; max-width: 350px; backdrop-filter: blur(10px); }
|
| 370 |
.chat-file-card .icon { font-size: 24px; background: rgba(0,0,0,0.1); width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); }
|
| 371 |
.chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
@@ -385,29 +366,15 @@
|
|
| 385 |
.btn-bot-action.action-tts { color: var(--brand-green-dark); border-color: rgba(19, 136, 8, 0.25); background: var(--brand-green-light); }
|
| 386 |
.btn-bot-action.action-tts:hover { background: rgba(19, 136, 8, 0.2); }
|
| 387 |
|
| 388 |
-
/* Markdown
|
| 389 |
.chat-bubble p { margin-bottom: 16px; }
|
| 390 |
.chat-bubble p:last-child { margin-bottom: 0; }
|
| 391 |
.chat-bubble strong { font-weight: 800; color: inherit; }
|
| 392 |
-
.chat-bubble em { font-style: italic; }
|
| 393 |
-
.chat-bubble ul, .chat-bubble ol { margin-bottom: 16px; padding-left: 24px; }
|
| 394 |
-
.chat-bubble li { margin-bottom: 6px; }
|
| 395 |
-
.chat-bubble blockquote { border-left: 4px solid var(--brand-saffron); padding-left: 16px; margin: 16px 0; color: var(--text-secondary); background: var(--bg-secondary); padding: 12px 16px; border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }
|
| 396 |
-
|
| 397 |
-
/* Advanced Tables */
|
| 398 |
-
.chat-bubble table { width: 100%; border-collapse: collapse; margin: 20px 0; border-radius: var(--radius-sm); overflow: hidden; box-shadow: var(--shadow-sm); }
|
| 399 |
-
.chat-bubble th, .chat-bubble td { border: 1px solid var(--border-light); padding: 12px 16px; text-align: left; }
|
| 400 |
-
.chat-bubble th { background: var(--bg-secondary); font-weight: 700; color: var(--text-primary); }
|
| 401 |
-
.chat-bubble tr:nth-child(even) { background: var(--bg-tertiary); }
|
| 402 |
-
|
| 403 |
.chat-bubble code { font-family: var(--font-mono); background: rgba(0,0,0,0.06); padding: 4px 8px; border-radius: 6px; font-size: 0.85em; color: #d946ef; font-weight: 600; border: 1px solid rgba(0,0,0,0.05); }
|
| 404 |
.user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); border-color: rgba(255,255,255,0.1); }
|
| 405 |
-
|
| 406 |
.chat-bubble img { max-width: 100%; border-radius: var(--radius-md); margin: 16px 0; box-shadow: var(--shadow-lg); border: 1px solid var(--border-light); display: block; }
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
.chat-bubble pre { background: #1e1e2e; color: #a6adc8; padding: 0; border-radius: var(--radius-md); overflow: hidden; margin: 20px 0; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; border: 1px solid #313244; box-shadow: var(--shadow-md); }
|
| 410 |
-
.chat-bubble pre code { background: transparent; color: inherit; padding: 20px; font-weight: 400; border: none; display: block; overflow-x: auto; }
|
| 411 |
|
| 412 |
/* Streaming Loading UI Component */
|
| 413 |
.streaming-code-container { background: #1e1e2e; border-radius: var(--radius-md); border: 1px solid #313244; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); }
|
|
@@ -431,12 +398,12 @@
|
|
| 431 |
I. BOTTOM INPUT DOCK & TOOLS
|
| 432 |
--------------------------------------------------------------------------------------- */
|
| 433 |
.input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); }
|
| 434 |
-
.input-master-container { display: flex; flex-direction: column; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); border: 1px solid var(--border-light); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); transition: var(--ease-smooth);
|
| 435 |
.input-master-container:focus-within { border-color: var(--brand-saffron); box-shadow: 0 20px 40px -5px rgba(255,153,51,0.15), 0 0 0 4px var(--brand-saffron-light); }
|
| 436 |
|
| 437 |
-
/* Upload Preview Header */
|
| 438 |
-
.upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px;
|
| 439 |
-
.upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease;
|
| 440 |
.upload-thumb { width: 52px; height: 52px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border-light); display: flex; justify-content: center; align-items: center; background: var(--bg-tertiary); font-size: 24px; box-shadow: var(--shadow-sm); }
|
| 441 |
.upload-meta { flex: 1; }
|
| 442 |
.upload-filename { font-size: 14px; font-weight: 700; color: var(--text-primary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
@@ -451,13 +418,9 @@
|
|
| 451 |
.main-textarea { flex: 1; border: none; outline: none; background: transparent; font-family: var(--font-sans); font-size: 16px; color: var(--text-primary); line-height: 1.5; resize: none; max-height: 200px; min-height: 24px; padding: 12px 0; margin: 0 8px; font-weight: 500; }
|
| 452 |
.main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; }
|
| 453 |
|
| 454 |
-
/* Real-time Interim Text Feedback */
|
| 455 |
-
.interim-text-overlay { position: absolute; pointer-events: none; color: var(--text-tertiary); font-style: italic; z-index: 2; padding: 12px 0; margin: 0 8px; left: 140px; top: 14px; right: 80px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; display: none; }
|
| 456 |
-
.interim-text-overlay.active { display: block; }
|
| 457 |
-
|
| 458 |
/* Attachment Menu Dropdown */
|
| 459 |
.attachment-module { position: relative; }
|
| 460 |
-
.btn-tool-icon { width: 44px; height: 44px; border-radius: var(--radius-md); background: transparent; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); transition: var(--ease-fast);
|
| 461 |
.btn-tool-icon:hover { background: var(--bg-tertiary); color: var(--text-primary); }
|
| 462 |
.btn-tool-icon svg { width: 24px; height: 24px; stroke-width: 2; }
|
| 463 |
|
|
@@ -475,19 +438,15 @@
|
|
| 475 |
.language-toggle-chip.hindi-active { background: var(--brand-green-light); color: var(--brand-green-dark); border-color: var(--brand-green); }
|
| 476 |
.language-toggle-chip svg { width: 16px; height: 16px; }
|
| 477 |
|
| 478 |
-
.btn-mic-tool {
|
| 479 |
-
|
| 480 |
-
.btn-mic-tool.active-listening::before { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--text-error); animation: rippleMic 1.5s infinite ease-out; }
|
| 481 |
-
@keyframes rippleMic { 0% { transform: scale(0.8); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } }
|
| 482 |
|
| 483 |
/* Master Send Button */
|
| 484 |
-
.btn-master-send { width: 48px; height: 48px; border-radius: 16px; border: none; background: linear-gradient(135deg, var(--brand-saffron) 0%, var(--brand-green) 100%); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 6px 20px rgba(19, 136, 8, 0.25);
|
| 485 |
-
.btn-master-send
|
| 486 |
-
.btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; position: relative; z-index: 2; }
|
| 487 |
.btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); }
|
| 488 |
-
.btn-master-send:hover::before { left: 100%; }
|
| 489 |
.btn-master-send:hover svg { transform: translate(2px, -2px); }
|
| 490 |
-
.btn-master-send:disabled { opacity: 0.
|
| 491 |
|
| 492 |
.bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; }
|
| 493 |
|
|
@@ -508,16 +467,12 @@
|
|
| 508 |
.btn-workspace-tool.close:hover { color: #e06c75; background: rgba(224, 108, 117, 0.1); }
|
| 509 |
|
| 510 |
.workspace-editor-surface { flex: 1; overflow-y: auto; background: #282c34; padding: 24px; position: relative; }
|
| 511 |
-
|
| 512 |
-
/* Line Numbers Implementation for Workspace */
|
| 513 |
-
.workspace-editor-content { display: flex; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; }
|
| 514 |
-
.workspace-line-numbers { padding-right: 15px; border-right: 1px solid #3e4451; color: #5c6370; text-align: right; user-select: none; }
|
| 515 |
-
.workspace-editor-surface pre { margin: 0; padding: 0 0 0 15px; background: transparent; overflow-x: auto; color: #abb2bf; border: none; box-shadow: none; flex: 1; }
|
| 516 |
|
| 517 |
/* ---------------------------------------------------------------------------------------
|
| 518 |
K. LIVE MODE FULLSCREEN OVERLAY
|
| 519 |
--------------------------------------------------------------------------------------- */
|
| 520 |
-
.live-mode-viewport { position: fixed; inset: 0; background: rgba(255, 255, 255, 0.98); z-index: var(--z-live); display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity var(--ease-smooth);
|
| 521 |
.live-mode-viewport.active { opacity: 1; pointer-events: auto; }
|
| 522 |
.btn-close-live { position: absolute; top: 40px; right: 40px; background: rgba(0,0,0,0.04); border: none; width: 56px; height: 56px; border-radius: 50%; font-size: 24px; cursor: pointer; transition: var(--ease-spring); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); }
|
| 523 |
.btn-close-live:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
|
|
@@ -525,22 +480,22 @@
|
|
| 525 |
.pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
|
| 526 |
.energy-core { width: 120px; height: 120px; border-radius: 50%; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); box-shadow: 0 0 50px rgba(19, 136, 8, 0.5); position: relative; z-index: 2; transition: transform 0.15s ease-out; }
|
| 527 |
.energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
|
| 528 |
-
@keyframes coreSpeak { 0% { transform: scale(1); box-shadow: 0 0 30px rgba(19,136,8,0.4); } 100% { transform: scale(1.
|
| 529 |
|
| 530 |
.energy-ring { position: absolute; inset: 0; border: 3px solid var(--brand-saffron); border-radius: 50%; opacity: 0; animation: energyRipple 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite; }
|
| 531 |
.energy-ring:nth-child(2) { animation-delay: 0.8s; border-color: var(--brand-green); }
|
| 532 |
.energy-ring:nth-child(3) { animation-delay: 1.6s; border-color: var(--text-primary); }
|
| 533 |
@keyframes energyRipple { 0% { transform: scale(0.4); opacity: 1; border-width: 6px; } 100% { transform: scale(1.6); opacity: 0; border-width: 1px; } }
|
| 534 |
|
| 535 |
-
.live-feedback-status { font-size: 28px; font-weight: 900; color: var(--text-primary); margin-bottom: 16px; font-family: var(--font-sans); letter-spacing: -0.5px;
|
| 536 |
-
.live-feedback-text { font-size: 18px; color: var(--text-secondary); max-width: 700px; text-align: center; line-height: 1.6; min-height: 60px; font-weight: 500; padding: 0 20px;
|
| 537 |
|
| 538 |
.live-control-deck { display: flex; gap: 24px; margin-top: 50px; }
|
| 539 |
.btn-live-deck { width: 80px; height: 80px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: var(--shadow-lg); transition: var(--ease-spring); }
|
| 540 |
.btn-live-deck.mic-control { background: var(--bg-primary); border: 3px solid var(--border-light); color: var(--text-primary); }
|
| 541 |
.btn-live-deck.mic-control:hover { transform: translateY(-6px); border-color: var(--brand-saffron); color: var(--brand-saffron); box-shadow: var(--shadow-xl); }
|
| 542 |
.btn-live-deck.mic-control.is-recording { background: var(--text-error); color: white; border-color: var(--text-error); animation: pulseMicLive 1.2s infinite; }
|
| 543 |
-
@keyframes pulseMicLive { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.6); } 70% { box-shadow: 0 0 0
|
| 544 |
|
| 545 |
/* Scroll Trigger Button */
|
| 546 |
.btn-scroll-trigger { position: absolute; bottom: 150px; left: 50%; width: 48px; height: 48px; border-radius: 50%; background: var(--bg-glass); backdrop-filter: blur(15px); border: 1px solid var(--border-light); box-shadow: var(--shadow-lg); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); opacity: 0; pointer-events: none; transform: translateX(-50%) translateY(20px); transition: var(--ease-smooth); z-index: 20; }
|
|
@@ -553,7 +508,7 @@
|
|
| 553 |
.secure-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(10px); z-index: var(--z-modal); display: none; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; }
|
| 554 |
.secure-modal-surface { background: var(--bg-primary); padding: 44px; border-radius: var(--radius-xl); width: 90%; max-width: 460px; box-shadow: var(--shadow-xl); position: relative; border: 1px solid rgba(255,255,255,0.4); }
|
| 555 |
.btn-modal-dismiss { position: absolute; top: 24px; right: 24px; background: var(--bg-secondary); border: none; width: 36px; height: 36px; border-radius: 50%; font-size: 18px; color: var(--text-secondary); cursor: pointer; transition: 0.2s; display: flex; align-items: center; justify-content: center; }
|
| 556 |
-
.btn-modal-dismiss:hover { background: #fee2e2; color: var(--text-error);
|
| 557 |
.modal-brand-header { text-align: center; margin-bottom: 36px; font-family: var(--font-sans); font-size: 28px; font-weight: 900; color: var(--text-primary); letter-spacing: -0.5px; }
|
| 558 |
|
| 559 |
.auth-tab-switch { display: flex; background: var(--bg-secondary); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; }
|
|
@@ -607,20 +562,11 @@
|
|
| 607 |
|
| 608 |
.input-tools-row { flex-wrap: wrap; }
|
| 609 |
.main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; }
|
| 610 |
-
.interim-text-overlay { left: 15px; top: 12px; }
|
| 611 |
}
|
| 612 |
</style>
|
| 613 |
</head>
|
| 614 |
<body>
|
| 615 |
|
| 616 |
-
<!-- =========================================================================================
|
| 617 |
-
DOM STRUCTURE: OFFLINE BANNER
|
| 618 |
-
========================================================================================= -->
|
| 619 |
-
<div id="networkStatusBanner" class="network-offline-banner">
|
| 620 |
-
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>
|
| 621 |
-
System Offline. Please check your internet connection.
|
| 622 |
-
</div>
|
| 623 |
-
|
| 624 |
<!-- =========================================================================================
|
| 625 |
DOM STRUCTURE: NOTIFICATIONS
|
| 626 |
========================================================================================= -->
|
|
@@ -687,7 +633,7 @@
|
|
| 687 |
<img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo">
|
| 688 |
<div class="brand-typography">
|
| 689 |
<span class="brand-name">ARJUN 2.O</span>
|
| 690 |
-
<span class="brand-edition">
|
| 691 |
</div>
|
| 692 |
</a>
|
| 693 |
<button class="btn-mobile-close" id="btnSidebarClose">
|
|
@@ -725,7 +671,7 @@
|
|
| 725 |
<!-- Wipe Memory Button -->
|
| 726 |
<button class="btn-erase-memory" id="btnClearMemory">
|
| 727 |
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
|
| 728 |
-
Wipe
|
| 729 |
</button>
|
| 730 |
</div>
|
| 731 |
</aside>
|
|
@@ -739,9 +685,9 @@
|
|
| 739 |
<button class="btn-hamburger" id="btnSidebarOpen">
|
| 740 |
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2.5" fill="none"><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>
|
| 741 |
</button>
|
| 742 |
-
<div class="system-status-pill"
|
| 743 |
<div class="pulse-dot"></div>
|
| 744 |
-
|
| 745 |
</div>
|
| 746 |
</div>
|
| 747 |
|
|
@@ -796,7 +742,7 @@
|
|
| 796 |
|
| 797 |
<!-- File Preview Component -->
|
| 798 |
<div class="upload-preview-bar" id="filePreviewBar">
|
| 799 |
-
<img class="upload-thumb" id="previewImgThumb" src=""
|
| 800 |
<div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div>
|
| 801 |
<div class="upload-meta">
|
| 802 |
<div class="upload-filename" id="previewFileName">document.pdf</div>
|
|
@@ -805,7 +751,7 @@
|
|
| 805 |
File ready to be transmitted
|
| 806 |
</div>
|
| 807 |
</div>
|
| 808 |
-
<button class="btn-discard-upload" id="btnDiscardFile"
|
| 809 |
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
| 810 |
</button>
|
| 811 |
</div>
|
|
@@ -857,11 +803,7 @@
|
|
| 857 |
</button>
|
| 858 |
|
| 859 |
<!-- Expanding Text Area -->
|
| 860 |
-
<
|
| 861 |
-
<!-- STT Interim Feedback Overlay -->
|
| 862 |
-
<div id="interimTextOverlay" class="interim-text-overlay"></div>
|
| 863 |
-
<textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1" style="width: 100%;"></textarea>
|
| 864 |
-
</div>
|
| 865 |
|
| 866 |
<!-- Master Send Button -->
|
| 867 |
<button class="btn-master-send" id="masterSendBtn">
|
|
@@ -891,10 +833,7 @@
|
|
| 891 |
</div>
|
| 892 |
</div>
|
| 893 |
<div class="workspace-editor-surface">
|
| 894 |
-
<
|
| 895 |
-
<div class="workspace-line-numbers" id="wsLineNumbers">1</div>
|
| 896 |
-
<pre><code id="workspaceCodeBlock" class="hljs"></code></pre>
|
| 897 |
-
</div>
|
| 898 |
</div>
|
| 899 |
</aside>
|
| 900 |
</div>
|
|
@@ -944,8 +883,11 @@
|
|
| 944 |
</div>
|
| 945 |
|
| 946 |
<!-- =========================================================================================
|
| 947 |
-
MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
|
| 948 |
========================================================================================= -->
|
|
|
|
|
|
|
|
|
|
| 949 |
<script>
|
| 950 |
// =======================================================================================
|
| 951 |
// 1. CONFIGURATION & STATE MANAGEMENT
|
|
@@ -955,7 +897,6 @@
|
|
| 955 |
LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
|
| 956 |
PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
|
| 957 |
API_ENDPOINT: '/api/chat', // Uses relative path to connect to Flask App.py
|
| 958 |
-
MAX_FILE_SIZE_MB: 10, // Prevent UI freeze on giant files
|
| 959 |
};
|
| 960 |
|
| 961 |
// Initialize PDF worker
|
|
@@ -973,19 +914,17 @@
|
|
| 973 |
isStreamingActive: false,
|
| 974 |
isLiveModeEngaged: false,
|
| 975 |
gradioClient: null,
|
| 976 |
-
isMicRecording: false
|
| 977 |
-
isOnline: navigator.onLine
|
| 978 |
};
|
| 979 |
|
| 980 |
-
// Initialize Gradio Client Dynamically
|
| 981 |
window.initGradioEngine = async function() {
|
| 982 |
try {
|
| 983 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
| 984 |
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
|
| 985 |
console.log("Neural TTS Engine connected successfully to Gradio.");
|
| 986 |
} catch(err) {
|
| 987 |
-
console.
|
| 988 |
-
// Non-blocking failure, app still works
|
| 989 |
}
|
| 990 |
};
|
| 991 |
window.initGradioEngine();
|
|
@@ -994,37 +933,38 @@
|
|
| 994 |
// 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners)
|
| 995 |
// =======================================================================================
|
| 996 |
const Utils = {
|
| 997 |
-
showToast: (message
|
| 998 |
const container = document.getElementById('toast-container');
|
| 999 |
const toast = document.createElement('div');
|
| 1000 |
-
toast.className =
|
| 1001 |
-
|
| 1002 |
-
let icon = '<polyline points="20 6 9 17 4 12"></polyline>'; // Checkmark
|
| 1003 |
-
if (type === 'error') icon = '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>';
|
| 1004 |
-
|
| 1005 |
-
toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">${icon}</svg> ${message}`;
|
| 1006 |
container.appendChild(toast);
|
| 1007 |
-
setTimeout(() =>
|
| 1008 |
},
|
| 1009 |
|
| 1010 |
escapeHTML: (str) => {
|
| 1011 |
-
if (!str) return '';
|
| 1012 |
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
| 1013 |
},
|
| 1014 |
|
| 1015 |
-
// ✨ Intelligent Text Cleaner for TTS (Ignores code, links, images)
|
| 1016 |
cleanTextForVoice: (rawText) => {
|
| 1017 |
if(!rawText) return "";
|
| 1018 |
let cleaned = rawText;
|
| 1019 |
|
| 1020 |
-
// Remove Markdown
|
| 1021 |
-
cleaned = cleaned.replace(/```[\s\S]*?```/g, '');
|
| 1022 |
-
|
| 1023 |
-
cleaned = cleaned.replace(/
|
| 1024 |
-
|
| 1025 |
-
cleaned = cleaned.replace(/
|
| 1026 |
-
|
| 1027 |
-
cleaned = cleaned.replace(/[*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1028 |
|
| 1029 |
return cleaned.trim();
|
| 1030 |
},
|
|
@@ -1034,7 +974,6 @@
|
|
| 1034 |
const textArea = document.createElement("textarea");
|
| 1035 |
textArea.value = text;
|
| 1036 |
textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed";
|
| 1037 |
-
textArea.style.opacity = "0";
|
| 1038 |
document.body.appendChild(textArea);
|
| 1039 |
textArea.focus(); textArea.select();
|
| 1040 |
|
|
@@ -1042,13 +981,13 @@
|
|
| 1042 |
const successful = document.execCommand('copy');
|
| 1043 |
if (successful) {
|
| 1044 |
const originalHTML = btnElement.innerHTML;
|
| 1045 |
-
btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied
|
| 1046 |
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
|
| 1047 |
} else {
|
| 1048 |
-
Utils.showToast("Clipboard access denied by browser."
|
| 1049 |
}
|
| 1050 |
} catch (err) {
|
| 1051 |
-
Utils.showToast("System error copying text."
|
| 1052 |
}
|
| 1053 |
document.body.removeChild(textArea);
|
| 1054 |
},
|
|
@@ -1060,7 +999,7 @@
|
|
| 1060 |
}
|
| 1061 |
navigator.clipboard.writeText(textToCopy).then(() => {
|
| 1062 |
const originalHTML = btnElement.innerHTML;
|
| 1063 |
-
btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied
|
| 1064 |
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
|
| 1065 |
}).catch((err) => {
|
| 1066 |
console.warn('Modern API failed, utilizing fallback...', err);
|
|
@@ -1070,7 +1009,7 @@
|
|
| 1070 |
};
|
| 1071 |
|
| 1072 |
// =======================================================================================
|
| 1073 |
-
// 3. AUTHENTICATION & SYNC MANAGER
|
| 1074 |
// =======================================================================================
|
| 1075 |
const AuthManager = {
|
| 1076 |
initUI: () => {
|
|
@@ -1109,9 +1048,8 @@
|
|
| 1109 |
document.getElementById(nextId).classList.add('active');
|
| 1110 |
},
|
| 1111 |
|
|
|
|
| 1112 |
process: async (actionType) => {
|
| 1113 |
-
if (!AppState.isOnline) return Utils.showToast("System is offline. Cannot authenticate.", "error");
|
| 1114 |
-
|
| 1115 |
const payload = { action: actionType };
|
| 1116 |
let buttonId = '';
|
| 1117 |
|
|
@@ -1119,18 +1057,18 @@
|
|
| 1119 |
payload.name = document.getElementById('authRegName').value.trim();
|
| 1120 |
payload.email = document.getElementById('authRegEmail').value.trim();
|
| 1121 |
payload.phone = "0000000000"; payload.organization = "Arjun Base";
|
| 1122 |
-
if (!payload.email || !payload.name) return Utils.showToast("Identification details required."
|
| 1123 |
buttonId = 'btn-fire-reg-otp';
|
| 1124 |
}
|
| 1125 |
else if (actionType === 'login_send_otp') {
|
| 1126 |
payload.email = document.getElementById('authLogEmail').value.trim();
|
| 1127 |
-
if (!payload.email) return Utils.showToast("Email required for validation."
|
| 1128 |
buttonId = 'btn-fire-log-otp';
|
| 1129 |
}
|
| 1130 |
else if (actionType === 'register_verify' || actionType === 'login_verify') {
|
| 1131 |
payload.email = document.getElementById(actionType === 'register_verify' ? 'authRegEmail' : 'authLogEmail').value.trim();
|
| 1132 |
payload.otp = document.getElementById(actionType === 'register_verify' ? 'authRegOTP' : 'authLogOTP').value.trim();
|
| 1133 |
-
if (!payload.otp) return Utils.showToast("Security token required."
|
| 1134 |
buttonId = actionType === 'register_verify' ? 'btn-fire-reg-verify' : 'btn-fire-log-verify';
|
| 1135 |
}
|
| 1136 |
|
|
@@ -1140,6 +1078,7 @@
|
|
| 1140 |
triggerBtn.innerText = 'Establishing Connection...';
|
| 1141 |
|
| 1142 |
try {
|
|
|
|
| 1143 |
const response = await fetch(Config.GAS_URL, {
|
| 1144 |
method: 'POST',
|
| 1145 |
mode: 'cors',
|
|
@@ -1150,7 +1089,7 @@
|
|
| 1150 |
const result = await response.json();
|
| 1151 |
|
| 1152 |
if (result.status === 'success') {
|
| 1153 |
-
Utils.showToast(result.message
|
| 1154 |
if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2');
|
| 1155 |
else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2');
|
| 1156 |
else if (actionType === 'register_verify' || actionType === 'login_verify') {
|
|
@@ -1161,11 +1100,11 @@
|
|
| 1161 |
ChatEngine.syncHistoryFromCloud();
|
| 1162 |
}
|
| 1163 |
} else {
|
| 1164 |
-
Utils.showToast(result.message
|
| 1165 |
}
|
| 1166 |
} catch (error) {
|
| 1167 |
console.error("Auth Network Error: ", error);
|
| 1168 |
-
Utils.showToast("Encrypted gateway error. Check network."
|
| 1169 |
}
|
| 1170 |
|
| 1171 |
triggerBtn.disabled = false;
|
|
@@ -1214,48 +1153,22 @@
|
|
| 1214 |
|
| 1215 |
toggleAttachMenu: () => {
|
| 1216 |
document.getElementById('attachDropdownMenu').classList.toggle('visible');
|
| 1217 |
-
},
|
| 1218 |
-
|
| 1219 |
-
updateNetworkStatus: () => {
|
| 1220 |
-
AppState.isOnline = navigator.onLine;
|
| 1221 |
-
const banner = document.getElementById('networkStatusBanner');
|
| 1222 |
-
const pill = document.getElementById('mainStatusPill');
|
| 1223 |
-
const pillText = document.getElementById('mainStatusText');
|
| 1224 |
-
|
| 1225 |
-
if (AppState.isOnline) {
|
| 1226 |
-
banner.classList.remove('active');
|
| 1227 |
-
pill.classList.remove('offline');
|
| 1228 |
-
pillText.innerText = 'System Online';
|
| 1229 |
-
if(!AppState.isProcessing && AppState.history.length > 0) {
|
| 1230 |
-
Utils.showToast("Network connection restored.", "success");
|
| 1231 |
-
}
|
| 1232 |
-
} else {
|
| 1233 |
-
banner.classList.add('active');
|
| 1234 |
-
pill.classList.add('offline');
|
| 1235 |
-
pillText.innerText = 'System Offline';
|
| 1236 |
-
}
|
| 1237 |
}
|
| 1238 |
};
|
| 1239 |
|
| 1240 |
// =======================================================================================
|
| 1241 |
-
// 5. SPEECH & TTS ENGINE (
|
| 1242 |
// =======================================================================================
|
| 1243 |
const VoiceEngine = {
|
| 1244 |
recognition: null,
|
| 1245 |
currentLanguage: 'en-IN',
|
| 1246 |
-
|
| 1247 |
-
silenceTimer: null, // ✨ KEY FIX: Detects silence for Live Mode dispatch
|
| 1248 |
-
|
| 1249 |
init: () => {
|
| 1250 |
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
| 1251 |
-
if (!SR)
|
| 1252 |
-
console.warn("Speech Recognition API not supported in this browser.");
|
| 1253 |
-
document.getElementById('masterVoiceBtn').style.display = 'none';
|
| 1254 |
-
return;
|
| 1255 |
-
}
|
| 1256 |
|
| 1257 |
VoiceEngine.recognition = new SR();
|
| 1258 |
-
//
|
| 1259 |
VoiceEngine.recognition.continuous = true;
|
| 1260 |
VoiceEngine.recognition.interimResults = true;
|
| 1261 |
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
|
|
@@ -1263,12 +1176,7 @@
|
|
| 1263 |
VoiceEngine.recognition.onstart = () => {
|
| 1264 |
AppState.isMicRecording = true;
|
| 1265 |
document.getElementById('masterVoiceBtn').classList.add('active-listening');
|
| 1266 |
-
|
| 1267 |
-
// SAVE BASE TEXT: So we don't blindly append duplicates
|
| 1268 |
-
VoiceEngine.baseInputText = document.getElementById('mainChatInput').value;
|
| 1269 |
-
|
| 1270 |
if (AppState.isLiveModeEngaged) {
|
| 1271 |
-
VoiceEngine.baseInputText = ''; // Clear for live mode
|
| 1272 |
document.getElementById('liveMicBtn').classList.add('is-recording');
|
| 1273 |
document.getElementById('liveStatusText').innerText = "Listening...";
|
| 1274 |
document.getElementById('liveOrb').classList.remove('speaking');
|
|
@@ -1277,56 +1185,34 @@
|
|
| 1277 |
};
|
| 1278 |
|
| 1279 |
VoiceEngine.recognition.onresult = (event) => {
|
| 1280 |
-
|
| 1281 |
-
|
| 1282 |
-
|
| 1283 |
-
let finalSpeech = '';
|
| 1284 |
-
let interimSpeech = '';
|
| 1285 |
|
| 1286 |
-
|
| 1287 |
-
// entirely because we construct the absolute truth string every tick.
|
| 1288 |
-
for (let i = 0; i < event.results.length; ++i) {
|
| 1289 |
if (event.results[i].isFinal) {
|
| 1290 |
-
|
| 1291 |
} else {
|
| 1292 |
-
|
| 1293 |
}
|
| 1294 |
}
|
| 1295 |
|
| 1296 |
-
|
| 1297 |
-
|
| 1298 |
-
|
| 1299 |
-
|
| 1300 |
-
}
|
| 1301 |
-
|
| 1302 |
-
if (AppState.isLiveModeEngaged) {
|
| 1303 |
-
// Update UI for Live Mode
|
| 1304 |
-
document.getElementById('liveTranscriptText').innerText = totalNewSpeech ? `"${totalNewSpeech}"` : "Listening...";
|
| 1305 |
-
document.getElementById('mainChatInput').value = totalNewSpeech;
|
| 1306 |
-
|
| 1307 |
-
// ✨ VAD / SILENCE DETECTOR: Wait 1.8 seconds of complete silence before dispatching
|
| 1308 |
-
VoiceEngine.silenceTimer = setTimeout(() => {
|
| 1309 |
-
if (totalNewSpeech.trim().length > 0) {
|
| 1310 |
-
VoiceEngine.recognition.stop();
|
| 1311 |
-
// stop() will naturally trigger onend, which handles dispatch
|
| 1312 |
-
}
|
| 1313 |
-
}, 1800);
|
| 1314 |
-
|
| 1315 |
-
} else {
|
| 1316 |
-
// Regular chat mode: append intelligently to base text
|
| 1317 |
-
const separator = (VoiceEngine.baseInputText && totalNewSpeech && !VoiceEngine.baseInputText.endsWith(' ')) ? ' ' : '';
|
| 1318 |
-
const combinedText = VoiceEngine.baseInputText + separator + totalNewSpeech;
|
| 1319 |
-
|
| 1320 |
-
document.getElementById('mainChatInput').value = combinedText;
|
| 1321 |
-
UIManager.autoGrowTextArea(document.getElementById('mainChatInput'));
|
| 1322 |
|
| 1323 |
-
|
| 1324 |
-
|
| 1325 |
-
|
| 1326 |
-
|
| 1327 |
-
|
|
|
|
|
|
|
|
|
|
| 1328 |
} else {
|
| 1329 |
-
|
|
|
|
|
|
|
| 1330 |
}
|
| 1331 |
}
|
| 1332 |
};
|
|
@@ -1334,31 +1220,20 @@
|
|
| 1334 |
VoiceEngine.recognition.onend = () => {
|
| 1335 |
AppState.isMicRecording = false;
|
| 1336 |
document.getElementById('masterVoiceBtn').classList.remove('active-listening');
|
| 1337 |
-
document.getElementById('interimTextOverlay').classList.remove('active');
|
| 1338 |
|
| 1339 |
-
if (AppState.isLiveModeEngaged) {
|
| 1340 |
document.getElementById('liveMicBtn').classList.remove('is-recording');
|
|
|
|
| 1341 |
document.getElementById('liveOrb').style.transform = "scale(1)";
|
| 1342 |
-
|
| 1343 |
-
const currentInput = document.getElementById('mainChatInput').value.trim();
|
| 1344 |
-
if (currentInput !== '' && !AppState.isProcessing) {
|
| 1345 |
-
// The silence timer finished, user stopped talking, auto-dispatch!
|
| 1346 |
-
document.getElementById('liveStatusText').innerText = "Processing...";
|
| 1347 |
-
ChatEngine.initiateDispatch();
|
| 1348 |
-
} else if (!AppState.isProcessing) {
|
| 1349 |
-
document.getElementById('liveStatusText').innerText = "Tap mic to interact";
|
| 1350 |
-
}
|
| 1351 |
}
|
| 1352 |
};
|
| 1353 |
|
| 1354 |
VoiceEngine.recognition.onerror = (event) => {
|
| 1355 |
AppState.isMicRecording = false;
|
| 1356 |
-
if(event.error !== 'no-speech'
|
| 1357 |
-
Utils.showToast("Voice module error: " + event.error
|
| 1358 |
}
|
| 1359 |
document.getElementById('masterVoiceBtn').classList.remove('active-listening');
|
| 1360 |
-
document.getElementById('interimTextOverlay').classList.remove('active');
|
| 1361 |
-
|
| 1362 |
if (AppState.isLiveModeEngaged) {
|
| 1363 |
document.getElementById('liveMicBtn').classList.remove('is-recording');
|
| 1364 |
document.getElementById('liveStatusText').innerText = "Audio Failure. Retry.";
|
|
@@ -1374,26 +1249,25 @@
|
|
| 1374 |
VoiceEngine.currentLanguage = 'hi-IN';
|
| 1375 |
badge.innerText = 'हि';
|
| 1376 |
btn.classList.add('hindi-active');
|
| 1377 |
-
Utils.showToast("Listening Protocol: Hindi (देवनागरी)"
|
| 1378 |
} else {
|
| 1379 |
VoiceEngine.currentLanguage = 'en-IN';
|
| 1380 |
badge.innerText = 'EN';
|
| 1381 |
btn.classList.remove('hindi-active');
|
| 1382 |
-
Utils.showToast("Listening Protocol: English"
|
| 1383 |
}
|
| 1384 |
|
| 1385 |
if (VoiceEngine.recognition) {
|
| 1386 |
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
|
| 1387 |
if(AppState.isMicRecording) {
|
| 1388 |
VoiceEngine.recognition.stop();
|
| 1389 |
-
|
| 1390 |
-
setTimeout(() => { try{VoiceEngine.recognition.start();}catch(e){} }, 400);
|
| 1391 |
}
|
| 1392 |
}
|
| 1393 |
},
|
| 1394 |
|
| 1395 |
toggleDictation: () => {
|
| 1396 |
-
if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported
|
| 1397 |
try {
|
| 1398 |
if(AppState.isMicRecording) {
|
| 1399 |
VoiceEngine.recognition.stop();
|
|
@@ -1403,12 +1277,13 @@
|
|
| 1403 |
} catch (e) { console.error("Mic Start Error", e); }
|
| 1404 |
},
|
| 1405 |
|
|
|
|
| 1406 |
executeTTS: async (rawText) => {
|
| 1407 |
// Apply smart text cleaner so AI doesn't read code or image links
|
| 1408 |
const cleanSpeechText = Utils.cleanTextForVoice(rawText);
|
| 1409 |
|
| 1410 |
if(!cleanSpeechText.trim()) {
|
| 1411 |
-
Utils.showToast("No readable
|
| 1412 |
return;
|
| 1413 |
}
|
| 1414 |
|
|
@@ -1419,6 +1294,7 @@
|
|
| 1419 |
|
| 1420 |
try {
|
| 1421 |
if(!AppState.gradioClient) {
|
|
|
|
| 1422 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
| 1423 |
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
|
| 1424 |
}
|
|
@@ -1428,8 +1304,8 @@
|
|
| 1428 |
voice_type: "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)"
|
| 1429 |
});
|
| 1430 |
|
| 1431 |
-
if (result.data && result.data) {
|
| 1432 |
-
const audioUrl = typeof result.data === 'string' ? result.data : result.data.url;
|
| 1433 |
const audio = new Audio(audioUrl);
|
| 1434 |
|
| 1435 |
audio.onended = () => {
|
|
@@ -1444,7 +1320,7 @@
|
|
| 1444 |
throw new Error("No audio payload returned.");
|
| 1445 |
}
|
| 1446 |
} catch (error) {
|
| 1447 |
-
Utils.showToast("Voice Neural Matrix is currently overloaded."
|
| 1448 |
console.error("Gradio TTS Error:", error);
|
| 1449 |
if (AppState.isLiveModeEngaged) {
|
| 1450 |
document.getElementById('liveOrb').classList.remove('speaking');
|
|
@@ -1463,7 +1339,7 @@
|
|
| 1463 |
if (VoiceEngine.recognition && !AppState.isMicRecording) {
|
| 1464 |
setTimeout(() => {
|
| 1465 |
try { VoiceEngine.recognition.start(); } catch(e){}
|
| 1466 |
-
},
|
| 1467 |
}
|
| 1468 |
},
|
| 1469 |
terminate: () => {
|
|
@@ -1476,7 +1352,7 @@
|
|
| 1476 |
};
|
| 1477 |
|
| 1478 |
// =======================================================================================
|
| 1479 |
-
// 6. FILE & DOCUMENT PROCESSOR (
|
| 1480 |
// =======================================================================================
|
| 1481 |
const FileProcessor = {
|
| 1482 |
triggerFileSelector: (type) => {
|
|
@@ -1485,25 +1361,17 @@
|
|
| 1485 |
},
|
| 1486 |
|
| 1487 |
processFile: async (inputElement, typeContext) => {
|
| 1488 |
-
const file = inputElement.files;
|
| 1489 |
if (!file) return;
|
| 1490 |
|
| 1491 |
-
// Size Validation to prevent UI thread lock
|
| 1492 |
-
const fileSizeMB = file.size / (1024 * 1024);
|
| 1493 |
-
if (fileSizeMB > Config.MAX_FILE_SIZE_MB) {
|
| 1494 |
-
Utils.showToast(`File exceeds ${Config.MAX_FILE_SIZE_MB}MB enterprise limit.`, "error");
|
| 1495 |
-
inputElement.value = '';
|
| 1496 |
-
return;
|
| 1497 |
-
}
|
| 1498 |
-
|
| 1499 |
const fName = file.name.toLowerCase();
|
| 1500 |
const mime = file.type;
|
| 1501 |
|
| 1502 |
-
if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required."
|
| 1503 |
-
if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required."
|
| 1504 |
-
if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required."
|
| 1505 |
|
| 1506 |
-
Utils.showToast(`
|
| 1507 |
|
| 1508 |
const thumbImg = document.getElementById('previewImgThumb');
|
| 1509 |
const docIcon = document.getElementById('previewDocIcon');
|
|
@@ -1517,7 +1385,7 @@
|
|
| 1517 |
|
| 1518 |
if (typeContext === 'image') {
|
| 1519 |
fileReader.onload = (e) => {
|
| 1520 |
-
AppState.pendingAttachment = { type: 'image', data: e.target.result.split(','), name: file.name };
|
| 1521 |
thumbImg.src = e.target.result;
|
| 1522 |
thumbImg.style.display = 'flex';
|
| 1523 |
};
|
|
@@ -1525,7 +1393,7 @@
|
|
| 1525 |
}
|
| 1526 |
else if (typeContext === 'video' || typeContext === 'audio') {
|
| 1527 |
fileReader.onload = (e) => {
|
| 1528 |
-
AppState.pendingAttachment = { type: typeContext, data: e.target.result.split(','), name: file.name };
|
| 1529 |
docIcon.innerText = typeContext === 'video' ? '🎥' : '🎵';
|
| 1530 |
docIcon.style.display = 'flex';
|
| 1531 |
};
|
|
@@ -1547,9 +1415,9 @@
|
|
| 1547 |
extractedText += content.items.map(s => s.str).join(' ') + "\n";
|
| 1548 |
}
|
| 1549 |
AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name };
|
| 1550 |
-
Utils.showToast("
|
| 1551 |
} catch (e) {
|
| 1552 |
-
Utils.showToast("PDF
|
| 1553 |
FileProcessor.discardFile();
|
| 1554 |
}
|
| 1555 |
};
|
|
@@ -1561,9 +1429,9 @@
|
|
| 1561 |
const buffer = this.result;
|
| 1562 |
const resultData = await mammoth.extractRawText({ arrayBuffer: buffer });
|
| 1563 |
AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name };
|
| 1564 |
-
Utils.showToast("
|
| 1565 |
} catch(e) {
|
| 1566 |
-
Utils.showToast("Document
|
| 1567 |
FileProcessor.discardFile();
|
| 1568 |
}
|
| 1569 |
};
|
|
@@ -1572,7 +1440,7 @@
|
|
| 1572 |
else {
|
| 1573 |
fileReader.onload = (e) => {
|
| 1574 |
AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
|
| 1575 |
-
Utils.showToast("
|
| 1576 |
};
|
| 1577 |
fileReader.readAsText(file);
|
| 1578 |
}
|
|
@@ -1583,31 +1451,23 @@
|
|
| 1583 |
discardFile: () => {
|
| 1584 |
AppState.pendingAttachment = null;
|
| 1585 |
document.getElementById('filePreviewBar').classList.remove('visible');
|
| 1586 |
-
document.getElementById('previewImgThumb').src = '';
|
| 1587 |
}
|
| 1588 |
};
|
| 1589 |
|
| 1590 |
// =======================================================================================
|
| 1591 |
-
// 7. WORKSPACE ENGINE &
|
| 1592 |
// =======================================================================================
|
| 1593 |
const WorkspaceEngine = {
|
| 1594 |
launch: (codeBlockId) => {
|
| 1595 |
AppState.currentWorkspaceId = codeBlockId;
|
| 1596 |
const codeData = AppState.generatedCodeBlocks[codeBlockId];
|
| 1597 |
|
| 1598 |
-
document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled
|
| 1599 |
const blockDisplay = document.getElementById('workspaceCodeBlock');
|
| 1600 |
blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`;
|
| 1601 |
blockDisplay.textContent = codeData.code;
|
| 1602 |
|
| 1603 |
hljs.highlightElement(blockDisplay);
|
| 1604 |
-
|
| 1605 |
-
// Add Line Numbers dynamically
|
| 1606 |
-
const lineCount = codeData.code.split('\n').length;
|
| 1607 |
-
let numbersHTML = '';
|
| 1608 |
-
for(let i=1; i<=lineCount; i++) { numbersHTML += `${i}<br>`; }
|
| 1609 |
-
document.getElementById('wsLineNumbers').innerHTML = numbersHTML;
|
| 1610 |
-
|
| 1611 |
document.getElementById('workspacePanel').classList.add('expanded');
|
| 1612 |
|
| 1613 |
if (window.innerWidth <= 1024) {
|
|
@@ -1625,18 +1485,17 @@
|
|
| 1625 |
}
|
| 1626 |
};
|
| 1627 |
|
| 1628 |
-
// Custom Marked Renderer for UI perfection
|
| 1629 |
const MD_Renderer = new marked.Renderer();
|
| 1630 |
MD_Renderer.code = function(token) {
|
| 1631 |
const rawCode = typeof token === 'string' ? token : (token.text || '');
|
| 1632 |
-
const langClass = typeof token === 'string' ? arguments : (token.lang || '');
|
| 1633 |
|
| 1634 |
if (AppState.isStreamingActive) {
|
| 1635 |
return `
|
| 1636 |
<div class="streaming-code-container">
|
| 1637 |
<div class="streaming-code-header">
|
| 1638 |
<div class="loading-ring"></div>
|
| 1639 |
-
Generating
|
| 1640 |
</div>
|
| 1641 |
<pre><code class="language-${langClass}">${Utils.escapeHTML(rawCode)}</code></pre>
|
| 1642 |
</div>`;
|
|
@@ -1653,36 +1512,15 @@
|
|
| 1653 |
</div>
|
| 1654 |
<div class="ws-card-details">
|
| 1655 |
<h4>Code Module Compiled</h4>
|
| 1656 |
-
<p>${langClass || 'Syntax
|
| 1657 |
</div>
|
| 1658 |
</div>
|
| 1659 |
<button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button>
|
| 1660 |
</div>`;
|
| 1661 |
};
|
|
|
|
| 1662 |
|
| 1663 |
-
|
| 1664 |
-
let html = '<table>';
|
| 1665 |
-
if (token.header) {
|
| 1666 |
-
html += '<thead><tr>';
|
| 1667 |
-
token.header.forEach(th => { html += `<th>${marked.parseInline(th.text)}</th>`; });
|
| 1668 |
-
html += '</tr></thead>';
|
| 1669 |
-
}
|
| 1670 |
-
if (token.rows) {
|
| 1671 |
-
html += '<tbody>';
|
| 1672 |
-
token.rows.forEach(tr => {
|
| 1673 |
-
html += '<tr>';
|
| 1674 |
-
tr.forEach(td => { html += `<td>${marked.parseInline(td.text)}</td>`; });
|
| 1675 |
-
html += '</tr>';
|
| 1676 |
-
});
|
| 1677 |
-
html += '</tbody>';
|
| 1678 |
-
}
|
| 1679 |
-
html += '</table>';
|
| 1680 |
-
return html;
|
| 1681 |
-
};
|
| 1682 |
-
|
| 1683 |
-
marked.use({ renderer: MD_Renderer, breaks: true, gfm: true });
|
| 1684 |
-
|
| 1685 |
-
// Event delegation for dynamically generated workspace buttons
|
| 1686 |
document.getElementById('msgs').addEventListener('click', function(e) {
|
| 1687 |
if (e.target && e.target.classList.contains('btn-launch-ws')) {
|
| 1688 |
const blockId = e.target.getAttribute('data-id');
|
|
@@ -1707,10 +1545,8 @@
|
|
| 1707 |
},
|
| 1708 |
|
| 1709 |
clearMemory: async () => {
|
| 1710 |
-
if(!confirm("Are you sure you want to wipe the neural context? This action cannot be undone.")) return;
|
| 1711 |
-
|
| 1712 |
if (AppState.currentUser) {
|
| 1713 |
-
Utils.showToast("Purging neural link memory..."
|
| 1714 |
try {
|
| 1715 |
await fetch(Config.GAS_URL, {
|
| 1716 |
method: 'POST',
|
|
@@ -1724,8 +1560,6 @@
|
|
| 1724 |
},
|
| 1725 |
|
| 1726 |
syncHistoryFromCloud: async () => {
|
| 1727 |
-
if (!AppState.isOnline) return;
|
| 1728 |
-
|
| 1729 |
const messageZone = document.getElementById('msgs');
|
| 1730 |
document.getElementById('welcomeState').style.display = 'none';
|
| 1731 |
messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>';
|
|
@@ -1761,7 +1595,7 @@
|
|
| 1761 |
},
|
| 1762 |
|
| 1763 |
saveHistoryToCloud: () => {
|
| 1764 |
-
if (AppState.currentUser
|
| 1765 |
fetch(Config.GAS_URL, {
|
| 1766 |
method: 'POST',
|
| 1767 |
mode: 'cors',
|
|
@@ -1774,13 +1608,13 @@
|
|
| 1774 |
buildPreviewHTML: (attachmentObj) => {
|
| 1775 |
if (!attachmentObj) return '';
|
| 1776 |
if (attachmentObj.type === 'image') {
|
| 1777 |
-
return `<img src="data:image/jpeg;base64,${attachmentObj.data}" class="chat-in-bubble-img" alt="Attached
|
| 1778 |
} else if (attachmentObj.type === 'video') {
|
| 1779 |
-
return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg></div><span class="name">${
|
| 1780 |
} else if (attachmentObj.type === 'audio') {
|
| 1781 |
-
return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg></div><span class="name">${
|
| 1782 |
} else {
|
| 1783 |
-
return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg></div><span class="name">${
|
| 1784 |
}
|
| 1785 |
},
|
| 1786 |
|
|
@@ -1790,7 +1624,7 @@
|
|
| 1790 |
let visibleText = textContent;
|
| 1791 |
if(textContent.includes('---DATA BEGIN---')) {
|
| 1792 |
const parts = textContent.split('User Prompt:');
|
| 1793 |
-
if(parts.length > 1) visibleText = parts.trim();
|
| 1794 |
}
|
| 1795 |
|
| 1796 |
const bubbleBox = document.createElement('div');
|
|
@@ -1835,7 +1669,7 @@
|
|
| 1835 |
let actionTray = bubbleDOM.querySelector('.bot-actions-row');
|
| 1836 |
if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
|
| 1837 |
const safeRawCopy = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
|
| 1838 |
-
//
|
| 1839 |
const safeRawTTS = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, ' ');
|
| 1840 |
|
| 1841 |
const actionsHTML = `
|
|
@@ -1857,7 +1691,6 @@
|
|
| 1857 |
},
|
| 1858 |
|
| 1859 |
initiateDispatch: async () => {
|
| 1860 |
-
if (!AppState.isOnline) return Utils.showToast("Cannot process request. System is Offline.", "error");
|
| 1861 |
if (AppState.isProcessing) return;
|
| 1862 |
|
| 1863 |
const inputField = document.getElementById('mainChatInput');
|
|
@@ -1869,14 +1702,14 @@
|
|
| 1869 |
if (!AppState.currentUser) {
|
| 1870 |
if (AppState.guestCount >= 3) {
|
| 1871 |
AuthManager.openModal();
|
| 1872 |
-
return Utils.showToast("Query limit reached. Secure Login required."
|
| 1873 |
}
|
| 1874 |
AppState.guestCount++;
|
| 1875 |
localStorage.setItem('arjun_guest', AppState.guestCount.toString());
|
| 1876 |
document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
|
| 1877 |
}
|
| 1878 |
|
| 1879 |
-
// Prepare UI
|
| 1880 |
inputField.value = '';
|
| 1881 |
inputField.style.height = 'auto';
|
| 1882 |
document.getElementById('masterSendBtn').disabled = true;
|
|
@@ -1919,21 +1752,21 @@
|
|
| 1919 |
const activeBotBubble = ChatEngine.renderBotMessage('', false);
|
| 1920 |
UIManager.forceScrollDown();
|
| 1921 |
|
| 1922 |
-
// Dynamic Pollinations
|
| 1923 |
const cryptographicSeed = Math.floor(Math.random() * 999999999);
|
| 1924 |
|
| 1925 |
-
// Advanced Cognitive System Instructions
|
| 1926 |
-
let cognitivePrompt = `You are Arjun 2.O, a
|
| 1927 |
-
LANGUAGE
|
| 1928 |
|
| 1929 |
IMAGE SYNTHESIS OVERRIDE:
|
| 1930 |
When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI.
|
| 1931 |
Formula: 
|
| 1932 |
Available Models: flux, flux-realism, flux-anime, flux-3d.
|
| 1933 |
-
CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node
|
| 1934 |
|
| 1935 |
if (AppState.isLiveModeEngaged) {
|
| 1936 |
-
cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE
|
| 1937 |
MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`;
|
| 1938 |
}
|
| 1939 |
|
|
@@ -1944,7 +1777,7 @@
|
|
| 1944 |
attachments: payloadAttachments,
|
| 1945 |
system_prompt: cognitivePrompt,
|
| 1946 |
history: secureHistory,
|
| 1947 |
-
max_tokens: AppState.isLiveModeEngaged ?
|
| 1948 |
temperature: 0.75
|
| 1949 |
};
|
| 1950 |
|
|
@@ -1978,8 +1811,8 @@
|
|
| 1978 |
|
| 1979 |
try {
|
| 1980 |
const jsonSegment = JSON.parse(parseableStr);
|
| 1981 |
-
if (jsonSegment.choices && jsonSegment.choices.delta.content) {
|
| 1982 |
-
responseBuffer += jsonSegment.choices.delta.content;
|
| 1983 |
ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true);
|
| 1984 |
UIManager.autoScroll();
|
| 1985 |
}
|
|
@@ -2016,12 +1849,14 @@
|
|
| 2016 |
// 9. EVENT DELEGATION & BOOTSTRAP INVOCATION
|
| 2017 |
// =======================================================================================
|
| 2018 |
|
|
|
|
| 2019 |
window.startArjunApp = function() {
|
| 2020 |
document.getElementById('welcomeOverlay').classList.add('hidden');
|
| 2021 |
localStorage.setItem('arjun_welcome_seen', 'true');
|
| 2022 |
setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
|
| 2023 |
};
|
| 2024 |
|
|
|
|
| 2025 |
document.addEventListener('DOMContentLoaded', () => {
|
| 2026 |
// Sidebar Controls
|
| 2027 |
document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar);
|
|
@@ -2083,10 +1918,6 @@
|
|
| 2083 |
document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState);
|
| 2084 |
document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown);
|
| 2085 |
|
| 2086 |
-
// Network Monitoring
|
| 2087 |
-
window.addEventListener('online', UIManager.updateNetworkStatus);
|
| 2088 |
-
window.addEventListener('offline', UIManager.updateNetworkStatus);
|
| 2089 |
-
|
| 2090 |
// Prevent unwanted default mobile behaviours on double-tap
|
| 2091 |
document.addEventListener('dblclick', function(event) {
|
| 2092 |
event.preventDefault();
|
|
@@ -2100,7 +1931,6 @@
|
|
| 2100 |
}
|
| 2101 |
|
| 2102 |
// Fire Boot Processes
|
| 2103 |
-
UIManager.updateNetworkStatus();
|
| 2104 |
VoiceEngine.init();
|
| 2105 |
AuthManager.initUI();
|
| 2106 |
if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); }
|
|
@@ -2109,3 +1939,4 @@
|
|
| 2109 |
</script>
|
| 2110 |
</body>
|
| 2111 |
</html>
|
|
|
|
|
|
|
|
|
| 1 |
<!DOCTYPE html>
|
| 2 |
<html lang="en" dir="ltr">
|
| 3 |
<head>
|
|
|
|
| 11 |
<title>Arjun 2.O - Professional Advanced AI</title>
|
| 12 |
|
| 13 |
<!-- =========================================================================================
|
| 14 |
+
[1] EXTERNAL RESOURCES, FONTS & LIBRARIES (बाहरी स्रोत)
|
| 15 |
========================================================================================= -->
|
| 16 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 17 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
|
|
| 29 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
|
| 30 |
|
| 31 |
<!-- =========================================================================================
|
| 32 |
+
[2] MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग)
|
| 33 |
========================================================================================= -->
|
| 34 |
<style>
|
| 35 |
/* ---------------------------------------------------------------------------------------
|
| 36 |
+
A. CSS VARIABLES, DESIGN TOKENS & TIRANGA BRANDING
|
| 37 |
--------------------------------------------------------------------------------------- */
|
| 38 |
:root {
|
| 39 |
+
/* Brand Identity: Saffron, White, Green (Tiranga) */
|
| 40 |
--brand-saffron: #FF9933;
|
| 41 |
--brand-saffron-light: rgba(255, 153, 51, 0.12);
|
| 42 |
--brand-saffron-dark: #e68a2e;
|
|
|
|
| 64 |
--text-tertiary: #9ca3af;
|
| 65 |
--text-inverse: #ffffff;
|
| 66 |
--text-error: #ef4444;
|
|
|
|
| 67 |
|
| 68 |
/* Borders & Dividers */
|
| 69 |
--border-light: rgba(0, 0, 0, 0.08);
|
| 70 |
--border-medium: rgba(0, 0, 0, 0.15);
|
| 71 |
+
--border-focus: rgba(255, 153, 51, 0.4);
|
| 72 |
|
| 73 |
/* Shadows & Elevation */
|
| 74 |
--shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
|
|
|
|
| 76 |
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
|
| 77 |
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
|
| 78 |
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
|
|
|
|
| 79 |
--shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06);
|
| 80 |
|
| 81 |
/* Font Families */
|
|
|
|
| 96 |
--ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
| 97 |
--ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
| 98 |
|
| 99 |
+
/* Z-Indices */
|
| 100 |
--z-ambient: -1;
|
| 101 |
--z-base: 1;
|
| 102 |
--z-header: 10;
|
|
|
|
| 107 |
--z-modal: 5000;
|
| 108 |
--z-toast: 9000;
|
| 109 |
--z-live: 9999;
|
|
|
|
| 110 |
}
|
| 111 |
|
| 112 |
/* ---------------------------------------------------------------------------------------
|
|
|
|
| 116 |
box-sizing: border-box;
|
| 117 |
margin: 0;
|
| 118 |
padding: 0;
|
| 119 |
+
/* CRITICAL: REMOVE BLUE TAP HIGHLIGHT ON MOBILE/BROWSERS */
|
| 120 |
-webkit-tap-highlight-color: transparent !important;
|
| 121 |
-webkit-touch-callout: none !important;
|
| 122 |
}
|
|
|
|
| 135 |
-moz-osx-font-smoothing: grayscale;
|
| 136 |
}
|
| 137 |
|
| 138 |
+
/* Remove default outlines and use custom focus states */
|
| 139 |
+
*:focus { outline: none !important; }
|
|
|
|
| 140 |
|
| 141 |
button, input, textarea, select {
|
| 142 |
font-family: inherit;
|
|
|
|
| 146 |
}
|
| 147 |
|
| 148 |
button { cursor: pointer; user-select: none; }
|
|
|
|
| 149 |
a { color: inherit; text-decoration: none; }
|
| 150 |
img { max-width: 100%; height: auto; display: block; }
|
| 151 |
svg { flex-shrink: 0; }
|
| 152 |
|
| 153 |
+
/* Highly Customized Scrollbars */
|
| 154 |
+
::-webkit-scrollbar { width: 6px; height: 6px; }
|
| 155 |
::-webkit-scrollbar-track { background: transparent; }
|
| 156 |
+
::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.12); border-radius: 10px; transition: background var(--ease-smooth); }
|
| 157 |
+
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
|
| 158 |
|
| 159 |
/* ---------------------------------------------------------------------------------------
|
| 160 |
+
C. AMBIENT BACKGROUND SYSTEM (प्रीमियम बैकग्राउंड इफ़ेक्ट्स)
|
| 161 |
--------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
.ambient-environment {
|
| 163 |
position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
|
| 164 |
background: linear-gradient(135deg, var(--brand-saffron-light) 0%, var(--bg-primary) 50%, var(--brand-green-light) 100%);
|
|
|
|
| 185 |
}
|
| 186 |
|
| 187 |
/* ---------------------------------------------------------------------------------------
|
| 188 |
+
D. TOAST NOTIFICATION ENGINE (सुंदर और स्पष्ट सूचनाएं)
|
| 189 |
--------------------------------------------------------------------------------------- */
|
| 190 |
.toast-wrapper {
|
| 191 |
position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
|
| 192 |
z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px;
|
| 193 |
+
pointer-events: none; width: 90%; max-width: 400px; align-items: center;
|
| 194 |
}
|
| 195 |
.toast-notification {
|
| 196 |
+
background: var(--text-primary); color: var(--text-inverse); padding: 14px 24px;
|
| 197 |
border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl);
|
| 198 |
animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards;
|
| 199 |
+
display: flex; align-items: center; gap: 10px; width: fit-content; max-width: 100%; word-break: break-word;
|
| 200 |
+
border: 1px solid rgba(255,255,255,0.1);
|
| 201 |
}
|
| 202 |
+
.toast-notification svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--brand-saffron); }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
@keyframes toastSlideIn { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } }
|
| 204 |
@keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
|
| 205 |
|
|
|
|
| 214 |
}
|
| 215 |
.startup-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
|
| 216 |
|
| 217 |
+
.startup-logo-container { position: relative; margin-bottom: 32px; animation: popIn var(--ease-spring) 0.3s both; }
|
| 218 |
.startup-logo-container img { width: 140px; height: 140px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 4px solid var(--bg-primary); position: relative; z-index: 2; }
|
| 219 |
.startup-logo-glow { position: absolute; inset: -20px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(30px); opacity: 0.4; border-radius: var(--radius-full); z-index: 1; animation: pulseGlow 3s infinite alternate; }
|
| 220 |
|
| 221 |
@keyframes pulseGlow { from { opacity: 0.3; transform: scale(0.95); } to { opacity: 0.6; transform: scale(1.05); } }
|
| 222 |
+
@keyframes popIn { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } }
|
| 223 |
|
| 224 |
+
.startup-title { font-family: var(--font-sans); font-size: 2.5rem; font-weight: 900; color: var(--text-primary); letter-spacing: -1px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.4s both; }
|
| 225 |
+
.startup-desc { font-size: 1.1rem; color: var(--text-secondary); line-height: 1.6; max-width: 550px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.5s both; font-weight: 500; }
|
| 226 |
|
| 227 |
+
.btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: 1.125rem; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 10px 25px rgba(0,0,0,0.15); animation: slideUp var(--ease-smooth) 0.6s both; display: flex; align-items: center; gap: 12px; position: relative; overflow: hidden; }
|
| 228 |
.btn-startup-launch::before { content: ''; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); transform: skewX(-20deg); transition: 0.5s; }
|
| 229 |
.btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); }
|
| 230 |
.btn-startup-launch:hover::before { left: 150%; }
|
| 231 |
|
| 232 |
+
@keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
|
| 233 |
|
| 234 |
/* ---------------------------------------------------------------------------------------
|
| 235 |
F. CORE APPLICATION LAYOUT & SIDEBAR
|
|
|
|
| 241 |
.sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
|
| 242 |
|
| 243 |
.brand-identity { display: flex; align-items: center; gap: 14px; text-decoration: none; }
|
| 244 |
+
.brand-identity img { width: 50px; height: 50px; border-radius: var(--radius-md); object-fit: cover; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); transition: transform var(--ease-spring); }
|
| 245 |
+
.brand-identity:hover img { transform: scale(1.08) rotate(-3deg); }
|
| 246 |
.brand-typography { display: flex; flex-direction: column; }
|
| 247 |
.brand-name { font-family: var(--font-sans); font-weight: 900; font-size: 20px; color: var(--text-primary); letter-spacing: -0.5px; line-height: 1.1; }
|
| 248 |
+
.brand-edition { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; background: linear-gradient(90deg, var(--brand-saffron), var(--brand-green)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-top: 4px; }
|
| 249 |
|
| 250 |
.btn-mobile-close { display: none; background: rgba(0,0,0,0.05); border: none; width: 36px; height: 36px; border-radius: 50%; color: var(--text-primary); cursor: pointer; align-items: center; justify-content: center; transition: var(--ease-fast); }
|
| 251 |
.btn-mobile-close:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
|
|
|
|
| 264 |
.user-details { flex: 1; overflow: hidden; }
|
| 265 |
.user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
| 266 |
.user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
|
| 267 |
+
.user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow: var(--shadow-glow-green); }
|
| 268 |
.btn-system-logout { background: rgba(239, 68, 68, 0.08); color: var(--text-error); border: none; width: 38px; height: 38px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-fast); }
|
| 269 |
.btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
|
| 270 |
|
|
|
|
| 285 |
--------------------------------------------------------------------------------------- */
|
| 286 |
.main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; }
|
| 287 |
|
| 288 |
+
.chat-top-bar { padding: 18px 32px; border-bottom: 1px solid var(--border-light); background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(15px); display: flex; align-items: center; justify-content: space-between; z-index: var(--z-header); }
|
| 289 |
.top-bar-left { display: flex; align-items: center; gap: 16px; }
|
| 290 |
.btn-hamburger { display: none; background: var(--bg-primary); border: 1px solid var(--border-light); cursor: pointer; color: var(--text-primary); width: 42px; height: 42px; border-radius: var(--radius-sm); align-items: center; justify-content: center; box-shadow: var(--shadow-sm); transition: var(--ease-fast); }
|
| 291 |
.btn-hamburger:hover { background: var(--bg-secondary); }
|
| 292 |
|
| 293 |
+
.system-status-pill { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 700; color: var(--text-primary); padding: 8px 18px; background: var(--bg-secondary); border-radius: var(--radius-full); border: 1px solid var(--border-light); }
|
| 294 |
+
.pulse-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 0 3px rgba(19, 136, 8, 0.2); animation: statusPulse 2s infinite; }
|
|
|
|
| 295 |
@keyframes statusPulse { 0% { box-shadow: 0 0 0 0 rgba(19,136,8,0.4); } 70% { box-shadow: 0 0 0 6px rgba(19,136,8,0); } 100% { box-shadow: 0 0 0 0 rgba(19,136,8,0); } }
|
| 296 |
|
| 297 |
/* DYNAMIC LIVE MODE ACTIVATOR */
|
|
|
|
| 309 |
.hero-avatar-wrapper img { width: 100px; height: 100px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 3px solid var(--bg-primary); position: relative; z-index: 2; }
|
| 310 |
.hero-avatar-glow { position: absolute; inset: -12px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(25px); opacity: 0.35; border-radius: 40px; z-index: 1; animation: rotateGlow 10s linear infinite;}
|
| 311 |
@keyframes rotateGlow { 100% { transform: rotate(360deg); } }
|
|
|
|
| 312 |
|
| 313 |
+
.hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); }
|
| 314 |
.hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; }
|
| 315 |
|
| 316 |
+
/* RESTORED: GUEST BADGE LIMIT DISPLAY */
|
| 317 |
.guest-warning-badge { font-size: 13px; font-weight: 700; color: var(--text-error); background: #fee2e2; padding: 10px 20px; border-radius: var(--radius-full); margin-bottom: 32px; display: none; align-items: center; gap: 8px; border: 1px solid #fca5a5; box-shadow: var(--shadow-sm); }
|
| 318 |
.guest-warning-badge svg { width: 18px; height: 18px; }
|
| 319 |
|
|
|
|
| 329 |
/* ---------------------------------------------------------------------------------------
|
| 330 |
H. CHAT MESSAGE BUBBLES & PREVIEWS
|
| 331 |
--------------------------------------------------------------------------------------- */
|
| 332 |
+
.chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.5s var(--ease-spring) both; }
|
| 333 |
+
@keyframes messagePopIn { from { opacity: 0; transform: translateY(25px) scale(0.97); } to { opacity: 1; transform: none; } }
|
| 334 |
.chat-message-row.user-msg { flex-direction: row-reverse; align-self: flex-end; }
|
| 335 |
.chat-message-row.bot-msg { align-self: flex-start; }
|
| 336 |
|
|
|
|
| 346 |
.file-badge svg { width: 12px; height: 12px; }
|
| 347 |
|
| 348 |
/* In-Bubble File Previews */
|
| 349 |
+
.chat-in-bubble-img { max-width: 320px; max-height: 320px; border-radius: var(--radius-md); object-fit: cover; border: 2px solid rgba(255,255,255,0.2); box-shadow: var(--shadow-md); margin-bottom: 12px; }
|
|
|
|
| 350 |
.chat-file-card { display: flex; align-items: center; gap: 14px; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); padding: 12px 18px; border-radius: var(--radius-md); margin-bottom: 12px; max-width: 350px; backdrop-filter: blur(10px); }
|
| 351 |
.chat-file-card .icon { font-size: 24px; background: rgba(0,0,0,0.1); width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); }
|
| 352 |
.chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
| 366 |
.btn-bot-action.action-tts { color: var(--brand-green-dark); border-color: rgba(19, 136, 8, 0.25); background: var(--brand-green-light); }
|
| 367 |
.btn-bot-action.action-tts:hover { background: rgba(19, 136, 8, 0.2); }
|
| 368 |
|
| 369 |
+
/* Markdown Rendering inside Bubbles */
|
| 370 |
.chat-bubble p { margin-bottom: 16px; }
|
| 371 |
.chat-bubble p:last-child { margin-bottom: 0; }
|
| 372 |
.chat-bubble strong { font-weight: 800; color: inherit; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
.chat-bubble code { font-family: var(--font-mono); background: rgba(0,0,0,0.06); padding: 4px 8px; border-radius: 6px; font-size: 0.85em; color: #d946ef; font-weight: 600; border: 1px solid rgba(0,0,0,0.05); }
|
| 374 |
.user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); border-color: rgba(255,255,255,0.1); }
|
|
|
|
| 375 |
.chat-bubble img { max-width: 100%; border-radius: var(--radius-md); margin: 16px 0; box-shadow: var(--shadow-lg); border: 1px solid var(--border-light); display: block; }
|
| 376 |
+
.chat-bubble pre { background: #282c34; color: #abb2bf; padding: 20px; border-radius: var(--radius-md); overflow-x: auto; margin: 20px 0; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; border: 1px solid #181a1f; box-shadow: var(--shadow-inner); }
|
| 377 |
+
.chat-bubble pre code { background: transparent; color: inherit; padding: 0; font-weight: 400; border: none; }
|
|
|
|
|
|
|
| 378 |
|
| 379 |
/* Streaming Loading UI Component */
|
| 380 |
.streaming-code-container { background: #1e1e2e; border-radius: var(--radius-md); border: 1px solid #313244; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); }
|
|
|
|
| 398 |
I. BOTTOM INPUT DOCK & TOOLS
|
| 399 |
--------------------------------------------------------------------------------------- */
|
| 400 |
.input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); }
|
| 401 |
+
.input-master-container { display: flex; flex-direction: column; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); border: 1px solid var(--border-light); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); transition: var(--ease-smooth); }
|
| 402 |
.input-master-container:focus-within { border-color: var(--brand-saffron); box-shadow: 0 20px 40px -5px rgba(255,153,51,0.15), 0 0 0 4px var(--brand-saffron-light); }
|
| 403 |
|
| 404 |
+
/* Upload Preview Header (Non-Technical Vocabulary) */
|
| 405 |
+
.upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; }
|
| 406 |
+
.upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; }
|
| 407 |
.upload-thumb { width: 52px; height: 52px; object-fit: cover; border-radius: var(--radius-sm); border: 1px solid var(--border-light); display: flex; justify-content: center; align-items: center; background: var(--bg-tertiary); font-size: 24px; box-shadow: var(--shadow-sm); }
|
| 408 |
.upload-meta { flex: 1; }
|
| 409 |
.upload-filename { font-size: 14px; font-weight: 700; color: var(--text-primary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
|
|
| 418 |
.main-textarea { flex: 1; border: none; outline: none; background: transparent; font-family: var(--font-sans); font-size: 16px; color: var(--text-primary); line-height: 1.5; resize: none; max-height: 200px; min-height: 24px; padding: 12px 0; margin: 0 8px; font-weight: 500; }
|
| 419 |
.main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; }
|
| 420 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 421 |
/* Attachment Menu Dropdown */
|
| 422 |
.attachment-module { position: relative; }
|
| 423 |
+
.btn-tool-icon { width: 44px; height: 44px; border-radius: var(--radius-md); background: transparent; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); transition: var(--ease-fast); }
|
| 424 |
.btn-tool-icon:hover { background: var(--bg-tertiary); color: var(--text-primary); }
|
| 425 |
.btn-tool-icon svg { width: 24px; height: 24px; stroke-width: 2; }
|
| 426 |
|
|
|
|
| 438 |
.language-toggle-chip.hindi-active { background: var(--brand-green-light); color: var(--brand-green-dark); border-color: var(--brand-green); }
|
| 439 |
.language-toggle-chip svg { width: 16px; height: 16px; }
|
| 440 |
|
| 441 |
+
.btn-mic-tool.active-listening { color: #ffffff; background: var(--text-error); animation: recordPulse 1.5s infinite; border-radius: var(--radius-full); }
|
| 442 |
+
@keyframes recordPulse { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.5); } 70% { box-shadow: 0 0 0 12px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } }
|
|
|
|
|
|
|
| 443 |
|
| 444 |
/* Master Send Button */
|
| 445 |
+
.btn-master-send { width: 48px; height: 48px; border-radius: 16px; border: none; background: linear-gradient(135deg, var(--brand-saffron) 0%, var(--brand-green) 100%); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 6px 20px rgba(19, 136, 8, 0.25); }
|
| 446 |
+
.btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; }
|
|
|
|
| 447 |
.btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); }
|
|
|
|
| 448 |
.btn-master-send:hover svg { transform: translate(2px, -2px); }
|
| 449 |
+
.btn-master-send:disabled { opacity: 0.4; cursor: not-allowed; filter: grayscale(100%); transform: none; box-shadow: none; }
|
| 450 |
|
| 451 |
.bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; }
|
| 452 |
|
|
|
|
| 467 |
.btn-workspace-tool.close:hover { color: #e06c75; background: rgba(224, 108, 117, 0.1); }
|
| 468 |
|
| 469 |
.workspace-editor-surface { flex: 1; overflow-y: auto; background: #282c34; padding: 24px; position: relative; }
|
| 470 |
+
.workspace-editor-surface pre { margin: 0; padding: 0; background: transparent; font-family: var(--font-mono); font-size: 15px; line-height: 1.6; overflow-x: auto; color: #abb2bf; border: none; box-shadow: none;}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 471 |
|
| 472 |
/* ---------------------------------------------------------------------------------------
|
| 473 |
K. LIVE MODE FULLSCREEN OVERLAY
|
| 474 |
--------------------------------------------------------------------------------------- */
|
| 475 |
+
.live-mode-viewport { position: fixed; inset: 0; background: rgba(255, 255, 255, 0.98); z-index: var(--z-live); display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity var(--ease-smooth); }
|
| 476 |
.live-mode-viewport.active { opacity: 1; pointer-events: auto; }
|
| 477 |
.btn-close-live { position: absolute; top: 40px; right: 40px; background: rgba(0,0,0,0.04); border: none; width: 56px; height: 56px; border-radius: 50%; font-size: 24px; cursor: pointer; transition: var(--ease-spring); display: flex; align-items: center; justify-content: center; color: var(--text-secondary); }
|
| 478 |
.btn-close-live:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); }
|
|
|
|
| 480 |
.pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
|
| 481 |
.energy-core { width: 120px; height: 120px; border-radius: 50%; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); box-shadow: 0 0 50px rgba(19, 136, 8, 0.5); position: relative; z-index: 2; transition: transform 0.15s ease-out; }
|
| 482 |
.energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
|
| 483 |
+
@keyframes coreSpeak { 0% { transform: scale(1); box-shadow: 0 0 30px rgba(19,136,8,0.4); } 100% { transform: scale(1.1); box-shadow: 0 0 60px rgba(255,153,51,0.6); } }
|
| 484 |
|
| 485 |
.energy-ring { position: absolute; inset: 0; border: 3px solid var(--brand-saffron); border-radius: 50%; opacity: 0; animation: energyRipple 2.5s cubic-bezier(0.4, 0, 0.2, 1) infinite; }
|
| 486 |
.energy-ring:nth-child(2) { animation-delay: 0.8s; border-color: var(--brand-green); }
|
| 487 |
.energy-ring:nth-child(3) { animation-delay: 1.6s; border-color: var(--text-primary); }
|
| 488 |
@keyframes energyRipple { 0% { transform: scale(0.4); opacity: 1; border-width: 6px; } 100% { transform: scale(1.6); opacity: 0; border-width: 1px; } }
|
| 489 |
|
| 490 |
+
.live-feedback-status { font-size: 28px; font-weight: 900; color: var(--text-primary); margin-bottom: 16px; font-family: var(--font-sans); letter-spacing: -0.5px; }
|
| 491 |
+
.live-feedback-text { font-size: 18px; color: var(--text-secondary); max-width: 700px; text-align: center; line-height: 1.6; min-height: 60px; font-weight: 500; padding: 0 20px; }
|
| 492 |
|
| 493 |
.live-control-deck { display: flex; gap: 24px; margin-top: 50px; }
|
| 494 |
.btn-live-deck { width: 80px; height: 80px; border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: var(--shadow-lg); transition: var(--ease-spring); }
|
| 495 |
.btn-live-deck.mic-control { background: var(--bg-primary); border: 3px solid var(--border-light); color: var(--text-primary); }
|
| 496 |
.btn-live-deck.mic-control:hover { transform: translateY(-6px); border-color: var(--brand-saffron); color: var(--brand-saffron); box-shadow: var(--shadow-xl); }
|
| 497 |
.btn-live-deck.mic-control.is-recording { background: var(--text-error); color: white; border-color: var(--text-error); animation: pulseMicLive 1.2s infinite; }
|
| 498 |
+
@keyframes pulseMicLive { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.6); } 70% { box-shadow: 0 0 0 20px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } }
|
| 499 |
|
| 500 |
/* Scroll Trigger Button */
|
| 501 |
.btn-scroll-trigger { position: absolute; bottom: 150px; left: 50%; width: 48px; height: 48px; border-radius: 50%; background: var(--bg-glass); backdrop-filter: blur(15px); border: 1px solid var(--border-light); box-shadow: var(--shadow-lg); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); opacity: 0; pointer-events: none; transform: translateX(-50%) translateY(20px); transition: var(--ease-smooth); z-index: 20; }
|
|
|
|
| 508 |
.secure-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(10px); z-index: var(--z-modal); display: none; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; }
|
| 509 |
.secure-modal-surface { background: var(--bg-primary); padding: 44px; border-radius: var(--radius-xl); width: 90%; max-width: 460px; box-shadow: var(--shadow-xl); position: relative; border: 1px solid rgba(255,255,255,0.4); }
|
| 510 |
.btn-modal-dismiss { position: absolute; top: 24px; right: 24px; background: var(--bg-secondary); border: none; width: 36px; height: 36px; border-radius: 50%; font-size: 18px; color: var(--text-secondary); cursor: pointer; transition: 0.2s; display: flex; align-items: center; justify-content: center; }
|
| 511 |
+
.btn-modal-dismiss:hover { background: #fee2e2; color: var(--text-error); }
|
| 512 |
.modal-brand-header { text-align: center; margin-bottom: 36px; font-family: var(--font-sans); font-size: 28px; font-weight: 900; color: var(--text-primary); letter-spacing: -0.5px; }
|
| 513 |
|
| 514 |
.auth-tab-switch { display: flex; background: var(--bg-secondary); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; }
|
|
|
|
| 562 |
|
| 563 |
.input-tools-row { flex-wrap: wrap; }
|
| 564 |
.main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; }
|
|
|
|
| 565 |
}
|
| 566 |
</style>
|
| 567 |
</head>
|
| 568 |
<body>
|
| 569 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 570 |
<!-- =========================================================================================
|
| 571 |
DOM STRUCTURE: NOTIFICATIONS
|
| 572 |
========================================================================================= -->
|
|
|
|
| 633 |
<img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo">
|
| 634 |
<div class="brand-typography">
|
| 635 |
<span class="brand-name">ARJUN 2.O</span>
|
| 636 |
+
<span class="brand-edition">Professional</span>
|
| 637 |
</div>
|
| 638 |
</a>
|
| 639 |
<button class="btn-mobile-close" id="btnSidebarClose">
|
|
|
|
| 671 |
<!-- Wipe Memory Button -->
|
| 672 |
<button class="btn-erase-memory" id="btnClearMemory">
|
| 673 |
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
|
| 674 |
+
Wipe Memory Context
|
| 675 |
</button>
|
| 676 |
</div>
|
| 677 |
</aside>
|
|
|
|
| 685 |
<button class="btn-hamburger" id="btnSidebarOpen">
|
| 686 |
<svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2.5" fill="none"><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>
|
| 687 |
</button>
|
| 688 |
+
<div class="system-status-pill">
|
| 689 |
<div class="pulse-dot"></div>
|
| 690 |
+
System Online
|
| 691 |
</div>
|
| 692 |
</div>
|
| 693 |
|
|
|
|
| 742 |
|
| 743 |
<!-- File Preview Component -->
|
| 744 |
<div class="upload-preview-bar" id="filePreviewBar">
|
| 745 |
+
<img class="upload-thumb" id="previewImgThumb" src="" style="display:none;">
|
| 746 |
<div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div>
|
| 747 |
<div class="upload-meta">
|
| 748 |
<div class="upload-filename" id="previewFileName">document.pdf</div>
|
|
|
|
| 751 |
File ready to be transmitted
|
| 752 |
</div>
|
| 753 |
</div>
|
| 754 |
+
<button class="btn-discard-upload" id="btnDiscardFile">
|
| 755 |
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
|
| 756 |
</button>
|
| 757 |
</div>
|
|
|
|
| 803 |
</button>
|
| 804 |
|
| 805 |
<!-- Expanding Text Area -->
|
| 806 |
+
<textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1"></textarea>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 807 |
|
| 808 |
<!-- Master Send Button -->
|
| 809 |
<button class="btn-master-send" id="masterSendBtn">
|
|
|
|
| 833 |
</div>
|
| 834 |
</div>
|
| 835 |
<div class="workspace-editor-surface">
|
| 836 |
+
<pre><code id="workspaceCodeBlock" class="hljs"></code></pre>
|
|
|
|
|
|
|
|
|
|
| 837 |
</div>
|
| 838 |
</aside>
|
| 839 |
</div>
|
|
|
|
| 883 |
</div>
|
| 884 |
|
| 885 |
<!-- =========================================================================================
|
| 886 |
+
[3] MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
|
| 887 |
========================================================================================= -->
|
| 888 |
+
<!-- CRITICAL FIX: Removed type="module" from the script block to ensure all elements
|
| 889 |
+
and functions remain within the window/global scope and are easily bound.
|
| 890 |
+
Gradio Client will be dynamically imported. -->
|
| 891 |
<script>
|
| 892 |
// =======================================================================================
|
| 893 |
// 1. CONFIGURATION & STATE MANAGEMENT
|
|
|
|
| 897 |
LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
|
| 898 |
PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
|
| 899 |
API_ENDPOINT: '/api/chat', // Uses relative path to connect to Flask App.py
|
|
|
|
| 900 |
};
|
| 901 |
|
| 902 |
// Initialize PDF worker
|
|
|
|
| 914 |
isStreamingActive: false,
|
| 915 |
isLiveModeEngaged: false,
|
| 916 |
gradioClient: null,
|
| 917 |
+
isMicRecording: false
|
|
|
|
| 918 |
};
|
| 919 |
|
| 920 |
+
// Initialize Gradio Client Dynamically (Fixes the Module Bug)
|
| 921 |
window.initGradioEngine = async function() {
|
| 922 |
try {
|
| 923 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
| 924 |
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
|
| 925 |
console.log("Neural TTS Engine connected successfully to Gradio.");
|
| 926 |
} catch(err) {
|
| 927 |
+
console.error("Gradio Connection Error:", err);
|
|
|
|
| 928 |
}
|
| 929 |
};
|
| 930 |
window.initGradioEngine();
|
|
|
|
| 933 |
// 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners)
|
| 934 |
// =======================================================================================
|
| 935 |
const Utils = {
|
| 936 |
+
showToast: (message) => {
|
| 937 |
const container = document.getElementById('toast-container');
|
| 938 |
const toast = document.createElement('div');
|
| 939 |
+
toast.className = 'toast-notification';
|
| 940 |
+
toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> ${message}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
container.appendChild(toast);
|
| 942 |
+
setTimeout(() => toast.remove(), 3000);
|
| 943 |
},
|
| 944 |
|
| 945 |
escapeHTML: (str) => {
|
|
|
|
| 946 |
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
| 947 |
},
|
| 948 |
|
| 949 |
+
// ✨ CRITICAL FIX: Intelligent Text Cleaner for TTS (Ignores code, links, images)
|
| 950 |
cleanTextForVoice: (rawText) => {
|
| 951 |
if(!rawText) return "";
|
| 952 |
let cleaned = rawText;
|
| 953 |
|
| 954 |
+
// 1. Remove Markdown Code Blocks (``` ... ```)
|
| 955 |
+
cleaned = cleaned.replace(/```[\s\S]*?```/g, '');
|
| 956 |
+
// 2. Remove Inline Code (`...`)
|
| 957 |
+
cleaned = cleaned.replace(/`.*?`/g, '');
|
| 958 |
+
// 3. Remove Markdown Images ()
|
| 959 |
+
cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, '');
|
| 960 |
+
// 4. Remove Markdown Links ([text](url)) - Extract just the text
|
| 961 |
+
cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1');
|
| 962 |
+
// 5. Remove Think Tags (<think>...</think>)
|
| 963 |
+
cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, '');
|
| 964 |
+
// 6. Remove URLs/HTTP links explicitly
|
| 965 |
+
cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, '');
|
| 966 |
+
// 7. Remove stray Markdown formatting symbols
|
| 967 |
+
cleaned = cleaned.replace(/[*_~#]/g, '');
|
| 968 |
|
| 969 |
return cleaned.trim();
|
| 970 |
},
|
|
|
|
| 974 |
const textArea = document.createElement("textarea");
|
| 975 |
textArea.value = text;
|
| 976 |
textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed";
|
|
|
|
| 977 |
document.body.appendChild(textArea);
|
| 978 |
textArea.focus(); textArea.select();
|
| 979 |
|
|
|
|
| 981 |
const successful = document.execCommand('copy');
|
| 982 |
if (successful) {
|
| 983 |
const originalHTML = btnElement.innerHTML;
|
| 984 |
+
btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Successfully`;
|
| 985 |
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
|
| 986 |
} else {
|
| 987 |
+
Utils.showToast("Clipboard access denied by browser.");
|
| 988 |
}
|
| 989 |
} catch (err) {
|
| 990 |
+
Utils.showToast("System error copying text.");
|
| 991 |
}
|
| 992 |
document.body.removeChild(textArea);
|
| 993 |
},
|
|
|
|
| 999 |
}
|
| 1000 |
navigator.clipboard.writeText(textToCopy).then(() => {
|
| 1001 |
const originalHTML = btnElement.innerHTML;
|
| 1002 |
+
btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Successfully`;
|
| 1003 |
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
|
| 1004 |
}).catch((err) => {
|
| 1005 |
console.warn('Modern API failed, utilizing fallback...', err);
|
|
|
|
| 1009 |
};
|
| 1010 |
|
| 1011 |
// =======================================================================================
|
| 1012 |
+
// 3. AUTHENTICATION & SYNC MANAGER (Robust Fetch)
|
| 1013 |
// =======================================================================================
|
| 1014 |
const AuthManager = {
|
| 1015 |
initUI: () => {
|
|
|
|
| 1048 |
document.getElementById(nextId).classList.add('active');
|
| 1049 |
},
|
| 1050 |
|
| 1051 |
+
// ✨ FIXED GAS SYNC LOGIC
|
| 1052 |
process: async (actionType) => {
|
|
|
|
|
|
|
| 1053 |
const payload = { action: actionType };
|
| 1054 |
let buttonId = '';
|
| 1055 |
|
|
|
|
| 1057 |
payload.name = document.getElementById('authRegName').value.trim();
|
| 1058 |
payload.email = document.getElementById('authRegEmail').value.trim();
|
| 1059 |
payload.phone = "0000000000"; payload.organization = "Arjun Base";
|
| 1060 |
+
if (!payload.email || !payload.name) return Utils.showToast("Identification details required.");
|
| 1061 |
buttonId = 'btn-fire-reg-otp';
|
| 1062 |
}
|
| 1063 |
else if (actionType === 'login_send_otp') {
|
| 1064 |
payload.email = document.getElementById('authLogEmail').value.trim();
|
| 1065 |
+
if (!payload.email) return Utils.showToast("Email required for validation.");
|
| 1066 |
buttonId = 'btn-fire-log-otp';
|
| 1067 |
}
|
| 1068 |
else if (actionType === 'register_verify' || actionType === 'login_verify') {
|
| 1069 |
payload.email = document.getElementById(actionType === 'register_verify' ? 'authRegEmail' : 'authLogEmail').value.trim();
|
| 1070 |
payload.otp = document.getElementById(actionType === 'register_verify' ? 'authRegOTP' : 'authLogOTP').value.trim();
|
| 1071 |
+
if (!payload.otp) return Utils.showToast("Security token required.");
|
| 1072 |
buttonId = actionType === 'register_verify' ? 'btn-fire-reg-verify' : 'btn-fire-log-verify';
|
| 1073 |
}
|
| 1074 |
|
|
|
|
| 1078 |
triggerBtn.innerText = 'Establishing Connection...';
|
| 1079 |
|
| 1080 |
try {
|
| 1081 |
+
// mode: 'cors' handles redirect issues from GAS effectively
|
| 1082 |
const response = await fetch(Config.GAS_URL, {
|
| 1083 |
method: 'POST',
|
| 1084 |
mode: 'cors',
|
|
|
|
| 1089 |
const result = await response.json();
|
| 1090 |
|
| 1091 |
if (result.status === 'success') {
|
| 1092 |
+
Utils.showToast(result.message);
|
| 1093 |
if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2');
|
| 1094 |
else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2');
|
| 1095 |
else if (actionType === 'register_verify' || actionType === 'login_verify') {
|
|
|
|
| 1100 |
ChatEngine.syncHistoryFromCloud();
|
| 1101 |
}
|
| 1102 |
} else {
|
| 1103 |
+
Utils.showToast(result.message);
|
| 1104 |
}
|
| 1105 |
} catch (error) {
|
| 1106 |
console.error("Auth Network Error: ", error);
|
| 1107 |
+
Utils.showToast("Encrypted gateway error. Check network.");
|
| 1108 |
}
|
| 1109 |
|
| 1110 |
triggerBtn.disabled = false;
|
|
|
|
| 1153 |
|
| 1154 |
toggleAttachMenu: () => {
|
| 1155 |
document.getElementById('attachDropdownMenu').classList.toggle('visible');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1156 |
}
|
| 1157 |
};
|
| 1158 |
|
| 1159 |
// =======================================================================================
|
| 1160 |
+
// 5. SPEECH & TTS ENGINE (Bilingual STT + Gradio Edge-TTS + Smart Cleaner)
|
| 1161 |
// =======================================================================================
|
| 1162 |
const VoiceEngine = {
|
| 1163 |
recognition: null,
|
| 1164 |
currentLanguage: 'en-IN',
|
| 1165 |
+
|
|
|
|
|
|
|
| 1166 |
init: () => {
|
| 1167 |
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
| 1168 |
+
if (!SR) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1169 |
|
| 1170 |
VoiceEngine.recognition = new SR();
|
| 1171 |
+
// FIX: Setting continuous to true prevents mic from stopping abruptly
|
| 1172 |
VoiceEngine.recognition.continuous = true;
|
| 1173 |
VoiceEngine.recognition.interimResults = true;
|
| 1174 |
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
|
|
|
|
| 1176 |
VoiceEngine.recognition.onstart = () => {
|
| 1177 |
AppState.isMicRecording = true;
|
| 1178 |
document.getElementById('masterVoiceBtn').classList.add('active-listening');
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1179 |
if (AppState.isLiveModeEngaged) {
|
|
|
|
| 1180 |
document.getElementById('liveMicBtn').classList.add('is-recording');
|
| 1181 |
document.getElementById('liveStatusText').innerText = "Listening...";
|
| 1182 |
document.getElementById('liveOrb').classList.remove('speaking');
|
|
|
|
| 1185 |
};
|
| 1186 |
|
| 1187 |
VoiceEngine.recognition.onresult = (event) => {
|
| 1188 |
+
let finalTranscript = '';
|
| 1189 |
+
let interimTranscript = '';
|
|
|
|
|
|
|
|
|
|
| 1190 |
|
| 1191 |
+
for (let i = event.resultIndex; i < event.results.length; ++i) {
|
|
|
|
|
|
|
| 1192 |
if (event.results[i].isFinal) {
|
| 1193 |
+
finalTranscript += event.results[i][0].transcript;
|
| 1194 |
} else {
|
| 1195 |
+
interimTranscript += event.results[i][0].transcript;
|
| 1196 |
}
|
| 1197 |
}
|
| 1198 |
|
| 1199 |
+
if (finalTranscript.trim().length > 0) {
|
| 1200 |
+
let formattedText = finalTranscript.trim();
|
| 1201 |
+
formattedText = formattedText.charAt(0).toUpperCase() + formattedText.slice(1);
|
| 1202 |
+
if (!/[.!?।]$/.test(formattedText)) formattedText += '.';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1203 |
|
| 1204 |
+
if (AppState.isLiveModeEngaged) {
|
| 1205 |
+
document.getElementById('liveTranscriptText').innerText = `"${formattedText}"`;
|
| 1206 |
+
document.getElementById('liveStatusText').innerText = "Synthesizing Response...";
|
| 1207 |
+
document.getElementById('mainChatInput').value = formattedText;
|
| 1208 |
+
|
| 1209 |
+
// Stop mic manually to trigger dispatch in Live Mode
|
| 1210 |
+
VoiceEngine.recognition.stop();
|
| 1211 |
+
ChatEngine.initiateDispatch();
|
| 1212 |
} else {
|
| 1213 |
+
const inputField = document.getElementById('mainChatInput');
|
| 1214 |
+
inputField.value = (inputField.value + ' ' + formattedText + ' ').trim();
|
| 1215 |
+
UIManager.autoGrowTextArea(inputField);
|
| 1216 |
}
|
| 1217 |
}
|
| 1218 |
};
|
|
|
|
| 1220 |
VoiceEngine.recognition.onend = () => {
|
| 1221 |
AppState.isMicRecording = false;
|
| 1222 |
document.getElementById('masterVoiceBtn').classList.remove('active-listening');
|
|
|
|
| 1223 |
|
| 1224 |
+
if (AppState.isLiveModeEngaged && !AppState.isProcessing) {
|
| 1225 |
document.getElementById('liveMicBtn').classList.remove('is-recording');
|
| 1226 |
+
document.getElementById('liveStatusText').innerText = "Tap mic to interact";
|
| 1227 |
document.getElementById('liveOrb').style.transform = "scale(1)";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1228 |
}
|
| 1229 |
};
|
| 1230 |
|
| 1231 |
VoiceEngine.recognition.onerror = (event) => {
|
| 1232 |
AppState.isMicRecording = false;
|
| 1233 |
+
if(event.error !== 'no-speech') {
|
| 1234 |
+
Utils.showToast("Voice module error: " + event.error);
|
| 1235 |
}
|
| 1236 |
document.getElementById('masterVoiceBtn').classList.remove('active-listening');
|
|
|
|
|
|
|
| 1237 |
if (AppState.isLiveModeEngaged) {
|
| 1238 |
document.getElementById('liveMicBtn').classList.remove('is-recording');
|
| 1239 |
document.getElementById('liveStatusText').innerText = "Audio Failure. Retry.";
|
|
|
|
| 1249 |
VoiceEngine.currentLanguage = 'hi-IN';
|
| 1250 |
badge.innerText = 'हि';
|
| 1251 |
btn.classList.add('hindi-active');
|
| 1252 |
+
Utils.showToast("Listening Protocol: Hindi (देवनागरी)");
|
| 1253 |
} else {
|
| 1254 |
VoiceEngine.currentLanguage = 'en-IN';
|
| 1255 |
badge.innerText = 'EN';
|
| 1256 |
btn.classList.remove('hindi-active');
|
| 1257 |
+
Utils.showToast("Listening Protocol: English");
|
| 1258 |
}
|
| 1259 |
|
| 1260 |
if (VoiceEngine.recognition) {
|
| 1261 |
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
|
| 1262 |
if(AppState.isMicRecording) {
|
| 1263 |
VoiceEngine.recognition.stop();
|
| 1264 |
+
setTimeout(() => { VoiceEngine.recognition.start(); }, 400);
|
|
|
|
| 1265 |
}
|
| 1266 |
}
|
| 1267 |
},
|
| 1268 |
|
| 1269 |
toggleDictation: () => {
|
| 1270 |
+
if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported.");
|
| 1271 |
try {
|
| 1272 |
if(AppState.isMicRecording) {
|
| 1273 |
VoiceEngine.recognition.stop();
|
|
|
|
| 1277 |
} catch (e) { console.error("Mic Start Error", e); }
|
| 1278 |
},
|
| 1279 |
|
| 1280 |
+
// ✨ GRADIO TTS INTEGRATION WITH SMART CLEANER
|
| 1281 |
executeTTS: async (rawText) => {
|
| 1282 |
// Apply smart text cleaner so AI doesn't read code or image links
|
| 1283 |
const cleanSpeechText = Utils.cleanTextForVoice(rawText);
|
| 1284 |
|
| 1285 |
if(!cleanSpeechText.trim()) {
|
| 1286 |
+
Utils.showToast("No readable text found.");
|
| 1287 |
return;
|
| 1288 |
}
|
| 1289 |
|
|
|
|
| 1294 |
|
| 1295 |
try {
|
| 1296 |
if(!AppState.gradioClient) {
|
| 1297 |
+
// Fallback dynamically import if not connected
|
| 1298 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
| 1299 |
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
|
| 1300 |
}
|
|
|
|
| 1304 |
voice_type: "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)"
|
| 1305 |
});
|
| 1306 |
|
| 1307 |
+
if (result.data && result.data[0]) {
|
| 1308 |
+
const audioUrl = typeof result.data[0] === 'string' ? result.data[0] : result.data[0].url;
|
| 1309 |
const audio = new Audio(audioUrl);
|
| 1310 |
|
| 1311 |
audio.onended = () => {
|
|
|
|
| 1320 |
throw new Error("No audio payload returned.");
|
| 1321 |
}
|
| 1322 |
} catch (error) {
|
| 1323 |
+
Utils.showToast("Voice Neural Matrix is currently overloaded.");
|
| 1324 |
console.error("Gradio TTS Error:", error);
|
| 1325 |
if (AppState.isLiveModeEngaged) {
|
| 1326 |
document.getElementById('liveOrb').classList.remove('speaking');
|
|
|
|
| 1339 |
if (VoiceEngine.recognition && !AppState.isMicRecording) {
|
| 1340 |
setTimeout(() => {
|
| 1341 |
try { VoiceEngine.recognition.start(); } catch(e){}
|
| 1342 |
+
}, 500);
|
| 1343 |
}
|
| 1344 |
},
|
| 1345 |
terminate: () => {
|
|
|
|
| 1352 |
};
|
| 1353 |
|
| 1354 |
// =======================================================================================
|
| 1355 |
+
// 6. FILE & DOCUMENT PROCESSOR (Non-Technical Vocabulary)
|
| 1356 |
// =======================================================================================
|
| 1357 |
const FileProcessor = {
|
| 1358 |
triggerFileSelector: (type) => {
|
|
|
|
| 1361 |
},
|
| 1362 |
|
| 1363 |
processFile: async (inputElement, typeContext) => {
|
| 1364 |
+
const file = inputElement.files[0];
|
| 1365 |
if (!file) return;
|
| 1366 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1367 |
const fName = file.name.toLowerCase();
|
| 1368 |
const mime = file.type;
|
| 1369 |
|
| 1370 |
+
if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required."); inputElement.value=''; return; }
|
| 1371 |
+
if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required."); inputElement.value=''; return; }
|
| 1372 |
+
if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required."); inputElement.value=''; return; }
|
| 1373 |
|
| 1374 |
+
Utils.showToast(`Uploading your file...`);
|
| 1375 |
|
| 1376 |
const thumbImg = document.getElementById('previewImgThumb');
|
| 1377 |
const docIcon = document.getElementById('previewDocIcon');
|
|
|
|
| 1385 |
|
| 1386 |
if (typeContext === 'image') {
|
| 1387 |
fileReader.onload = (e) => {
|
| 1388 |
+
AppState.pendingAttachment = { type: 'image', data: e.target.result.split(',')[1], name: file.name };
|
| 1389 |
thumbImg.src = e.target.result;
|
| 1390 |
thumbImg.style.display = 'flex';
|
| 1391 |
};
|
|
|
|
| 1393 |
}
|
| 1394 |
else if (typeContext === 'video' || typeContext === 'audio') {
|
| 1395 |
fileReader.onload = (e) => {
|
| 1396 |
+
AppState.pendingAttachment = { type: typeContext, data: e.target.result.split(',')[1], name: file.name };
|
| 1397 |
docIcon.innerText = typeContext === 'video' ? '🎥' : '🎵';
|
| 1398 |
docIcon.style.display = 'flex';
|
| 1399 |
};
|
|
|
|
| 1415 |
extractedText += content.items.map(s => s.str).join(' ') + "\n";
|
| 1416 |
}
|
| 1417 |
AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name };
|
| 1418 |
+
Utils.showToast("Your PDF is ready!");
|
| 1419 |
} catch (e) {
|
| 1420 |
+
Utils.showToast("PDF parsing encountered an error.");
|
| 1421 |
FileProcessor.discardFile();
|
| 1422 |
}
|
| 1423 |
};
|
|
|
|
| 1429 |
const buffer = this.result;
|
| 1430 |
const resultData = await mammoth.extractRawText({ arrayBuffer: buffer });
|
| 1431 |
AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name };
|
| 1432 |
+
Utils.showToast("Your Word document is ready!");
|
| 1433 |
} catch(e) {
|
| 1434 |
+
Utils.showToast("Document parsing encountered an error.");
|
| 1435 |
FileProcessor.discardFile();
|
| 1436 |
}
|
| 1437 |
};
|
|
|
|
| 1440 |
else {
|
| 1441 |
fileReader.onload = (e) => {
|
| 1442 |
AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
|
| 1443 |
+
Utils.showToast("Your file is ready!");
|
| 1444 |
};
|
| 1445 |
fileReader.readAsText(file);
|
| 1446 |
}
|
|
|
|
| 1451 |
discardFile: () => {
|
| 1452 |
AppState.pendingAttachment = null;
|
| 1453 |
document.getElementById('filePreviewBar').classList.remove('visible');
|
|
|
|
| 1454 |
}
|
| 1455 |
};
|
| 1456 |
|
| 1457 |
// =======================================================================================
|
| 1458 |
+
// 7. WORKSPACE ENGINE & MARKDOWN RENDERING
|
| 1459 |
// =======================================================================================
|
| 1460 |
const WorkspaceEngine = {
|
| 1461 |
launch: (codeBlockId) => {
|
| 1462 |
AppState.currentWorkspaceId = codeBlockId;
|
| 1463 |
const codeData = AppState.generatedCodeBlocks[codeBlockId];
|
| 1464 |
|
| 1465 |
+
document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled Code";
|
| 1466 |
const blockDisplay = document.getElementById('workspaceCodeBlock');
|
| 1467 |
blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`;
|
| 1468 |
blockDisplay.textContent = codeData.code;
|
| 1469 |
|
| 1470 |
hljs.highlightElement(blockDisplay);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1471 |
document.getElementById('workspacePanel').classList.add('expanded');
|
| 1472 |
|
| 1473 |
if (window.innerWidth <= 1024) {
|
|
|
|
| 1485 |
}
|
| 1486 |
};
|
| 1487 |
|
|
|
|
| 1488 |
const MD_Renderer = new marked.Renderer();
|
| 1489 |
MD_Renderer.code = function(token) {
|
| 1490 |
const rawCode = typeof token === 'string' ? token : (token.text || '');
|
| 1491 |
+
const langClass = typeof token === 'string' ? arguments[1] : (token.lang || '');
|
| 1492 |
|
| 1493 |
if (AppState.isStreamingActive) {
|
| 1494 |
return `
|
| 1495 |
<div class="streaming-code-container">
|
| 1496 |
<div class="streaming-code-header">
|
| 1497 |
<div class="loading-ring"></div>
|
| 1498 |
+
Generating Architecture...
|
| 1499 |
</div>
|
| 1500 |
<pre><code class="language-${langClass}">${Utils.escapeHTML(rawCode)}</code></pre>
|
| 1501 |
</div>`;
|
|
|
|
| 1512 |
</div>
|
| 1513 |
<div class="ws-card-details">
|
| 1514 |
<h4>Code Module Compiled</h4>
|
| 1515 |
+
<p>${langClass || 'Syntax Detected'}</p>
|
| 1516 |
</div>
|
| 1517 |
</div>
|
| 1518 |
<button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button>
|
| 1519 |
</div>`;
|
| 1520 |
};
|
| 1521 |
+
marked.use({ renderer: MD_Renderer });
|
| 1522 |
|
| 1523 |
+
// Event delegation for workspace buttons
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1524 |
document.getElementById('msgs').addEventListener('click', function(e) {
|
| 1525 |
if (e.target && e.target.classList.contains('btn-launch-ws')) {
|
| 1526 |
const blockId = e.target.getAttribute('data-id');
|
|
|
|
| 1545 |
},
|
| 1546 |
|
| 1547 |
clearMemory: async () => {
|
|
|
|
|
|
|
| 1548 |
if (AppState.currentUser) {
|
| 1549 |
+
Utils.showToast("Purging neural link memory...");
|
| 1550 |
try {
|
| 1551 |
await fetch(Config.GAS_URL, {
|
| 1552 |
method: 'POST',
|
|
|
|
| 1560 |
},
|
| 1561 |
|
| 1562 |
syncHistoryFromCloud: async () => {
|
|
|
|
|
|
|
| 1563 |
const messageZone = document.getElementById('msgs');
|
| 1564 |
document.getElementById('welcomeState').style.display = 'none';
|
| 1565 |
messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>';
|
|
|
|
| 1595 |
},
|
| 1596 |
|
| 1597 |
saveHistoryToCloud: () => {
|
| 1598 |
+
if (AppState.currentUser) {
|
| 1599 |
fetch(Config.GAS_URL, {
|
| 1600 |
method: 'POST',
|
| 1601 |
mode: 'cors',
|
|
|
|
| 1608 |
buildPreviewHTML: (attachmentObj) => {
|
| 1609 |
if (!attachmentObj) return '';
|
| 1610 |
if (attachmentObj.type === 'image') {
|
| 1611 |
+
return `<img src="data:image/jpeg;base64,${attachmentObj.data}" class="chat-in-bubble-img" alt="Attached Image">`;
|
| 1612 |
} else if (attachmentObj.type === 'video') {
|
| 1613 |
+
return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"></polygon><rect x="1" y="5" width="15" height="14" rx="2" ry="2"></rect></svg></div><span class="name">${attachmentObj.name}</span></div>`;
|
| 1614 |
} else if (attachmentObj.type === 'audio') {
|
| 1615 |
+
return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg></div><span class="name">${attachmentObj.name}</span></div>`;
|
| 1616 |
} else {
|
| 1617 |
+
return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg></div><span class="name">${attachmentObj.name}</span></div>`;
|
| 1618 |
}
|
| 1619 |
},
|
| 1620 |
|
|
|
|
| 1624 |
let visibleText = textContent;
|
| 1625 |
if(textContent.includes('---DATA BEGIN---')) {
|
| 1626 |
const parts = textContent.split('User Prompt:');
|
| 1627 |
+
if(parts.length > 1) visibleText = parts[1].trim();
|
| 1628 |
}
|
| 1629 |
|
| 1630 |
const bubbleBox = document.createElement('div');
|
|
|
|
| 1669 |
let actionTray = bubbleDOM.querySelector('.bot-actions-row');
|
| 1670 |
if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
|
| 1671 |
const safeRawCopy = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
|
| 1672 |
+
// safeRawTTS is passed as is, because the executeTTS function now handles the Smart Cleaning internally
|
| 1673 |
const safeRawTTS = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, ' ');
|
| 1674 |
|
| 1675 |
const actionsHTML = `
|
|
|
|
| 1691 |
},
|
| 1692 |
|
| 1693 |
initiateDispatch: async () => {
|
|
|
|
| 1694 |
if (AppState.isProcessing) return;
|
| 1695 |
|
| 1696 |
const inputField = document.getElementById('mainChatInput');
|
|
|
|
| 1702 |
if (!AppState.currentUser) {
|
| 1703 |
if (AppState.guestCount >= 3) {
|
| 1704 |
AuthManager.openModal();
|
| 1705 |
+
return Utils.showToast("Query limit reached. Secure Login required.");
|
| 1706 |
}
|
| 1707 |
AppState.guestCount++;
|
| 1708 |
localStorage.setItem('arjun_guest', AppState.guestCount.toString());
|
| 1709 |
document.getElementById('guestCountDisplay').innerText = AppState.guestCount;
|
| 1710 |
}
|
| 1711 |
|
| 1712 |
+
// Prepare UI
|
| 1713 |
inputField.value = '';
|
| 1714 |
inputField.style.height = 'auto';
|
| 1715 |
document.getElementById('masterSendBtn').disabled = true;
|
|
|
|
| 1752 |
const activeBotBubble = ChatEngine.renderBotMessage('', false);
|
| 1753 |
UIManager.forceScrollDown();
|
| 1754 |
|
| 1755 |
+
// 🎲 Dynamic Pollinations Generator
|
| 1756 |
const cryptographicSeed = Math.floor(Math.random() * 999999999);
|
| 1757 |
|
| 1758 |
+
// 🧠 Advanced Cognitive System Instructions
|
| 1759 |
+
let cognitivePrompt = `You are Arjun 2.O, a sophisticated enterprise AI system architected by Abhay Kumar.
|
| 1760 |
+
LANGUAGE REGULATION: Your default cognitive language is ENGLISH. If the user writes in English, reply in purely professional English. If the user writes in Hindi or Hinglish, reply gracefully in Hindi. Never force Hindi translation if the prompt is English.
|
| 1761 |
|
| 1762 |
IMAGE SYNTHESIS OVERRIDE:
|
| 1763 |
When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI.
|
| 1764 |
Formula: 
|
| 1765 |
Available Models: flux, flux-realism, flux-anime, flux-3d.
|
| 1766 |
+
CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node.`;
|
| 1767 |
|
| 1768 |
if (AppState.isLiveModeEngaged) {
|
| 1769 |
+
cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE]: You are currently engaged in a LIVE, REAL-TIME VOCAL INTERFACE.
|
| 1770 |
MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`;
|
| 1771 |
}
|
| 1772 |
|
|
|
|
| 1777 |
attachments: payloadAttachments,
|
| 1778 |
system_prompt: cognitivePrompt,
|
| 1779 |
history: secureHistory,
|
| 1780 |
+
max_tokens: AppState.isLiveModeEngaged ? 120 : 4096,
|
| 1781 |
temperature: 0.75
|
| 1782 |
};
|
| 1783 |
|
|
|
|
| 1811 |
|
| 1812 |
try {
|
| 1813 |
const jsonSegment = JSON.parse(parseableStr);
|
| 1814 |
+
if (jsonSegment.choices && jsonSegment.choices[0].delta.content) {
|
| 1815 |
+
responseBuffer += jsonSegment.choices[0].delta.content;
|
| 1816 |
ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true);
|
| 1817 |
UIManager.autoScroll();
|
| 1818 |
}
|
|
|
|
| 1849 |
// 9. EVENT DELEGATION & BOOTSTRAP INVOCATION
|
| 1850 |
// =======================================================================================
|
| 1851 |
|
| 1852 |
+
// Define global function for welcome screen overlay
|
| 1853 |
window.startArjunApp = function() {
|
| 1854 |
document.getElementById('welcomeOverlay').classList.add('hidden');
|
| 1855 |
localStorage.setItem('arjun_welcome_seen', 'true');
|
| 1856 |
setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
|
| 1857 |
};
|
| 1858 |
|
| 1859 |
+
// Bind all interactive elements safely using Event Listeners to avoid scope issues
|
| 1860 |
document.addEventListener('DOMContentLoaded', () => {
|
| 1861 |
// Sidebar Controls
|
| 1862 |
document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar);
|
|
|
|
| 1918 |
document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState);
|
| 1919 |
document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown);
|
| 1920 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1921 |
// Prevent unwanted default mobile behaviours on double-tap
|
| 1922 |
document.addEventListener('dblclick', function(event) {
|
| 1923 |
event.preventDefault();
|
|
|
|
| 1931 |
}
|
| 1932 |
|
| 1933 |
// Fire Boot Processes
|
|
|
|
| 1934 |
VoiceEngine.init();
|
| 1935 |
AuthManager.initUI();
|
| 1936 |
if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); }
|
|
|
|
| 1939 |
</script>
|
| 1940 |
</body>
|
| 1941 |
</html>
|
| 1942 |
+
|