Spaces:
Restarting
Restarting
| <html lang="en" dir="ltr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
| <!-- Viewport Settings: Disables zoom, removes blue tap highlights on mobile devices --> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> | |
| <meta name="description" content="Arjun 2.O Ultimate Enterprise Artificial Intelligence System engineered by Abhay Kumar."> | |
| <meta name="theme-color" content="#FF9933"> | |
| <title>Arjun 2.O - Professional Advanced AI</title> | |
| <!-- ========================================================================================= | |
| EXTERNAL RESOURCES, FONTS & LIBRARIES (बाहरी स्रोत) | |
| ========================================================================================= --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <!-- Professional Typography: Inter for UI, Geist Mono for Code, Instrument Serif for Headers --> | |
| <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"> | |
| <!-- Syntax Highlighting (Atom One Dark for Workspace Environment) --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"> | |
| <!-- Data Extraction & Rendering Utilities --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script> | |
| <!-- ========================================================================================= | |
| MASSIVE ENTERPRISE CSS ARCHITECTURE (विस्तृत और उन्नत स्टाइलिंग) | |
| ========================================================================================= --> | |
| <style> | |
| /* --------------------------------------------------------------------------------------- | |
| A. CSS VARIABLES, DESIGN TOKENS & BRANDING | |
| --------------------------------------------------------------------------------------- */ | |
| :root { | |
| /* Brand Identity: Saffron, White, Green (Tiranga Theme) */ | |
| --brand-saffron: #FF9933; | |
| --brand-saffron-light: rgba(255, 153, 51, 0.12); | |
| --brand-saffron-dark: #e68a2e; | |
| --brand-saffron-glow: rgba(255, 153, 51, 0.4); | |
| --brand-white: #FFFFFF; | |
| --brand-white-glass: rgba(255, 255, 255, 0.88); | |
| --brand-green: #138808; | |
| --brand-green-light: rgba(19, 136, 8, 0.12); | |
| --brand-green-dark: #0f6e06; | |
| --brand-green-glow: rgba(19, 136, 8, 0.4); | |
| /* Structural Colors & Backgrounds */ | |
| --bg-primary: #ffffff; | |
| --bg-secondary: #f8f9fa; | |
| --bg-tertiary: #f1f3f5; | |
| --bg-glass: rgba(255, 255, 255, 0.75); | |
| --bg-glass-heavy: rgba(255, 255, 255, 0.95); | |
| --bg-overlay: rgba(0, 0, 0, 0.5); | |
| /* Text & Typography Colors */ | |
| --text-primary: #111827; | |
| --text-secondary: #4b5563; | |
| --text-tertiary: #9ca3af; | |
| --text-inverse: #ffffff; | |
| --text-error: #ef4444; | |
| --text-success: #10b981; | |
| /* Borders & Dividers */ | |
| --border-light: rgba(0, 0, 0, 0.08); | |
| --border-medium: rgba(0, 0, 0, 0.15); | |
| --border-focus: rgba(255, 153, 51, 0.5); | |
| /* Shadows & Elevation */ | |
| --shadow-xs: 0 1px 2px rgba(0,0,0,0.04); | |
| --shadow-sm: 0 1px 3px rgba(0,0,0,0.05), 0 1px 2px rgba(0,0,0,0.03); | |
| --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.05), 0 2px 4px -1px rgba(0,0,0,0.03); | |
| --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.05), 0 4px 6px -2px rgba(0,0,0,0.025); | |
| --shadow-xl: 0 20px 25px -5px rgba(0,0,0,0.05), 0 10px 10px -5px rgba(0,0,0,0.02); | |
| --shadow-float: 0 25px 50px -12px rgba(0,0,0,0.15); | |
| --shadow-inner: inset 0 2px 4px rgba(0,0,0,0.06); | |
| /* Font Families */ | |
| --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| --font-mono: 'Geist Mono', Consolas, Monaco, monospace; | |
| --font-serif: 'Instrument Serif', Georgia, serif; | |
| /* Radii */ | |
| --radius-xs: 4px; | |
| --radius-sm: 8px; | |
| --radius-md: 12px; | |
| --radius-lg: 16px; | |
| --radius-xl: 24px; | |
| --radius-full: 9999px; | |
| /* Animation Easing */ | |
| --ease-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1); | |
| --ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| --ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| /* Z-Indices - Properly Layered Enterprise System */ | |
| --z-ambient: -1; | |
| --z-base: 1; | |
| --z-header: 10; | |
| --z-dock: 20; | |
| --z-workspace: 25; | |
| --z-dropdown: 50; | |
| --z-sidebar: 100; | |
| --z-modal: 5000; | |
| --z-toast: 9000; | |
| --z-live: 9999; | |
| --z-offline: 10000; | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| B. GLOBAL RESET & ANTI-BLUE-HIGHLIGHT | |
| --------------------------------------------------------------------------------------- */ | |
| *, *::before, *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| -webkit-tap-highlight-color: transparent ; | |
| -webkit-touch-callout: none ; | |
| } | |
| html { font-size: 16px; -webkit-text-size-adjust: 100%; scroll-behavior: smooth; } | |
| body { | |
| height: 100dvh; | |
| width: 100vw; | |
| overflow: hidden; | |
| background-color: var(--bg-primary); | |
| color: var(--text-primary); | |
| font-family: var(--font-sans); | |
| line-height: 1.6; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| } | |
| /* Accessibilty focus states */ | |
| *:focus-visible { outline: 2px solid var(--brand-saffron); outline-offset: 2px; } | |
| *:focus { outline: none; } | |
| button, input, textarea, select { | |
| font-family: inherit; | |
| color: inherit; | |
| border: none; | |
| background: transparent; | |
| } | |
| button { cursor: pointer; user-select: none; } | |
| button:disabled { cursor: not-allowed; opacity: 0.6; } | |
| a { color: inherit; text-decoration: none; } | |
| img { max-width: 100%; height: auto; display: block; } | |
| svg { flex-shrink: 0; } | |
| /* Custom Enterprise Scrollbars */ | |
| ::-webkit-scrollbar { width: 8px; height: 8px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 10px; border: 2px solid transparent; background-clip: padding-box; transition: background var(--ease-smooth); } | |
| ::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.3); border: 2px solid transparent; background-clip: padding-box; } | |
| /* --------------------------------------------------------------------------------------- | |
| C. NETWORK OFFLINE & AMBIENT BACKGROUND SYSTEM | |
| --------------------------------------------------------------------------------------- */ | |
| .network-offline-banner { | |
| position: fixed; top: 0; left: 0; right: 0; background: var(--text-error); color: white; | |
| text-align: center; padding: 8px; font-size: 14px; font-weight: 700; z-index: var(--z-offline); | |
| transform: translateY(-100%); transition: transform var(--ease-spring); display: flex; align-items: center; justify-content: center; gap: 8px; box-shadow: var(--shadow-md); | |
| } | |
| .network-offline-banner.active { transform: translateY(0); } | |
| .ambient-environment { | |
| position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none; | |
| background: linear-gradient(135deg, var(--brand-saffron-light) 0%, var(--bg-primary) 50%, var(--brand-green-light) 100%); | |
| } | |
| .ambient-orb { | |
| position: absolute; border-radius: 50%; filter: blur(120px); opacity: 0.35; | |
| animation: orbFloat 40s ease-in-out infinite alternate; will-change: transform; | |
| } | |
| .orb-top-left { | |
| width: 650px; height: 650px; | |
| background: radial-gradient(circle, rgba(255,153,51,0.2) 0%, transparent 70%); | |
| top: -200px; left: -150px; | |
| } | |
| .orb-bottom-right { | |
| width: 550px; height: 550px; | |
| background: radial-gradient(circle, rgba(19,136,8,0.15) 0%, transparent 70%); | |
| bottom: -150px; right: -100px; animation-delay: -20s; | |
| } | |
| @keyframes orbFloat { | |
| 0% { transform: translate(0, 0) scale(1); } | |
| 33% { transform: translate(50px, 70px) scale(1.05); } | |
| 66% { transform: translate(-30px, 40px) scale(0.95); } | |
| 100% { transform: translate(60px, -20px) scale(1.1); } | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| D. ENTERPRISE TOAST NOTIFICATION ENGINE | |
| --------------------------------------------------------------------------------------- */ | |
| .toast-wrapper { | |
| position: absolute; top: 24px; left: 50%; transform: translateX(-50%); | |
| z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px; | |
| pointer-events: none; width: 90%; max-width: 450px; align-items: center; | |
| } | |
| .toast-notification { | |
| background: rgba(17, 24, 39, 0.95); color: var(--text-inverse); padding: 14px 24px; | |
| border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl); | |
| animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards; | |
| display: flex; align-items: center; gap: 12px; width: fit-content; max-width: 100%; word-break: break-word; | |
| backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1); | |
| } | |
| .toast-notification.error { background: rgba(239, 68, 68, 0.95); border-color: rgba(255,255,255,0.2); } | |
| .toast-notification.success { background: rgba(16, 185, 129, 0.95); border-color: rgba(255,255,255,0.2); } | |
| .toast-notification svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--brand-saffron); } | |
| .toast-notification.error svg, .toast-notification.success svg { color: white; } | |
| @keyframes toastSlideIn { from { opacity: 0; transform: translateY(-30px) scale(0.9); } to { opacity: 1; transform: translateY(0) scale(1); } } | |
| @keyframes toastFadeOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } } | |
| /* --------------------------------------------------------------------------------------- | |
| E. INITIAL WELCOME OVERLAY | |
| --------------------------------------------------------------------------------------- */ | |
| .startup-overlay { | |
| position: fixed; inset: 0; background: var(--brand-white-glass); | |
| backdrop-filter: blur(25px); -webkit-backdrop-filter: blur(25px); z-index: calc(var(--z-toast) + 100); | |
| display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 24px; | |
| transition: opacity var(--ease-smooth), visibility var(--ease-smooth); | |
| } | |
| .startup-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; } | |
| .startup-logo-container { position: relative; margin-bottom: 32px; animation: popIn var(--ease-spring) 0.5s both; } | |
| .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; } | |
| .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; } | |
| @keyframes pulseGlow { from { opacity: 0.3; transform: scale(0.95); } to { opacity: 0.6; transform: scale(1.05); } } | |
| @keyframes popIn { 0% { opacity: 0; transform: scale(0.8) translateY(20px); } 100% { opacity: 1; transform: scale(1) translateY(0); } } | |
| .startup-title { font-family: var(--font-sans); font-size: 2.8rem; font-weight: 900; color: var(--text-primary); letter-spacing: -1px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.6s both; } | |
| .startup-desc { font-size: 1.15rem; color: var(--text-secondary); line-height: 1.6; max-width: 600px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.7s both; font-weight: 500; } | |
| .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.8s both; display: flex; align-items: center; gap: 12px; position: relative; overflow: hidden; } | |
| .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; } | |
| .btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); } | |
| .btn-startup-launch:hover::before { left: 150%; } | |
| @keyframes slideUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } | |
| /* --------------------------------------------------------------------------------------- | |
| F. CORE APPLICATION LAYOUT & SIDEBAR | |
| --------------------------------------------------------------------------------------- */ | |
| .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); } | |
| /* Sidebar Navigation System */ | |
| .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); } | |
| .sidebar-header { padding: 28px 24px; border-bottom: 1px solid var(--border-light); display: flex; justify-content: space-between; align-items: center; } | |
| .brand-identity { display: flex; align-items: center; gap: 14px; text-decoration: none; } | |
| .brand-identity img { width: 48px; height: 48px; border-radius: var(--radius-md); object-fit: cover; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); transition: transform var(--ease-spring); } | |
| .brand-identity:hover img { transform: scale(1.08) rotate(-5deg); box-shadow: var(--shadow-md); } | |
| .brand-typography { display: flex; flex-direction: column; } | |
| .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; } | |
| .brand-edition { font-size: 11px; font-weight: 800; letter-spacing: 1.5px; text-transform: uppercase; background: linear-gradient(90deg, var(--brand-saffron-dark), var(--brand-green-dark)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; margin-top: 4px; } | |
| .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); } | |
| .btn-mobile-close:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); } | |
| .sidebar-body { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 28px; } | |
| /* Advanced Auth Widget in Sidebar */ | |
| .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); } | |
| .auth-widget:hover { box-shadow: var(--shadow-md); border-color: var(--border-medium); } | |
| .btn-secure-connect { width: 100%; padding: 14px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-md); font-size: 14px; font-weight: 700; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 10px; transition: var(--ease-fast); } | |
| .btn-secure-connect:hover { background: #000000; transform: translateY(-2px); box-shadow: var(--shadow-md); } | |
| .user-profile-display { display: none; align-items: center; gap: 14px; } | |
| .avatar-badge { width: 46px; height: 46px; border-radius: var(--radius-full); background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); color: var(--brand-white); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 18px; box-shadow: var(--shadow-sm); border: 2px solid var(--bg-primary); text-shadow: 0 1px 2px rgba(0,0,0,0.3); } | |
| .user-details { flex: 1; overflow: hidden; } | |
| .user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; } | |
| .user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 5px var(--brand-green-glow); } | |
| .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); } | |
| .btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); } | |
| /* Developer Box with Tiranga Accent */ | |
| .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; } | |
| .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)); } | |
| .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); } | |
| .developer-credit-box:hover img { transform: scale(1.05); } | |
| .dev-box-title { font-size: 18px; font-weight: 800; color: var(--text-primary); margin-bottom: 6px; } | |
| .dev-box-subtitle { font-size: 11px; font-weight: 800; color: var(--text-tertiary); letter-spacing: 1px; text-transform: uppercase; } | |
| /* Dangerous Action Button */ | |
| .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; } | |
| .btn-erase-memory:hover { background: #fee2e2; color: var(--text-error); border-color: #fca5a5; } | |
| /* --------------------------------------------------------------------------------------- | |
| G. MAIN CHAT AREA & HEADER | |
| --------------------------------------------------------------------------------------- */ | |
| .main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; } | |
| .chat-top-bar { padding: 16px 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); } | |
| .top-bar-left { display: flex; align-items: center; gap: 16px; } | |
| .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); } | |
| .btn-hamburger:hover { background: var(--bg-secondary); } | |
| .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); transition: var(--ease-smooth); } | |
| .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; transition: background var(--ease-smooth); } | |
| .system-status-pill.offline .pulse-dot { background: var(--text-error); box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.2); animation: none; } | |
| @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); } } | |
| /* DYNAMIC LIVE MODE ACTIVATOR */ | |
| .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; } | |
| .btn-activate-live:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 8px 25px rgba(239, 68, 68, 0.45); } | |
| .btn-activate-live svg { width: 18px; height: 18px; animation: liveBlink 1.5s infinite; } | |
| @keyframes liveBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } } | |
| /* Chat Scrollable Area */ | |
| .chat-scroll-area { flex: 1; overflow-y: auto; padding: 40px 10%; display: flex; flex-direction: column; gap: 36px; scroll-behavior: smooth; position: relative; } | |
| /* Internal Welcome Hero Box */ | |
| .chat-hero-section { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 60px 20px; margin: auto; animation: slideUpFade 0.7s var(--ease-spring) both; max-width: 750px; } | |
| .hero-avatar-wrapper { position: relative; margin-bottom: 36px; } | |
| .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; } | |
| .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;} | |
| @keyframes rotateGlow { 100% { transform: rotate(360deg); } } | |
| @keyframes slideUpFade { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } | |
| .hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); line-height: 1.2; } | |
| .hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; } | |
| /* GUEST BADGE LIMIT DISPLAY */ | |
| .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); } | |
| .guest-warning-badge svg { width: 18px; height: 18px; } | |
| .prompt-suggestions-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; width: 100%; } | |
| .prompt-card { background: rgba(255, 255, 255, 0.7); backdrop-filter: blur(15px); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 24px; cursor: pointer; text-align: left; transition: var(--ease-smooth); box-shadow: var(--shadow-sm); position: relative; overflow: hidden; } | |
| .prompt-card::after { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: var(--brand-saffron); opacity: 0; transition: var(--ease-fast); } | |
| .prompt-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); border-color: var(--brand-saffron); background: rgba(255, 255, 255, 0.95); } | |
| .prompt-card:hover::after { opacity: 1; } | |
| .prompt-icon { font-size: 28px; margin-bottom: 14px; display: inline-block; background: var(--bg-tertiary); padding: 10px; border-radius: var(--radius-md); } | |
| .prompt-title { font-size: 15px; font-weight: 800; color: var(--text-primary); margin-bottom: 8px; } | |
| .prompt-desc { font-size: 13px; color: var(--text-secondary); line-height: 1.5; } | |
| /* --------------------------------------------------------------------------------------- | |
| H. CHAT MESSAGE BUBBLES & PREVIEWS | |
| --------------------------------------------------------------------------------------- */ | |
| .chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.4s var(--ease-spring) both; } | |
| @keyframes messagePopIn { from { opacity: 0; transform: translateY(20px) scale(0.97); } to { opacity: 1; transform: none; } } | |
| .chat-message-row.user-msg { flex-direction: row-reverse; align-self: flex-end; } | |
| .chat-message-row.bot-msg { align-self: flex-start; } | |
| .msg-avatar { width: 42px; height: 42px; border-radius: var(--radius-md); flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800; box-shadow: var(--shadow-sm); } | |
| .user-msg .msg-avatar { background: var(--text-primary); color: var(--brand-white); } | |
| .bot-msg .msg-avatar { background: var(--bg-primary); border: 1px solid var(--border-light); padding: 3px; } | |
| .bot-msg .msg-avatar img { width: 100%; height: 100%; border-radius: 8px; object-fit: cover; } | |
| .msg-content-column { display: flex; flex-direction: column; gap: 8px; max-width: 100%; min-width: 0; } | |
| .user-msg .msg-content-column { align-items: flex-end; } | |
| .file-badge { font-size: 11px; font-weight: 700; color: var(--brand-saffron-dark); background: var(--brand-saffron-light); padding: 4px 12px; border-radius: var(--radius-full); margin-bottom: 4px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(255,153,51,0.2); } | |
| .file-badge svg { width: 12px; height: 12px; } | |
| /* In-Bubble File Previews */ | |
| .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; transition: transform var(--ease-smooth); cursor: zoom-in; } | |
| .chat-in-bubble-img:hover { transform: scale(1.02); } | |
| .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); } | |
| .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); } | |
| .chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .chat-bubble { padding: 18px 24px; font-size: 16px; line-height: 1.6; position: relative; word-wrap: break-word; overflow-wrap: anywhere; } | |
| .user-msg .chat-bubble { background: var(--text-primary); color: var(--text-inverse); border-radius: 24px 24px 6px 24px; box-shadow: var(--shadow-md); } | |
| .bot-msg .chat-bubble { background: var(--bg-primary); color: var(--text-primary); border: 1px solid var(--border-light); border-radius: 6px 24px 24px 24px; box-shadow: var(--shadow-sm); width: 100%; } | |
| /* Bot Action Buttons (Copy & TTS) */ | |
| .bot-actions-row { display: flex; gap: 10px; margin-top: 8px; padding-left: 14px; opacity: 0; transition: opacity var(--ease-smooth); flex-wrap: wrap; } | |
| .bot-msg:hover .bot-actions-row { opacity: 1; } | |
| .btn-bot-action { background: var(--bg-secondary); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 13px; font-weight: 700; cursor: pointer; display: flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: var(--radius-full); transition: var(--ease-fast); } | |
| .btn-bot-action:hover { background: var(--bg-primary); color: var(--text-primary); transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: var(--border-medium); } | |
| .btn-bot-action svg { width: 16px; height: 16px; } | |
| .btn-bot-action.action-tts { color: var(--brand-green-dark); border-color: rgba(19, 136, 8, 0.25); background: var(--brand-green-light); } | |
| .btn-bot-action.action-tts:hover { background: rgba(19, 136, 8, 0.2); } | |
| /* Markdown Formatting inside Bubbles */ | |
| .chat-bubble p { margin-bottom: 16px; } | |
| .chat-bubble p:last-child { margin-bottom: 0; } | |
| .chat-bubble strong { font-weight: 800; color: inherit; } | |
| .chat-bubble em { font-style: italic; } | |
| .chat-bubble ul, .chat-bubble ol { margin-bottom: 16px; padding-left: 24px; } | |
| .chat-bubble li { margin-bottom: 6px; } | |
| .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; } | |
| /* Advanced Tables */ | |
| .chat-bubble table { width: 100%; border-collapse: collapse; margin: 20px 0; border-radius: var(--radius-sm); overflow: hidden; box-shadow: var(--shadow-sm); } | |
| .chat-bubble th, .chat-bubble td { border: 1px solid var(--border-light); padding: 12px 16px; text-align: left; } | |
| .chat-bubble th { background: var(--bg-secondary); font-weight: 700; color: var(--text-primary); } | |
| .chat-bubble tr:nth-child(even) { background: var(--bg-tertiary); } | |
| .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); } | |
| .user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); border-color: rgba(255,255,255,0.1); } | |
| .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; } | |
| /* Custom Pre-Code Blocks */ | |
| .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); } | |
| .chat-bubble pre code { background: transparent; color: inherit; padding: 20px; font-weight: 400; border: none; display: block; overflow-x: auto; } | |
| /* Streaming Loading UI Component */ | |
| .streaming-code-container { background: #1e1e2e; border-radius: var(--radius-md); border: 1px solid #313244; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); } | |
| .streaming-code-header { background: #11111b; padding: 14px 20px; font-size: 12px; font-weight: 700; color: #a6adc8; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid #313244; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 1.5px; } | |
| .loading-ring { width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.1); border-top-color: var(--brand-saffron); border-radius: 50%; animation: ringSpin 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; } | |
| @keyframes ringSpin { to { transform: rotate(360deg); } } | |
| .streaming-code-container pre { margin: 0; background: transparent; border: none; border-radius: 0; box-shadow: none; } | |
| /* Workspace Execute Card */ | |
| .workspace-execute-card { background: var(--bg-secondary); border: 1px solid var(--border-light); border-radius: var(--radius-md); padding: 20px; margin: 20px 0; display: flex; align-items: center; justify-content: space-between; box-shadow: var(--shadow-sm); transition: var(--ease-smooth); } | |
| .workspace-execute-card:hover { border-color: var(--brand-saffron-light); box-shadow: var(--shadow-md); background: var(--bg-primary); } | |
| .ws-card-left { display: flex; align-items: center; gap: 16px; } | |
| .ws-card-icon-box { width: 54px; height: 54px; border-radius: var(--radius-sm); background: var(--bg-primary); display: flex; align-items: center; justify-content: center; font-size: 26px; box-shadow: var(--shadow-sm); border: 1px solid var(--border-light); color: var(--text-primary); } | |
| .ws-card-icon-box svg { color: var(--brand-saffron); } | |
| .ws-card-details h4 { font-size: 16px; font-weight: 800; margin-bottom: 4px; color: var(--text-primary); } | |
| .ws-card-details p { font-size: 12px; color: var(--text-secondary); font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; } | |
| .btn-launch-workspace { padding: 12px 24px; background: var(--text-primary); color: var(--brand-white); border: none; border-radius: var(--radius-sm); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: var(--shadow-sm); } | |
| .btn-launch-workspace:hover { transform: scale(1.05); background: var(--brand-saffron); box-shadow: 0 6px 15px rgba(255,153,51,0.35); } | |
| /* --------------------------------------------------------------------------------------- | |
| I. BOTTOM INPUT DOCK & TOOLS | |
| --------------------------------------------------------------------------------------- */ | |
| .input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); } | |
| .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); position: relative; } | |
| .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); } | |
| /* Upload Preview Header */ | |
| .upload-preview-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; border-bottom: 1px solid transparent; } | |
| .upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; border-bottom-color: var(--border-light); padding-bottom: 15px; } | |
| .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); } | |
| .upload-meta { flex: 1; } | |
| .upload-filename { font-size: 14px; font-weight: 700; color: var(--text-primary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .upload-status-text { font-size: 12px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 6px; } | |
| .upload-status-text svg { width: 14px; height: 14px; } | |
| .btn-discard-upload { background: rgba(239, 68, 68, 0.1); border: none; width: 32px; height: 32px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--text-error); transition: var(--ease-fast); } | |
| .btn-discard-upload:hover { background: var(--text-error); color: #fff; } | |
| .input-tools-row { display: flex; align-items: flex-end; gap: 12px; padding: 14px 20px 14px 24px; } | |
| .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; } | |
| .main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; } | |
| /* Real-time Interim Text Feedback */ | |
| .interim-text-overlay { position: absolute; pointer-events: none; color: var(--brand-saffron-dark); 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; font-weight: 600; } | |
| .interim-text-overlay.active { display: block; } | |
| /* Attachment Menu Dropdown */ | |
| .attachment-module { position: relative; } | |
| .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); position: relative; } | |
| .btn-tool-icon:hover { background: var(--bg-tertiary); color: var(--text-primary); } | |
| .btn-tool-icon svg { width: 24px; height: 24px; stroke-width: 2; } | |
| .attachment-dropdown { position: absolute; bottom: 60px; left: 0; background: rgba(255,255,255,0.95); backdrop-filter: blur(25px); -webkit-backdrop-filter: blur(25px); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 10px; box-shadow: var(--shadow-xl); display: none; flex-direction: column; gap: 6px; z-index: var(--z-dropdown); min-width: 240px; transform: translateY(15px) scale(0.95); opacity: 0; transition: all var(--ease-fast); transform-origin: bottom left; } | |
| .attachment-dropdown.visible { display: flex; transform: translateY(0) scale(1); opacity: 1; } | |
| .dropdown-item { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-radius: var(--radius-sm); cursor: pointer; font-size: 15px; font-weight: 600; color: var(--text-primary); transition: var(--ease-fast); } | |
| .dropdown-item:hover { background: var(--bg-tertiary); color: var(--brand-saffron-dark); } | |
| .dropdown-item svg { width: 20px; height: 20px; color: var(--text-secondary); } | |
| .dropdown-item:hover svg { color: var(--brand-saffron); } | |
| .stealth-input { display: none; } | |
| /* Smart Language Toggle & Mic */ | |
| .language-toggle-chip { font-size: 13px; font-weight: 800; color: var(--text-secondary); border: 2px solid var(--border-light); background: var(--bg-primary); border-radius: 10px; padding: 6px 12px; cursor: pointer; transition: var(--ease-smooth); display: flex; align-items: center; gap: 6px; user-select: none; } | |
| .language-toggle-chip:hover { background: var(--brand-saffron-light); color: var(--brand-saffron-dark); border-color: var(--brand-saffron); } | |
| .language-toggle-chip.hindi-active { background: var(--brand-green-light); color: var(--brand-green-dark); border-color: var(--brand-green); } | |
| .language-toggle-chip svg { width: 16px; height: 16px; } | |
| .btn-mic-tool { position: relative; } | |
| .btn-mic-tool.active-listening { color: #ffffff; background: var(--text-error); border-radius: var(--radius-full); } | |
| .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; } | |
| @keyframes rippleMic { 0% { transform: scale(0.8); opacity: 1; } 100% { transform: scale(1.5); opacity: 0; } } | |
| /* Master Send Button */ | |
| .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); position: relative; overflow: hidden; } | |
| .btn-master-send::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); transition: 0.5s; } | |
| .btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; position: relative; z-index: 2; } | |
| .btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); } | |
| .btn-master-send:hover::before { left: 100%; } | |
| .btn-master-send:hover svg { transform: translate(2px, -2px); } | |
| .btn-master-send:disabled { opacity: 0.5; cursor: not-allowed; filter: grayscale(100%); transform: none; box-shadow: none; } | |
| .bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; } | |
| /* --------------------------------------------------------------------------------------- | |
| J. WORKSPACE PRO (VS-CODE LIKE EDITOR PANEL) | |
| --------------------------------------------------------------------------------------- */ | |
| .code-workspace-panel { width: 0; background: #1e1e1e; border-left: 1px solid var(--border-light); display: flex; flex-direction: column; transition: width var(--ease-smooth); overflow: hidden; box-shadow: -15px 0 40px rgba(0,0,0,0.15); z-index: var(--z-workspace); } | |
| .code-workspace-panel.expanded { width: 55%; } | |
| .workspace-header-bar { padding: 16px 24px; border-bottom: 1px solid #333; background: #252526; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } | |
| .workspace-title-group { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 10px; color: #abb2bf; font-family: var(--font-mono); letter-spacing: 0.5px;} | |
| .workspace-tools { display: flex; gap: 10px; } | |
| .btn-workspace-tool { padding: 8px 16px; border-radius: var(--radius-sm); background: #3e4451; border: 1px solid #181a1f; cursor: pointer; display: flex; align-items: center; gap: 8px; color: #fff; transition: var(--ease-fast); font-size: 13px; font-weight: 600; } | |
| .btn-workspace-tool:hover { background: #4b5263; } | |
| .btn-workspace-tool.close { padding: 8px; background: transparent; border-color: transparent; color: #abb2bf; } | |
| .btn-workspace-tool.close:hover { color: #e06c75; background: rgba(224, 108, 117, 0.1); } | |
| .workspace-editor-surface { flex: 1; overflow-y: auto; background: #282c34; padding: 24px; position: relative; } | |
| /* Line Numbers Implementation for Workspace */ | |
| .workspace-editor-content { display: flex; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; } | |
| .workspace-line-numbers { padding-right: 15px; border-right: 1px solid #3e4451; color: #5c6370; text-align: right; user-select: none; } | |
| .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; } | |
| /* --------------------------------------------------------------------------------------- | |
| K. LIVE MODE FULLSCREEN OVERLAY | |
| --------------------------------------------------------------------------------------- */ | |
| .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); backdrop-filter: blur(20px); } | |
| .live-mode-viewport.active { opacity: 1; pointer-events: auto; } | |
| .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); } | |
| .btn-close-live:hover { background: rgba(239, 68, 68, 0.15); color: var(--text-error); transform: rotate(90deg); } | |
| .pulsing-orb-wrapper { position: relative; width: 250px; height: 250px; display: flex; align-items: center; justify-content: center; margin-bottom: 50px; } | |
| .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; } | |
| .energy-core.speaking { animation: coreSpeak 0.5s infinite alternate; } | |
| @keyframes coreSpeak { 0% { transform: scale(1); box-shadow: 0 0 30px rgba(19,136,8,0.4); } 100% { transform: scale(1.2); box-shadow: 0 0 80px rgba(255,153,51,0.7); } } | |
| .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; } | |
| .energy-ring:nth-child(2) { animation-delay: 0.8s; border-color: var(--brand-green); } | |
| .energy-ring:nth-child(3) { animation-delay: 1.6s; border-color: var(--text-primary); } | |
| @keyframes energyRipple { 0% { transform: scale(0.4); opacity: 1; border-width: 6px; } 100% { transform: scale(1.6); opacity: 0; border-width: 1px; } } | |
| .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; transition: color var(--ease-fast); } | |
| .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; transition: opacity var(--ease-smooth); } | |
| .live-control-deck { display: flex; gap: 24px; margin-top: 50px; } | |
| .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); } | |
| .btn-live-deck.mic-control { background: var(--bg-primary); border: 3px solid var(--border-light); color: var(--text-primary); } | |
| .btn-live-deck.mic-control:hover { transform: translateY(-6px); border-color: var(--brand-saffron); color: var(--brand-saffron); box-shadow: var(--shadow-xl); } | |
| .btn-live-deck.mic-control.is-recording { background: var(--text-error); color: white; border-color: var(--text-error); animation: pulseMicLive 1.2s infinite; } | |
| @keyframes pulseMicLive { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.6); } 70% { box-shadow: 0 0 0 25px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } } | |
| /* Scroll Trigger Button */ | |
| .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; } | |
| .btn-scroll-trigger.visible { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); } | |
| .btn-scroll-trigger:hover { background: var(--text-primary); color: var(--text-inverse); transform: translateX(-50%) translateY(-5px); box-shadow: var(--shadow-xl); } | |
| /* --------------------------------------------------------------------------------------- | |
| L. AUTHENTICATION SECURE GATEWAY (MODAL) | |
| --------------------------------------------------------------------------------------- */ | |
| .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; } | |
| .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); } | |
| .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; } | |
| .btn-modal-dismiss:hover { background: #fee2e2; color: var(--text-error); transform: rotate(90deg); } | |
| .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; } | |
| .auth-tab-switch { display: flex; background: var(--bg-secondary); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; } | |
| .auth-tab-item { flex: 1; padding: 14px; text-align: center; border-radius: var(--radius-sm); font-size: 15px; font-weight: 800; color: var(--text-secondary); cursor: pointer; transition: var(--ease-fast); } | |
| .auth-tab-item.active { background: var(--bg-primary); color: var(--text-primary); box-shadow: var(--shadow-sm); } | |
| .auth-form-view { display: none; flex-direction: column; animation: slideIn 0.3s ease; } | |
| .auth-form-view.active { display: flex; } | |
| .auth-input-element { width: 100%; padding: 18px; border: 2px solid var(--border-light); border-radius: var(--radius-md); font-size: 16px; outline: none; background: var(--bg-secondary); transition: var(--ease-fast); font-family: var(--font-sans); margin-bottom: 20px; font-weight: 500; } | |
| .auth-input-element:focus { border-color: var(--brand-saffron); background: var(--bg-primary); box-shadow: 0 0 0 4px var(--brand-saffron-light); } | |
| .btn-auth-execute { width: 100%; padding: 18px; background: var(--text-primary); color: var(--brand-white); border: none; border-radius: var(--radius-md); font-size: 16px; font-weight: 800; cursor: pointer; transition: var(--ease-fast); margin-top: 10px; } | |
| .btn-auth-execute:hover { background: #000000; transform: translateY(-2px); box-shadow: var(--shadow-md); } | |
| .btn-auth-return { width: 100%; padding: 14px; background: transparent; color: var(--text-tertiary); border: none; font-size: 15px; font-weight: 700; cursor: pointer; margin-top: 10px; transition: 0.2s; } | |
| .btn-auth-return:hover { color: var(--text-primary); } | |
| @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } | |
| @keyframes slideIn { from { opacity: 0; transform: translateX(25px); } to { opacity: 1; transform: none; } } | |
| /* Cursor & Loading UI */ | |
| .typing-cursor { display: inline-block; width: 10px; height: 18px; background: var(--brand-saffron); margin-left: 4px; animation: cursorBlink 1s step-end infinite; vertical-align: middle; } | |
| @keyframes cursorBlink { 50% { opacity: 0; } } | |
| .loading-dots-container { display: flex; align-items: center; gap: 6px; padding: 6px; } | |
| .loading-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-tertiary); opacity: 0.4; animation: dotBounce 1.4s infinite ease-in-out both; } | |
| .loading-dot:nth-child(1) { animation-delay: -0.32s; } .loading-dot:nth-child(2) { animation-delay: -0.16s; } | |
| @keyframes dotBounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } } | |
| /* --------------------------------------------------------------------------------------- | |
| M. RESPONSIVE DESIGN (MOBILE & TABLET ADAPTATIONS) | |
| --------------------------------------------------------------------------------------- */ | |
| @media (max-width: 1024px) { | |
| .code-workspace-panel.expanded { width: 100%; position: absolute; top: 0; left: 0; height: 100%; z-index: 2000; } | |
| } | |
| @media (max-width: 900px) { | |
| .sidebar-container { position: absolute; left: -320px; z-index: 1000; height: 100%; box-shadow: var(--shadow-float); } | |
| .sidebar-container.active { left: 0; } | |
| .btn-hamburger { display: flex; } | |
| .btn-mobile-close { display: flex; } | |
| .chat-scroll-area { padding: 24px 15px; } | |
| .input-dock { padding: 10px 15px 20px; } | |
| .chat-message-row { max-width: 98%; } | |
| .btn-scroll-trigger { bottom: 130px; } | |
| .hero-greeting { font-size: 32px; } | |
| .prompt-suggestions-grid { grid-template-columns: 1fr; } | |
| .input-tools-row { flex-wrap: wrap; } | |
| .main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; } | |
| .interim-text-overlay { left: 15px; top: 12px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: OFFLINE BANNER | |
| ========================================================================================= --> | |
| <div id="networkStatusBanner" class="network-offline-banner"> | |
| <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> | |
| System Offline. Please check your internet connection. | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: NOTIFICATIONS | |
| ========================================================================================= --> | |
| <div id="toast-container" class="toast-wrapper"></div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: STARTUP OVERLAY | |
| ========================================================================================= --> | |
| <div class="startup-overlay" id="welcomeOverlay"> | |
| <div class="startup-logo-container"> | |
| <div class="startup-logo-glow"></div> | |
| <img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Core Identity"> | |
| </div> | |
| <h1 class="startup-title">Welcome to Arjun 2.O</h1> | |
| <p class="startup-desc">Professional Enterprise Edition. Experience secure workspace logic generation, high-fidelity visual rendering, and zero-latency live conversational mode.</p> | |
| <button class="btn-startup-launch" id="btnLaunchSystem"> | |
| Initialize System | |
| <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg> | |
| </button> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: LIVE MODE FULLSCREEN OVERLAY | |
| ========================================================================================= --> | |
| <div class="live-mode-viewport" id="liveOverlay"> | |
| <button class="btn-close-live" id="btnExitLiveMode" title="Exit Live Mode"> | |
| <svg viewBox="0 0 24 24" 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> | |
| </button> | |
| <div class="pulsing-orb-wrapper"> | |
| <div class="energy-ring"></div> | |
| <div class="energy-ring"></div> | |
| <div class="energy-ring"></div> | |
| <div class="energy-core" id="liveOrb"></div> | |
| </div> | |
| <div class="live-feedback-status" id="liveStatusText">Initializing Audio Stream...</div> | |
| <div class="live-feedback-text" id="liveTranscriptText">Speak directly to Arjun. Natural language processing active.</div> | |
| <div class="live-control-deck"> | |
| <button class="btn-live-deck mic-control" id="liveMicBtn"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" x2="12" y1="19" y2="22"></line></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: AMBIENT BACKGROUND | |
| ========================================================================================= --> | |
| <div class="ambient-environment"> | |
| <div class="ambient-orb orb-top-left"></div> | |
| <div class="ambient-orb orb-bottom-right"></div> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: MASTER APPLICATION CONTAINER | |
| ========================================================================================= --> | |
| <div class="app-root"> | |
| <!-- A. NAVIGATION SIDEBAR --> | |
| <aside class="sidebar-container" id="sidebar"> | |
| <div class="sidebar-header"> | |
| <a href="#" class="brand-identity"> | |
| <img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo"> | |
| <div class="brand-typography"> | |
| <span class="brand-name">ARJUN 2.O</span> | |
| <span class="brand-edition">Enterprise</span> | |
| </div> | |
| </a> | |
| <button class="btn-mobile-close" id="btnSidebarClose"> | |
| <svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" stroke-width="2.5" fill="none"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> | |
| </button> | |
| </div> | |
| <div class="sidebar-body"> | |
| <!-- Authentication Widget --> | |
| <div class="auth-widget"> | |
| <button id="loginPromptBtn" class="btn-secure-connect"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg> | |
| Secure Login | |
| </button> | |
| <div id="userProfile" class="user-profile-display"> | |
| <div class="avatar-badge" id="uAvatar">U</div> | |
| <div class="user-details"> | |
| <div class="user-email-id" id="uEmail">user@network.com</div> | |
| <div class="user-clearance-level">Verified Clearance</div> | |
| </div> | |
| <button class="btn-system-logout" id="btnLogout" title="Terminate Session"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Branding Box --> | |
| <div class="developer-credit-box"> | |
| <img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Core Image"> | |
| <h3 class="dev-box-title">Arjun Intelligence</h3> | |
| <p class="dev-box-subtitle">ENGINEERED BY ABHAY KUMAR</p> | |
| </div> | |
| <!-- Wipe Memory Button --> | |
| <button class="btn-erase-memory" id="btnClearMemory"> | |
| <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> | |
| Wipe Neural Context | |
| </button> | |
| </div> | |
| </aside> | |
| <!-- B. MAIN CHAT ENGINE INTERFACE --> | |
| <main class="main-chat-wrapper"> | |
| <!-- Top Status Bar --> | |
| <header class="chat-top-bar"> | |
| <div class="top-bar-left"> | |
| <button class="btn-hamburger" id="btnSidebarOpen"> | |
| <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> | |
| </button> | |
| <div class="system-status-pill" id="mainStatusPill"> | |
| <div class="pulse-dot"></div> | |
| <span id="mainStatusText">System Online</span> | |
| </div> | |
| </div> | |
| <!-- LIVE MODE ACTIVATOR --> | |
| <button class="btn-activate-live" id="btnStartLiveMode"> | |
| <svg viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5" fill="none"><circle cx="12" cy="12" r="10"></circle><circle cx="12" cy="12" r="4" fill="currentColor"></circle></svg> | |
| LIVE MODE | |
| </button> | |
| </header> | |
| <!-- Scrollable Conversation Area --> | |
| <div class="chat-scroll-area" id="msgs"> | |
| <!-- Internal Welcome / Guest Warning State --> | |
| <div class="chat-hero-section" id="welcomeState"> | |
| <div class="hero-avatar-wrapper"> | |
| <div class="hero-avatar-glow"></div> | |
| <img src="https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png" alt="Arjun Logo Large"> | |
| </div> | |
| <h2 class="hero-greeting">How can I assist you today?</h2> | |
| <p class="hero-description">Experience next-generation reasoning, seamless multi-file analysis, and secure workspace code generation engineered by Abhay Kumar.</p> | |
| <!-- GUEST BADGE LIMIT DISPLAY --> | |
| <div id="guestBadge" class="guest-warning-badge"> | |
| <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> | |
| Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login. | |
| </div> | |
| <div class="prompt-suggestions-grid"> | |
| <div class="prompt-card" id="suggCodeBtn"> | |
| <span class="prompt-icon">💻</span> | |
| <div class="prompt-title">Generate Production Code</div> | |
| <div class="prompt-desc">Create secure, workspace-ready architecture instantly.</div> | |
| </div> | |
| <div class="prompt-card" id="suggImgBtn"> | |
| <span class="prompt-icon">🎨</span> | |
| <div class="prompt-title">Render Stunning Visions</div> | |
| <div class="prompt-desc">Utilize advanced AI to paint your imagination.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Floating Scroll Down Button --> | |
| <button class="btn-scroll-trigger" id="scrollTriggerBtn"> | |
| <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"></polyline></svg> | |
| </button> | |
| <!-- Bottom Input Dock --> | |
| <div class="input-dock"> | |
| <div class="input-master-container"> | |
| <!-- File Preview Component --> | |
| <div class="upload-preview-bar" id="filePreviewBar"> | |
| <img class="upload-thumb" id="previewImgThumb" src="" alt="Thumbnail" style="display:none;"> | |
| <div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div> | |
| <div class="upload-meta"> | |
| <div class="upload-filename" id="previewFileName">document.pdf</div> | |
| <div class="upload-status-text"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"></polyline></svg> | |
| File ready to be transmitted | |
| </div> | |
| </div> | |
| <button class="btn-discard-upload" id="btnDiscardFile" title="Remove Attachment"> | |
| <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> | |
| </button> | |
| </div> | |
| <!-- Main Tool & Input Row --> | |
| <div class="input-tools-row"> | |
| <!-- Attachment Dropdown Module --> | |
| <div class="attachment-module"> | |
| <button class="btn-tool-icon" id="btnAttachMenuToggle" title="Attach File"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg> | |
| </button> | |
| <div class="attachment-dropdown" id="attachDropdownMenu"> | |
| <div class="dropdown-item" id="opt-image"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg> | |
| High-Res Image | |
| </div> | |
| <div class="dropdown-item" id="opt-video"> | |
| <svg viewBox="0 0 24 24" 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> | |
| Video Media | |
| </div> | |
| <div class="dropdown-item" id="opt-audio"> | |
| <svg viewBox="0 0 24 24" 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> | |
| Audio Track | |
| </div> | |
| <div class="dropdown-item" id="opt-document"> | |
| <svg viewBox="0 0 24 24" 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> | |
| Document / Code | |
| </div> | |
| </div> | |
| <!-- Hidden File Inputs --> | |
| <input type="file" id="sys-inp-image" class="stealth-input" accept="image/*"> | |
| <input type="file" id="sys-inp-video" class="stealth-input" accept="video/*"> | |
| <input type="file" id="sys-inp-audio" class="stealth-input" accept="audio/*"> | |
| <input type="file" id="sys-inp-document" class="stealth-input" accept=".pdf,.doc,.docx,.txt,.md,.csv,.json,.py,.js,.html,.css,.cpp,.c,.java"> | |
| </div> | |
| <!-- Smart Language Toggle Button (Bilingual STT logic) --> | |
| <button class="language-toggle-chip" id="smartLangToggle" title="Toggle Voice Engine Language"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><line x1="2" y1="12" x2="22" y2="12"></line><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path></svg> | |
| <span id="langDisplayBadge">EN</span> | |
| </button> | |
| <!-- Voice Dictation Button --> | |
| <button class="btn-tool-icon btn-mic-tool" id="masterVoiceBtn" title="Voice Dictation"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" x2="12" y1="19" y2="22"></line></svg> | |
| </button> | |
| <!-- Expanding Text Area --> | |
| <div style="flex:1; position: relative;"> | |
| <!-- STT Interim Feedback Overlay --> | |
| <div id="interimTextOverlay" class="interim-text-overlay"></div> | |
| <textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1" style="width: 100%;"></textarea> | |
| </div> | |
| <!-- Master Send Button --> | |
| <button class="btn-master-send" id="masterSendBtn"> | |
| <svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bottom-branding-text">Secured by Arjun Core Architecture • Developed by Abhay Kumar</div> | |
| </div> | |
| </main> | |
| <!-- C. WORKSPACE CODE EDITOR PANEL --> | |
| <aside class="code-workspace-panel" id="workspacePanel"> | |
| <div class="workspace-header-bar"> | |
| <div class="workspace-title-group"> | |
| <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg> | |
| <span id="wsTitleText">Workspace Logic</span> | |
| </div> | |
| <div class="workspace-tools"> | |
| <button class="btn-workspace-tool" id="btnWsCopy"> | |
| <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg> | |
| Copy Source | |
| </button> | |
| <button class="btn-workspace-tool close" id="btnWsClose" title="Close Editor"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" 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> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="workspace-editor-surface"> | |
| <div class="workspace-editor-content"> | |
| <div class="workspace-line-numbers" id="wsLineNumbers">1</div> | |
| <pre><code id="workspaceCodeBlock" class="hljs"></code></pre> | |
| </div> | |
| </div> | |
| </aside> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: SECURE AUTHENTICATION MODAL | |
| ========================================================================================= --> | |
| <div class="secure-modal-backdrop" id="secureAuthModal"> | |
| <div class="secure-modal-surface"> | |
| <button class="btn-modal-dismiss" id="btnAuthClose"> | |
| <svg viewBox="0 0 24 24" 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> | |
| </button> | |
| <div class="modal-brand-header">Arjun Network</div> | |
| <div class="auth-tab-switch"> | |
| <div class="auth-tab-item active" id="btn-tab-login">Connect</div> | |
| <div class="auth-tab-item" id="btn-tab-register">Enroll</div> | |
| </div> | |
| <!-- Login Flow --> | |
| <div id="auth-flow-login"> | |
| <div class="auth-form-view active" id="auth-log-phase-1"> | |
| <input type="email" class="auth-input-element" id="authLogEmail" placeholder="Authorized Email Address"> | |
| <button class="btn-auth-execute" id="btn-fire-log-otp">Generate Secure Token (OTP)</button> | |
| </div> | |
| <div class="auth-form-view" id="auth-log-phase-2"> | |
| <input type="number" class="auth-input-element" id="authLogOTP" placeholder="Validation Code (OTP)"> | |
| <button class="btn-auth-execute" id="btn-fire-log-verify">Authenticate Session</button> | |
| <button class="btn-auth-return" id="btnLogBack">← Return</button> | |
| </div> | |
| </div> | |
| <!-- Register Flow --> | |
| <div id="auth-flow-register" style="display:none;"> | |
| <div class="auth-form-view active" id="auth-reg-phase-1"> | |
| <input type="text" class="auth-input-element" id="authRegName" placeholder="Full Legal Name"> | |
| <input type="email" class="auth-input-element" id="authRegEmail" placeholder="Communication Email"> | |
| <button class="btn-auth-execute" id="btn-fire-reg-otp">Verify Identity</button> | |
| </div> | |
| <div class="auth-form-view" id="auth-reg-phase-2"> | |
| <input type="number" class="auth-input-element" id="authRegOTP" placeholder="Identity Token (OTP)"> | |
| <button class="btn-auth-execute" id="btn-fire-reg-verify">Initialize Account</button> | |
| <button class="btn-auth-return" id="btnRegBack">← Return</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ========================================================================================= | |
| MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE | |
| ========================================================================================= --> | |
| <script> | |
| // ======================================================================================= | |
| // 1. CONFIGURATION & STATE MANAGEMENT | |
| // ======================================================================================= | |
| const Config = { | |
| GAS_URL: "https://script.google.com/macros/s/AKfycbzTsXGoVh97JjtFAAG825GF4WUZqf7FDB3Zbxyf0nrLXt_1HjJSSqA829UcdoamRPvg0A/exec", | |
| LOGO_URL: "https://i.ibb.co/0y2sdbq6/PT-20260523-133251-0000.png", | |
| PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js', | |
| API_ENDPOINT: '/api/chat', // Uses relative path to connect to Flask App.py | |
| MAX_FILE_SIZE_MB: 10, // Prevent UI freeze on giant files | |
| }; | |
| // Initialize PDF worker | |
| if (typeof pdfjsLib !== 'undefined') { | |
| pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER; | |
| } | |
| const AppState = { | |
| currentUser: localStorage.getItem('arjun_user') || null, | |
| guestCount: parseInt(localStorage.getItem('arjun_guest') || '0', 10), | |
| history: [], | |
| pendingAttachment: null, | |
| isProcessing: false, | |
| isUserScrolling: false, | |
| generatedCodeBlocks: [], | |
| currentWorkspaceId: null, | |
| isStreamingActive: false, | |
| isLiveModeEngaged: false, | |
| gradioClient: null, | |
| isMicRecording: false, | |
| isOnline: navigator.onLine | |
| }; | |
| // Initialize Gradio Client Dynamically for TTS | |
| window.initGradioEngine = async function() { | |
| try { | |
| const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"); | |
| AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS"); | |
| console.log("Neural TTS Engine connected successfully to Gradio."); | |
| } catch(err) { | |
| console.warn("Gradio Connection Warning:", err.message); | |
| // Non-blocking failure, app still works | |
| } | |
| }; | |
| window.initGradioEngine(); | |
| // ======================================================================================= | |
| // 2. UTILITY ENGINE (Robust Copy, Notifications, and Text Cleaners) | |
| // ======================================================================================= | |
| const Utils = { | |
| showToast: (message, type = 'info') => { | |
| const container = document.getElementById('toast-container'); | |
| const toast = document.createElement('div'); | |
| toast.className = `toast-notification ${type}`; | |
| let icon = '<polyline points="20 6 9 17 4 12"></polyline>'; // Checkmark | |
| if (type === 'error') icon = '<line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line>'; | |
| toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">${icon}</svg> ${Utils.escapeHTML(message)}`; | |
| container.appendChild(toast); | |
| setTimeout(() => { if (toast.parentNode) toast.remove(); }, 3500); | |
| }, | |
| escapeHTML: (str) => { | |
| if (str === null || str === undefined) return ''; | |
| return String(str).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); | |
| }, | |
| // ✨ Intelligent Text Cleaner for TTS (Ignores code, links, images) | |
| cleanTextForVoice: (rawText) => { | |
| if(!rawText) return ""; | |
| let cleaned = String(rawText); | |
| // Remove Markdown Elements sequentially to prevent regex conflicts | |
| cleaned = cleaned.replace(/```[\s\S]*?```/g, ''); // Code blocks | |
| cleaned = cleaned.replace(/`.*?`/g, ''); // Inline code | |
| cleaned = cleaned.replace(/!\[.*?\]\(.*?\)/g, ''); // Images | |
| cleaned = cleaned.replace(/\[(.*?)\]\(.*?\)/g, '$1'); // Links | |
| cleaned = cleaned.replace(/<think>[\s\S]*?<\/think>/gi, ''); // Think Tags | |
| cleaned = cleaned.replace(/https?:\/\/[^\s]+/g, ''); // Bare URLs | |
| cleaned = cleaned.replace(/[*_~#|-]/g, ''); // Formatting symbols | |
| return cleaned.trim(); | |
| }, | |
| // Robust Fallback Copy Mechanism | |
| executeFallbackCopy: (text, btnElement) => { | |
| const textArea = document.createElement("textarea"); | |
| textArea.value = text; | |
| textArea.style.top = "0"; textArea.style.left = "0"; textArea.style.position = "fixed"; | |
| textArea.style.opacity = "0"; | |
| document.body.appendChild(textArea); | |
| textArea.focus(); textArea.select(); | |
| try { | |
| const successful = document.execCommand('copy'); | |
| if (successful) { | |
| const originalHTML = btnElement.innerHTML; | |
| 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 Data`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| } else { | |
| Utils.showToast("Clipboard access denied by browser.", "error"); | |
| } | |
| } catch (err) { | |
| Utils.showToast("System error copying text.", "error"); | |
| } | |
| document.body.removeChild(textArea); | |
| }, | |
| copyToClipboard: (btnElement, textToCopy) => { | |
| if (!navigator.clipboard) { | |
| Utils.executeFallbackCopy(textToCopy, btnElement); | |
| return; | |
| } | |
| navigator.clipboard.writeText(textToCopy).then(() => { | |
| const originalHTML = btnElement.innerHTML; | |
| 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 Data`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| }).catch((err) => { | |
| console.warn('Modern API failed, utilizing fallback...', err); | |
| Utils.executeFallbackCopy(textToCopy, btnElement); | |
| }); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 3. AUTHENTICATION & SYNC MANAGER | |
| // ======================================================================================= | |
| const AuthManager = { | |
| initUI: () => { | |
| const promptBtn = document.getElementById('loginPromptBtn'); | |
| const profileCard = document.getElementById('userProfile'); | |
| const guestBadge = document.getElementById('guestBadge'); | |
| if (AppState.currentUser) { | |
| promptBtn.style.display = 'none'; | |
| profileCard.style.display = 'flex'; | |
| document.getElementById('uEmail').innerText = AppState.currentUser; | |
| document.getElementById('uAvatar').innerText = AppState.currentUser.charAt(0).toUpperCase(); | |
| if(guestBadge) guestBadge.style.display = 'none'; | |
| } else { | |
| promptBtn.style.display = 'flex'; | |
| profileCard.style.display = 'none'; | |
| if(guestBadge) { | |
| guestBadge.style.display = 'inline-flex'; | |
| document.getElementById('guestCountDisplay').innerText = AppState.guestCount; | |
| } | |
| } | |
| }, | |
| openModal: () => { document.getElementById('secureAuthModal').style.display = 'flex'; }, | |
| closeModal: () => { document.getElementById('secureAuthModal').style.display = 'none'; }, | |
| switchTab: (tabName) => { | |
| document.querySelectorAll('.auth-tab-item').forEach(el => el.classList.remove('active')); | |
| document.getElementById(tabName === 'login' ? 'btn-tab-login' : 'btn-tab-register').classList.add('active'); | |
| document.getElementById('auth-flow-login').style.display = tabName === 'login' ? 'block' : 'none'; | |
| document.getElementById('auth-flow-register').style.display = tabName === 'register' ? 'block' : 'none'; | |
| }, | |
| switchPhase: (currentId, nextId) => { | |
| document.getElementById(currentId).classList.remove('active'); | |
| document.getElementById(nextId).classList.add('active'); | |
| }, | |
| process: async (actionType) => { | |
| if (!AppState.isOnline) return Utils.showToast("System is offline. Cannot authenticate.", "error"); | |
| const payload = { action: actionType }; | |
| let buttonId = ''; | |
| if (actionType === 'register_send_otp') { | |
| payload.name = document.getElementById('authRegName').value.trim(); | |
| payload.email = document.getElementById('authRegEmail').value.trim(); | |
| payload.phone = "0000000000"; payload.organization = "Arjun Base"; | |
| if (!payload.email || !payload.name) return Utils.showToast("Identification details required.", "error"); | |
| buttonId = 'btn-fire-reg-otp'; | |
| } | |
| else if (actionType === 'login_send_otp') { | |
| payload.email = document.getElementById('authLogEmail').value.trim(); | |
| if (!payload.email) return Utils.showToast("Email required for validation.", "error"); | |
| buttonId = 'btn-fire-log-otp'; | |
| } | |
| else if (actionType === 'register_verify' || actionType === 'login_verify') { | |
| payload.email = document.getElementById(actionType === 'register_verify' ? 'authRegEmail' : 'authLogEmail').value.trim(); | |
| payload.otp = document.getElementById(actionType === 'register_verify' ? 'authRegOTP' : 'authLogOTP').value.trim(); | |
| if (!payload.otp) return Utils.showToast("Security token required.", "error"); | |
| buttonId = actionType === 'register_verify' ? 'btn-fire-reg-verify' : 'btn-fire-log-verify'; | |
| } | |
| const triggerBtn = document.getElementById(buttonId); | |
| const originalText = triggerBtn.innerHTML; | |
| triggerBtn.disabled = true; | |
| triggerBtn.innerText = 'Establishing Connection...'; | |
| try { | |
| const response = await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| mode: 'cors', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify(payload) | |
| }); | |
| const result = await response.json(); | |
| if (result.status === 'success') { | |
| Utils.showToast(result.message, "success"); | |
| if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2'); | |
| else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2'); | |
| else if (actionType === 'register_verify' || actionType === 'login_verify') { | |
| AppState.currentUser = payload.email; | |
| localStorage.setItem('arjun_user', AppState.currentUser); | |
| AuthManager.closeModal(); | |
| AuthManager.initUI(); | |
| ChatEngine.syncHistoryFromCloud(); | |
| } | |
| } else { | |
| Utils.showToast(result.message, "error"); | |
| } | |
| } catch (error) { | |
| console.error("Auth Network Error: ", error); | |
| Utils.showToast("Encrypted gateway error. Check network.", "error"); | |
| } | |
| triggerBtn.disabled = false; | |
| triggerBtn.innerHTML = originalText; | |
| }, | |
| logout: () => { | |
| localStorage.removeItem('arjun_user'); | |
| location.reload(); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 4. UI & DOM MANAGER | |
| // ======================================================================================= | |
| const UIManager = { | |
| toggleSidebar: () => { document.getElementById('sidebar').classList.toggle('active'); }, | |
| checkScrollState: () => { | |
| const msgArea = document.getElementById('msgs'); | |
| const isAtBottom = Math.abs((msgArea.scrollHeight - msgArea.scrollTop) - msgArea.clientHeight) < 80; | |
| AppState.isUserScrolling = !isAtBottom; | |
| const scrollBtn = document.getElementById('scrollTriggerBtn'); | |
| if (AppState.isUserScrolling) scrollBtn.classList.add('visible'); | |
| else scrollBtn.classList.remove('visible'); | |
| }, | |
| forceScrollDown: () => { | |
| const msgArea = document.getElementById('msgs'); | |
| msgArea.scrollTo({ top: msgArea.scrollHeight, behavior: 'smooth' }); | |
| AppState.isUserScrolling = false; | |
| document.getElementById('scrollTriggerBtn').classList.remove('visible'); | |
| }, | |
| autoScroll: () => { | |
| if (!AppState.isUserScrolling) { | |
| const msgArea = document.getElementById('msgs'); | |
| msgArea.scrollTop = msgArea.scrollHeight; | |
| } | |
| }, | |
| autoGrowTextArea: (element) => { | |
| element.style.height = 'auto'; | |
| element.style.height = Math.min(element.scrollHeight, 200) + 'px'; | |
| }, | |
| toggleAttachMenu: () => { | |
| document.getElementById('attachDropdownMenu').classList.toggle('visible'); | |
| }, | |
| updateNetworkStatus: () => { | |
| AppState.isOnline = navigator.onLine; | |
| const banner = document.getElementById('networkStatusBanner'); | |
| const pill = document.getElementById('mainStatusPill'); | |
| const pillText = document.getElementById('mainStatusText'); | |
| if (AppState.isOnline) { | |
| banner.classList.remove('active'); | |
| pill.classList.remove('offline'); | |
| pillText.innerText = 'System Online'; | |
| if(!AppState.isProcessing && AppState.history.length > 0) { | |
| Utils.showToast("Network connection restored.", "success"); | |
| } | |
| } else { | |
| banner.classList.add('active'); | |
| pill.classList.add('offline'); | |
| pillText.innerText = 'System Offline'; | |
| } | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 5. THE BUG-FREE SPEECH & TTS ENGINE (STT DUPLICATION FIX IMPLEMENTED) | |
| // ======================================================================================= | |
| const VoiceEngine = { | |
| recognition: null, | |
| currentLanguage: 'en-IN', | |
| silenceTimer: null, | |
| liveSessionText: "", | |
| init: () => { | |
| const SR = window.SpeechRecognition || window.webkitSpeechRecognition; | |
| if (!SR) { | |
| console.warn("Speech Recognition API not supported in this browser."); | |
| document.getElementById('masterVoiceBtn').style.display = 'none'; | |
| return; | |
| } | |
| VoiceEngine.recognition = new SR(); | |
| VoiceEngine.recognition.continuous = true; | |
| VoiceEngine.recognition.interimResults = true; | |
| VoiceEngine.recognition.lang = VoiceEngine.currentLanguage; | |
| VoiceEngine.recognition.onstart = () => { | |
| AppState.isMicRecording = true; | |
| document.getElementById('masterVoiceBtn').classList.add('active-listening'); | |
| VoiceEngine.liveSessionText = ""; | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveMicBtn').classList.add('is-recording'); | |
| document.getElementById('liveStatusText').innerText = "Listening..."; | |
| document.getElementById('liveOrb').classList.remove('speaking'); | |
| document.getElementById('liveOrb').style.transform = "scale(1.25)"; | |
| } | |
| }; | |
| VoiceEngine.recognition.onresult = (event) => { | |
| if (VoiceEngine.silenceTimer) clearTimeout(VoiceEngine.silenceTimer); | |
| let finalTranscript = ''; | |
| let interimTranscript = ''; | |
| // ✨ The Standard Loop - Prevents all Duplication and Undefined errors | |
| for (let i = event.resultIndex; i < event.results.length; ++i) { | |
| let transcriptSegment = event.results[i].transcript; | |
| if (transcriptSegment === undefined || transcriptSegment === null) continue; | |
| if (event.results[i].isFinal) { | |
| finalTranscript += transcriptSegment; | |
| } else { | |
| interimTranscript += transcriptSegment; | |
| } | |
| } | |
| if (AppState.isLiveModeEngaged) { | |
| if (finalTranscript) { | |
| VoiceEngine.liveSessionText += (VoiceEngine.liveSessionText ? ' ' : '') + finalTranscript.trim(); | |
| } | |
| let displayString = (VoiceEngine.liveSessionText + ' ' + interimTranscript).trim(); | |
| if (displayString) { | |
| document.getElementById('liveTranscriptText').innerText = `"${displayString}"`; | |
| document.getElementById('mainChatInput').value = displayString; | |
| } | |
| // Silence Detector | |
| VoiceEngine.silenceTimer = setTimeout(() => { | |
| if (document.getElementById('mainChatInput').value.trim().length > 0) { | |
| VoiceEngine.recognition.stop(); | |
| } | |
| }, 1800); | |
| } else { | |
| // Regular Chat Text Box Appending | |
| if (finalTranscript) { | |
| const inputField = document.getElementById('mainChatInput'); | |
| let currentVal = inputField.value; | |
| const separator = (currentVal && !currentVal.endsWith(' ')) ? ' ' : ''; | |
| inputField.value = currentVal + separator + finalTranscript.trim(); | |
| UIManager.autoGrowTextArea(inputField); | |
| } | |
| // Show visual feedback for interim vs final | |
| const interimOverlay = document.getElementById('interimTextOverlay'); | |
| if (interimTranscript) { | |
| interimOverlay.innerText = interimTranscript.trim(); | |
| interimOverlay.classList.add('active'); | |
| } else { | |
| interimOverlay.classList.remove('active'); | |
| } | |
| } | |
| }; | |
| VoiceEngine.recognition.onend = () => { | |
| AppState.isMicRecording = false; | |
| document.getElementById('masterVoiceBtn').classList.remove('active-listening'); | |
| document.getElementById('interimTextOverlay').classList.remove('active'); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveMicBtn').classList.remove('is-recording'); | |
| document.getElementById('liveOrb').style.transform = "scale(1)"; | |
| const currentInput = document.getElementById('mainChatInput').value.trim(); | |
| if (currentInput !== '' && !AppState.isProcessing) { | |
| document.getElementById('liveStatusText').innerText = "Processing..."; | |
| ChatEngine.initiateDispatch(); | |
| } else if (!AppState.isProcessing) { | |
| document.getElementById('liveStatusText').innerText = "Tap mic to interact"; | |
| } | |
| } | |
| }; | |
| VoiceEngine.recognition.onerror = (event) => { | |
| AppState.isMicRecording = false; | |
| if(event.error !== 'no-speech' && event.error !== 'aborted') { | |
| Utils.showToast("Voice module error: " + event.error, "error"); | |
| } | |
| document.getElementById('masterVoiceBtn').classList.remove('active-listening'); | |
| document.getElementById('interimTextOverlay').classList.remove('active'); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveMicBtn').classList.remove('is-recording'); | |
| document.getElementById('liveStatusText').innerText = "Audio Failure. Retry."; | |
| } | |
| }; | |
| }, | |
| switchLanguage: () => { | |
| const btn = document.getElementById('smartLangToggle'); | |
| const badge = document.getElementById('langDisplayBadge'); | |
| if (VoiceEngine.currentLanguage === 'en-IN') { | |
| VoiceEngine.currentLanguage = 'hi-IN'; | |
| badge.innerText = 'हि'; | |
| btn.classList.add('hindi-active'); | |
| Utils.showToast("Listening Protocol: Hindi (देवनागरी)", "success"); | |
| } else { | |
| VoiceEngine.currentLanguage = 'en-IN'; | |
| badge.innerText = 'EN'; | |
| btn.classList.remove('hindi-active'); | |
| Utils.showToast("Listening Protocol: English", "success"); | |
| } | |
| if (VoiceEngine.recognition) { | |
| VoiceEngine.recognition.lang = VoiceEngine.currentLanguage; | |
| if(AppState.isMicRecording) { | |
| VoiceEngine.recognition.stop(); | |
| // Slight delay to allow system to halt before restarting | |
| setTimeout(() => { try{VoiceEngine.recognition.start();}catch(e){} }, 400); | |
| } | |
| } | |
| }, | |
| toggleDictation: () => { | |
| if (!VoiceEngine.recognition) return Utils.showToast("Hardware dictation unsupported in this browser.", "error"); | |
| try { | |
| if(AppState.isMicRecording) { | |
| VoiceEngine.recognition.stop(); | |
| } else { | |
| VoiceEngine.recognition.start(); | |
| } | |
| } catch (e) { console.error("Mic Start Error", e); } | |
| }, | |
| executeTTS: async (rawText) => { | |
| const cleanSpeechText = Utils.cleanTextForVoice(rawText); | |
| if(!cleanSpeechText.trim()) { | |
| Utils.showToast("No readable conversational text found in this block.", "error"); | |
| return; | |
| } | |
| Utils.showToast("🔊 Linking with Neural Voice Matrix..."); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveOrb').classList.add('speaking'); | |
| } | |
| try { | |
| if(!AppState.gradioClient) { | |
| const module = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js"); | |
| AppState.gradioClient = await module.Client.connect("Vedika66/Edge-TTS"); | |
| } | |
| const result = await AppState.gradioClient.predict("/smart_hybrid_tts", { | |
| text: cleanSpeechText, | |
| voice_type: "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)" | |
| }); | |
| if (result.data && result.data) { | |
| const audioUrl = typeof result.data === 'string' ? result.data : result.data.url; | |
| const audio = new Audio(audioUrl); | |
| audio.onended = () => { | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveOrb').classList.remove('speaking'); | |
| document.getElementById('liveStatusText').innerText = "Tap mic to respond"; | |
| } | |
| }; | |
| audio.play(); | |
| } else { | |
| throw new Error("No audio payload returned."); | |
| } | |
| } catch (error) { | |
| Utils.showToast("Voice Neural Matrix is currently overloaded.", "error"); | |
| console.error("Gradio TTS Error:", error); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveOrb').classList.remove('speaking'); | |
| } | |
| } | |
| } | |
| }; | |
| /** | |
| * Live Mode Controller | |
| */ | |
| const LiveModeController = { | |
| initialize: () => { | |
| AppState.isLiveModeEngaged = true; | |
| document.getElementById('liveOverlay').classList.add('active'); | |
| if (VoiceEngine.recognition && !AppState.isMicRecording) { | |
| setTimeout(() => { | |
| try { VoiceEngine.recognition.start(); } catch(e){} | |
| }, 600); | |
| } | |
| }, | |
| terminate: () => { | |
| AppState.isLiveModeEngaged = false; | |
| document.getElementById('liveOverlay').classList.remove('active'); | |
| if (VoiceEngine.recognition && AppState.isMicRecording) { | |
| try { VoiceEngine.recognition.stop(); } catch(e){} | |
| } | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 6. FILE & DOCUMENT PROCESSOR (Robust & Size Validated) | |
| // ======================================================================================= | |
| const FileProcessor = { | |
| triggerFileSelector: (type) => { | |
| document.getElementById('attachDropdownMenu').classList.remove('visible'); | |
| document.getElementById('sys-inp-' + type).click(); | |
| }, | |
| processFile: async (inputElement, typeContext) => { | |
| const file = inputElement.files; | |
| if (!file) return; | |
| // Size Validation to prevent UI thread lock | |
| const fileSizeMB = file.size / (1024 * 1024); | |
| if (fileSizeMB > Config.MAX_FILE_SIZE_MB) { | |
| Utils.showToast(`File exceeds ${Config.MAX_FILE_SIZE_MB}MB enterprise limit.`, "error"); | |
| inputElement.value = ''; | |
| return; | |
| } | |
| const fName = file.name.toLowerCase(); | |
| const mime = file.type; | |
| if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required.", "error"); inputElement.value=''; return; } | |
| if (typeContext === 'video' && !mime.startsWith('video/')) { Utils.showToast("Video media required.", "error"); inputElement.value=''; return; } | |
| if (typeContext === 'audio' && !mime.startsWith('audio/')) { Utils.showToast("Audio media required.", "error"); inputElement.value=''; return; } | |
| Utils.showToast(`Analyzing ${file.name}...`, "info"); | |
| const thumbImg = document.getElementById('previewImgThumb'); | |
| const docIcon = document.getElementById('previewDocIcon'); | |
| thumbImg.style.display = 'none'; | |
| docIcon.style.display = 'none'; | |
| document.getElementById('previewFileName').innerText = file.name; | |
| document.getElementById('filePreviewBar').classList.add('visible'); | |
| const fileReader = new FileReader(); | |
| if (typeContext === 'image') { | |
| fileReader.onload = (e) => { | |
| AppState.pendingAttachment = { type: 'image', data: e.target.result.split(','), name: file.name }; | |
| thumbImg.src = e.target.result; | |
| thumbImg.style.display = 'flex'; | |
| }; | |
| fileReader.readAsDataURL(file); | |
| } | |
| else if (typeContext === 'video' || typeContext === 'audio') { | |
| fileReader.onload = (e) => { | |
| AppState.pendingAttachment = { type: typeContext, data: e.target.result.split(','), name: file.name }; | |
| docIcon.innerText = typeContext === 'video' ? '🎥' : '🎵'; | |
| docIcon.style.display = 'flex'; | |
| }; | |
| fileReader.readAsDataURL(file); | |
| } | |
| else if (typeContext === 'document') { | |
| docIcon.innerText = '📄'; | |
| docIcon.style.display = 'flex'; | |
| if (fName.endsWith('.pdf')) { | |
| fileReader.onload = async function() { | |
| try { | |
| const typedArray = new Uint8Array(this.result); | |
| const pdfDoc = await pdfjsLib.getDocument(typedArray).promise; | |
| let extractedText = ""; | |
| for (let i = 1; i <= pdfDoc.numPages; i++) { | |
| const page = await pdfDoc.getPage(i); | |
| const content = await page.getTextContent(); | |
| extractedText += content.items.map(s => s.str).join(' ') + "\n"; | |
| } | |
| AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name }; | |
| Utils.showToast("Document payload secured.", "success"); | |
| } catch (e) { | |
| Utils.showToast("PDF architecture parsing failed.", "error"); | |
| FileProcessor.discardFile(); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(file); | |
| } | |
| else if (fName.endsWith('.docx') || fName.endsWith('.doc')) { | |
| fileReader.onload = async function() { | |
| try { | |
| const buffer = this.result; | |
| const resultData = await mammoth.extractRawText({ arrayBuffer: buffer }); | |
| AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name }; | |
| Utils.showToast("Document payload secured.", "success"); | |
| } catch(e) { | |
| Utils.showToast("Document architecture parsing failed.", "error"); | |
| FileProcessor.discardFile(); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(file); | |
| } | |
| else { | |
| fileReader.onload = (e) => { | |
| AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name }; | |
| Utils.showToast("File payload secured.", "success"); | |
| }; | |
| fileReader.readAsText(file); | |
| } | |
| } | |
| inputElement.value = ''; | |
| }, | |
| discardFile: () => { | |
| AppState.pendingAttachment = null; | |
| document.getElementById('filePreviewBar').classList.remove('visible'); | |
| document.getElementById('previewImgThumb').src = ''; | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 7. WORKSPACE ENGINE & ADVANCED MARKDOWN RENDERING | |
| // ======================================================================================= | |
| const WorkspaceEngine = { | |
| launch: (codeBlockId) => { | |
| AppState.currentWorkspaceId = codeBlockId; | |
| const codeData = AppState.generatedCodeBlocks[codeBlockId]; | |
| document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled Logic"; | |
| const blockDisplay = document.getElementById('workspaceCodeBlock'); | |
| blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`; | |
| blockDisplay.textContent = codeData.code; | |
| hljs.highlightElement(blockDisplay); | |
| // Add Line Numbers dynamically | |
| const lineCount = codeData.code.split('\n').length; | |
| let numbersHTML = ''; | |
| for(let i=1; i<=lineCount; i++) { numbersHTML += `${i}<br>`; } | |
| document.getElementById('wsLineNumbers').innerHTML = numbersHTML; | |
| document.getElementById('workspacePanel').classList.add('expanded'); | |
| if (window.innerWidth <= 1024) { | |
| document.getElementById('sidebar').classList.remove('active'); | |
| } | |
| }, | |
| closePanel: () => { document.getElementById('workspacePanel').classList.remove('expanded'); }, | |
| executeCopy: (btnElement) => { | |
| if (AppState.currentWorkspaceId !== null) { | |
| const srcCode = AppState.generatedCodeBlocks[AppState.currentWorkspaceId].code; | |
| Utils.copyToClipboard(btnElement, srcCode); | |
| } | |
| } | |
| }; | |
| // Custom Marked Renderer for UI perfection | |
| const MD_Renderer = new marked.Renderer(); | |
| MD_Renderer.code = function(token) { | |
| const rawCode = typeof token === 'string' ? token : (token.text || ''); | |
| const langClass = typeof token === 'string' ? arguments : (token.lang || ''); | |
| if (AppState.isStreamingActive) { | |
| return ` | |
| <div class="streaming-code-container"> | |
| <div class="streaming-code-header"> | |
| <div class="loading-ring"></div> | |
| Generating Secure Architecture... | |
| </div> | |
| <pre><code class="language-${Utils.escapeHTML(langClass)}">${Utils.escapeHTML(rawCode)}</code></pre> | |
| </div>`; | |
| } | |
| const internalId = AppState.generatedCodeBlocks.length; | |
| AppState.generatedCodeBlocks.push({ code: rawCode, lang: langClass }); | |
| return ` | |
| <div class="workspace-execute-card"> | |
| <div class="ws-card-left"> | |
| <div class="ws-card-icon-box"> | |
| <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg> | |
| </div> | |
| <div class="ws-card-details"> | |
| <h4>Code Module Compiled</h4> | |
| <p>${Utils.escapeHTML(langClass) || 'Syntax Module'}</p> | |
| </div> | |
| </div> | |
| <button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button> | |
| </div>`; | |
| }; | |
| MD_Renderer.table = function(token) { | |
| let html = '<table>'; | |
| if (token.header) { | |
| html += '<thead><tr>'; | |
| token.header.forEach(th => { html += `<th>${marked.parseInline(th.text)}</th>`; }); | |
| html += '</tr></thead>'; | |
| } | |
| if (token.rows) { | |
| html += '<tbody>'; | |
| token.rows.forEach(tr => { | |
| html += '<tr>'; | |
| tr.forEach(td => { html += `<td>${marked.parseInline(td.text)}</td>`; }); | |
| html += '</tr>'; | |
| }); | |
| html += '</tbody>'; | |
| } | |
| html += '</table>'; | |
| return html; | |
| }; | |
| marked.use({ renderer: MD_Renderer, breaks: true, gfm: true }); | |
| // Event delegation for dynamically generated workspace buttons | |
| document.getElementById('msgs').addEventListener('click', function(e) { | |
| if (e.target && e.target.classList.contains('btn-launch-ws')) { | |
| const blockId = e.target.getAttribute('data-id'); | |
| WorkspaceEngine.launch(blockId); | |
| } | |
| }); | |
| // ======================================================================================= | |
| // 8. CORE CHAT ENGINE & LLM LOGIC | |
| // ======================================================================================= | |
| const ChatEngine = { | |
| handleKeyboard: (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| ChatEngine.initiateDispatch(); | |
| } | |
| }, | |
| sendExample: (queryText) => { | |
| document.getElementById('mainChatInput').value = queryText; | |
| ChatEngine.initiateDispatch(); | |
| }, | |
| clearMemory: async () => { | |
| if(!confirm("Are you sure you want to wipe the neural context? This action cannot be undone.")) return; | |
| if (AppState.currentUser) { | |
| Utils.showToast("Purging neural link memory...", "info"); | |
| try { | |
| await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| mode: 'cors', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify({ action: "delete_history", email: AppState.currentUser }) | |
| }); | |
| } catch(e) {} | |
| } | |
| location.reload(); | |
| }, | |
| syncHistoryFromCloud: async () => { | |
| if (!AppState.isOnline) return; | |
| const messageZone = document.getElementById('msgs'); | |
| document.getElementById('welcomeState').style.display = 'none'; | |
| messageZone.innerHTML = '<div style="text-align:center; padding:80px; font-weight:800; color:var(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>'; | |
| try { | |
| const response = await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| mode: 'cors', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify({ action: "get_history", email: AppState.currentUser }) | |
| }); | |
| const resData = await response.json(); | |
| messageZone.innerHTML = ''; | |
| if (resData.status === 'success' && resData.historyJSON !== "[]") { | |
| AppState.history = JSON.parse(resData.historyJSON); | |
| AppState.history.forEach(msgObj => { | |
| if (msgObj.role === 'user') { | |
| ChatEngine.renderUserMessage(msgObj.content, msgObj.badge, msgObj.previewHTML); | |
| } else { | |
| AppState.isStreamingActive = false; | |
| ChatEngine.renderBotMessage(msgObj.content, true); | |
| } | |
| }); | |
| setTimeout(UIManager.forceScrollDown, 150); | |
| } else { | |
| document.getElementById('welcomeState').style.display = 'flex'; | |
| } | |
| } catch (err) { | |
| messageZone.innerHTML = ''; | |
| document.getElementById('welcomeState').style.display = 'flex'; | |
| } | |
| }, | |
| saveHistoryToCloud: () => { | |
| if (AppState.currentUser && AppState.isOnline) { | |
| fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| mode: 'cors', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify({ action: "save_history", email: AppState.currentUser, historyJSON: JSON.stringify(AppState.history) }) | |
| }); | |
| } | |
| }, | |
| buildPreviewHTML: (attachmentObj) => { | |
| if (!attachmentObj) return ''; | |
| if (attachmentObj.type === 'image') { | |
| return `<img src="data:image/jpeg;base64,${Utils.escapeHTML(attachmentObj.data)}" class="chat-in-bubble-img" alt="Attached Media">`; | |
| } else if (attachmentObj.type === 'video') { | |
| 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">${Utils.escapeHTML(attachmentObj.name)}</span></div>`; | |
| } else if (attachmentObj.type === 'audio') { | |
| 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">${Utils.escapeHTML(attachmentObj.name)}</span></div>`; | |
| } else { | |
| 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">${Utils.escapeHTML(attachmentObj.name)}</span></div>`; | |
| } | |
| }, | |
| renderUserMessage: (textContent, badgeText, previewHTMLString = '') => { | |
| let badgeNode = badgeText ? `<div class="file-badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg> ${Utils.escapeHTML(badgeText)}</div>` : ''; | |
| let visibleText = textContent || ''; | |
| if(visibleText.includes('---DATA BEGIN---')) { | |
| const parts = visibleText.split('User Prompt:'); | |
| if(parts.length > 1) visibleText = parts.trim(); | |
| } | |
| const bubbleBox = document.createElement('div'); | |
| bubbleBox.className = 'chat-message-row user-msg'; | |
| bubbleBox.innerHTML = ` | |
| <div class="msg-avatar">U</div> | |
| <div class="msg-content-column"> | |
| ${badgeNode} | |
| <div class="chat-bubble"> | |
| ${previewHTMLString} | |
| ${Utils.escapeHTML(visibleText)} | |
| </div> | |
| </div>`; | |
| document.getElementById('msgs').appendChild(bubbleBox); | |
| }, | |
| renderBotMessage: (textContent, bypassStreamFormatting = false) => { | |
| const bubbleBox = document.createElement('div'); | |
| bubbleBox.className = 'chat-message-row bot-msg'; | |
| bubbleBox.innerHTML = ` | |
| <div class="msg-avatar"><img src="${Config.LOGO_URL}" alt="AI"></div> | |
| <div class="msg-content-column"> | |
| <div class="chat-bubble"></div> | |
| </div>`; | |
| document.getElementById('msgs').appendChild(bubbleBox); | |
| ChatEngine.updateBotBubble(bubbleBox, textContent || '', !bypassStreamFormatting); | |
| return bubbleBox; | |
| }, | |
| updateBotBubble: (bubbleDOM, rawMarkup, isCurrentlyStreaming) => { | |
| if(!rawMarkup) rawMarkup = ''; | |
| const contentTarget = bubbleDOM.querySelector('.chat-bubble'); | |
| const strippedMarkup = rawMarkup.replace(/<think>([\s\S]*?)(<\/think>|$)/gi, ''); | |
| let renderHTML = marked.parse(strippedMarkup.trim()); | |
| if (isCurrentlyStreaming) { | |
| renderHTML += `<div class="loading-dots-container"><div class="loading-dot"></div><div class="loading-dot"></div><div class="loading-dot"></div></div>`; | |
| } | |
| contentTarget.innerHTML = renderHTML; | |
| let actionTray = bubbleDOM.querySelector('.bot-actions-row'); | |
| if (!isCurrentlyStreaming && !actionTray && strippedMarkup.trim().length > 0) { | |
| const safeRawCopy = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, ''); | |
| const safeRawTTS = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, ' '); | |
| const actionsHTML = ` | |
| <div class="bot-actions-row"> | |
| <button class="btn-bot-action btn-cpy-action" data-cpy="${safeRawCopy}"> | |
| <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg> | |
| Copy Data | |
| </button> | |
| <button class="btn-bot-action action-tts btn-tts-action" data-tts="${safeRawTTS}"> | |
| <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg> | |
| Read Aloud | |
| </button> | |
| </div>`; | |
| bubbleDOM.querySelector('.msg-content-column').insertAdjacentHTML('beforeend', actionsHTML); | |
| bubbleDOM.querySelector('.btn-cpy-action').addEventListener('click', function() { Utils.copyToClipboard(this, this.getAttribute('data-cpy')); }); | |
| bubbleDOM.querySelector('.btn-tts-action').addEventListener('click', function() { VoiceEngine.executeTTS(this.getAttribute('data-tts')); }); | |
| } | |
| }, | |
| initiateDispatch: async () => { | |
| if (!AppState.isOnline) return Utils.showToast("Cannot process request. System is Offline.", "error"); | |
| if (AppState.isProcessing) return; | |
| const inputField = document.getElementById('mainChatInput'); | |
| const rawUserText = inputField.value.trim(); | |
| if (!rawUserText && !AppState.pendingAttachment) return; | |
| // VALIDATE GUEST LIMIT | |
| if (!AppState.currentUser) { | |
| if (AppState.guestCount >= 3) { | |
| AuthManager.openModal(); | |
| return Utils.showToast("Query limit reached. Secure Login required.", "error"); | |
| } | |
| AppState.guestCount++; | |
| localStorage.setItem('arjun_guest', AppState.guestCount.toString()); | |
| document.getElementById('guestCountDisplay').innerText = AppState.guestCount; | |
| } | |
| // Prepare UI for Dispatch | |
| inputField.value = ''; | |
| inputField.style.height = 'auto'; | |
| document.getElementById('masterSendBtn').disabled = true; | |
| AppState.isProcessing = true; | |
| const wState = document.getElementById('welcomeState'); | |
| if (wState) wState.style.display = 'none'; | |
| let payloadStr = rawUserText; | |
| let payloadAttachments = []; | |
| let visualBadge = null; | |
| let previewHTMLForChat = ''; | |
| // Attachment Processing Logic | |
| if (AppState.pendingAttachment) { | |
| previewHTMLForChat = ChatEngine.buildPreviewHTML(AppState.pendingAttachment); | |
| if (AppState.pendingAttachment.type === 'text') { | |
| payloadStr = `[Document Analyzed: ${AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`; | |
| visualBadge = 'File Appended'; | |
| } else { | |
| payloadAttachments.push({ | |
| type: AppState.pendingAttachment.type, | |
| data: AppState.pendingAttachment.data, | |
| name: AppState.pendingAttachment.name | |
| }); | |
| visualBadge = "Media Appended"; | |
| } | |
| ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat); | |
| AppState.history.push({ role: 'user', content: payloadStr, badge: visualBadge, previewHTML: previewHTMLForChat }); | |
| } else { | |
| ChatEngine.renderUserMessage(rawUserText, null, ''); | |
| AppState.history.push({ role: 'user', content: rawUserText }); | |
| } | |
| FileProcessor.discardFile(); | |
| ChatEngine.saveHistoryToCloud(); | |
| const activeBotBubble = ChatEngine.renderBotMessage('', false); | |
| UIManager.forceScrollDown(); | |
| // Dynamic Pollinations Seed Generator | |
| const cryptographicSeed = Math.floor(Math.random() * 999999999); | |
| // Advanced Cognitive System Instructions | |
| let cognitivePrompt = `You are Arjun 2.O, a highly advanced enterprise AI system architected and engineered by Abhay Kumar. | |
| LANGUAGE PROTOCOL: Your primary logic is English. If the user interacts in Hindi/Hinglish, you must dynamically switch to a professional Hindi response. Never force translation on pure English prompts. | |
| IMAGE SYNTHESIS OVERRIDE: | |
| When commanded to render, generate, or create an image/photograph, you MUST reply with a precise markdown image node targeting Pollinations AI. | |
| Formula:  | |
| Available Models: flux, flux-realism, flux-anime, flux-3d. | |
| CRITICAL: The seed parameter is mandatory to bypass cache mechanics. Always render this markdown node inline.`; | |
| if (AppState.isLiveModeEngaged) { | |
| cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE ACTIVE]: You are currently engaged in a LIVE, REAL-TIME VOCAL INTERFACE. | |
| MANDATORY direct answers. Maximum brevity. Eliminate complex markdown, massive code blocks, or extended lists. Replicate human telephonic brevity perfectly.`; | |
| } | |
| const secureHistory = AppState.history.slice(0, -1).map(h => ({ role: h.role, content: h.content })); | |
| const transmissionPayload = { | |
| message: payloadStr, | |
| attachments: payloadAttachments, | |
| system_prompt: cognitivePrompt, | |
| history: secureHistory, | |
| max_tokens: AppState.isLiveModeEngaged ? 150 : 4096, | |
| temperature: 0.75 | |
| }; | |
| // Network Transmission Logic | |
| try { | |
| const fetchOp = await fetch(Config.API_ENDPOINT, { | |
| method: 'POST', | |
| headers: {'Content-Type': 'application/json'}, | |
| body: JSON.stringify(transmissionPayload) | |
| }); | |
| if (!fetchOp.ok) throw new Error("API Matrix Disconnected."); | |
| const networkReader = fetchOp.body.getReader(); | |
| const textDecoder = new TextDecoder(); | |
| let responseBuffer = ""; | |
| AppState.isStreamingActive = true; | |
| while (true) { | |
| const { done, value } = await networkReader.read(); | |
| if (done) break; | |
| const decodedChunk = textDecoder.decode(value, { stream: true }); | |
| const fragmentedLines = decodedChunk.split('\n'); | |
| for (let line of fragmentedLines) { | |
| if (line.startsWith('data: ')) { | |
| const parseableStr = line.substring(6); | |
| if (parseableStr.trim() === '[DONE]') continue; | |
| try { | |
| const jsonSegment = JSON.parse(parseableStr); | |
| if (jsonSegment.choices && jsonSegment.choices.delta.content) { | |
| responseBuffer += jsonSegment.choices.delta.content; | |
| ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true); | |
| UIManager.autoScroll(); | |
| } | |
| } catch (e) { } | |
| } | |
| } | |
| } | |
| AppState.isStreamingActive = false; | |
| ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, false); | |
| AppState.history.push({ role: 'bot', content: responseBuffer }); | |
| ChatEngine.saveHistoryToCloud(); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Arjun Transmitting..."; | |
| await VoiceEngine.executeTTS(responseBuffer); | |
| } | |
| } catch(error) { | |
| AppState.isStreamingActive = false; | |
| ChatEngine.updateBotBubble(activeBotBubble, `**System Error:** Communication array offline. Verification needed.`, false); | |
| if (AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Neural Link Severed."; | |
| } | |
| } | |
| AppState.isProcessing = false; | |
| document.getElementById('masterSendBtn').disabled = false; | |
| UIManager.autoScroll(); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 9. EVENT DELEGATION & BOOTSTRAP INVOCATION | |
| // ======================================================================================= | |
| window.startArjunApp = function() { | |
| document.getElementById('welcomeOverlay').classList.add('hidden'); | |
| localStorage.setItem('arjun_welcome_seen', 'true'); | |
| setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400); | |
| }; | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Sidebar Controls | |
| document.getElementById('btnSidebarOpen').addEventListener('click', UIManager.toggleSidebar); | |
| document.getElementById('btnSidebarClose').addEventListener('click', UIManager.toggleSidebar); | |
| document.getElementById('btnLaunchSystem').addEventListener('click', window.startArjunApp); | |
| // Auth Flow Controls | |
| document.getElementById('loginPromptBtn').addEventListener('click', AuthManager.openModal); | |
| document.getElementById('btnAuthClose').addEventListener('click', AuthManager.closeModal); | |
| document.getElementById('btn-tab-login').addEventListener('click', () => AuthManager.switchTab('login')); | |
| document.getElementById('btn-tab-register').addEventListener('click', () => AuthManager.switchTab('register')); | |
| document.getElementById('btn-fire-log-otp').addEventListener('click', () => AuthManager.process('login_send_otp')); | |
| document.getElementById('btn-fire-log-verify').addEventListener('click', () => AuthManager.process('login_verify')); | |
| document.getElementById('btn-fire-reg-otp').addEventListener('click', () => AuthManager.process('register_send_otp')); | |
| document.getElementById('btn-fire-reg-verify').addEventListener('click', () => AuthManager.process('register_verify')); | |
| document.getElementById('btnLogBack').addEventListener('click', () => AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1')); | |
| document.getElementById('btnRegBack').addEventListener('click', () => AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1')); | |
| document.getElementById('btnLogout').addEventListener('click', AuthManager.logout); | |
| document.getElementById('btnClearMemory').addEventListener('click', ChatEngine.clearMemory); | |
| // File Attachment Routing | |
| document.getElementById('btnAttachMenuToggle').addEventListener('click', UIManager.toggleAttachMenu); | |
| document.getElementById('opt-image').addEventListener('click', () => FileProcessor.triggerFileSelector('image')); | |
| document.getElementById('opt-video').addEventListener('click', () => FileProcessor.triggerFileSelector('video')); | |
| document.getElementById('opt-audio').addEventListener('click', () => FileProcessor.triggerFileSelector('audio')); | |
| document.getElementById('opt-document').addEventListener('click', () => FileProcessor.triggerFileSelector('document')); | |
| document.getElementById('sys-inp-image').addEventListener('change', function() { FileProcessor.processFile(this, 'image'); }); | |
| document.getElementById('sys-inp-video').addEventListener('change', function() { FileProcessor.processFile(this, 'video'); }); | |
| document.getElementById('sys-inp-audio').addEventListener('change', function() { FileProcessor.processFile(this, 'audio'); }); | |
| document.getElementById('sys-inp-document').addEventListener('change', function() { FileProcessor.processFile(this, 'document'); }); | |
| document.getElementById('btnDiscardFile').addEventListener('click', FileProcessor.discardFile); | |
| // Primary Message Controls | |
| document.getElementById('masterSendBtn').addEventListener('click', ChatEngine.initiateDispatch); | |
| document.getElementById('mainChatInput').addEventListener('keydown', ChatEngine.handleKeyboard); | |
| document.getElementById('mainChatInput').addEventListener('input', function() { UIManager.autoGrowTextArea(this); }); | |
| // Example Prompt Controls | |
| document.getElementById('suggCodeBtn').addEventListener('click', () => ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.')); | |
| document.getElementById('suggImgBtn').addEventListener('click', () => ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.')); | |
| // Voice & STT Options | |
| document.getElementById('smartLangToggle').addEventListener('click', VoiceEngine.switchLanguage); | |
| document.getElementById('masterVoiceBtn').addEventListener('click', VoiceEngine.toggleDictation); | |
| // Live Mode Options | |
| document.getElementById('btnStartLiveMode').addEventListener('click', LiveModeController.initialize); | |
| document.getElementById('btnExitLiveMode').addEventListener('click', LiveModeController.terminate); | |
| document.getElementById('liveMicBtn').addEventListener('click', VoiceEngine.toggleDictation); | |
| // Workspace Logic Hooks | |
| document.getElementById('btnWsClose').addEventListener('click', WorkspaceEngine.closePanel); | |
| document.getElementById('btnWsCopy').addEventListener('click', function() { WorkspaceEngine.executeCopy(this); }); | |
| // Interaction Scroll Listeners | |
| document.getElementById('msgs').addEventListener('scroll', UIManager.checkScrollState); | |
| document.getElementById('scrollTriggerBtn').addEventListener('click', UIManager.forceScrollDown); | |
| // Network Monitoring | |
| window.addEventListener('online', UIManager.updateNetworkStatus); | |
| window.addEventListener('offline', UIManager.updateNetworkStatus); | |
| // Prevent unwanted default mobile behaviours on double-tap | |
| document.addEventListener('dblclick', function(event) { | |
| event.preventDefault(); | |
| }, { passive: false }); | |
| // Ensure startup screen displays if memory cleared | |
| if(!localStorage.getItem('arjun_welcome_seen')) { | |
| document.getElementById('welcomeOverlay').style.display = 'flex'; | |
| } else { | |
| document.getElementById('welcomeOverlay').style.display = 'none'; | |
| } | |
| // Fire Boot Processes | |
| UIManager.updateNetworkStatus(); | |
| VoiceEngine.init(); | |
| AuthManager.initUI(); | |
| if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |