Spaces:
Restarting
Restarting
| <html lang="en" dir="ltr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
| <!-- Viewport settings strictly structured to prevent mobile keyboard layout shifting --> | |
| <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 Advanced Artificial Intelligence System engineered by Abhay Kumar."> | |
| <meta name="theme-color" content="#FF9933"> | |
| <meta name="apple-mobile-web-app-capable" content="yes"> | |
| <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> | |
| <title>Arjun 2.O - Professional Advanced AI</title> | |
| <!-- ========================================================================================= | |
| 1. EXTERNAL RESOURCES & LIBRARIES | |
| ========================================================================================= --> | |
| <!-- Preconnect for Performance Optimization --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <!-- Professional Typography: Inter (Sans), Geist Mono (Code), Instrument Serif (Display) --> | |
| <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 Theme (Atom One Dark for Professional Coding Workspace) --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"> | |
| <!-- Core External Scripts for Data Extraction and Rendering --> | |
| <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> | |
| <!-- ========================================================================================= | |
| 2. MASSIVE CSS ARCHITECTURE (ENTERPRISE SCALED) | |
| ========================================================================================= --> | |
| <style> | |
| /* --------------------------------------------------------------------------------------- | |
| A. CSS VARIABLES & DESIGN TOKENS | |
| --------------------------------------------------------------------------------------- */ | |
| :root { | |
| /* Branding: Professional Theme (Arjun Base) */ | |
| --brand-saffron: #FF9933; | |
| --brand-saffron-light: rgba(255, 153, 51, 0.12); | |
| --brand-saffron-hover: #e68a2e; | |
| --brand-saffron-active: #cc7a29; | |
| --brand-saffron-glow: rgba(255, 153, 51, 0.4); | |
| --brand-white: #FFFFFF; | |
| --brand-white-glass: rgba(255, 255, 255, 0.85); | |
| --brand-white-dim: rgba(255, 255, 255, 0.6); | |
| --brand-green: #138808; | |
| --brand-green-light: rgba(19, 136, 8, 0.12); | |
| --brand-green-hover: #0f6e06; | |
| --brand-green-active: #0c5905; | |
| --brand-green-glow: rgba(19, 136, 8, 0.4); | |
| /* Core UI Colors */ | |
| --bg-primary: #ffffff; | |
| --bg-secondary: #f8f9fa; | |
| --bg-tertiary: #f1f3f5; | |
| --bg-glass: rgba(255, 255, 255, 0.75); | |
| --bg-overlay: rgba(0, 0, 0, 0.5); | |
| --bg-workspace: #282c34; | |
| /* Text Hierarchy */ | |
| --text-primary: #111827; | |
| --text-secondary: #4b5563; | |
| --text-tertiary: #9ca3af; | |
| --text-inverse: #ffffff; | |
| --text-danger: #ef4444; | |
| /* Border & Dividers */ | |
| --border-light: rgba(0, 0, 0, 0.08); | |
| --border-medium: rgba(0, 0, 0, 0.15); | |
| --border-strong: rgba(0, 0, 0, 0.25); | |
| --border-focus: rgba(255, 153, 51, 0.4); | |
| /* Depth & Elevation (Shadows) */ | |
| --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); | |
| /* Typography Scale */ | |
| --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| --font-mono: 'Geist Mono', Consolas, Monaco, "Ubuntu Mono", monospace; | |
| --font-serif: 'Instrument Serif', Georgia, serif; | |
| --text-xs: 0.75rem; | |
| --text-sm: 0.875rem; | |
| --text-base: 1rem; | |
| --text-lg: 1.125rem; | |
| --text-xl: 1.25rem; | |
| --text-2xl: 1.5rem; | |
| --text-3xl: 1.875rem; | |
| --text-4xl: 2.25rem; | |
| /* Border Radii */ | |
| --radius-xs: 4px; | |
| --radius-sm: 8px; | |
| --radius-md: 12px; | |
| --radius-lg: 16px; | |
| --radius-xl: 24px; | |
| --radius-2xl: 32px; | |
| --radius-full: 9999px; | |
| /* Transitions & 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); | |
| --ease-bounce: 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); | |
| /* Z-Index Hierarchy */ | |
| --z-bg: -1; | |
| --z-base: 1; | |
| --z-overlay: 10; | |
| --z-dropdown: 50; | |
| --z-sidebar: 100; | |
| --z-modal: 5000; | |
| --z-toast: 9000; | |
| --z-live-mode: 9999; | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| B. RESET & GLOBAL BASE | |
| --------------------------------------------------------------------------------------- */ | |
| *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } | |
| html { font-size: 16px; -webkit-text-size-adjust: 100%; height: 100%; } | |
| /* Ensures the body takes up exactly the visible screen, fixing mobile keyboard shift */ | |
| body { | |
| height: 100%; | |
| height: 100dvh; | |
| width: 100vw; | |
| overflow: hidden; | |
| background-color: var(--bg-primary); | |
| color: var(--text-primary); | |
| font-family: var(--font-sans); | |
| line-height: 1.5; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| display: flex; | |
| flex-direction: column; | |
| } | |
| button, input, textarea, select { font-family: inherit; color: inherit; } | |
| a { color: inherit; text-decoration: none; } | |
| img { max-width: 100%; height: auto; display: block; } | |
| ul, ol { list-style: none; } | |
| /* --------------------------------------------------------------------------------------- | |
| C. AMBIENT BACKGROUND EFFECTS | |
| --------------------------------------------------------------------------------------- */ | |
| .ambient-environment { | |
| position: fixed; top: 0; left: 0; right: 0; bottom: 0; | |
| z-index: var(--z-bg); overflow: hidden; pointer-events: none; | |
| background: linear-gradient(135deg, var(--brand-saffron-light) 0%, #ffffff 50%, var(--brand-green-light) 100%); | |
| } | |
| .ambient-orb { | |
| position: absolute; border-radius: 50%; filter: blur(120px); opacity: 0.45; | |
| animation: orbFloat 35s ease-in-out infinite alternate; will-change: transform; | |
| } | |
| .orb-top-left { | |
| width: 650px; height: 650px; | |
| background: radial-gradient(circle, rgba(255,153,51,0.25) 0%, transparent 70%); | |
| top: -200px; left: -150px; | |
| } | |
| .orb-bottom-right { | |
| width: 550px; height: 550px; | |
| background: radial-gradient(circle, rgba(19,136,8,0.2) 0%, transparent 70%); | |
| bottom: -150px; right: -100px; animation-delay: -15s; animation-duration: 40s; | |
| } | |
| @keyframes orbFloat { | |
| 0% { transform: translate(0, 0) scale(1); } | |
| 33% { transform: translate(60px, 80px) scale(1.1); } | |
| 66% { transform: translate(-40px, 50px) scale(0.95); } | |
| 100% { transform: translate(70px, -30px) scale(1.05); } | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| D. TOAST NOTIFICATION SYSTEM | |
| --------------------------------------------------------------------------------------- */ | |
| .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; | |
| } | |
| .toast-notification { | |
| background: var(--text-primary); color: var(--text-inverse); padding: 14px 28px; | |
| border-radius: var(--radius-full); font-size: var(--text-sm); font-weight: 600; | |
| box-shadow: var(--shadow-lg); animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 2.6s forwards; | |
| display: flex; align-items: center; gap: 10px; | |
| } | |
| .toast-notification svg { width: 18px; height: 18px; stroke-width: 2.5; } | |
| @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.2s both; } | |
| .startup-logo-container img { width: 140px; height: 140px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 3px solid var(--bg-primary); position: relative; z-index: 2; } | |
| .startup-logo-glow { position: absolute; inset: -15px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(25px); 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 { from { opacity: 0; transform: scale(0.8); } to { opacity: 1; transform: scale(1); } } | |
| .startup-title { font-family: var(--font-sans); font-size: var(--text-4xl); font-weight: 900; color: var(--text-primary); letter-spacing: -1.5px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.3s both; } | |
| .startup-desc { font-size: var(--text-lg); color: var(--text-secondary); line-height: 1.6; max-width: 500px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.4s both; } | |
| .btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: var(--text-lg); 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.5s both; display: flex; align-items: center; gap: 12px; } | |
| .btn-startup-launch:hover { background: #000000; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(0,0,0,0.25); } | |
| @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } | |
| /* --------------------------------------------------------------------------------------- | |
| F. CORE APPLICATION LAYOUT (FLEX ARCHITECTURE) | |
| --------------------------------------------------------------------------------------- */ | |
| .app-root { | |
| position: relative; z-index: var(--z-base); display: flex; | |
| height: 100%; width: 100vw; overflow: hidden; background: var(--bg-glass); | |
| backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); flex: 1; | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| G. SIDEBAR NAVIGATION | |
| --------------------------------------------------------------------------------------- */ | |
| .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); backdrop-filter: blur(15px); height: 100%; | |
| } | |
| .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: 52px; height: 52px; 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(-3deg); } | |
| .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), var(--brand-green)); -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: #ef4444; } | |
| .sidebar-body { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 28px; } | |
| .sidebar-body::-webkit-scrollbar { width: 5px; } | |
| .sidebar-body::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 10px; } | |
| .sidebar-body::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.2); } | |
| /* Auth Widget */ | |
| .auth-widget { background: var(--bg-primary); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-sm); position: relative; overflow: hidden; } | |
| .btn-secure-connect { width: 100%; padding: 14px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-md); font-size: var(--text-sm); 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: 44px; height: 44px; 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); } | |
| .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); } | |
| .btn-system-logout { background: rgba(239, 68, 68, 0.1); color: #ef4444; border: none; width: 36px; height: 36px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-fast); } | |
| .btn-system-logout:hover { background: #ef4444; color: #ffffff; } | |
| /* Branding Box */ | |
| .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); } | |
| .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; } | |
| .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: var(--text-sm); 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: #ef4444; border-color: #fca5a5; } | |
| /* --------------------------------------------------------------------------------------- | |
| H. MAIN CHAT INTERFACE | |
| --------------------------------------------------------------------------------------- */ | |
| .main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; height: 100%; } | |
| .chat-top-bar { padding: 18px 32px; border-bottom: 1px solid var(--border-light); background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(15px); -webkit-backdrop-filter: blur(15px); display: flex; align-items: center; justify-content: space-between; z-index: var(--z-overlay); flex-shrink:0; } | |
| .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: 40px; height: 40px; border-radius: var(--radius-sm); align-items: center; justify-content: center; box-shadow: var(--shadow-sm); } | |
| .system-status-pill { display: flex; align-items: center; gap: 10px; font-size: var(--text-sm); 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); box-shadow: inset 0 1px 2px rgba(255,255,255,0.5); } | |
| .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; } | |
| @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); } } | |
| .btn-activate-live { background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%); color: white; border: none; padding: 10px 20px; 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.02); 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; } } | |
| /* --------------------------------------------------------------------------------------- | |
| I. CONVERSATION SCROLL AREA & WELCOME | |
| --------------------------------------------------------------------------------------- */ | |
| .chat-scroll-area { flex: 1; overflow-y: auto; padding: 40px 10%; display: flex; flex-direction: column; gap: 36px; scroll-behavior: smooth; position: relative; min-height: 0; } | |
| .chat-scroll-area::-webkit-scrollbar { width: 6px; } | |
| .chat-scroll-area::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.15); border-radius: 10px; } | |
| .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; } | |
| .hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); } | |
| .hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 400; } | |
| .guest-warning-badge { font-size: 13px; font-weight: 700; color: #ef4444; background: #fee2e2; padding: 8px 16px; border-radius: var(--radius-full); margin-bottom: 32px; display: none; align-items: center; gap: 8px; border: 1px solid #fca5a5; } | |
| .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); } | |
| .prompt-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); border-color: var(--brand-saffron); background: rgba(255, 255, 255, 0.95); } | |
| .prompt-icon { font-size: 28px; margin-bottom: 14px; display: inline-block; } | |
| .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; } | |
| /* --------------------------------------------------------------------------------------- | |
| J. CHAT MESSAGE BUBBLES | |
| --------------------------------------------------------------------------------------- */ | |
| .chat-message-row { display: flex; gap: 20px; max-width: 88%; animation: messagePopIn 0.5s var(--ease-spring) both; } | |
| @keyframes messagePopIn { from { opacity: 0; transform: translateY(25px) 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-sm); 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: 6px; 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 Preview Cards within bubble */ | |
| .chat-in-bubble-img { max-width: 300px; max-height: 300px; border-radius: var(--radius-md); object-fit: cover; border: 2px solid rgba(255,255,255,0.2); box-shadow: var(--shadow-md); margin-bottom: 8px; } | |
| .chat-file-card { display: flex; align-items: center; gap: 12px; background: rgba(255,255,255,0.15); border: 1px solid rgba(255,255,255,0.3); padding: 12px 16px; border-radius: var(--radius-md); margin-bottom: 8px; backdrop-filter: blur(5px); max-width: 350px; } | |
| .chat-file-card .icon { font-size: 24px; background: rgba(0,0,0,0.1); width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); } | |
| .chat-file-card .name { font-size: 13px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .chat-bubble { padding: 18px 24px; font-size: 15px; 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 */ | |
| .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: 12px; 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); } | |
| .btn-bot-action.action-tts { color: var(--brand-green-hover); 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); } | |
| /* --------------------------------------------------------------------------------------- | |
| K. MARKDOWN & CODE RENDERING STYLES | |
| --------------------------------------------------------------------------------------- */ | |
| .chat-bubble p { margin-bottom: 16px; } | |
| .chat-bubble p:last-child { margin-bottom: 0; } | |
| .chat-bubble strong { font-weight: 800; color: inherit; } | |
| .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; } | |
| .user-msg .chat-bubble code { background: rgba(255,255,255,0.2); color: var(--brand-white); } | |
| .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; } | |
| /* Standard Pre Code Block */ | |
| .chat-bubble pre { background: var(--bg-workspace); color: #abb2bf; padding: 20px; border-radius: var(--radius-md); overflow-x: auto; margin: 20px 0; font-family: var(--font-mono); font-size: 14px; line-height: 1.6; border: 1px solid #181a1f; } | |
| .chat-bubble pre code { background: transparent; color: inherit; padding: 0; font-weight: 400; } | |
| /* Streaming Code Container */ | |
| .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: 12px 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; } | |
| /* Final 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(--border-medium); box-shadow: var(--shadow-md); } | |
| .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-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); } | |
| .btn-launch-workspace:hover { transform: scale(1.05); background: var(--brand-saffron); box-shadow: 0 6px 15px rgba(255,153,51,0.35); } | |
| /* --------------------------------------------------------------------------------------- | |
| L. INPUT AREA & CONTROLS (BOTTOM BAR) | |
| --------------------------------------------------------------------------------------- */ | |
| .input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: 20; } | |
| .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-2xl); box-shadow: var(--shadow-xl); transition: var(--ease-smooth); } | |
| .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-bar { display: none; padding: 20px 28px 0; align-items: center; gap: 16px; } | |
| .upload-preview-bar.visible { display: flex; animation: fadeIn 0.3s ease; } | |
| .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; } | |
| .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: #ef4444; transition: var(--ease-fast); } | |
| .btn-discard-upload:hover { background: #ef4444; 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; } | |
| .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: 220px; 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-hover); } | |
| .dropdown-item span.emoji-icon { font-size: 20px; } | |
| .stealth-input { display: none; } | |
| /* 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 10px; 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); } | |
| .btn-mic-tool.active-listening { color: #ffffff; background: #ef4444; animation: recordPulse 1.5s infinite; border-radius: var(--radius-full); } | |
| @keyframes recordPulse { 0% { box-shadow: 0 0 0 0 rgba(239,68,68,0.5); } 70% { box-shadow: 0 0 0 12px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } } | |
| /* Primary 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); } | |
| .btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; } | |
| .btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 10px 25px rgba(255, 153, 51, 0.4); } | |
| .btn-master-send:hover svg { transform: translate(2px, -2px); } | |
| .btn-master-send:disabled { opacity: 0.4; 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; } | |
| /* --------------------------------------------------------------------------------------- | |
| M. LIVE MODE FULLSCREEN OVERLAY | |
| --------------------------------------------------------------------------------------- */ | |
| .live-mode-viewport { position: fixed; inset: 0; background: rgba(255, 255, 255, 0.98); z-index: var(--z-live-mode); display: flex; flex-direction: column; align-items: center; justify-content: center; opacity: 0; pointer-events: none; transition: opacity var(--ease-smooth); } | |
| .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: #ef4444; 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-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; } | |
| .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; } | |
| .live-control-deck { display: flex; gap: 24px; margin-top: 50px; } | |
| .btn-live-deck { width: 76px; height: 76px; 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: #ef4444; color: white; border-color: #ef4444; 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 20px rgba(239,68,68,0); } 100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); } } | |
| .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(--bg-primary); color: var(--text-primary); transform: translateX(-50%) translateY(-5px); box-shadow: var(--shadow-xl); } | |
| /* --------------------------------------------------------------------------------------- | |
| N. WORKSPACE (CODE EXECUTION PANEL) | |
| --------------------------------------------------------------------------------------- */ | |
| .code-workspace-panel { width: 0; background: var(--bg-primary); 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.04); z-index: 25; } | |
| .code-workspace-panel.expanded { width: 55%; } | |
| .workspace-header-bar { padding: 20px 28px; border-bottom: 1px solid var(--border-light); background: var(--bg-primary); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } | |
| .workspace-title-group { font-size: 16px; font-weight: 800; display: flex; align-items: center; gap: 12px; color: var(--text-primary); } | |
| .workspace-tools { display: flex; gap: 12px; } | |
| .btn-workspace-tool { padding: 10px 18px; border-radius: var(--radius-sm); background: var(--bg-secondary); border: 1px solid var(--border-light); cursor: pointer; display: flex; align-items: center; gap: 8px; color: var(--text-primary); transition: var(--ease-fast); font-size: 14px; font-weight: 700; } | |
| .btn-workspace-tool:hover { background: var(--bg-tertiary); border-color: var(--border-medium); } | |
| .btn-workspace-tool.close { padding: 10px; } | |
| .btn-workspace-tool.close:hover { color: #ef4444; background: #fee2e2; border-color: #fca5a5; } | |
| .workspace-editor-surface { flex: 1; overflow-y: auto; background: var(--bg-secondary); padding: 30px; } | |
| .workspace-editor-surface pre { margin: 0; padding: 28px; background: var(--bg-workspace); border: 1px solid var(--border-light); border-radius: var(--radius-lg); font-family: var(--font-mono); font-size: 15px; line-height: 1.6; overflow-x: auto; box-shadow: var(--shadow-lg); color: #abb2bf; } | |
| /* --------------------------------------------------------------------------------------- | |
| O. AUTHENTICATION MODAL (SECURE GATEWAY) | |
| --------------------------------------------------------------------------------------- */ | |
| .secure-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.5); backdrop-filter: blur(10px); -webkit-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: #ef4444; } | |
| .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); } | |
| /* Core Animations */ | |
| @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } | |
| @keyframes slideIn { from { opacity: 0; transform: translateX(25px); } to { opacity: 1; transform: none; } } | |
| .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); } } | |
| /* --------------------------------------------------------------------------------------- | |
| P. RESPONSIVE MEDIA QUERIES | |
| --------------------------------------------------------------------------------------- */ | |
| @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, .btn-mobile-close { display: flex; } | |
| .chat-scroll-area { padding: 24px 15px; } | |
| .input-dock { padding: 10px 15px 20px; } | |
| .chat-message-row { max-width: 95%; } | |
| .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; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- ========================================================================================= | |
| DOM ELEMENT 1: GLOBAL NOTIFICATIONS | |
| ========================================================================================= --> | |
| <div id="toast-container" class="toast-wrapper"></div> | |
| <!-- ========================================================================================= | |
| DOM ELEMENT 2: INITIAL 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" onclick="ApplicationCore.launchSystem()"> | |
| Initialize System | |
| <svg viewBox="0 0 24 24" width="20" height="20" 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 ELEMENT 3: LIVE MODE FULLSCREEN OVERLAY | |
| ========================================================================================= --> | |
| <div class="live-mode-viewport" id="liveOverlay"> | |
| <button class="btn-close-live" onclick="LiveModeController.terminate()" 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" onclick="VoiceEngine.toggleLive()"> | |
| <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 ELEMENT 4: AMBIENT BACKGROUND | |
| ========================================================================================= --> | |
| <div class="ambient-environment"> | |
| <div class="ambient-orb orb-top-left"></div> | |
| <div class="ambient-orb orb-bottom-right"></div> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM ELEMENT 5: 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">Professional</span> | |
| </div> | |
| </a> | |
| <button class="btn-mobile-close" onclick="UIManager.toggleSidebar()"> | |
| <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" onclick="AuthManager.openModal()"> | |
| <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" onclick="AuthManager.logout()" 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 & Developer Info --> | |
| <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> | |
| <!-- Clear Memory Context --> | |
| <button class="btn-erase-memory" onclick="ChatEngine.clearMemory()"> | |
| <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 Memory 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" onclick="UIManager.toggleSidebar()"> | |
| <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"> | |
| <div class="pulse-dot"></div> | |
| System Online | |
| </div> | |
| </div> | |
| <!-- LIVE MODE ACTIVATOR --> | |
| <button class="btn-activate-live" onclick="LiveModeController.initialize()"> | |
| <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" onscroll="UIManager.checkScrollState()"> | |
| <!-- Internal Welcome / Empty 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> | |
| <div id="guestBadge" class="guest-warning-badge"> | |
| ⚠️ Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login. | |
| </div> | |
| <div class="prompt-suggestions-grid"> | |
| <div class="prompt-card" onclick="ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.')"> | |
| <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" onclick="ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.')"> | |
| <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> | |
| <!-- Dynamic Chat Bubbles will be appended here --> | |
| </div> | |
| <!-- Floating Scroll Down Button --> | |
| <button class="btn-scroll-trigger" id="scrollTriggerBtn" onclick="UIManager.forceScrollDown()"> | |
| <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="" 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">File ready to analyze</div> | |
| </div> | |
| <button class="btn-discard-upload" onclick="FileProcessor.discardFile()"> | |
| <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" onclick="UIManager.toggleAttachMenu()" 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" onclick="FileProcessor.triggerFileSelector('image')"> | |
| <span class="emoji-icon">🖼️</span> High-Res Image | |
| </div> | |
| <div class="dropdown-item" onclick="FileProcessor.triggerFileSelector('video')"> | |
| <span class="emoji-icon">🎥</span> Video Media | |
| </div> | |
| <div class="dropdown-item" onclick="FileProcessor.triggerFileSelector('audio')"> | |
| <span class="emoji-icon">🎵</span> Audio Track | |
| </div> | |
| <div class="dropdown-item" onclick="FileProcessor.triggerFileSelector('document')"> | |
| <span class="emoji-icon">📄</span> Document / Code | |
| </div> | |
| </div> | |
| <!-- Hidden File Inputs --> | |
| <input type="file" id="sys-inp-image" class="stealth-input" accept="image/*" onchange="FileProcessor.processFile(this, 'image')"> | |
| <input type="file" id="sys-inp-video" class="stealth-input" accept="video/*" onchange="FileProcessor.processFile(this, 'video')"> | |
| <input type="file" id="sys-inp-audio" class="stealth-input" accept="audio/*" onchange="FileProcessor.processFile(this, '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" onchange="FileProcessor.processFile(this, 'document')"> | |
| </div> | |
| <!-- Smart Language Toggle Button --> | |
| <button class="language-toggle-chip" id="smartLangToggle" onclick="VoiceEngine.switchLanguage()" title="Switch Voice Engine Language"> | |
| 🌐 <span id="langDisplayBadge">EN</span> | |
| </button> | |
| <!-- Voice Dictation Button --> | |
| <button class="btn-tool-icon btn-mic-tool" id="masterVoiceBtn" onclick="VoiceEngine.toggleDictation()" 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 --> | |
| <textarea class="main-textarea" id="mainChatInput" placeholder="Message Arjun Intelligence..." rows="1" onkeydown="ChatEngine.handleKeyboard(event)" oninput="UIManager.autoGrowTextArea(this)"></textarea> | |
| <!-- Master Send Button --> | |
| <button class="btn-master-send" id="masterSendBtn" onclick="ChatEngine.initiateDispatch()"> | |
| <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="workspaceTitleBadge">Workspace</span> | |
| </div> | |
| <div class="workspace-tools"> | |
| <button class="btn-workspace-tool" onclick="WorkspaceEngine.executeCopy(this)"> | |
| <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" onclick="WorkspaceEngine.closePanel()" 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"> | |
| <pre><code id="workspaceCodeBlock" class="hljs"></code></pre> | |
| </div> | |
| </aside> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM ELEMENT 6: SECURE AUTHENTICATION MODAL | |
| ========================================================================================= --> | |
| <div class="secure-modal-backdrop" id="secureAuthModal"> | |
| <div class="secure-modal-surface"> | |
| <button class="btn-modal-dismiss" onclick="AuthManager.closeModal()"> | |
| <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" onclick="AuthManager.switchTab('login')">Connect</div> | |
| <div class="auth-tab-item" id="btn-tab-register" onclick="AuthManager.switchTab('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" onclick="AuthManager.process('login_send_otp')">Generate 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" onclick="AuthManager.process('login_verify')">Authenticate</button> | |
| <button class="btn-auth-return" onclick="AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1')">← Go Back</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="Email Address"> | |
| <button class="btn-auth-execute" id="btn-fire-reg-otp" onclick="AuthManager.process('register_send_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" onclick="AuthManager.process('register_verify')">Initialize Account</button> | |
| <button class="btn-auth-return" onclick="AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1')">← Go Back</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ========================================================================================= | |
| 7. ENTERPRISE JAVASCRIPT LOGIC (ROBUST GRADIO INTEGRATION) | |
| ========================================================================================= --> | |
| <script> | |
| /** | |
| * System Configuration & Global Variables | |
| */ | |
| 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' | |
| }; | |
| // Strict mapping of global application state | |
| window.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 | |
| }; | |
| // Initialize PDF worker | |
| pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER; | |
| /** | |
| * Core Utilities | |
| */ | |
| window.Utils = { | |
| showToast: (message) => { | |
| const container = document.getElementById('toast-container'); | |
| const toast = document.createElement('div'); | |
| toast.className = 'toast-notification'; | |
| toast.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><polyline points="20 6 9 17 4 12"></polyline></svg> ${message}`; | |
| container.appendChild(toast); | |
| setTimeout(() => toast.remove(), 3000); | |
| }, | |
| escapeHTML: (str) => { | |
| return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); | |
| }, | |
| copyToClipboard: (btnElement, textToCopy) => { | |
| const textArea = document.createElement("textarea"); | |
| textArea.value = textToCopy; | |
| textArea.style.top = "0"; | |
| textArea.style.left = "0"; | |
| textArea.style.position = "fixed"; | |
| 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> Success`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| } else { | |
| window.Utils.showToast("Clipboard access denied."); | |
| } | |
| } catch (err) { | |
| window.Utils.showToast("System error copying text."); | |
| } | |
| document.body.removeChild(textArea); | |
| } | |
| }; | |
| /** | |
| * Authentication Manager (GAS Integration) | |
| */ | |
| window.AuthManager = { | |
| initUI: () => { | |
| const promptBtn = document.getElementById('loginPromptBtn'); | |
| const profileCard = document.getElementById('userProfile'); | |
| const guestBadge = document.getElementById('guestBadge'); | |
| if (window.AppState.currentUser) { | |
| promptBtn.style.display = 'none'; | |
| profileCard.style.display = 'flex'; | |
| document.getElementById('uEmail').innerText = window.AppState.currentUser; | |
| document.getElementById('uAvatar').innerText = window.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 = window.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(`btn-tab-${tabName}`).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) => { | |
| 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 window.Utils.showToast("Identification details required."); | |
| buttonId = 'btn-fire-reg-otp'; | |
| } | |
| else if (actionType === 'login_send_otp') { | |
| payload.email = document.getElementById('authLogEmail').value.trim(); | |
| if (!payload.email) return window.Utils.showToast("Email required for validation."); | |
| 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 window.Utils.showToast("Security token required."); | |
| 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', body: JSON.stringify(payload) }); | |
| const result = await response.json(); | |
| if (result.status === 'success') { | |
| window.Utils.showToast(result.message); | |
| if (actionType === 'register_send_otp') window.AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2'); | |
| else if (actionType === 'login_send_otp') window.AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2'); | |
| else if (actionType === 'register_verify' || actionType === 'login_verify') { | |
| window.AppState.currentUser = payload.email; | |
| localStorage.setItem('arjun_user', window.AppState.currentUser); | |
| window.AuthManager.closeModal(); | |
| window.AuthManager.initUI(); | |
| window.ChatEngine.syncHistoryFromCloud(); | |
| } | |
| } else { | |
| window.Utils.showToast(result.message); | |
| } | |
| } catch (error) { | |
| window.Utils.showToast("Encrypted gateway error. Check network."); | |
| } | |
| triggerBtn.disabled = false; | |
| triggerBtn.innerHTML = originalText; | |
| }, | |
| logout: () => { | |
| localStorage.removeItem('arjun_user'); | |
| location.reload(); | |
| } | |
| }; | |
| /** | |
| * UI Layout Management | |
| */ | |
| window.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; | |
| window.AppState.isUserScrolling = !isAtBottom; | |
| const scrollBtn = document.getElementById('scrollTriggerBtn'); | |
| if (window.AppState.isUserScrolling) scrollBtn.classList.add('visible'); | |
| else scrollBtn.classList.remove('visible'); | |
| }, | |
| forceScrollDown: () => { | |
| const msgArea = document.getElementById('msgs'); | |
| msgArea.scrollTo({ top: msgArea.scrollHeight, behavior: 'smooth' }); | |
| window.AppState.isUserScrolling = false; | |
| document.getElementById('scrollTriggerBtn').classList.remove('visible'); | |
| }, | |
| autoScroll: () => { | |
| if (!window.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'); | |
| } | |
| }; | |
| // Attach global listener to close menus | |
| document.addEventListener('click', (event) => { | |
| const wrapper = document.querySelector('.attachment-module'); | |
| if (wrapper && !wrapper.contains(event.target)) { | |
| const menu = document.getElementById('attachDropdownMenu'); | |
| if(menu) menu.classList.remove('visible'); | |
| } | |
| }); | |
| /** | |
| * Voice & Speech Engine (Includes Gradio Edge-TTS) | |
| */ | |
| window.VoiceEngine = { | |
| recognition: null, | |
| currentLanguage: 'en-IN', | |
| currentAudioNode: null, | |
| init: () => { | |
| const SR = window.SpeechRecognition || window.webkitSpeechRecognition; | |
| if (!SR) return; | |
| window.VoiceEngine.recognition = new SR(); | |
| window.VoiceEngine.recognition.continuous = false; | |
| window.VoiceEngine.recognition.interimResults = false; | |
| window.VoiceEngine.recognition.lang = window.VoiceEngine.currentLanguage; | |
| window.VoiceEngine.recognition.onstart = () => { | |
| document.getElementById('masterVoiceBtn').classList.add('active-listening'); | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveMicBtn').classList.add('is-recording'); | |
| document.getElementById('liveStatusText').innerText = "Analyzing Input..."; | |
| document.getElementById('liveOrb').style.transform = "scale(1.25)"; | |
| } | |
| }; | |
| window.VoiceEngine.recognition.onresult = (event) => { | |
| let transcript = ''; | |
| for (let i = event.resultIndex; i < event.results.length; ++i) { | |
| transcript += event.results[i].transcript; | |
| } | |
| transcript = transcript.trim(); | |
| if (transcript.length > 0) { | |
| transcript = transcript.charAt(0).toUpperCase() + transcript.slice(1); | |
| if (!/[.!?।]$/.test(transcript)) transcript += '.'; | |
| transcript += ' '; | |
| } | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveTranscriptText').innerText = `"${transcript}"`; | |
| document.getElementById('liveStatusText').innerText = "Synthesizing Response..."; | |
| document.getElementById('mainChatInput').value = transcript; | |
| window.ChatEngine.initiateDispatch(); | |
| } else { | |
| const inputField = document.getElementById('mainChatInput'); | |
| inputField.value = (inputField.value + ' ' + transcript).trim(); | |
| window.UIManager.autoGrowTextArea(inputField); | |
| } | |
| }; | |
| window.VoiceEngine.recognition.onend = () => { | |
| document.getElementById('masterVoiceBtn').classList.remove('active-listening'); | |
| if (window.AppState.isLiveModeEngaged && !window.AppState.isProcessing) { | |
| document.getElementById('liveMicBtn').classList.remove('is-recording'); | |
| document.getElementById('liveStatusText').innerText = "Tap mic to interact"; | |
| document.getElementById('liveOrb').style.transform = "scale(1)"; | |
| } | |
| }; | |
| window.VoiceEngine.recognition.onerror = (event) => { | |
| window.Utils.showToast("Voice module error."); | |
| document.getElementById('masterVoiceBtn').classList.remove('active-listening'); | |
| if (window.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 (window.VoiceEngine.currentLanguage === 'en-IN') { | |
| window.VoiceEngine.currentLanguage = 'hi-IN'; | |
| badge.innerText = 'HI'; | |
| btn.classList.add('hindi-active'); | |
| window.Utils.showToast("Acoustic Protocol: Pure Hindi / Hinglish"); | |
| } else { | |
| window.VoiceEngine.currentLanguage = 'en-IN'; | |
| badge.innerText = 'EN'; | |
| btn.classList.remove('hindi-active'); | |
| window.Utils.showToast("Acoustic Protocol: English / Hybrid"); | |
| } | |
| if (window.VoiceEngine.recognition) { | |
| window.VoiceEngine.recognition.lang = window.VoiceEngine.currentLanguage; | |
| } | |
| }, | |
| toggleDictation: () => { | |
| if (!window.VoiceEngine.recognition) return window.Utils.showToast("Hardware dictation unsupported."); | |
| try { window.VoiceEngine.recognition.start(); } catch (e) { window.VoiceEngine.recognition.stop(); } | |
| }, | |
| toggleLive: () => { | |
| if (!window.VoiceEngine.recognition) return window.Utils.showToast("Hardware dictation unsupported."); | |
| try { window.VoiceEngine.recognition.start(); } catch (e) { window.VoiceEngine.recognition.stop(); } | |
| }, | |
| // Gradio TTS Module Integration | |
| executeTTS: async (text) => { | |
| return new Promise(async (resolve) => { | |
| const cleanText = text.replace(/[*_~`#]/g, '').replace(/<[^>]*>?/gm, '').trim(); | |
| if (!cleanText) return resolve(); | |
| if (window.VoiceEngine.currentAudioNode) { | |
| window.VoiceEngine.currentAudioNode.pause(); | |
| window.VoiceEngine.currentAudioNode = null; | |
| } | |
| window.Utils.showToast("🔊 Connecting to Neural Voice Matrix (Gradio)..."); | |
| try { | |
| // Dynamic import of Gradio Client to avoid broken native module support | |
| const { Client } = await import('https://cdn.jsdelivr.net/npm/@gradio/client/+esm'); | |
| const client = await Client.connect("Vedika66/Edge-TTS"); | |
| const assignedVoice = window.VoiceEngine.currentLanguage === 'hi-IN' | |
| ? "प्रभात (भारी और प्राकृतिक आवाज़ - हिंग्लिश के लिए)" | |
| : "Christopher (Professional and Natural - US English)"; | |
| const result = await client.predict("/smart_hybrid_tts", { | |
| text: cleanText, | |
| voice_type: assignedVoice, | |
| }); | |
| if (result && result.data && result.data.length > 0) { | |
| const audioResponseData = result.data; | |
| const targetAudioUrl = typeof audioResponseData === 'object' && audioResponseData !== null | |
| ? audioResponseData.url : audioResponseData; | |
| const playbackAudio = new Audio(targetAudioUrl); | |
| window.VoiceEngine.currentAudioNode = playbackAudio; | |
| playbackAudio.onplay = () => { | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Arjun Transmitting..."; | |
| } else { | |
| window.Utils.showToast("🔊 Neural audio playback active..."); | |
| } | |
| }; | |
| playbackAudio.onended = () => { | |
| window.VoiceEngine.currentAudioNode = null; | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Tap mic to respond"; | |
| } | |
| resolve(); | |
| }; | |
| playbackAudio.onerror = () => { | |
| window.Utils.showToast("Audio playback stream encountered an anomaly."); | |
| resolve(); | |
| }; | |
| await playbackAudio.play(); | |
| } else { | |
| throw new Error("Invalid Output from Gradio Node."); | |
| } | |
| } catch (error) { | |
| console.error("Gradio Integration Error:", error); | |
| window.Utils.showToast("Neural link failed. Verify Gradio Edge-TTS server."); | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Acoustic Module Offline."; | |
| } | |
| resolve(); | |
| } | |
| }); | |
| } | |
| }; | |
| // Initialize voice API if available | |
| window.VoiceEngine.init(); | |
| /** | |
| * Live Mode Controller | |
| */ | |
| window.LiveModeController = { | |
| initialize: () => { | |
| window.AppState.isLiveModeEngaged = true; | |
| document.getElementById('liveOverlay').classList.add('active'); | |
| if (window.VoiceEngine.recognition) { | |
| setTimeout(() => { | |
| try { window.VoiceEngine.recognition.start(); } catch(e){} | |
| }, 600); | |
| } | |
| }, | |
| terminate: () => { | |
| window.AppState.isLiveModeEngaged = false; | |
| document.getElementById('liveOverlay').classList.remove('active'); | |
| if (window.VoiceEngine.currentAudioNode) { | |
| window.VoiceEngine.currentAudioNode.pause(); | |
| window.VoiceEngine.currentAudioNode = null; | |
| } | |
| if (window.VoiceEngine.recognition) { | |
| try { window.VoiceEngine.recognition.stop(); } catch(e){} | |
| } | |
| } | |
| }; | |
| /** | |
| * File & Attachment Processor | |
| */ | |
| window.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; | |
| const fName = file.name.toLowerCase(); | |
| const mime = file.type; | |
| if (typeContext === 'image' && !mime.startsWith('image/')) { window.Utils.showToast("Format Rejected."); inputElement.value=''; return; } | |
| if (typeContext === 'video' && !mime.startsWith('video/')) { window.Utils.showToast("Format Rejected."); inputElement.value=''; return; } | |
| if (typeContext === 'audio' && !mime.startsWith('audio/')) { window.Utils.showToast("Format Rejected."); inputElement.value=''; return; } | |
| window.Utils.showToast("Uploading your file, please wait..."); | |
| 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) => { | |
| window.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) => { | |
| window.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"; | |
| } | |
| window.AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name }; | |
| window.Utils.showToast("Your PDF is ready!"); | |
| } catch (e) { | |
| window.Utils.showToast("PDF parsing encountered an error."); | |
| window.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 }); | |
| window.AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name }; | |
| window.Utils.showToast("Your Word document is ready!"); | |
| } catch(e) { | |
| window.Utils.showToast("Document parsing encountered an error."); | |
| window.FileProcessor.discardFile(); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(file); | |
| } | |
| else { | |
| fileReader.onload = (e) => { | |
| window.AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name }; | |
| window.Utils.showToast("Your file is ready!"); | |
| }; | |
| fileReader.readAsText(file); | |
| } | |
| } | |
| inputElement.value = ''; | |
| }, | |
| discardFile: () => { | |
| window.AppState.pendingAttachment = null; | |
| document.getElementById('filePreviewBar').classList.remove('visible'); | |
| } | |
| }; | |
| /** | |
| * Workspace Code Engine | |
| */ | |
| window.WorkspaceEngine = { | |
| launch: (codeBlockId) => { | |
| window.AppState.currentWorkspaceId = codeBlockId; | |
| const codeData = window.AppState.generatedCodeBlocks[codeBlockId]; | |
| document.getElementById('wsTitleText').innerText = codeData.lang ? `Generated ${codeData.lang.toUpperCase()}` : "Compiled Code"; | |
| const blockDisplay = document.getElementById('workspaceCodeBlock'); | |
| blockDisplay.className = `hljs language-${codeData.lang || 'plaintext'}`; | |
| blockDisplay.textContent = codeData.code; | |
| hljs.highlightElement(blockDisplay); | |
| 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 (window.AppState.currentWorkspaceId !== null) { | |
| const srcCode = window.AppState.generatedCodeBlocks[window.AppState.currentWorkspaceId].code; | |
| window.Utils.copyToClipboard(btnElement, srcCode); | |
| } | |
| } | |
| }; | |
| /** | |
| * Marked.js Custom Renderer & Configuration | |
| */ | |
| const MD_Renderer = new marked.Renderer(); | |
| MD_Renderer.code = function(token) { | |
| const rawCode = typeof token === 'string' ? token : (token.text || ''); | |
| // Critical Syntax Fix for proper marked.js API integration avoiding crash | |
| const langClass = typeof token === 'string' | |
| ? (arguments.length > 1 ? arguments : '') | |
| : (token.lang || ''); | |
| // STREAMING STATE GUARD | |
| if (window.AppState.isStreamingActive) { | |
| return ` | |
| <div class="streaming-code-container"> | |
| <div class="streaming-code-header"> | |
| <div class="loading-ring"></div> | |
| Generating Architecture... | |
| </div> | |
| <pre><code class="language-${langClass}">${window.Utils.escapeHTML(rawCode)}</code></pre> | |
| </div>`; | |
| } | |
| // MOUNT BUTTON ONLY WHEN COMPLETED | |
| const internalId = window.AppState.generatedCodeBlocks.length; | |
| window.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>${langClass || 'Syntax Detected'}</p> | |
| </div> | |
| </div> | |
| <button class="btn-launch-workspace" onclick="WorkspaceEngine.launch(${internalId})">Open Workspace</button> | |
| </div>`; | |
| }; | |
| marked.use({ renderer: MD_Renderer }); | |
| /** | |
| * Core Chat Processing Engine | |
| */ | |
| window.ChatEngine = { | |
| handleKeyboard: (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| window.ChatEngine.initiateDispatch(); | |
| } | |
| }, | |
| sendExample: (queryText) => { | |
| document.getElementById('mainChatInput').value = queryText; | |
| window.ChatEngine.initiateDispatch(); | |
| }, | |
| clearMemory: async () => { | |
| if (window.AppState.currentUser) { | |
| window.Utils.showToast("Purging neural link memory..."); | |
| await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| body: JSON.stringify({ action: "delete_history", email: window.AppState.currentUser }) | |
| }); | |
| } | |
| location.reload(); | |
| }, | |
| syncHistoryFromCloud: async () => { | |
| 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(--text-tertiary); font-size:18px;">Decrypting Historic Archives...</div>'; | |
| try { | |
| const response = await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| body: JSON.stringify({ action: "get_history", email: window.AppState.currentUser }) | |
| }); | |
| const resData = await response.json(); | |
| messageZone.innerHTML = ''; | |
| if (resData.status === 'success' && resData.historyJSON !== "[]") { | |
| window.AppState.history = JSON.parse(resData.historyJSON); | |
| window.AppState.history.forEach(msgObj => { | |
| if (msgObj.role === 'user') { | |
| window.ChatEngine.renderUserMessage(msgObj.content, msgObj.badge, msgObj.previewHTML); | |
| } else { | |
| window.AppState.isStreamingActive = false; | |
| window.ChatEngine.renderBotMessage(msgObj.content, true); | |
| } | |
| }); | |
| setTimeout(window.UIManager.forceScrollDown, 150); | |
| } else { | |
| document.getElementById('welcomeState').style.display = 'flex'; | |
| } | |
| } catch (err) { | |
| messageZone.innerHTML = ''; | |
| document.getElementById('welcomeState').style.display = 'flex'; | |
| } | |
| }, | |
| saveHistoryToCloud: () => { | |
| if (window.AppState.currentUser) { | |
| fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| body: JSON.stringify({ action: "save_history", email: window.AppState.currentUser, historyJSON: JSON.stringify(window.AppState.history) }) | |
| }); | |
| } | |
| }, | |
| buildPreviewHTML: (attachmentObj) => { | |
| if (!attachmentObj) return ''; | |
| if (attachmentObj.type === 'image') { | |
| return `<img src="data:image/jpeg;base64,${attachmentObj.data}" class="chat-in-bubble-img" alt="Attached Image">`; | |
| } else if (attachmentObj.type === 'video') { | |
| return `<div class="chat-file-card"><span class="icon">🎥</span><span class="name">${attachmentObj.name}</span></div>`; | |
| } else if (attachmentObj.type === 'audio') { | |
| return `<div class="chat-file-card"><span class="icon">🎵</span><span class="name">${attachmentObj.name}</span></div>`; | |
| } else { | |
| return `<div class="chat-file-card"><span class="icon">📄</span><span class="name">${attachmentObj.name}</span></div>`; | |
| } | |
| }, | |
| renderUserMessage: (textContent, badgeText, previewHTMLString = '') => { | |
| let badgeNode = badgeText ? `<div style="font-size:11px;font-weight:700;color:var(--brand-saffron);margin-bottom:6px;">${window.Utils.escapeHTML(badgeText)}</div>` : ''; | |
| 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} | |
| ${window.Utils.escapeHTML(textContent)} | |
| </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); | |
| window.ChatEngine.updateBotBubble(bubbleBox, textContent, !bypassStreamFormatting); | |
| return bubbleBox; | |
| }, | |
| updateBotBubble: (bubbleDOM, rawMarkup, isCurrentlyStreaming) => { | |
| 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" onclick="Utils.copyToClipboard(this, \`${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 Logic | |
| </button> | |
| <button class="btn-bot-action action-tts" onclick="VoiceEngine.executeTTS(\`${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> | |
| Neural Voice | |
| </button> | |
| </div>`; | |
| bubbleDOM.querySelector('.msg-content-column').insertAdjacentHTML('beforeend', actionsHTML); | |
| } | |
| }, | |
| initiateDispatch: async () => { | |
| if (window.AppState.isProcessing) return; | |
| const inputField = document.getElementById('mainChatInput'); | |
| const rawUserText = inputField.value.trim(); | |
| if (!rawUserText && !window.AppState.pendingAttachment) return; | |
| if (!window.AppState.currentUser) { | |
| if (window.AppState.guestCount >= 3) { | |
| window.AuthManager.openModal(); | |
| return window.Utils.showToast("Unregistered query limit reached. Secure Login required."); | |
| } | |
| window.AppState.guestCount++; | |
| localStorage.setItem('arjun_guest', window.AppState.guestCount.toString()); | |
| document.getElementById('guestCountDisplay').innerText = window.AppState.guestCount; | |
| } | |
| inputField.value = ''; | |
| inputField.style.height = 'auto'; | |
| document.getElementById('masterSendBtn').disabled = true; | |
| window.AppState.isProcessing = true; | |
| const wState = document.getElementById('welcomeState'); | |
| if (wState) wState.style.display = 'none'; | |
| let payloadStr = rawUserText; | |
| let payloadAttachments = []; | |
| let visualBadge = null; | |
| let previewHTMLForChat = ''; | |
| if (window.AppState.pendingAttachment) { | |
| previewHTMLForChat = window.ChatEngine.buildPreviewHTML(window.AppState.pendingAttachment); | |
| if (window.AppState.pendingAttachment.type === 'text') { | |
| payloadStr = `[Document Analyzed: ${window.AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${window.AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`; | |
| visualBadge = '📄 File Appended'; | |
| } else { | |
| payloadAttachments.push({ | |
| type: window.AppState.pendingAttachment.type, | |
| data: window.AppState.pendingAttachment.data, | |
| name: window.AppState.pendingAttachment.name | |
| }); | |
| const icoMap = { 'video': '🎥 ', 'audio': '🎵 ', 'image': '🖼️ ' }; | |
| visualBadge = (icoMap[window.AppState.pendingAttachment.type] || '📎 ') + "Media Appended"; | |
| } | |
| window.ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat); | |
| window.AppState.history.push({ role: 'user', content: payloadStr, badge: visualBadge, previewHTML: previewHTMLForChat }); | |
| } else { | |
| window.ChatEngine.renderUserMessage(rawUserText, null, ''); | |
| window.AppState.history.push({ role: 'user', content: rawUserText }); | |
| } | |
| window.FileProcessor.discardFile(); | |
| window.ChatEngine.saveHistoryToCloud(); | |
| const activeBotBubble = window.ChatEngine.renderBotMessage('', false); | |
| window.UIManager.forceScrollDown(); | |
| const cryptographicSeed = Math.floor(Math.random() * 999999999); | |
| let cognitivePrompt = `You are Arjun 2.O, a sophisticated enterprise AI system architected by Abhay Kumar. | |
| LANGUAGE REGULATION: You possess strict bilingual fluency. You MUST analyze the user's language and respond seamlessly in BOTH English and Hindi. | |
| - If the prompt is purely English, output pure English. | |
| - If the prompt contains Hindi (Devanagari or Hinglish), respond in natural Hindi. | |
| - Adapt tone to be highly professional, intelligent, and authoritative. | |
| 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.`; | |
| if (window.AppState.isLiveModeEngaged) { | |
| cognitivePrompt += `\n\n[LIVE ACOUSTIC OVERRIDE]: 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.`; | |
| } | |
| // SECURE PAYLOAD PREP - Fixes HuggingFace crash by strictly formatting history array | |
| const secureHistory = window.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: window.AppState.isLiveModeEngaged ? 150 : 4096, | |
| temperature: 0.75 | |
| }; | |
| try { | |
| const fetchOp = await fetch('/api/chat', { | |
| 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 = ""; | |
| window.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); | |
| // CRITICAL BUG FIX: Correct array targeting (choices) prevents silent crash during stream iteration | |
| if (jsonSegment.choices && jsonSegment.choices.length > 0 && jsonSegment.choices.delta && jsonSegment.choices.delta.content) { | |
| responseBuffer += jsonSegment.choices.delta.content; | |
| window.ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true); | |
| window.UIManager.autoScroll(); | |
| } | |
| } catch (e) { | |
| // Silently catch fragmented packets | |
| } | |
| } | |
| } | |
| } | |
| window.AppState.isStreamingActive = false; | |
| window.ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, false); | |
| window.AppState.history.push({ role: 'bot', content: responseBuffer }); | |
| window.ChatEngine.saveHistoryToCloud(); | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Synthesizing Audio..."; | |
| await window.VoiceEngine.executeTTS(responseBuffer); | |
| } | |
| } catch(error) { | |
| console.error(error); | |
| window.AppState.isStreamingActive = false; | |
| window.ChatEngine.updateBotBubble(activeBotBubble, `**System Error:** Communication array offline. Verification needed.`, false); | |
| if (window.AppState.isLiveModeEngaged) { | |
| document.getElementById('liveStatusText').innerText = "Neural Link Severed."; | |
| } | |
| } | |
| window.AppState.isProcessing = false; | |
| document.getElementById('masterSendBtn').disabled = false; | |
| window.UIManager.autoScroll(); | |
| } | |
| }; | |
| // Bootstrap the System | |
| window.ApplicationCore = { | |
| launchSystem: startArjunApp | |
| }; | |
| // Start initialization process automatically upon module mount completion | |
| function startArjunApp() { | |
| const overlay = document.getElementById('welcomeOverlay'); | |
| if(overlay) { | |
| overlay.classList.add('hidden'); | |
| localStorage.setItem('arjun_welcome_seen', 'true'); | |
| setTimeout(() => { overlay.style.display = 'none'; }, 400); | |
| } | |
| } | |
| // Final Document Ready Catch to ensure bindings | |
| document.addEventListener('DOMContentLoaded', () => { | |
| window.AuthManager.initUI(); | |
| if(window.AppState.currentUser) { | |
| window.ChatEngine.syncHistoryFromCloud(); | |
| } else { | |
| const guestBadge = document.getElementById('guestBadge'); | |
| if(guestBadge) guestBadge.style.display = 'inline-flex'; | |
| const guestDisplay = document.getElementById('guestCountDisplay'); | |
| if(guestDisplay) guestDisplay.innerText = window.AppState.guestCount; | |
| } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |