Spaces:
Running
Running
Vedika commited on
Update index.html
Browse files- index.html +162 -150
index.html
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
|
|
| 1 |
<html lang="en" dir="ltr">
|
| 2 |
<head>
|
| 3 |
<meta charset="UTF-8">
|
| 4 |
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
| 5 |
-
<!-- Viewport Settings: Disables zoom, removes blue tap highlights on mobile devices -->
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
| 7 |
<meta name="description" content="Arjun 2.O Ultimate Enterprise Artificial Intelligence System engineered by Abhay Kumar.">
|
| 8 |
<meta name="theme-color" content="#FF9933">
|
|
@@ -10,12 +11,12 @@
|
|
| 10 |
<title>Arjun 2.O - Professional Advanced AI</title>
|
| 11 |
|
| 12 |
<!-- =========================================================================================
|
| 13 |
-
[1] EXTERNAL RESOURCES, FONTS & LIBRARIES
|
| 14 |
========================================================================================= -->
|
| 15 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 16 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 17 |
|
| 18 |
-
<!-- Professional Typography
|
| 19 |
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@300;400;500;600;700;800;900&family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 20 |
|
| 21 |
<!-- Syntax Highlighting (Atom One Dark for Workspace Environment) -->
|
|
@@ -28,18 +29,17 @@
|
|
| 28 |
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script>
|
| 29 |
|
| 30 |
<!-- =========================================================================================
|
| 31 |
-
[2] MASSIVE ENTERPRISE CSS ARCHITECTURE
|
| 32 |
========================================================================================= -->
|
| 33 |
<style>
|
| 34 |
/* ---------------------------------------------------------------------------------------
|
| 35 |
-
A. CSS VARIABLES
|
| 36 |
--------------------------------------------------------------------------------------- */
|
| 37 |
:root {
|
| 38 |
-
/*
|
| 39 |
--brand-saffron: #FF9933;
|
| 40 |
--brand-saffron-light: rgba(255, 153, 51, 0.12);
|
| 41 |
--brand-saffron-dark: #e68a2e;
|
| 42 |
-
--brand-saffron-glow: rgba(255, 153, 51, 0.4);
|
| 43 |
|
| 44 |
--brand-white: #FFFFFF;
|
| 45 |
--brand-white-glass: rgba(255, 255, 255, 0.88);
|
|
@@ -47,15 +47,12 @@
|
|
| 47 |
--brand-green: #138808;
|
| 48 |
--brand-green-light: rgba(19, 136, 8, 0.12);
|
| 49 |
--brand-green-dark: #0f6e06;
|
| 50 |
-
--brand-green-glow: rgba(19, 136, 8, 0.4);
|
| 51 |
|
| 52 |
-
/* Structural Colors
|
| 53 |
--bg-primary: #ffffff;
|
| 54 |
--bg-secondary: #f8f9fa;
|
| 55 |
--bg-tertiary: #f1f3f5;
|
| 56 |
--bg-glass: rgba(255, 255, 255, 0.75);
|
| 57 |
-
--bg-glass-heavy: rgba(255, 255, 255, 0.95);
|
| 58 |
-
--bg-overlay: rgba(0, 0, 0, 0.5);
|
| 59 |
|
| 60 |
/* Text & Typography Colors */
|
| 61 |
--text-primary: #111827;
|
|
@@ -67,7 +64,6 @@
|
|
| 67 |
/* Borders & Dividers */
|
| 68 |
--border-light: rgba(0, 0, 0, 0.08);
|
| 69 |
--border-medium: rgba(0, 0, 0, 0.15);
|
| 70 |
-
--border-focus: rgba(255, 153, 51, 0.4);
|
| 71 |
|
| 72 |
/* Shadows & Elevation */
|
| 73 |
--shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
|
|
@@ -75,7 +71,6 @@
|
|
| 75 |
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
|
| 76 |
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
|
| 77 |
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
|
| 78 |
-
--shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06);
|
| 79 |
|
| 80 |
/* Font Families */
|
| 81 |
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
@@ -83,7 +78,6 @@
|
|
| 83 |
--font-serif: 'Instrument Serif', Georgia, serif;
|
| 84 |
|
| 85 |
/* Radii */
|
| 86 |
-
--radius-xs: 4px;
|
| 87 |
--radius-sm: 8px;
|
| 88 |
--radius-md: 12px;
|
| 89 |
--radius-lg: 16px;
|
|
@@ -99,8 +93,6 @@
|
|
| 99 |
--z-ambient: -1;
|
| 100 |
--z-base: 1;
|
| 101 |
--z-header: 10;
|
| 102 |
-
--z-dock: 20;
|
| 103 |
-
--z-workspace: 25;
|
| 104 |
--z-dropdown: 50;
|
| 105 |
--z-sidebar: 100;
|
| 106 |
--z-modal: 5000;
|
|
@@ -109,13 +101,13 @@
|
|
| 109 |
}
|
| 110 |
|
| 111 |
/* ---------------------------------------------------------------------------------------
|
| 112 |
-
B. GLOBAL RESET & ANTI-BLUE-HIGHLIGHT
|
| 113 |
--------------------------------------------------------------------------------------- */
|
| 114 |
*, *::before, *::after {
|
| 115 |
box-sizing: border-box;
|
| 116 |
margin: 0;
|
| 117 |
padding: 0;
|
| 118 |
-
/* CRITICAL:
|
| 119 |
-webkit-tap-highlight-color: transparent !important;
|
| 120 |
-webkit-touch-callout: none !important;
|
| 121 |
}
|
|
@@ -134,7 +126,7 @@
|
|
| 134 |
-moz-osx-font-smoothing: grayscale;
|
| 135 |
}
|
| 136 |
|
| 137 |
-
/*
|
| 138 |
*:focus { outline: none !important; }
|
| 139 |
|
| 140 |
button, input, textarea, select {
|
|
@@ -149,14 +141,14 @@
|
|
| 149 |
img { max-width: 100%; height: auto; display: block; }
|
| 150 |
svg { flex-shrink: 0; }
|
| 151 |
|
| 152 |
-
/*
|
| 153 |
::-webkit-scrollbar { width: 6px; height: 6px; }
|
| 154 |
::-webkit-scrollbar-track { background: transparent; }
|
| 155 |
::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.12); border-radius: 10px; transition: background var(--ease-smooth); }
|
| 156 |
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
|
| 157 |
|
| 158 |
/* ---------------------------------------------------------------------------------------
|
| 159 |
-
C. AMBIENT BACKGROUND SYSTEM
|
| 160 |
--------------------------------------------------------------------------------------- */
|
| 161 |
.ambient-environment {
|
| 162 |
position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
|
|
@@ -184,7 +176,7 @@
|
|
| 184 |
}
|
| 185 |
|
| 186 |
/* ---------------------------------------------------------------------------------------
|
| 187 |
-
D. TOAST NOTIFICATION ENGINE
|
| 188 |
--------------------------------------------------------------------------------------- */
|
| 189 |
.toast-wrapper {
|
| 190 |
position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
|
|
@@ -203,7 +195,7 @@
|
|
| 203 |
@keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
|
| 204 |
|
| 205 |
/* ---------------------------------------------------------------------------------------
|
| 206 |
-
E. INITIAL WELCOME OVERLAY
|
| 207 |
--------------------------------------------------------------------------------------- */
|
| 208 |
.startup-overlay {
|
| 209 |
position: fixed; inset: 0; background: var(--brand-white-glass);
|
|
@@ -235,7 +227,7 @@
|
|
| 235 |
--------------------------------------------------------------------------------------- */
|
| 236 |
.app-root { position: relative; z-index: var(--z-base); display: flex; height: 100dvh; width: 100vw; overflow: hidden; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); }
|
| 237 |
|
| 238 |
-
/* Sidebar Navigation
|
| 239 |
.sidebar-container { width: 320px; display: flex; flex-direction: column; background: rgba(248, 249, 250, 0.85); border-right: 1px solid var(--border-light); flex-shrink: 0; z-index: var(--z-sidebar); transition: transform var(--ease-smooth), box-shadow var(--ease-smooth); backdrop-filter: blur(15px); }
|
| 240 |
.sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
|
| 241 |
|
|
@@ -251,7 +243,7 @@
|
|
| 251 |
|
| 252 |
.sidebar-body { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 28px; }
|
| 253 |
|
| 254 |
-
/*
|
| 255 |
.auth-widget { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-sm); transition: var(--ease-smooth); }
|
| 256 |
.auth-widget:hover { box-shadow: var(--shadow-md); border-color: var(--border-medium); }
|
| 257 |
|
|
@@ -263,11 +255,11 @@
|
|
| 263 |
.user-details { flex: 1; overflow: hidden; }
|
| 264 |
.user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
| 265 |
.user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
|
| 266 |
-
.user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow:
|
| 267 |
.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); }
|
| 268 |
.btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
|
| 269 |
|
| 270 |
-
/* Developer Box
|
| 271 |
.developer-credit-box { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 28px 20px; text-align: center; box-shadow: var(--shadow-sm); margin-top: auto; position: relative; overflow: hidden; }
|
| 272 |
.developer-credit-box::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--brand-saffron), var(--brand-white), var(--brand-green)); }
|
| 273 |
.developer-credit-box img { width: 72px; height: 72px; border-radius: var(--radius-lg); object-fit: cover; margin-bottom: 16px; box-shadow: var(--shadow-md); border: 1px solid var(--border-light); margin-left: auto; margin-right: auto; transition: var(--ease-spring); }
|
|
@@ -275,7 +267,7 @@
|
|
| 275 |
.dev-box-title { font-size: 18px; font-weight: 800; color: var(--text-primary); margin-bottom: 6px; }
|
| 276 |
.dev-box-subtitle { font-size: 11px; font-weight: 800; color: var(--text-tertiary); letter-spacing: 1px; text-transform: uppercase; }
|
| 277 |
|
| 278 |
-
/*
|
| 279 |
.btn-erase-memory { width: 100%; padding: 16px; border-radius: var(--radius-md); background: var(--bg-primary); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-fast); display: flex; align-items: center; justify-content: center; gap: 10px; }
|
| 280 |
.btn-erase-memory:hover { background: #fee2e2; color: var(--text-error); border-color: #fca5a5; }
|
| 281 |
|
|
@@ -293,7 +285,7 @@
|
|
| 293 |
.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; }
|
| 294 |
@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); } }
|
| 295 |
|
| 296 |
-
/*
|
| 297 |
.btn-activate-live { background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%); color: white; border: none; padding: 10px 22px; border-radius: var(--radius-full); font-size: 14px; font-weight: 800; display: flex; align-items: center; gap: 8px; cursor: pointer; box-shadow: 0 4px 15px rgba(239, 68, 68, 0.35); transition: var(--ease-spring); letter-spacing: 0.5px; }
|
| 298 |
.btn-activate-live:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 25px rgba(239, 68, 68, 0.45); }
|
| 299 |
.btn-activate-live svg { width: 18px; height: 18px; animation: liveBlink 1.5s infinite; }
|
|
@@ -347,7 +339,7 @@
|
|
| 347 |
/* In-Bubble File Previews */
|
| 348 |
.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; }
|
| 349 |
.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); }
|
| 350 |
-
.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); }
|
| 351 |
.chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
| 352 |
|
| 353 |
.chat-bubble { padding: 18px 24px; font-size: 16px; line-height: 1.6; position: relative; word-wrap: break-word; overflow-wrap: anywhere; }
|
|
@@ -478,6 +470,7 @@
|
|
| 478 |
|
| 479 |
.pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
|
| 480 |
.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; }
|
|
|
|
| 481 |
.energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
|
| 482 |
@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); } }
|
| 483 |
|
|
@@ -545,7 +538,7 @@
|
|
| 545 |
}
|
| 546 |
|
| 547 |
@media (max-width: 900px) {
|
| 548 |
-
.sidebar-container { position: absolute; left: -320px; z-index: 1000; height: 100%; box-shadow: var(--shadow-
|
| 549 |
.sidebar-container.active { left: 0; }
|
| 550 |
.btn-hamburger { display: flex; }
|
| 551 |
.btn-mobile-close { display: flex; }
|
|
@@ -709,7 +702,7 @@
|
|
| 709 |
<h2 class="hero-greeting">How can I assist you today?</h2>
|
| 710 |
<p class="hero-description">Experience next-generation reasoning, seamless multi-file analysis, and secure workspace code generation engineered by Abhay Kumar.</p>
|
| 711 |
|
| 712 |
-
<!-- GUEST BADGE LIMIT DISPLAY -->
|
| 713 |
<div id="guestBadge" class="guest-warning-badge">
|
| 714 |
<svg viewBox="0 0 24 24" 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>
|
| 715 |
Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login.
|
|
@@ -884,9 +877,6 @@
|
|
| 884 |
<!-- =========================================================================================
|
| 885 |
[3] MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
|
| 886 |
========================================================================================= -->
|
| 887 |
-
<!-- CRITICAL FIX: Removed type="module" from the script block to ensure all elements
|
| 888 |
-
and functions remain within the window/global scope and are easily bound.
|
| 889 |
-
Gradio Client will be dynamically imported. -->
|
| 890 |
<script>
|
| 891 |
// =======================================================================================
|
| 892 |
// 1. CONFIGURATION & STATE MANAGEMENT
|
|
@@ -895,10 +885,9 @@
|
|
| 895 |
GAS_URL: "https://script.google.com/macros/s/AKfycbzTsXGoVh97JjtFAAG825GF4WUZqf7FDB3Zbxyf0nrLXt_1HjJSSqA829UcdoamRPvg0A/exec",
|
| 896 |
LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
|
| 897 |
PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
|
| 898 |
-
API_ENDPOINT: '/api/chat', //
|
| 899 |
};
|
| 900 |
|
| 901 |
-
// Initialize PDF worker
|
| 902 |
pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER;
|
| 903 |
|
| 904 |
const AppState = {
|
|
@@ -916,7 +905,7 @@
|
|
| 916 |
isMicRecording: false
|
| 917 |
};
|
| 918 |
|
| 919 |
-
// Initialize Gradio Client Dynamically
|
| 920 |
window.initGradioEngine = async function() {
|
| 921 |
try {
|
| 922 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
|
@@ -945,30 +934,23 @@
|
|
| 945 |
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
| 946 |
},
|
| 947 |
|
| 948 |
-
// ✨ CRITICAL FIX: Intelligent Text Cleaner for TTS
|
|
|
|
| 949 |
cleanTextForVoice: (rawText) => {
|
| 950 |
if(!rawText) return "";
|
| 951 |
let cleaned = rawText;
|
| 952 |
|
| 953 |
-
//
|
| 954 |
-
cleaned = cleaned.replace(/`
|
| 955 |
-
//
|
| 956 |
-
cleaned = cleaned.replace(/
|
| 957 |
-
//
|
| 958 |
-
cleaned = cleaned.replace(/
|
| 959 |
-
|
| 960 |
-
cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1');
|
| 961 |
-
// 5. Remove Think Tags (<think>...</think>)
|
| 962 |
-
cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, '');
|
| 963 |
-
// 6. Remove URLs/HTTP links explicitly
|
| 964 |
-
cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, '');
|
| 965 |
-
// 7. Remove stray Markdown formatting symbols
|
| 966 |
-
cleaned = cleaned.replace(/[*_~#]/g, '');
|
| 967 |
|
| 968 |
return cleaned.trim();
|
| 969 |
},
|
| 970 |
|
| 971 |
-
// Robust Fallback Copy Mechanism
|
| 972 |
executeFallbackCopy: (text, btnElement) => {
|
| 973 |
const textArea = document.createElement("textarea");
|
| 974 |
textArea.value = text;
|
|
@@ -1001,14 +983,13 @@
|
|
| 1001 |
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`;
|
| 1002 |
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
|
| 1003 |
}).catch((err) => {
|
| 1004 |
-
console.warn('Modern API failed, utilizing fallback...', err);
|
| 1005 |
Utils.executeFallbackCopy(textToCopy, btnElement);
|
| 1006 |
});
|
| 1007 |
}
|
| 1008 |
};
|
| 1009 |
|
| 1010 |
// =======================================================================================
|
| 1011 |
-
// 3. AUTHENTICATION & SYNC MANAGER
|
| 1012 |
// =======================================================================================
|
| 1013 |
const AuthManager = {
|
| 1014 |
initUI: () => {
|
|
@@ -1047,7 +1028,6 @@
|
|
| 1047 |
document.getElementById(nextId).classList.add('active');
|
| 1048 |
},
|
| 1049 |
|
| 1050 |
-
// ✨ FIXED GAS SYNC LOGIC
|
| 1051 |
process: async (actionType) => {
|
| 1052 |
const payload = { action: actionType };
|
| 1053 |
let buttonId = '';
|
|
@@ -1077,7 +1057,7 @@
|
|
| 1077 |
triggerBtn.innerText = 'Establishing Connection...';
|
| 1078 |
|
| 1079 |
try {
|
| 1080 |
-
// mode: 'cors' handles redirect issues from GAS effectively
|
| 1081 |
const response = await fetch(Config.GAS_URL, {
|
| 1082 |
method: 'POST',
|
| 1083 |
mode: 'cors',
|
|
@@ -1102,7 +1082,6 @@
|
|
| 1102 |
Utils.showToast(result.message);
|
| 1103 |
}
|
| 1104 |
} catch (error) {
|
| 1105 |
-
console.error("Auth Network Error: ", error);
|
| 1106 |
Utils.showToast("Encrypted gateway error. Check network.");
|
| 1107 |
}
|
| 1108 |
|
|
@@ -1156,24 +1135,30 @@
|
|
| 1156 |
};
|
| 1157 |
|
| 1158 |
// =======================================================================================
|
| 1159 |
-
// 5. SPEECH & TTS ENGINE (Bilingual STT + Gradio Edge-TTS
|
| 1160 |
// =======================================================================================
|
| 1161 |
const VoiceEngine = {
|
| 1162 |
recognition: null,
|
| 1163 |
-
currentLanguage: 'en-
|
|
|
|
| 1164 |
|
| 1165 |
init: () => {
|
| 1166 |
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
| 1167 |
if (!SR) return;
|
| 1168 |
|
| 1169 |
VoiceEngine.recognition = new SR();
|
| 1170 |
-
// FIX:
|
| 1171 |
-
VoiceEngine.recognition.continuous =
|
| 1172 |
VoiceEngine.recognition.interimResults = true;
|
| 1173 |
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
|
| 1174 |
|
| 1175 |
VoiceEngine.recognition.onstart = () => {
|
| 1176 |
AppState.isMicRecording = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1177 |
document.getElementById('masterVoiceBtn').classList.add('active-listening');
|
| 1178 |
if (AppState.isLiveModeEngaged) {
|
| 1179 |
document.getElementById('liveMicBtn').classList.add('is-recording');
|
|
@@ -1184,8 +1169,8 @@
|
|
| 1184 |
};
|
| 1185 |
|
| 1186 |
VoiceEngine.recognition.onresult = (event) => {
|
| 1187 |
-
let finalTranscript = '';
|
| 1188 |
let interimTranscript = '';
|
|
|
|
| 1189 |
|
| 1190 |
for (let i = event.resultIndex; i < event.results.length; ++i) {
|
| 1191 |
if (event.results[i].isFinal) {
|
|
@@ -1195,23 +1180,28 @@
|
|
| 1195 |
}
|
| 1196 |
}
|
| 1197 |
|
| 1198 |
-
|
| 1199 |
-
|
| 1200 |
-
|
| 1201 |
-
|
| 1202 |
-
|
| 1203 |
-
|
| 1204 |
-
|
| 1205 |
-
|
| 1206 |
-
|
| 1207 |
-
|
| 1208 |
-
|
| 1209 |
VoiceEngine.recognition.stop();
|
| 1210 |
ChatEngine.initiateDispatch();
|
| 1211 |
-
}
|
| 1212 |
-
|
| 1213 |
-
|
| 1214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1215 |
}
|
| 1216 |
}
|
| 1217 |
};
|
|
@@ -1244,13 +1234,13 @@
|
|
| 1244 |
const btn = document.getElementById('smartLangToggle');
|
| 1245 |
const badge = document.getElementById('langDisplayBadge');
|
| 1246 |
|
| 1247 |
-
if (VoiceEngine.currentLanguage === 'en-
|
| 1248 |
VoiceEngine.currentLanguage = 'hi-IN';
|
| 1249 |
badge.innerText = 'हि';
|
| 1250 |
btn.classList.add('hindi-active');
|
| 1251 |
Utils.showToast("Listening Protocol: Hindi (देवनागरी)");
|
| 1252 |
} else {
|
| 1253 |
-
VoiceEngine.currentLanguage = 'en-
|
| 1254 |
badge.innerText = 'EN';
|
| 1255 |
btn.classList.remove('hindi-active');
|
| 1256 |
Utils.showToast("Listening Protocol: English");
|
|
@@ -1276,13 +1266,17 @@
|
|
| 1276 |
} catch (e) { console.error("Mic Start Error", e); }
|
| 1277 |
},
|
| 1278 |
|
| 1279 |
-
// ✨ GRADIO TTS INTEGRATION WITH SMART CLEANER
|
| 1280 |
executeTTS: async (rawText) => {
|
| 1281 |
-
// Apply smart text cleaner so AI doesn't read code or image links
|
| 1282 |
const cleanSpeechText = Utils.cleanTextForVoice(rawText);
|
| 1283 |
|
| 1284 |
if(!cleanSpeechText.trim()) {
|
| 1285 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1286 |
return;
|
| 1287 |
}
|
| 1288 |
|
|
@@ -1293,7 +1287,6 @@
|
|
| 1293 |
|
| 1294 |
try {
|
| 1295 |
if(!AppState.gradioClient) {
|
| 1296 |
-
// Fallback dynamically import if not connected
|
| 1297 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
| 1298 |
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
|
| 1299 |
}
|
|
@@ -1307,14 +1300,19 @@
|
|
| 1307 |
const audioUrl = typeof result.data[0] === 'string' ? result.data[0] : result.data[0].url;
|
| 1308 |
const audio = new Audio(audioUrl);
|
| 1309 |
|
|
|
|
| 1310 |
audio.onended = () => {
|
| 1311 |
if (AppState.isLiveModeEngaged) {
|
| 1312 |
document.getElementById('liveOrb').classList.remove('speaking');
|
| 1313 |
-
document.getElementById('liveStatusText').innerText = "
|
|
|
|
| 1314 |
}
|
| 1315 |
};
|
| 1316 |
|
| 1317 |
-
audio.play()
|
|
|
|
|
|
|
|
|
|
| 1318 |
} else {
|
| 1319 |
throw new Error("No audio payload returned.");
|
| 1320 |
}
|
|
@@ -1328,9 +1326,9 @@
|
|
| 1328 |
}
|
| 1329 |
};
|
| 1330 |
|
| 1331 |
-
/
|
| 1332 |
-
|
| 1333 |
-
|
| 1334 |
const LiveModeController = {
|
| 1335 |
initialize: () => {
|
| 1336 |
AppState.isLiveModeEngaged = true;
|
|
@@ -1351,7 +1349,7 @@
|
|
| 1351 |
};
|
| 1352 |
|
| 1353 |
// =======================================================================================
|
| 1354 |
-
//
|
| 1355 |
// =======================================================================================
|
| 1356 |
const FileProcessor = {
|
| 1357 |
triggerFileSelector: (type) => {
|
|
@@ -1439,22 +1437,25 @@
|
|
| 1439 |
else {
|
| 1440 |
fileReader.onload = (e) => {
|
| 1441 |
AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
|
| 1442 |
-
Utils.showToast("Your file is ready!");
|
| 1443 |
};
|
| 1444 |
fileReader.readAsText(file);
|
| 1445 |
}
|
| 1446 |
}
|
| 1447 |
-
|
|
|
|
|
|
|
| 1448 |
},
|
| 1449 |
|
| 1450 |
discardFile: () => {
|
| 1451 |
AppState.pendingAttachment = null;
|
| 1452 |
document.getElementById('filePreviewBar').classList.remove('visible');
|
|
|
|
| 1453 |
}
|
| 1454 |
};
|
| 1455 |
|
| 1456 |
// =======================================================================================
|
| 1457 |
-
//
|
| 1458 |
// =======================================================================================
|
| 1459 |
const WorkspaceEngine = {
|
| 1460 |
launch: (codeBlockId) => {
|
|
@@ -1519,7 +1520,7 @@
|
|
| 1519 |
};
|
| 1520 |
marked.use({ renderer: MD_Renderer });
|
| 1521 |
|
| 1522 |
-
// Event delegation for
|
| 1523 |
document.getElementById('msgs').addEventListener('click', function(e) {
|
| 1524 |
if (e.target && e.target.classList.contains('btn-launch-ws')) {
|
| 1525 |
const blockId = e.target.getAttribute('data-id');
|
|
@@ -1528,7 +1529,7 @@
|
|
| 1528 |
});
|
| 1529 |
|
| 1530 |
// =======================================================================================
|
| 1531 |
-
//
|
| 1532 |
// =======================================================================================
|
| 1533 |
const ChatEngine = {
|
| 1534 |
handleKeyboard: (e) => {
|
|
@@ -1668,7 +1669,7 @@
|
|
| 1668 |
let actionTray = bubbleDOM.querySelector('.bot-actions-row');
|
| 1669 |
if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) {
|
| 1670 |
const safeRawCopy = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, '');
|
| 1671 |
-
// safeRawTTS is passed
|
| 1672 |
const safeRawTTS = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, ' ');
|
| 1673 |
|
| 1674 |
const actionsHTML = `
|
|
@@ -1718,6 +1719,7 @@
|
|
| 1718 |
if (wState) wState.style.display = 'none';
|
| 1719 |
|
| 1720 |
let payloadStr = rawUserText;
|
|
|
|
| 1721 |
let payloadAttachments = [];
|
| 1722 |
let visualBadge = null;
|
| 1723 |
let previewHTMLForChat = '';
|
|
@@ -1728,6 +1730,8 @@
|
|
| 1728 |
|
| 1729 |
if (AppState.pendingAttachment.type === 'text') {
|
| 1730 |
payloadStr = `[Document Analyzed: ${AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`;
|
|
|
|
|
|
|
| 1731 |
visualBadge = 'File Appended';
|
| 1732 |
} else {
|
| 1733 |
payloadAttachments.push({
|
|
@@ -1739,7 +1743,7 @@
|
|
| 1739 |
}
|
| 1740 |
|
| 1741 |
ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat);
|
| 1742 |
-
AppState.history.push({ role: 'user', content:
|
| 1743 |
} else {
|
| 1744 |
ChatEngine.renderUserMessage(rawUserText, null, '');
|
| 1745 |
AppState.history.push({ role: 'user', content: rawUserText });
|
|
@@ -1776,7 +1780,7 @@
|
|
| 1776 |
attachments: payloadAttachments,
|
| 1777 |
system_prompt: cognitivePrompt,
|
| 1778 |
history: secureHistory,
|
| 1779 |
-
max_tokens: AppState.isLiveModeEngaged ?
|
| 1780 |
temperature: 0.75
|
| 1781 |
};
|
| 1782 |
|
|
@@ -1793,15 +1797,19 @@
|
|
| 1793 |
const networkReader = fetchOp.body.getReader();
|
| 1794 |
const textDecoder = new TextDecoder();
|
| 1795 |
let responseBuffer = "";
|
| 1796 |
-
|
|
|
|
| 1797 |
AppState.isStreamingActive = true;
|
| 1798 |
|
| 1799 |
while (true) {
|
| 1800 |
const { done, value } = await networkReader.read();
|
| 1801 |
if (done) break;
|
| 1802 |
|
| 1803 |
-
|
| 1804 |
-
const fragmentedLines =
|
|
|
|
|
|
|
|
|
|
| 1805 |
|
| 1806 |
for (let line of fragmentedLines) {
|
| 1807 |
if (line.startsWith('data: ')) {
|
|
@@ -1845,7 +1853,7 @@
|
|
| 1845 |
};
|
| 1846 |
|
| 1847 |
// =======================================================================================
|
| 1848 |
-
//
|
| 1849 |
// =======================================================================================
|
| 1850 |
|
| 1851 |
// Define global function for welcome screen overlay
|
|
@@ -1855,78 +1863,82 @@
|
|
| 1855 |
setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
|
| 1856 |
};
|
| 1857 |
|
| 1858 |
-
// Bind all interactive elements safely
|
| 1859 |
document.addEventListener('DOMContentLoaded', () => {
|
| 1860 |
// Sidebar Controls
|
| 1861 |
-
document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar);
|
| 1862 |
-
document.getElementById('btnSidebarClose').addEventListener('click', UIManager.toggleSidebar);
|
| 1863 |
-
document.getElementById('btnLaunchSystem').addEventListener('click', window.startArjunApp);
|
| 1864 |
|
| 1865 |
// Auth Flow Controls
|
| 1866 |
-
document.getElementById('loginPromptBtn').addEventListener('click', AuthManager.openModal);
|
| 1867 |
-
document.getElementById('btnAuthClose').addEventListener('click', AuthManager.closeModal);
|
| 1868 |
-
document.getElementById('btn-tab-login').addEventListener('click', () => AuthManager.switchTab('login'));
|
| 1869 |
-
document.getElementById('btn-tab-register').addEventListener('click', () => AuthManager.switchTab('register'));
|
| 1870 |
|
| 1871 |
-
document.getElementById('btn-fire-log-otp').addEventListener('click', () => AuthManager.process('login_send_otp'));
|
| 1872 |
-
document.getElementById('btn-fire-log-verify').addEventListener('click', () => AuthManager.process('login_verify'));
|
| 1873 |
-
document.getElementById('btn-fire-reg-otp').addEventListener('click', () => AuthManager.process('register_send_otp'));
|
| 1874 |
-
document.getElementById('btn-fire-reg-verify').addEventListener('click', () => AuthManager.process('register_verify'));
|
| 1875 |
|
| 1876 |
-
document.getElementById('btnLogBack').addEventListener('click', () => AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1'));
|
| 1877 |
-
document.getElementById('btnRegBack').addEventListener('click', () => AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1'));
|
| 1878 |
-
document.getElementById('btnLogout').addEventListener('click', AuthManager.logout);
|
| 1879 |
-
document.getElementById('btnClearMemory').addEventListener('click', ChatEngine.clearMemory);
|
| 1880 |
|
| 1881 |
// File Attachment Routing
|
| 1882 |
-
document.getElementById('btnAttachMenuToggle').addEventListener('click', UIManager.toggleAttachMenu);
|
| 1883 |
-
document.getElementById('opt-image').addEventListener('click', () => FileProcessor.triggerFileSelector('image'));
|
| 1884 |
-
document.getElementById('opt-video').addEventListener('click', () => FileProcessor.triggerFileSelector('video'));
|
| 1885 |
-
document.getElementById('opt-audio').addEventListener('click', () => FileProcessor.triggerFileSelector('audio'));
|
| 1886 |
-
document.getElementById('opt-document').addEventListener('click', () => FileProcessor.triggerFileSelector('document'));
|
| 1887 |
|
| 1888 |
-
|
| 1889 |
-
document.getElementById('
|
| 1890 |
-
|
| 1891 |
-
|
| 1892 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1893 |
|
| 1894 |
// Primary Message Controls
|
| 1895 |
-
document.getElementById('masterSendBtn').addEventListener('click', ChatEngine.initiateDispatch);
|
| 1896 |
-
document.getElementById('mainChatInput').addEventListener('keydown', ChatEngine.handleKeyboard);
|
| 1897 |
-
document.getElementById('mainChatInput').addEventListener('input', function() { UIManager.autoGrowTextArea(this); });
|
| 1898 |
|
| 1899 |
// Example Prompt Controls
|
| 1900 |
-
document.getElementById('suggCodeBtn').addEventListener('click', () => ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.'));
|
| 1901 |
-
document.getElementById('suggImgBtn').addEventListener('click', () => ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.'));
|
| 1902 |
|
| 1903 |
// Voice & STT Options
|
| 1904 |
-
document.getElementById('smartLangToggle').addEventListener('click', VoiceEngine.switchLanguage);
|
| 1905 |
-
document.getElementById('masterVoiceBtn').addEventListener('click', VoiceEngine.toggleDictation);
|
| 1906 |
|
| 1907 |
// Live Mode Options
|
| 1908 |
-
document.getElementById('btnStartLiveMode').addEventListener('click', LiveModeController.initialize);
|
| 1909 |
-
document.getElementById('btnExitLiveMode').addEventListener('click', LiveModeController.terminate);
|
| 1910 |
-
document.getElementById('liveMicBtn').addEventListener('click', VoiceEngine.toggleDictation);
|
| 1911 |
|
| 1912 |
// Workspace Logic Hooks
|
| 1913 |
-
document.getElementById('btnWsClose').addEventListener('click', WorkspaceEngine.closePanel);
|
| 1914 |
-
document.getElementById('btnWsCopy').addEventListener('click', function() { WorkspaceEngine.executeCopy(this); });
|
| 1915 |
|
| 1916 |
// Interaction Scroll Listeners
|
| 1917 |
-
document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState);
|
| 1918 |
-
document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown);
|
| 1919 |
-
|
| 1920 |
-
// Prevent unwanted default mobile behaviours on double-tap
|
| 1921 |
-
document.addEventListener('dblclick', function(event) {
|
| 1922 |
-
event.preventDefault();
|
| 1923 |
-
}, { passive: false });
|
| 1924 |
|
| 1925 |
// Ensure startup screen displays if memory cleared
|
| 1926 |
if(!localStorage.getItem('arjun_welcome_seen')) {
|
| 1927 |
-
document.getElementById('welcomeOverlay')
|
|
|
|
| 1928 |
} else {
|
| 1929 |
-
document.getElementById('welcomeOverlay')
|
|
|
|
| 1930 |
}
|
| 1931 |
|
| 1932 |
// Fire Boot Processes
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
<html lang="en" dir="ltr">
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
| 6 |
+
<!-- Viewport Settings: Disables zoom, completely removes blue tap highlights on mobile devices -->
|
| 7 |
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
|
| 8 |
<meta name="description" content="Arjun 2.O Ultimate Enterprise Artificial Intelligence System engineered by Abhay Kumar.">
|
| 9 |
<meta name="theme-color" content="#FF9933">
|
|
|
|
| 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>
|
| 18 |
|
| 19 |
+
<!-- Professional Typography -->
|
| 20 |
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@300;400;500;600;700;800;900&family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
| 21 |
|
| 22 |
<!-- Syntax Highlighting (Atom One Dark for Workspace Environment) -->
|
|
|
|
| 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
|
| 37 |
--------------------------------------------------------------------------------------- */
|
| 38 |
:root {
|
| 39 |
+
/* Branding Colors */
|
| 40 |
--brand-saffron: #FF9933;
|
| 41 |
--brand-saffron-light: rgba(255, 153, 51, 0.12);
|
| 42 |
--brand-saffron-dark: #e68a2e;
|
|
|
|
| 43 |
|
| 44 |
--brand-white: #FFFFFF;
|
| 45 |
--brand-white-glass: rgba(255, 255, 255, 0.88);
|
|
|
|
| 47 |
--brand-green: #138808;
|
| 48 |
--brand-green-light: rgba(19, 136, 8, 0.12);
|
| 49 |
--brand-green-dark: #0f6e06;
|
|
|
|
| 50 |
|
| 51 |
+
/* Structural Colors */
|
| 52 |
--bg-primary: #ffffff;
|
| 53 |
--bg-secondary: #f8f9fa;
|
| 54 |
--bg-tertiary: #f1f3f5;
|
| 55 |
--bg-glass: rgba(255, 255, 255, 0.75);
|
|
|
|
|
|
|
| 56 |
|
| 57 |
/* Text & Typography Colors */
|
| 58 |
--text-primary: #111827;
|
|
|
|
| 64 |
/* Borders & Dividers */
|
| 65 |
--border-light: rgba(0, 0, 0, 0.08);
|
| 66 |
--border-medium: rgba(0, 0, 0, 0.15);
|
|
|
|
| 67 |
|
| 68 |
/* Shadows & Elevation */
|
| 69 |
--shadow-xs: 0 1px 2px rgba(0,0,0,0.04);
|
|
|
|
| 71 |
--shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03);
|
| 72 |
--shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025);
|
| 73 |
--shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02);
|
|
|
|
| 74 |
|
| 75 |
/* Font Families */
|
| 76 |
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
|
|
| 78 |
--font-serif: 'Instrument Serif', Georgia, serif;
|
| 79 |
|
| 80 |
/* Radii */
|
|
|
|
| 81 |
--radius-sm: 8px;
|
| 82 |
--radius-md: 12px;
|
| 83 |
--radius-lg: 16px;
|
|
|
|
| 93 |
--z-ambient: -1;
|
| 94 |
--z-base: 1;
|
| 95 |
--z-header: 10;
|
|
|
|
|
|
|
| 96 |
--z-dropdown: 50;
|
| 97 |
--z-sidebar: 100;
|
| 98 |
--z-modal: 5000;
|
|
|
|
| 101 |
}
|
| 102 |
|
| 103 |
/* ---------------------------------------------------------------------------------------
|
| 104 |
+
B. GLOBAL RESET & ANTI-BLUE-HIGHLIGHT BUG FIX
|
| 105 |
--------------------------------------------------------------------------------------- */
|
| 106 |
*, *::before, *::after {
|
| 107 |
box-sizing: border-box;
|
| 108 |
margin: 0;
|
| 109 |
padding: 0;
|
| 110 |
+
/* CRITICAL FIX: Eliminates blue selection rectangles on Android/iOS browsers */
|
| 111 |
-webkit-tap-highlight-color: transparent !important;
|
| 112 |
-webkit-touch-callout: none !important;
|
| 113 |
}
|
|
|
|
| 126 |
-moz-osx-font-smoothing: grayscale;
|
| 127 |
}
|
| 128 |
|
| 129 |
+
/* Global Focus Reset */
|
| 130 |
*:focus { outline: none !important; }
|
| 131 |
|
| 132 |
button, input, textarea, select {
|
|
|
|
| 141 |
img { max-width: 100%; height: auto; display: block; }
|
| 142 |
svg { flex-shrink: 0; }
|
| 143 |
|
| 144 |
+
/* Elegant Scrollbars */
|
| 145 |
::-webkit-scrollbar { width: 6px; height: 6px; }
|
| 146 |
::-webkit-scrollbar-track { background: transparent; }
|
| 147 |
::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.12); border-radius: 10px; transition: background var(--ease-smooth); }
|
| 148 |
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.25); }
|
| 149 |
|
| 150 |
/* ---------------------------------------------------------------------------------------
|
| 151 |
+
C. AMBIENT BACKGROUND SYSTEM
|
| 152 |
--------------------------------------------------------------------------------------- */
|
| 153 |
.ambient-environment {
|
| 154 |
position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none;
|
|
|
|
| 176 |
}
|
| 177 |
|
| 178 |
/* ---------------------------------------------------------------------------------------
|
| 179 |
+
D. TOAST NOTIFICATION ENGINE
|
| 180 |
--------------------------------------------------------------------------------------- */
|
| 181 |
.toast-wrapper {
|
| 182 |
position: absolute; top: 24px; left: 50%; transform: translateX(-50%);
|
|
|
|
| 195 |
@keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } }
|
| 196 |
|
| 197 |
/* ---------------------------------------------------------------------------------------
|
| 198 |
+
E. INITIAL WELCOME OVERLAY
|
| 199 |
--------------------------------------------------------------------------------------- */
|
| 200 |
.startup-overlay {
|
| 201 |
position: fixed; inset: 0; background: var(--brand-white-glass);
|
|
|
|
| 227 |
--------------------------------------------------------------------------------------- */
|
| 228 |
.app-root { position: relative; z-index: var(--z-base); display: flex; height: 100dvh; width: 100vw; overflow: hidden; background: var(--bg-glass); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); }
|
| 229 |
|
| 230 |
+
/* Sidebar Navigation */
|
| 231 |
.sidebar-container { width: 320px; display: flex; flex-direction: column; background: rgba(248, 249, 250, 0.85); border-right: 1px solid var(--border-light); flex-shrink: 0; z-index: var(--z-sidebar); transition: transform var(--ease-smooth), box-shadow var(--ease-smooth); backdrop-filter: blur(15px); }
|
| 232 |
.sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; }
|
| 233 |
|
|
|
|
| 243 |
|
| 244 |
.sidebar-body { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 28px; }
|
| 245 |
|
| 246 |
+
/* Auth Widget in Sidebar */
|
| 247 |
.auth-widget { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-sm); transition: var(--ease-smooth); }
|
| 248 |
.auth-widget:hover { box-shadow: var(--shadow-md); border-color: var(--border-medium); }
|
| 249 |
|
|
|
|
| 255 |
.user-details { flex: 1; overflow: hidden; }
|
| 256 |
.user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
| 257 |
.user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; }
|
| 258 |
+
.user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 5px rgba(19, 136, 8, 0.5); }
|
| 259 |
.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); }
|
| 260 |
.btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); }
|
| 261 |
|
| 262 |
+
/* Developer Box */
|
| 263 |
.developer-credit-box { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 28px 20px; text-align: center; box-shadow: var(--shadow-sm); margin-top: auto; position: relative; overflow: hidden; }
|
| 264 |
.developer-credit-box::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: linear-gradient(90deg, var(--brand-saffron), var(--brand-white), var(--brand-green)); }
|
| 265 |
.developer-credit-box img { width: 72px; height: 72px; border-radius: var(--radius-lg); object-fit: cover; margin-bottom: 16px; box-shadow: var(--shadow-md); border: 1px solid var(--border-light); margin-left: auto; margin-right: auto; transition: var(--ease-spring); }
|
|
|
|
| 267 |
.dev-box-title { font-size: 18px; font-weight: 800; color: var(--text-primary); margin-bottom: 6px; }
|
| 268 |
.dev-box-subtitle { font-size: 11px; font-weight: 800; color: var(--text-tertiary); letter-spacing: 1px; text-transform: uppercase; }
|
| 269 |
|
| 270 |
+
/* Wipe Memory Button */
|
| 271 |
.btn-erase-memory { width: 100%; padding: 16px; border-radius: var(--radius-md); background: var(--bg-primary); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-fast); display: flex; align-items: center; justify-content: center; gap: 10px; }
|
| 272 |
.btn-erase-memory:hover { background: #fee2e2; color: var(--text-error); border-color: #fca5a5; }
|
| 273 |
|
|
|
|
| 285 |
.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; }
|
| 286 |
@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); } }
|
| 287 |
|
| 288 |
+
/* LIVE MODE ACTIVATOR */
|
| 289 |
.btn-activate-live { background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%); color: white; border: none; padding: 10px 22px; border-radius: var(--radius-full); font-size: 14px; font-weight: 800; display: flex; align-items: center; gap: 8px; cursor: pointer; box-shadow: 0 4px 15px rgba(239, 68, 68, 0.35); transition: var(--ease-spring); letter-spacing: 0.5px; }
|
| 290 |
.btn-activate-live:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 25px rgba(239, 68, 68, 0.45); }
|
| 291 |
.btn-activate-live svg { width: 18px; height: 18px; animation: liveBlink 1.5s infinite; }
|
|
|
|
| 339 |
/* In-Bubble File Previews */
|
| 340 |
.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; }
|
| 341 |
.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); }
|
| 342 |
+
.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); color: var(--brand-white); }
|
| 343 |
.chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
| 344 |
|
| 345 |
.chat-bubble { padding: 18px 24px; font-size: 16px; line-height: 1.6; position: relative; word-wrap: break-word; overflow-wrap: anywhere; }
|
|
|
|
| 470 |
|
| 471 |
.pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; }
|
| 472 |
.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; }
|
| 473 |
+
/* Voice speaking animation */
|
| 474 |
.energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; }
|
| 475 |
@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); } }
|
| 476 |
|
|
|
|
| 538 |
}
|
| 539 |
|
| 540 |
@media (max-width: 900px) {
|
| 541 |
+
.sidebar-container { position: absolute; left: -320px; z-index: 1000; height: 100%; box-shadow: var(--shadow-xl); }
|
| 542 |
.sidebar-container.active { left: 0; }
|
| 543 |
.btn-hamburger { display: flex; }
|
| 544 |
.btn-mobile-close { display: flex; }
|
|
|
|
| 702 |
<h2 class="hero-greeting">How can I assist you today?</h2>
|
| 703 |
<p class="hero-description">Experience next-generation reasoning, seamless multi-file analysis, and secure workspace code generation engineered by Abhay Kumar.</p>
|
| 704 |
|
| 705 |
+
<!-- RESTORED: GUEST BADGE LIMIT DISPLAY -->
|
| 706 |
<div id="guestBadge" class="guest-warning-badge">
|
| 707 |
<svg viewBox="0 0 24 24" 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>
|
| 708 |
Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login.
|
|
|
|
| 877 |
<!-- =========================================================================================
|
| 878 |
[3] MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE
|
| 879 |
========================================================================================= -->
|
|
|
|
|
|
|
|
|
|
| 880 |
<script>
|
| 881 |
// =======================================================================================
|
| 882 |
// 1. CONFIGURATION & STATE MANAGEMENT
|
|
|
|
| 885 |
GAS_URL: "https://script.google.com/macros/s/AKfycbzTsXGoVh97JjtFAAG825GF4WUZqf7FDB3Zbxyf0nrLXt_1HjJSSqA829UcdoamRPvg0A/exec",
|
| 886 |
LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png",
|
| 887 |
PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js',
|
| 888 |
+
API_ENDPOINT: '/api/chat', // Change to 'http://localhost:7860/api/chat' if running UI separately
|
| 889 |
};
|
| 890 |
|
|
|
|
| 891 |
pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER;
|
| 892 |
|
| 893 |
const AppState = {
|
|
|
|
| 905 |
isMicRecording: false
|
| 906 |
};
|
| 907 |
|
| 908 |
+
// Initialize Gradio Client Dynamically
|
| 909 |
window.initGradioEngine = async function() {
|
| 910 |
try {
|
| 911 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
|
|
|
| 934 |
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
| 935 |
},
|
| 936 |
|
| 937 |
+
// ✨ CRITICAL BUG FIX 1: Intelligent Text Cleaner for TTS
|
| 938 |
+
// Ignores code, links, images, so the voice doesn't read garbage.
|
| 939 |
cleanTextForVoice: (rawText) => {
|
| 940 |
if(!rawText) return "";
|
| 941 |
let cleaned = rawText;
|
| 942 |
|
| 943 |
+
cleaned = cleaned.replace(/```[\s\S]*?```/g, ''); // Remove Markdown Code Blocks
|
| 944 |
+
cleaned = cleaned.replace(/`.*?`/g, ''); // Remove Inline Code
|
| 945 |
+
cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, ''); // Remove Markdown Images
|
| 946 |
+
cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1'); // Extract just the text from Links
|
| 947 |
+
cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, ''); // Remove Think Tags
|
| 948 |
+
cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, ''); // Remove stray URLs
|
| 949 |
+
cleaned = cleaned.replace(/[*_~#]/g, ''); // Remove Markdown formatting symbols
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 950 |
|
| 951 |
return cleaned.trim();
|
| 952 |
},
|
| 953 |
|
|
|
|
| 954 |
executeFallbackCopy: (text, btnElement) => {
|
| 955 |
const textArea = document.createElement("textarea");
|
| 956 |
textArea.value = text;
|
|
|
|
| 983 |
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`;
|
| 984 |
setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500);
|
| 985 |
}).catch((err) => {
|
|
|
|
| 986 |
Utils.executeFallbackCopy(textToCopy, btnElement);
|
| 987 |
});
|
| 988 |
}
|
| 989 |
};
|
| 990 |
|
| 991 |
// =======================================================================================
|
| 992 |
+
// 3. AUTHENTICATION & SYNC MANAGER
|
| 993 |
// =======================================================================================
|
| 994 |
const AuthManager = {
|
| 995 |
initUI: () => {
|
|
|
|
| 1028 |
document.getElementById(nextId).classList.add('active');
|
| 1029 |
},
|
| 1030 |
|
|
|
|
| 1031 |
process: async (actionType) => {
|
| 1032 |
const payload = { action: actionType };
|
| 1033 |
let buttonId = '';
|
|
|
|
| 1057 |
triggerBtn.innerText = 'Establishing Connection...';
|
| 1058 |
|
| 1059 |
try {
|
| 1060 |
+
// ✨ CRITICAL BUG FIX: mode: 'cors' handles redirect issues from GAS effectively
|
| 1061 |
const response = await fetch(Config.GAS_URL, {
|
| 1062 |
method: 'POST',
|
| 1063 |
mode: 'cors',
|
|
|
|
| 1082 |
Utils.showToast(result.message);
|
| 1083 |
}
|
| 1084 |
} catch (error) {
|
|
|
|
| 1085 |
Utils.showToast("Encrypted gateway error. Check network.");
|
| 1086 |
}
|
| 1087 |
|
|
|
|
| 1135 |
};
|
| 1136 |
|
| 1137 |
// =======================================================================================
|
| 1138 |
+
// 5. SPEECH & TTS ENGINE (Bilingual STT + Gradio Edge-TTS)
|
| 1139 |
// =======================================================================================
|
| 1140 |
const VoiceEngine = {
|
| 1141 |
recognition: null,
|
| 1142 |
+
currentLanguage: 'en-US', // Default changed to purely English
|
| 1143 |
+
sessionTranscript: '',
|
| 1144 |
|
| 1145 |
init: () => {
|
| 1146 |
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
| 1147 |
if (!SR) return;
|
| 1148 |
|
| 1149 |
VoiceEngine.recognition = new SR();
|
| 1150 |
+
// ✨ CRITICAL BUG FIX 2: Set continuous to false to capture natural pauses perfectly.
|
| 1151 |
+
VoiceEngine.recognition.continuous = false;
|
| 1152 |
VoiceEngine.recognition.interimResults = true;
|
| 1153 |
VoiceEngine.recognition.lang = VoiceEngine.currentLanguage;
|
| 1154 |
|
| 1155 |
VoiceEngine.recognition.onstart = () => {
|
| 1156 |
AppState.isMicRecording = true;
|
| 1157 |
+
VoiceEngine.sessionTranscript = document.getElementById('mainChatInput').value;
|
| 1158 |
+
if(VoiceEngine.sessionTranscript && !VoiceEngine.sessionTranscript.endsWith(' ')) {
|
| 1159 |
+
VoiceEngine.sessionTranscript += ' ';
|
| 1160 |
+
}
|
| 1161 |
+
|
| 1162 |
document.getElementById('masterVoiceBtn').classList.add('active-listening');
|
| 1163 |
if (AppState.isLiveModeEngaged) {
|
| 1164 |
document.getElementById('liveMicBtn').classList.add('is-recording');
|
|
|
|
| 1169 |
};
|
| 1170 |
|
| 1171 |
VoiceEngine.recognition.onresult = (event) => {
|
|
|
|
| 1172 |
let interimTranscript = '';
|
| 1173 |
+
let finalTranscript = '';
|
| 1174 |
|
| 1175 |
for (let i = event.resultIndex; i < event.results.length; ++i) {
|
| 1176 |
if (event.results[i].isFinal) {
|
|
|
|
| 1180 |
}
|
| 1181 |
}
|
| 1182 |
|
| 1183 |
+
let currentDictation = finalTranscript + interimTranscript;
|
| 1184 |
+
if (currentDictation) {
|
| 1185 |
+
currentDictation = currentDictation.charAt(0).toUpperCase() + currentDictation.slice(1);
|
| 1186 |
+
}
|
| 1187 |
+
|
| 1188 |
+
if (AppState.isLiveModeEngaged) {
|
| 1189 |
+
document.getElementById('liveTranscriptText').innerText = `"${currentDictation}"`;
|
| 1190 |
+
// Once the sentence is finalized, send it.
|
| 1191 |
+
if(finalTranscript.trim().length > 0) {
|
| 1192 |
+
document.getElementById('liveStatusText').innerText = "Synthesizing...";
|
| 1193 |
+
document.getElementById('mainChatInput').value = finalTranscript.trim();
|
| 1194 |
VoiceEngine.recognition.stop();
|
| 1195 |
ChatEngine.initiateDispatch();
|
| 1196 |
+
}
|
| 1197 |
+
} else {
|
| 1198 |
+
const inputField = document.getElementById('mainChatInput');
|
| 1199 |
+
inputField.value = VoiceEngine.sessionTranscript + currentDictation;
|
| 1200 |
+
UIManager.autoGrowTextArea(inputField);
|
| 1201 |
+
|
| 1202 |
+
if(finalTranscript.trim().length > 0) {
|
| 1203 |
+
VoiceEngine.sessionTranscript = inputField.value;
|
| 1204 |
+
if(!VoiceEngine.sessionTranscript.endsWith(' ')) VoiceEngine.sessionTranscript += ' ';
|
| 1205 |
}
|
| 1206 |
}
|
| 1207 |
};
|
|
|
|
| 1234 |
const btn = document.getElementById('smartLangToggle');
|
| 1235 |
const badge = document.getElementById('langDisplayBadge');
|
| 1236 |
|
| 1237 |
+
if (VoiceEngine.currentLanguage === 'en-US') {
|
| 1238 |
VoiceEngine.currentLanguage = 'hi-IN';
|
| 1239 |
badge.innerText = 'हि';
|
| 1240 |
btn.classList.add('hindi-active');
|
| 1241 |
Utils.showToast("Listening Protocol: Hindi (देवनागरी)");
|
| 1242 |
} else {
|
| 1243 |
+
VoiceEngine.currentLanguage = 'en-US';
|
| 1244 |
badge.innerText = 'EN';
|
| 1245 |
btn.classList.remove('hindi-active');
|
| 1246 |
Utils.showToast("Listening Protocol: English");
|
|
|
|
| 1266 |
} catch (e) { console.error("Mic Start Error", e); }
|
| 1267 |
},
|
| 1268 |
|
|
|
|
| 1269 |
executeTTS: async (rawText) => {
|
|
|
|
| 1270 |
const cleanSpeechText = Utils.cleanTextForVoice(rawText);
|
| 1271 |
|
| 1272 |
if(!cleanSpeechText.trim()) {
|
| 1273 |
+
// Nothing readable found (e.g., just code blocks)
|
| 1274 |
+
if (AppState.isLiveModeEngaged) {
|
| 1275 |
+
document.getElementById('liveOrb').classList.remove('speaking');
|
| 1276 |
+
document.getElementById('liveStatusText').innerText = "Tap mic to respond";
|
| 1277 |
+
// Auto-start mic again
|
| 1278 |
+
setTimeout(()=> VoiceEngine.toggleDictation(), 800);
|
| 1279 |
+
}
|
| 1280 |
return;
|
| 1281 |
}
|
| 1282 |
|
|
|
|
| 1287 |
|
| 1288 |
try {
|
| 1289 |
if(!AppState.gradioClient) {
|
|
|
|
| 1290 |
const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
|
| 1291 |
AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS");
|
| 1292 |
}
|
|
|
|
| 1300 |
const audioUrl = typeof result.data[0] === 'string' ? result.data[0] : result.data[0].url;
|
| 1301 |
const audio = new Audio(audioUrl);
|
| 1302 |
|
| 1303 |
+
// ✨ CRITICAL BUG FIX 3: True Live Mode Conversation (Auto-restarts Mic)
|
| 1304 |
audio.onended = () => {
|
| 1305 |
if (AppState.isLiveModeEngaged) {
|
| 1306 |
document.getElementById('liveOrb').classList.remove('speaking');
|
| 1307 |
+
document.getElementById('liveStatusText').innerText = "Listening...";
|
| 1308 |
+
VoiceEngine.toggleDictation(); // Automatically restart mic for the next turn
|
| 1309 |
}
|
| 1310 |
};
|
| 1311 |
|
| 1312 |
+
audio.play().catch(e => {
|
| 1313 |
+
Utils.showToast("Autoplay blocked. Please interact with the page.");
|
| 1314 |
+
if (AppState.isLiveModeEngaged) document.getElementById('liveOrb').classList.remove('speaking');
|
| 1315 |
+
});
|
| 1316 |
} else {
|
| 1317 |
throw new Error("No audio payload returned.");
|
| 1318 |
}
|
|
|
|
| 1326 |
}
|
| 1327 |
};
|
| 1328 |
|
| 1329 |
+
// =======================================================================================
|
| 1330 |
+
// 6. LIVE MODE CONTROLLER
|
| 1331 |
+
// =======================================================================================
|
| 1332 |
const LiveModeController = {
|
| 1333 |
initialize: () => {
|
| 1334 |
AppState.isLiveModeEngaged = true;
|
|
|
|
| 1349 |
};
|
| 1350 |
|
| 1351 |
// =======================================================================================
|
| 1352 |
+
// 7. FILE & DOCUMENT PROCESSOR (Non-Technical Vocabulary)
|
| 1353 |
// =======================================================================================
|
| 1354 |
const FileProcessor = {
|
| 1355 |
triggerFileSelector: (type) => {
|
|
|
|
| 1437 |
else {
|
| 1438 |
fileReader.onload = (e) => {
|
| 1439 |
AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name };
|
| 1440 |
+
Utils.showToast("Your Code file is ready!");
|
| 1441 |
};
|
| 1442 |
fileReader.readAsText(file);
|
| 1443 |
}
|
| 1444 |
}
|
| 1445 |
+
|
| 1446 |
+
// Reset stealth inputs so the same file can be selected again
|
| 1447 |
+
document.querySelectorAll('.stealth-input').forEach(i => i.value = '');
|
| 1448 |
},
|
| 1449 |
|
| 1450 |
discardFile: () => {
|
| 1451 |
AppState.pendingAttachment = null;
|
| 1452 |
document.getElementById('filePreviewBar').classList.remove('visible');
|
| 1453 |
+
document.querySelectorAll('.stealth-input').forEach(i => i.value = '');
|
| 1454 |
}
|
| 1455 |
};
|
| 1456 |
|
| 1457 |
// =======================================================================================
|
| 1458 |
+
// 8. WORKSPACE ENGINE & MARKDOWN RENDERING
|
| 1459 |
// =======================================================================================
|
| 1460 |
const WorkspaceEngine = {
|
| 1461 |
launch: (codeBlockId) => {
|
|
|
|
| 1520 |
};
|
| 1521 |
marked.use({ renderer: MD_Renderer });
|
| 1522 |
|
| 1523 |
+
// Event delegation for dynamically rendered 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');
|
|
|
|
| 1529 |
});
|
| 1530 |
|
| 1531 |
// =======================================================================================
|
| 1532 |
+
// 9. CORE CHAT ENGINE & LLM LOGIC
|
| 1533 |
// =======================================================================================
|
| 1534 |
const ChatEngine = {
|
| 1535 |
handleKeyboard: (e) => {
|
|
|
|
| 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 raw because VoiceEngine.executeTTS will clean it properly
|
| 1673 |
const safeRawTTS = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, ' ');
|
| 1674 |
|
| 1675 |
const actionsHTML = `
|
|
|
|
| 1719 |
if (wState) wState.style.display = 'none';
|
| 1720 |
|
| 1721 |
let payloadStr = rawUserText;
|
| 1722 |
+
let historyStr = rawUserText; // ✨ CRITICAL BUG FIX 4: Prevent Memory Blob Explosion
|
| 1723 |
let payloadAttachments = [];
|
| 1724 |
let visualBadge = null;
|
| 1725 |
let previewHTMLForChat = '';
|
|
|
|
| 1730 |
|
| 1731 |
if (AppState.pendingAttachment.type === 'text') {
|
| 1732 |
payloadStr = `[Document Analyzed: ${AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`;
|
| 1733 |
+
// For history, only store the prompt to save tokens!
|
| 1734 |
+
historyStr = `[Document previously attached: ${AppState.pendingAttachment.name}]\nUser Prompt: ${rawUserText}`;
|
| 1735 |
visualBadge = 'File Appended';
|
| 1736 |
} else {
|
| 1737 |
payloadAttachments.push({
|
|
|
|
| 1743 |
}
|
| 1744 |
|
| 1745 |
ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat);
|
| 1746 |
+
AppState.history.push({ role: 'user', content: historyStr, badge: visualBadge, previewHTML: previewHTMLForChat });
|
| 1747 |
} else {
|
| 1748 |
ChatEngine.renderUserMessage(rawUserText, null, '');
|
| 1749 |
AppState.history.push({ role: 'user', content: rawUserText });
|
|
|
|
| 1780 |
attachments: payloadAttachments,
|
| 1781 |
system_prompt: cognitivePrompt,
|
| 1782 |
history: secureHistory,
|
| 1783 |
+
max_tokens: AppState.isLiveModeEngaged ? 150 : 4096,
|
| 1784 |
temperature: 0.75
|
| 1785 |
};
|
| 1786 |
|
|
|
|
| 1797 |
const networkReader = fetchOp.body.getReader();
|
| 1798 |
const textDecoder = new TextDecoder();
|
| 1799 |
let responseBuffer = "";
|
| 1800 |
+
let streamChunkBuffer = ""; // ✨ CRITICAL BUG FIX 5: Resolves fragmented JSON network chunks
|
| 1801 |
+
|
| 1802 |
AppState.isStreamingActive = true;
|
| 1803 |
|
| 1804 |
while (true) {
|
| 1805 |
const { done, value } = await networkReader.read();
|
| 1806 |
if (done) break;
|
| 1807 |
|
| 1808 |
+
streamChunkBuffer += textDecoder.decode(value, { stream: true });
|
| 1809 |
+
const fragmentedLines = streamChunkBuffer.split('\n');
|
| 1810 |
+
|
| 1811 |
+
// Keep the last incomplete line in the buffer
|
| 1812 |
+
streamChunkBuffer = fragmentedLines.pop();
|
| 1813 |
|
| 1814 |
for (let line of fragmentedLines) {
|
| 1815 |
if (line.startsWith('data: ')) {
|
|
|
|
| 1853 |
};
|
| 1854 |
|
| 1855 |
// =======================================================================================
|
| 1856 |
+
// 10. EVENT DELEGATION & BOOTSTRAP INVOCATION
|
| 1857 |
// =======================================================================================
|
| 1858 |
|
| 1859 |
// Define global function for welcome screen overlay
|
|
|
|
| 1863 |
setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400);
|
| 1864 |
};
|
| 1865 |
|
| 1866 |
+
// Bind all interactive elements safely
|
| 1867 |
document.addEventListener('DOMContentLoaded', () => {
|
| 1868 |
// Sidebar Controls
|
| 1869 |
+
document.getElementById('btnSidebarOpen')?.addEventListener('click', UIManager.toggleSidebar);
|
| 1870 |
+
document.getElementById('btnSidebarClose')?.addEventListener('click', UIManager.toggleSidebar);
|
| 1871 |
+
document.getElementById('btnLaunchSystem')?.addEventListener('click', window.startArjunApp);
|
| 1872 |
|
| 1873 |
// Auth Flow Controls
|
| 1874 |
+
document.getElementById('loginPromptBtn')?.addEventListener('click', AuthManager.openModal);
|
| 1875 |
+
document.getElementById('btnAuthClose')?.addEventListener('click', AuthManager.closeModal);
|
| 1876 |
+
document.getElementById('btn-tab-login')?.addEventListener('click', () => AuthManager.switchTab('login'));
|
| 1877 |
+
document.getElementById('btn-tab-register')?.addEventListener('click', () => AuthManager.switchTab('register'));
|
| 1878 |
|
| 1879 |
+
document.getElementById('btn-fire-log-otp')?.addEventListener('click', () => AuthManager.process('login_send_otp'));
|
| 1880 |
+
document.getElementById('btn-fire-log-verify')?.addEventListener('click', () => AuthManager.process('login_verify'));
|
| 1881 |
+
document.getElementById('btn-fire-reg-otp')?.addEventListener('click', () => AuthManager.process('register_send_otp'));
|
| 1882 |
+
document.getElementById('btn-fire-reg-verify')?.addEventListener('click', () => AuthManager.process('register_verify'));
|
| 1883 |
|
| 1884 |
+
document.getElementById('btnLogBack')?.addEventListener('click', () => AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1'));
|
| 1885 |
+
document.getElementById('btnRegBack')?.addEventListener('click', () => AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1'));
|
| 1886 |
+
document.getElementById('btnLogout')?.addEventListener('click', AuthManager.logout);
|
| 1887 |
+
document.getElementById('btnClearMemory')?.addEventListener('click', ChatEngine.clearMemory);
|
| 1888 |
|
| 1889 |
// File Attachment Routing
|
| 1890 |
+
document.getElementById('btnAttachMenuToggle')?.addEventListener('click', UIManager.toggleAttachMenu);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1891 |
|
| 1892 |
+
// Reattach clicking events to the options
|
| 1893 |
+
document.getElementById('attachDropdownMenu')?.addEventListener('click', (e) => {
|
| 1894 |
+
const target = e.target.closest('.dropdown-item');
|
| 1895 |
+
if(!target) return;
|
| 1896 |
+
|
| 1897 |
+
if(target.id === 'opt-image') FileProcessor.triggerFileSelector('image');
|
| 1898 |
+
if(target.id === 'opt-video') FileProcessor.triggerFileSelector('video');
|
| 1899 |
+
if(target.id === 'opt-audio') FileProcessor.triggerFileSelector('audio');
|
| 1900 |
+
if(target.id === 'opt-document') FileProcessor.triggerFileSelector('document');
|
| 1901 |
+
});
|
| 1902 |
+
|
| 1903 |
+
document.getElementById('sys-inp-image')?.addEventListener('change', function() { FileProcessor.processFile(this, 'image'); });
|
| 1904 |
+
document.getElementById('sys-inp-video')?.addEventListener('change', function() { FileProcessor.processFile(this, 'video'); });
|
| 1905 |
+
document.getElementById('sys-inp-audio')?.addEventListener('change', function() { FileProcessor.processFile(this, 'audio'); });
|
| 1906 |
+
document.getElementById('sys-inp-document')?.addEventListener('change', function() { FileProcessor.processFile(this, 'document'); });
|
| 1907 |
+
document.getElementById('btnDiscardFile')?.addEventListener('click', FileProcessor.discardFile);
|
| 1908 |
|
| 1909 |
// Primary Message Controls
|
| 1910 |
+
document.getElementById('masterSendBtn')?.addEventListener('click', ChatEngine.initiateDispatch);
|
| 1911 |
+
document.getElementById('mainChatInput')?.addEventListener('keydown', ChatEngine.handleKeyboard);
|
| 1912 |
+
document.getElementById('mainChatInput')?.addEventListener('input', function() { UIManager.autoGrowTextArea(this); });
|
| 1913 |
|
| 1914 |
// Example Prompt Controls
|
| 1915 |
+
document.getElementById('suggCodeBtn')?.addEventListener('click', () => ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.'));
|
| 1916 |
+
document.getElementById('suggImgBtn')?.addEventListener('click', () => ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.'));
|
| 1917 |
|
| 1918 |
// Voice & STT Options
|
| 1919 |
+
document.getElementById('smartLangToggle')?.addEventListener('click', VoiceEngine.switchLanguage);
|
| 1920 |
+
document.getElementById('masterVoiceBtn')?.addEventListener('click', VoiceEngine.toggleDictation);
|
| 1921 |
|
| 1922 |
// Live Mode Options
|
| 1923 |
+
document.getElementById('btnStartLiveMode')?.addEventListener('click', LiveModeController.initialize);
|
| 1924 |
+
document.getElementById('btnExitLiveMode')?.addEventListener('click', LiveModeController.terminate);
|
| 1925 |
+
document.getElementById('liveMicBtn')?.addEventListener('click', VoiceEngine.toggleDictation);
|
| 1926 |
|
| 1927 |
// Workspace Logic Hooks
|
| 1928 |
+
document.getElementById('btnWsClose')?.addEventListener('click', WorkspaceEngine.closePanel);
|
| 1929 |
+
document.getElementById('btnWsCopy')?.addEventListener('click', function() { WorkspaceEngine.executeCopy(this); });
|
| 1930 |
|
| 1931 |
// Interaction Scroll Listeners
|
| 1932 |
+
document.getElementById('msgs')?.addEventListener('scroll', UIManager.checkScrollState);
|
| 1933 |
+
document.getElementById('scrollTriggerBtn')?.addEventListener('click', UIManager.forceScrollDown);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1934 |
|
| 1935 |
// Ensure startup screen displays if memory cleared
|
| 1936 |
if(!localStorage.getItem('arjun_welcome_seen')) {
|
| 1937 |
+
const overlay = document.getElementById('welcomeOverlay');
|
| 1938 |
+
if(overlay) overlay.style.display = 'flex';
|
| 1939 |
} else {
|
| 1940 |
+
const overlay = document.getElementById('welcomeOverlay');
|
| 1941 |
+
if(overlay) overlay.style.display = 'none';
|
| 1942 |
}
|
| 1943 |
|
| 1944 |
// Fire Boot Processes
|