Spaces:
Sleeping
Sleeping
| <html lang="en" dir="ltr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
| <!-- Viewport Settings: Disables zoom, completely removes blue tap highlights on mobile devices --> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> | |
| <meta name="description" content="CODE VED Ultimate Enterprise Artificial Intelligence System engineered by Abhay Kumar."> | |
| <meta name="theme-color" content="#000000"> | |
| <title>CODE VED - Premium AI Workspace</title> | |
| <!-- ========================================================================================= | |
| [1] EXTERNAL RESOURCES, FONTS & LIBRARIES | |
| ========================================================================================= --> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <!-- Professional Typography --> | |
| <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Inter:wght@300;400;500;600;700;800;900&family=Geist+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> | |
| <!-- Syntax Highlighting (Atom One Dark for Workspace Environment) --> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css"> | |
| <!-- Data Extraction & Rendering Utilities --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.6.0/mammoth.browser.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.1/marked.min.js"></script> | |
| <!-- ========================================================================================= | |
| [2] MASSIVE ENTERPRISE CSS ARCHITECTURE (APPLE DARK GLASSMORPHISM) | |
| ========================================================================================= --> | |
| <style> | |
| /* --------------------------------------------------------------------------------------- | |
| A. CSS VARIABLES & DESIGN TOKENS (DARK MODE) | |
| --------------------------------------------------------------------------------------- */ | |
| :root { | |
| /* Branding Colors - Indian Identity */ | |
| --brand-saffron: #FF9933; | |
| --brand-saffron-light: rgba(255, 153, 51, 0.2); | |
| --brand-saffron-dark: #e68a2e; | |
| --brand-white: #FFFFFF; | |
| --brand-white-glass: rgba(255, 255, 255, 0.1); | |
| --brand-green: #138808; | |
| --brand-green-light: rgba(19, 136, 8, 0.2); | |
| --brand-green-dark: #0f6e06; | |
| /* Structural Colors - Pure Apple Dark */ | |
| --bg-primary: #000000; | |
| --bg-secondary: #1c1c1e; | |
| --bg-tertiary: #2c2c2e; | |
| --bg-glass: rgba(28, 28, 30, 0.65); | |
| /* Text & Typography Colors */ | |
| --text-primary: #ffffff; | |
| --text-secondary: #a1a1a6; | |
| --text-tertiary: #86868b; | |
| --text-inverse: #000000; | |
| --text-error: #ff453a; | |
| /* Borders & Dividers */ | |
| --border-light: rgba(255, 255, 255, 0.12); | |
| --border-medium: rgba(255, 255, 255, 0.25); | |
| /* Shadows & Elevation */ | |
| --shadow-xs: 0 1px 2px rgba(0,0,0,0.5); | |
| --shadow-sm: 0 4px 12px rgba(0,0,0,0.5); | |
| --shadow-md: 0 8px 24px rgba(0,0,0,0.6); | |
| --shadow-lg: 0 12px 32px rgba(0,0,0,0.7); | |
| --shadow-xl: 0 20px 40px rgba(0,0,0,0.8); | |
| /* Font Families */ | |
| --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; | |
| --font-mono: 'Geist Mono', Consolas, Monaco, monospace; | |
| /* Radii */ | |
| --radius-sm: 8px; | |
| --radius-md: 12px; | |
| --radius-lg: 18px; | |
| --radius-xl: 24px; | |
| --radius-full: 9999px; | |
| /* Animation Easing */ | |
| --ease-fast: 0.15s cubic-bezier(0.4, 0, 0.2, 1); | |
| --ease-smooth: 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| --ease-spring: 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| /* Z-Indices */ | |
| --z-ambient: -1; | |
| --z-base: 1; | |
| --z-header: 10; | |
| --z-dropdown: 50; | |
| --z-sidebar: 100; | |
| --z-workspace: 200; | |
| --z-modal: 5000; | |
| --z-toast: 9000; | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| B. GLOBAL RESET & ANTI-BLUE-HIGHLIGHT BUG FIX | |
| --------------------------------------------------------------------------------------- */ | |
| *, *::before, *::after { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| -webkit-tap-highlight-color: transparent ; | |
| -webkit-touch-callout: none ; | |
| } | |
| html { font-size: 16px; -webkit-text-size-adjust: 100%; scroll-behavior: smooth; } | |
| body { | |
| height: 100dvh; | |
| width: 100vw; | |
| overflow: hidden; | |
| background-color: var(--bg-primary); | |
| color: var(--text-primary); | |
| font-family: var(--font-sans); | |
| line-height: 1.6; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| } | |
| *:focus { outline: none ; } | |
| button, input, textarea, select { | |
| font-family: inherit; | |
| color: inherit; | |
| border: none; | |
| background: transparent; | |
| } | |
| button { cursor: pointer; user-select: none; } | |
| a { color: inherit; text-decoration: none; } | |
| img { max-width: 100%; height: auto; display: block; } | |
| svg { flex-shrink: 0; } | |
| ::-webkit-scrollbar { width: 6px; height: 6px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.2); border-radius: 10px; transition: background var(--ease-smooth); } | |
| ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.4); } | |
| /* --------------------------------------------------------------------------------------- | |
| C. AMBIENT BACKGROUND SYSTEM (DARK ORBS) | |
| --------------------------------------------------------------------------------------- */ | |
| .ambient-environment { | |
| position: fixed; inset: 0; z-index: var(--z-ambient); overflow: hidden; pointer-events: none; | |
| background: #000000; | |
| } | |
| .ambient-orb { | |
| position: absolute; border-radius: 50%; filter: blur(140px); opacity: 0.15; | |
| animation: orbFloat 40s ease-in-out infinite alternate; will-change: transform; | |
| } | |
| .orb-top-left { | |
| width: 700px; height: 700px; | |
| background: radial-gradient(circle, var(--brand-saffron) 0%, transparent 70%); | |
| top: -200px; left: -150px; | |
| } | |
| .orb-bottom-right { | |
| width: 600px; height: 600px; | |
| background: radial-gradient(circle, var(--brand-green) 0%, transparent 70%); | |
| bottom: -150px; right: -100px; animation-delay: -20s; | |
| } | |
| @keyframes orbFloat { | |
| 0% { transform: translate(0, 0) scale(1); } | |
| 33% { transform: translate(30px, 50px) scale(1.05); } | |
| 66% { transform: translate(-20px, 30px) scale(0.95); } | |
| 100% { transform: translate(40px, -20px) scale(1.1); } | |
| } | |
| /* --------------------------------------------------------------------------------------- | |
| D. TOAST NOTIFICATION ENGINE | |
| --------------------------------------------------------------------------------------- */ | |
| .toast-wrapper { | |
| position: absolute; top: 24px; left: 50%; transform: translateX(-50%); | |
| z-index: var(--z-toast); display: flex; flex-direction: column; gap: 12px; | |
| pointer-events: none; width: 90%; max-width: 400px; align-items: center; | |
| } | |
| .toast-notification { | |
| background: rgba(40, 40, 42, 0.9); backdrop-filter: blur(20px); color: var(--text-primary); padding: 14px 24px; | |
| border-radius: var(--radius-full); font-size: 14px; font-weight: 600; box-shadow: var(--shadow-xl); | |
| animation: toastSlideIn var(--ease-spring) forwards, toastFadeOut 0.4s 3.5s forwards; | |
| display: flex; align-items: center; gap: 10px; width: fit-content; max-width: 100%; word-break: break-word; | |
| border: 1px solid rgba(255,255,255,0.1); | |
| } | |
| .toast-notification svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--brand-saffron); } | |
| @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: rgba(0, 0, 0, 0.85); | |
| backdrop-filter: blur(35px) saturate(180%); -webkit-backdrop-filter: blur(35px) saturate(180%); 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.3s both; } | |
| .startup-logo-container img { width: 140px; height: 140px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 1px solid rgba(255,255,255,0.2); position: relative; z-index: 2; } | |
| .startup-logo-glow { position: absolute; inset: -20px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(35px); opacity: 0.3; border-radius: var(--radius-full); z-index: 1; animation: pulseGlow 3s infinite alternate; } | |
| @keyframes pulseGlow { from { opacity: 0.2; transform: scale(0.95); } to { opacity: 0.4; 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: 2.5rem; font-weight: 900; color: var(--text-primary); letter-spacing: -1px; margin-bottom: 16px; animation: slideUp var(--ease-smooth) 0.4s both; } | |
| .startup-desc { font-size: 1.1rem; color: var(--text-secondary); line-height: 1.6; max-width: 550px; margin-bottom: 40px; animation: slideUp var(--ease-smooth) 0.5s both; font-weight: 500; } | |
| .btn-startup-launch { padding: 18px 48px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-xl); font-size: 1.125rem; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 10px 25px rgba(255,255,255,0.1); animation: slideUp var(--ease-smooth) 0.6s both; display: flex; align-items: center; gap: 12px; position: relative; overflow: hidden; } | |
| .btn-startup-launch::before { content: ''; position: absolute; top: 0; left: -100%; width: 50%; height: 100%; background: linear-gradient(90deg, transparent, rgba(0,0,0,0.1), transparent); transform: skewX(-20deg); transition: 0.5s; } | |
| .btn-startup-launch:hover { background: #e0e0e0; transform: translateY(-4px) scale(1.02); box-shadow: 0 15px 35px rgba(255,255,255,0.2); } | |
| .btn-startup-launch:hover::before { left: 150%; } | |
| @keyframes slideUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } | |
| /* --------------------------------------------------------------------------------------- | |
| F. CORE APPLICATION LAYOUT & SIDEBAR (GLASSMORPHISM) | |
| --------------------------------------------------------------------------------------- */ | |
| .app-root { position: relative; z-index: var(--z-base); display: flex; height: 100dvh; width: 100vw; overflow: hidden; background: transparent; } | |
| /* Sidebar Navigation */ | |
| .sidebar-container { width: 320px; display: flex; flex-direction: column; background: rgba(28, 28, 30, 0.75); border-right: 1px solid var(--border-light); flex-shrink: 0; z-index: var(--z-sidebar); transition: transform var(--ease-smooth), box-shadow var(--ease-smooth); backdrop-filter: blur(25px) saturate(180%); -webkit-backdrop-filter: blur(25px) saturate(180%); } | |
| .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: 50px; height: 50px; border-radius: var(--radius-md); object-fit: cover; box-shadow: var(--shadow-sm); border: 1px solid var(--border-light); 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(255,255,255,0.1); 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(255, 69, 58, 0.2); color: var(--text-error); transform: rotate(90deg); } | |
| .sidebar-body { flex: 1; overflow-y: auto; padding: 24px; display: flex; flex-direction: column; gap: 28px; } | |
| /* Auth Widget in Sidebar */ | |
| .auth-widget { background: rgba(0,0,0,0.3); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 20px; box-shadow: var(--shadow-sm); transition: var(--ease-smooth); backdrop-filter: blur(10px); } | |
| .auth-widget:hover { box-shadow: var(--shadow-md); border-color: var(--border-medium); } | |
| .btn-secure-connect { width: 100%; padding: 14px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-md); font-size: 14px; font-weight: 700; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 10px; transition: var(--ease-fast); } | |
| .btn-secure-connect:hover { background: #e0e0e0; transform: translateY(-2px); box-shadow: 0 4px 15px rgba(255,255,255,0.1); } | |
| .user-profile-display { display: none; align-items: center; gap: 14px; } | |
| .avatar-badge { width: 46px; height: 46px; border-radius: var(--radius-full); background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); color: var(--brand-white); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 18px; box-shadow: var(--shadow-sm); text-shadow: 0 1px 2px rgba(0,0,0,0.5); } | |
| .user-details { flex: 1; overflow: hidden; } | |
| .user-email-id { font-size: 14px; font-weight: 700; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .user-clearance-level { font-size: 11px; color: var(--brand-green); font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 4px; } | |
| .user-clearance-level::before { content: ''; display: block; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 5px rgba(19, 136, 8, 0.8); } | |
| .btn-system-logout { background: rgba(255, 69, 58, 0.15); color: var(--text-error); border: none; width: 38px; height: 38px; border-radius: var(--radius-md); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-fast); border: 1px solid rgba(255, 69, 58, 0.2); } | |
| .btn-system-logout:hover { background: var(--text-error); color: #ffffff; transform: scale(1.05); } | |
| /* Developer Box */ | |
| .developer-credit-box { background: rgba(0,0,0,0.3); 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; backdrop-filter: blur(10px); } | |
| .developer-credit-box::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: linear-gradient(90deg, var(--brand-saffron), var(--brand-white), var(--brand-green)); } | |
| .developer-credit-box img { width: 72px; height: 72px; border-radius: var(--radius-lg); object-fit: cover; margin-bottom: 16px; box-shadow: var(--shadow-md); border: 1px solid var(--border-light); margin-left: auto; margin-right: auto; transition: var(--ease-spring); } | |
| .developer-credit-box:hover img { transform: scale(1.05); } | |
| .dev-box-title { font-size: 18px; font-weight: 800; color: var(--text-primary); margin-bottom: 6px; } | |
| .dev-box-subtitle { font-size: 11px; font-weight: 800; color: var(--text-tertiary); letter-spacing: 1px; text-transform: uppercase; } | |
| /* Wipe Memory Button */ | |
| .btn-erase-memory { width: 100%; padding: 16px; border-radius: var(--radius-md); background: rgba(0,0,0,0.2); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-fast); display: flex; align-items: center; justify-content: center; gap: 10px; } | |
| .btn-erase-memory:hover { background: rgba(255, 69, 58, 0.1); color: var(--text-error); border-color: rgba(255, 69, 58, 0.3); } | |
| /* --------------------------------------------------------------------------------------- | |
| G. MAIN CHAT AREA & HEADER (GLASSMORPHISM) | |
| --------------------------------------------------------------------------------------- */ | |
| .main-chat-wrapper { flex: 1; display: flex; flex-direction: column; position: relative; min-width: 320px; transition: width var(--ease-smooth); background: transparent; } | |
| .chat-top-bar { padding: 18px 32px; border-bottom: 1px solid var(--border-light); background: rgba(28, 28, 30, 0.6); backdrop-filter: blur(25px) saturate(180%); -webkit-backdrop-filter: blur(25px) saturate(180%); display: flex; align-items: center; justify-content: space-between; z-index: var(--z-header); } | |
| .top-bar-left { display: flex; align-items: center; gap: 16px; } | |
| .btn-hamburger { display: none; background: rgba(255,255,255,0.05); border: 1px solid var(--border-light); cursor: pointer; color: var(--text-primary); width: 42px; height: 42px; border-radius: var(--radius-sm); align-items: center; justify-content: center; box-shadow: var(--shadow-sm); transition: var(--ease-fast); } | |
| .btn-hamburger:hover { background: rgba(255,255,255,0.1); } | |
| .system-status-pill { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 700; color: var(--text-primary); padding: 8px 18px; background: rgba(0,0,0,0.4); border-radius: var(--radius-full); border: 1px solid var(--border-light); } | |
| .pulse-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--brand-green); box-shadow: 0 0 0 3px rgba(19, 136, 8, 0.3); animation: statusPulse 2s infinite; } | |
| @keyframes statusPulse { 0% { box-shadow: 0 0 0 0 rgba(19,136,8,0.6); } 70% { box-shadow: 0 0 0 6px rgba(19,136,8,0); } 100% { box-shadow: 0 0 0 0 rgba(19,136,8,0); } } | |
| /* Chat Scrollable Area */ | |
| .chat-scroll-area { flex: 1; overflow-y: auto; padding: 40px 10%; display: flex; flex-direction: column; gap: 36px; scroll-behavior: smooth; position: relative; } | |
| /* Internal Welcome Hero Box */ | |
| .chat-hero-section { display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 60px 20px; margin: auto; animation: slideUpFade 0.7s var(--ease-spring) both; max-width: 750px; } | |
| .hero-avatar-wrapper { position: relative; margin-bottom: 36px; } | |
| .hero-avatar-wrapper img { width: 100px; height: 100px; border-radius: var(--radius-xl); object-fit: cover; box-shadow: var(--shadow-xl); border: 1px solid var(--border-light); position: relative; z-index: 2; } | |
| .hero-avatar-glow { position: absolute; inset: -12px; background: linear-gradient(135deg, var(--brand-saffron), var(--brand-green)); filter: blur(30px); opacity: 0.25; border-radius: 40px; z-index: 1; animation: rotateGlow 10s linear infinite;} | |
| @keyframes rotateGlow { 100% { transform: rotate(360deg); } } | |
| .hero-greeting { font-size: 42px; font-weight: 900; letter-spacing: -1.5px; margin-bottom: 18px; color: var(--text-primary); text-shadow: 0 4px 10px rgba(0,0,0,0.5); } | |
| .hero-description { font-size: 17px; color: var(--text-secondary); line-height: 1.6; margin-bottom: 40px; font-weight: 500; } | |
| .guest-warning-badge { font-size: 13px; font-weight: 700; color: #ff6961; background: rgba(255, 69, 58, 0.1); padding: 10px 20px; border-radius: var(--radius-full); margin-bottom: 32px; display: none; align-items: center; gap: 8px; border: 1px solid rgba(255, 69, 58, 0.3); box-shadow: var(--shadow-sm); } | |
| .guest-warning-badge svg { width: 18px; height: 18px; } | |
| .prompt-suggestions-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; width: 100%; } | |
| .prompt-card { background: rgba(28, 28, 30, 0.5); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border: 1px solid var(--border-light); border-radius: var(--radius-lg); padding: 24px; cursor: pointer; text-align: left; transition: var(--ease-smooth); box-shadow: var(--shadow-sm); position: relative; overflow: hidden; } | |
| .prompt-card::after { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: var(--brand-saffron); opacity: 0; transition: var(--ease-fast); } | |
| .prompt-card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); border-color: rgba(255,255,255,0.4); background: rgba(28, 28, 30, 0.8); } | |
| .prompt-card:hover::after { opacity: 1; } | |
| .prompt-icon { font-size: 28px; margin-bottom: 14px; display: inline-block; background: rgba(255,255,255,0.05); padding: 10px; border-radius: var(--radius-md); border: 1px solid var(--border-light); } | |
| .prompt-title { font-size: 15px; font-weight: 800; color: var(--text-primary); margin-bottom: 8px; } | |
| .prompt-desc { font-size: 13px; color: var(--text-secondary); line-height: 1.5; } | |
| /* --------------------------------------------------------------------------------------- | |
| H. CHAT MESSAGE BUBBLES & PREVIEWS (DARK MODE) | |
| --------------------------------------------------------------------------------------- */ | |
| .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-md); flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 15px; font-weight: 800; box-shadow: var(--shadow-md); border: 1px solid var(--border-light); } | |
| .user-msg .msg-avatar { background: linear-gradient(135deg, var(--brand-saffron), var(--brand-saffron-dark)); color: var(--brand-white); border: none; } | |
| .bot-msg .msg-avatar { background: var(--bg-secondary); padding: 2px; } | |
| .bot-msg .msg-avatar img { width: 100%; height: 100%; border-radius: 10px; object-fit: cover; } | |
| .msg-content-column { display: flex; flex-direction: column; gap: 8px; max-width: 100%; min-width: 0; } | |
| .user-msg .msg-content-column { align-items: flex-end; } | |
| .file-badge { font-size: 11px; font-weight: 700; color: var(--brand-saffron); background: rgba(255, 153, 51, 0.15); padding: 4px 12px; border-radius: var(--radius-full); margin-bottom: 4px; display: inline-flex; align-items: center; gap: 6px; border: 1px solid rgba(255,153,51,0.3); } | |
| .file-badge svg { width: 12px; height: 12px; } | |
| /* In-Bubble File Previews */ | |
| .chat-in-bubble-img { max-width: 320px; max-height: 320px; border-radius: var(--radius-md); object-fit: cover; border: 1px solid var(--border-light); box-shadow: var(--shadow-md); margin-bottom: 12px; } | |
| .chat-file-card { display: flex; align-items: center; gap: 14px; background: rgba(0,0,0,0.3); border: 1px solid var(--border-light); padding: 12px 18px; border-radius: var(--radius-md); margin-bottom: 12px; max-width: 350px; backdrop-filter: blur(10px); } | |
| .chat-file-card .icon { font-size: 24px; background: rgba(255,255,255,0.05); width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); color: var(--brand-white); border: 1px solid var(--border-light); } | |
| .chat-file-card .name { font-size: 14px; font-weight: 600; color: var(--brand-white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .chat-bubble { padding: 18px 24px; font-size: 16px; line-height: 1.6; position: relative; word-wrap: break-word; overflow-wrap: anywhere; } | |
| .user-msg .chat-bubble { background: var(--bg-tertiary); color: var(--text-primary); border-radius: 24px 24px 6px 24px; box-shadow: var(--shadow-md); border: 1px solid var(--border-light); } | |
| .bot-msg .chat-bubble { background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); color: var(--text-primary); border: 1px solid var(--border-medium); border-radius: 6px 24px 24px 24px; box-shadow: var(--shadow-md); width: 100%; min-width: 100px;} | |
| .error-bubble { color: #ff453a ; border-color: rgba(255, 69, 58, 0.5) ; background: rgba(255, 69, 58, 0.1) ; font-weight: 500; } | |
| /* 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: rgba(255,255,255,0.05); border: 1px solid var(--border-light); color: var(--text-secondary); font-size: 13px; font-weight: 700; cursor: pointer; display: flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: var(--radius-full); transition: var(--ease-fast); backdrop-filter: blur(10px); } | |
| .btn-bot-action:hover { background: rgba(255,255,255,0.15); color: var(--text-primary); transform: translateY(-2px); box-shadow: var(--shadow-sm); border-color: rgba(255,255,255,0.3); } | |
| .btn-bot-action svg { width: 16px; height: 16px; } | |
| /* Markdown Rendering inside Bubbles */ | |
| .chat-bubble p { margin-bottom: 16px; } | |
| .chat-bubble p:last-child { margin-bottom: 0; } | |
| .chat-bubble strong { font-weight: 800; color: #ffffff; } | |
| .chat-bubble code { font-family: var(--font-mono); background: rgba(255,255,255,0.1); padding: 4px 8px; border-radius: 6px; font-size: 0.85em; color: #ff9f0a; font-weight: 600; border: 1px solid rgba(255,255,255,0.1); } | |
| .user-msg .chat-bubble code { background: rgba(0,0,0,0.3); color: var(--brand-saffron); border-color: rgba(0,0,0,0.5); } | |
| .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; } | |
| .chat-bubble pre { background: #000000; 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 #333; box-shadow: inset 0 2px 10px rgba(0,0,0,0.5); } | |
| .chat-bubble pre code { background: transparent; color: inherit; padding: 0; font-weight: 400; border: none; } | |
| /* Streaming Loading UI Component */ | |
| .streaming-code-container { background: #000000; border-radius: var(--radius-md); border: 1px solid #333; overflow: hidden; margin: 20px 0; box-shadow: var(--shadow-lg); } | |
| .streaming-code-header { background: #111; padding: 14px 20px; font-size: 12px; font-weight: 700; color: #888; display: flex; align-items: center; gap: 12px; border-bottom: 1px solid #333; font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 1.5px; } | |
| .loading-ring { width: 16px; height: 16px; border: 2px solid rgba(255,255,255,0.1); border-top-color: var(--brand-saffron); border-radius: 50%; animation: ringSpin 1s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; } | |
| @keyframes ringSpin { to { transform: rotate(360deg); } } | |
| .streaming-code-container pre { margin: 0; background: transparent; border: none; border-radius: 0; box-shadow: none; } | |
| /* Workspace Execute Card */ | |
| .workspace-execute-card { background: rgba(0,0,0,0.4); 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); backdrop-filter: blur(10px); } | |
| .workspace-execute-card:hover { border-color: rgba(255,255,255,0.4); box-shadow: var(--shadow-md); background: rgba(255,255,255,0.05); } | |
| .ws-card-left { display: flex; align-items: center; gap: 16px; } | |
| .ws-card-icon-box { width: 54px; height: 54px; border-radius: var(--radius-sm); background: rgba(255,255,255,0.05); display: flex; align-items: center; justify-content: center; font-size: 26px; box-shadow: var(--shadow-sm); border: 1px solid var(--border-light); color: var(--text-primary); } | |
| .ws-card-icon-box svg { color: var(--brand-saffron); } | |
| .ws-card-details h4 { font-size: 16px; font-weight: 800; margin-bottom: 4px; color: var(--text-primary); } | |
| .ws-card-details p { font-size: 12px; color: var(--text-secondary); font-family: var(--font-mono); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 600; } | |
| .btn-launch-workspace { padding: 12px 24px; background: var(--text-primary); color: var(--text-inverse); border: none; border-radius: var(--radius-sm); font-size: 14px; font-weight: 700; cursor: pointer; transition: var(--ease-spring); box-shadow: var(--shadow-sm); } | |
| .btn-launch-workspace:hover { transform: scale(1.05); background: var(--brand-saffron); color: white; box-shadow: 0 6px 15px rgba(255,153,51,0.35); } | |
| /* --------------------------------------------------------------------------------------- | |
| I. BOTTOM INPUT DOCK & TOOLS (GLASSMORPHISM) | |
| --------------------------------------------------------------------------------------- */ | |
| .input-dock { flex-shrink: 0; padding: 0 40px 32px; background: transparent; position: relative; z-index: var(--z-dock); } | |
| .input-master-container { display: flex; flex-direction: column; background: rgba(28, 28, 30, 0.75); backdrop-filter: blur(35px) saturate(180%); -webkit-backdrop-filter: blur(35px) saturate(180%); border: 1px solid var(--border-medium); border-radius: var(--radius-xl); box-shadow: var(--shadow-xl); transition: var(--ease-smooth); } | |
| .input-master-container:focus-within { border-color: rgba(255,255,255,0.5); box-shadow: 0 20px 40px -5px rgba(0,0,0,0.8), 0 0 0 4px rgba(255,255,255,0.1); } | |
| /* Upload Preview Header */ | |
| .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: rgba(0,0,0,0.5); 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: #32d74b; font-weight: 600; margin-top: 2px; display: flex; align-items: center; gap: 6px; } | |
| .upload-status-text svg { width: 14px; height: 14px; } | |
| .btn-discard-upload { background: rgba(255, 69, 58, 0.15); border: 1px solid rgba(255, 69, 58, 0.3); width: 32px; height: 32px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--text-error); transition: var(--ease-fast); } | |
| .btn-discard-upload:hover { background: var(--text-error); color: #fff; } | |
| .input-tools-row { display: flex; align-items: flex-end; gap: 12px; padding: 14px 20px 14px 24px; } | |
| .main-textarea { flex: 1; border: none; outline: none; background: transparent; font-family: var(--font-sans); font-size: 16px; color: var(--text-primary); line-height: 1.5; resize: none; max-height: 200px; min-height: 24px; padding: 12px 0; margin: 0 8px; font-weight: 500; } | |
| .main-textarea::placeholder { color: var(--text-tertiary); font-weight: 400; } | |
| /* Attachment Menu Dropdown */ | |
| .attachment-module { position: relative; } | |
| .btn-tool-icon { width: 44px; height: 44px; border-radius: var(--radius-md); background: transparent; border: none; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-secondary); transition: var(--ease-fast); } | |
| .btn-tool-icon:hover { background: rgba(255,255,255,0.1); 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(40, 40, 42, 0.95); backdrop-filter: blur(30px); -webkit-backdrop-filter: blur(30px); border: 1px solid var(--border-medium); border-radius: var(--radius-lg); padding: 10px; box-shadow: var(--shadow-xl); display: none; flex-direction: column; gap: 6px; z-index: var(--z-dropdown); min-width: 240px; transform: translateY(15px) scale(0.95); opacity: 0; transition: all var(--ease-fast); transform-origin: bottom left; } | |
| .attachment-dropdown.visible { display: flex; transform: translateY(0) scale(1); opacity: 1; } | |
| .dropdown-item { display: flex; align-items: center; gap: 14px; padding: 14px 18px; border-radius: var(--radius-sm); cursor: pointer; font-size: 15px; font-weight: 600; color: var(--text-primary); transition: var(--ease-fast); } | |
| .dropdown-item:hover { background: rgba(255,255,255,0.1); color: var(--brand-saffron); } | |
| .dropdown-item svg { width: 20px; height: 20px; color: var(--text-secondary); } | |
| .dropdown-item:hover svg { color: var(--brand-saffron); } | |
| .stealth-input { display: none; } | |
| /* Master Send Button */ | |
| .btn-master-send { width: 48px; height: 48px; border-radius: 16px; border: 1px solid rgba(255,255,255,0.2); background: linear-gradient(135deg, var(--brand-saffron) 0%, var(--brand-saffron-dark) 100%); display: flex; align-items: center; justify-content: center; cursor: pointer; transition: var(--ease-spring); box-shadow: 0 4px 15px rgba(255, 153, 51, 0.3); } | |
| .btn-master-send svg { width: 20px; height: 20px; fill: white; transition: transform 0.2s; } | |
| .btn-master-send:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(255, 153, 51, 0.5); border-color: rgba(255,255,255,0.5); } | |
| .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; border-color: transparent; } | |
| .bottom-branding-text { text-align: center; font-size: 12px; color: var(--text-tertiary); margin-top: 16px; font-weight: 600; letter-spacing: 0.5px; } | |
| /* Scroll Trigger Button */ | |
| .btn-scroll-trigger { position: absolute; bottom: 150px; left: 50%; width: 48px; height: 48px; border-radius: 50%; background: rgba(28, 28, 30, 0.8); backdrop-filter: blur(25px); border: 1px solid var(--border-medium); box-shadow: var(--shadow-xl); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-primary); opacity: 0; pointer-events: none; transform: translateX(-50%) translateY(20px); transition: var(--ease-smooth); z-index: 20; } | |
| .btn-scroll-trigger.visible { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); } | |
| .btn-scroll-trigger:hover { background: var(--text-primary); color: var(--text-inverse); transform: translateX(-50%) translateY(-5px); } | |
| /* --------------------------------------------------------------------------------------- | |
| J. WORKSPACE PRO (DARK COMPILER PANEL WITH TABS) | |
| --------------------------------------------------------------------------------------- */ | |
| .code-workspace-panel { width: 0; background: #000000; 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.8); z-index: var(--z-workspace); } | |
| .code-workspace-panel.expanded { width: 55%; } | |
| .workspace-header-bar { padding: 12px 24px; border-bottom: 1px solid #333; background: #111; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; } | |
| .workspace-tabs { display: flex; background: #222; border-radius: var(--radius-sm); padding: 4px; gap: 4px; } | |
| .ws-tab { padding: 6px 16px; border-radius: 6px; font-size: 13px; font-weight: 700; color: #888; cursor: pointer; transition: 0.2s; display: flex; align-items: center; gap: 8px; } | |
| .ws-tab:hover { color: #fff; } | |
| .ws-tab.active { background: #444; color: #fff; box-shadow: 0 2px 5px rgba(0,0,0,0.5); } | |
| .ws-tab svg { width: 14px; height: 14px; } | |
| .workspace-tools { display: flex; gap: 10px; } | |
| .btn-workspace-tool { padding: 8px 16px; border-radius: var(--radius-sm); background: #222; border: 1px solid #333; cursor: pointer; display: flex; align-items: center; gap: 8px; color: #fff; transition: var(--ease-fast); font-size: 13px; font-weight: 600; } | |
| .btn-workspace-tool:hover { background: #333; border-color: #555; } | |
| .btn-workspace-tool.close { padding: 8px; background: transparent; border-color: transparent; color: #abb2bf; } | |
| .btn-workspace-tool.close:hover { color: #ff453a; background: rgba(255, 69, 58, 0.1); } | |
| .workspace-editor-surface { flex: 1; overflow-y: auto; background: #000; padding: 24px; position: relative; } | |
| .workspace-editor-surface pre { margin: 0; padding: 0; background: transparent; font-family: var(--font-mono); font-size: 15px; line-height: 1.6; overflow-x: auto; color: #abb2bf; border: none; box-shadow: none;} | |
| .workspace-preview-surface { display: none; flex: 1; flex-direction: column; background: #000; overflow: hidden; position: relative; } | |
| .console-output { background: #0c0c0c; color: #00ff00; font-family: var(--font-mono); padding: 20px; flex: 1; overflow-y: auto; font-size: 14px; line-height: 1.5; white-space: pre-wrap; margin:0;} | |
| .console-output.error { color: #ff453a; } | |
| .compiling-loader { display: flex; align-items: center; justify-content: center; height: 100%; color: var(--brand-saffron); font-weight: bold; font-family: var(--font-mono); gap: 10px; } | |
| .compiling-loader::after { content: ''; width: 16px; height: 16px; border: 2px solid var(--brand-saffron); border-top-color: transparent; border-radius: 50%; animation: spin 1s linear infinite; } | |
| @keyframes spin { to { transform: rotate(360deg); } } | |
| /* --------------------------------------------------------------------------------------- | |
| K. AUTHENTICATION SECURE GATEWAY (MODAL) | |
| --------------------------------------------------------------------------------------- */ | |
| .secure-modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,0.8); backdrop-filter: blur(20px); z-index: var(--z-modal); display: none; justify-content: center; align-items: center; animation: fadeIn 0.3s ease; } | |
| .secure-modal-surface { background: rgba(28, 28, 30, 0.95); padding: 44px; border-radius: var(--radius-xl); width: 90%; max-width: 460px; box-shadow: 0 25px 50px -12px rgba(0,0,0,1); position: relative; border: 1px solid rgba(255,255,255,0.15); backdrop-filter: blur(30px); } | |
| .btn-modal-dismiss { position: absolute; top: 24px; right: 24px; background: rgba(255,255,255,0.05); border: 1px solid transparent; 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: rgba(255, 69, 58, 0.1); color: var(--text-error); border-color: rgba(255, 69, 58, 0.3); } | |
| .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: rgba(0,0,0,0.3); padding: 6px; border-radius: var(--radius-md); margin-bottom: 28px; border: 1px solid rgba(255,255,255,0.05); } | |
| .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: rgba(255,255,255,0.1); 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: 1px solid rgba(255,255,255,0.1); border-radius: var(--radius-md); font-size: 16px; outline: none; background: rgba(0,0,0,0.2); color: var(--text-primary); 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: rgba(0,0,0,0.4); box-shadow: 0 0 0 4px rgba(255, 153, 51, 0.15); } | |
| .auth-input-element::placeholder { color: rgba(255,255,255,0.3); } | |
| .btn-auth-execute { width: 100%; padding: 18px; background: var(--text-primary); color: var(--text-inverse); 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: #e0e0e0; transform: translateY(-2px); box-shadow: var(--shadow-md); } | |
| .btn-auth-return { width: 100%; padding: 14px; background: transparent; color: var(--text-tertiary); border: none; font-size: 15px; font-weight: 700; cursor: pointer; margin-top: 10px; transition: 0.2s; } | |
| .btn-auth-return:hover { color: var(--text-primary); } | |
| @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } | |
| @keyframes slideIn { from { opacity: 0; transform: translateX(25px); } to { opacity: 1; transform: none; } } | |
| /* Cursor & Loading UI */ | |
| .typing-cursor { display: inline-block; width: 10px; height: 18px; background: var(--brand-saffron); margin-left: 4px; animation: cursorBlink 1s step-end infinite; vertical-align: middle; } | |
| @keyframes cursorBlink { 50% { opacity: 0; } } | |
| .loading-dots-container { display: flex; align-items: center; gap: 6px; padding: 6px; } | |
| .loading-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-tertiary); opacity: 0.4; animation: dotBounce 1.4s infinite ease-in-out both; } | |
| .loading-dot:nth-child(1) { animation-delay: -0.32s; } .loading-dot:nth-child(2) { animation-delay: -0.16s; } | |
| @keyframes dotBounce { 0%, 80%, 100% { transform: scale(0); } 40% { transform: scale(1); } } | |
| /* --------------------------------------------------------------------------------------- | |
| L. RESPONSIVE DESIGN (MOBILE & TABLET ADAPTATIONS) | |
| --------------------------------------------------------------------------------------- */ | |
| @media (max-width: 1024px) { | |
| .code-workspace-panel.expanded { width: 100%; position: absolute; top: 0; left: 0; height: 100%; z-index: 2000; } | |
| } | |
| @media (max-width: 900px) { | |
| .sidebar-container { position: absolute; left: -320px; z-index: 1000; height: 100%; box-shadow: var(--shadow-xl); } | |
| .sidebar-container.active { left: 0; } | |
| .btn-hamburger { display: flex; } | |
| .btn-mobile-close { display: flex; } | |
| .chat-scroll-area { padding: 24px 15px; } | |
| .input-dock { padding: 10px 15px 20px; } | |
| .chat-message-row { max-width: 98%; } | |
| .btn-scroll-trigger { bottom: 130px; } | |
| .hero-greeting { font-size: 32px; } | |
| .prompt-suggestions-grid { grid-template-columns: 1fr; } | |
| .input-tools-row { flex-wrap: wrap; } | |
| .main-textarea { min-width: 100%; order: -1; margin-bottom: 10px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: NOTIFICATIONS | |
| ========================================================================================= --> | |
| <div id="toast-container" class="toast-wrapper"></div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: STARTUP OVERLAY | |
| ========================================================================================= --> | |
| <div class="startup-overlay" id="welcomeOverlay"> | |
| <div class="startup-logo-container"> | |
| <div class="startup-logo-glow"></div> | |
| <img src="https://i.ibb.co/MxKsrXDj/TIRANGA-20260525-172109-0000.png" alt="CODE VED Core Identity"> | |
| </div> | |
| <h1 class="startup-title">Welcome to CODE VED</h1> | |
| <p class="startup-desc">Premium AI Workspace. Experience secure multi-language code generation and high-fidelity visual rendering.</p> | |
| <button class="btn-startup-launch" id="btnLaunchSystem"> | |
| Initialize Workspace | |
| <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg> | |
| </button> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: AMBIENT BACKGROUND | |
| ========================================================================================= --> | |
| <div class="ambient-environment"> | |
| <div class="ambient-orb orb-top-left"></div> | |
| <div class="ambient-orb orb-bottom-right"></div> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: MASTER APPLICATION CONTAINER | |
| ========================================================================================= --> | |
| <div class="app-root"> | |
| <!-- A. NAVIGATION SIDEBAR --> | |
| <aside class="sidebar-container" id="sidebar"> | |
| <div class="sidebar-header"> | |
| <a href="#" class="brand-identity"> | |
| <img src="https://i.ibb.co/MxKsrXDj/TIRANGA-20260525-172109-0000.png" alt="CODE VED Logo"> | |
| <div class="brand-typography"> | |
| <span class="brand-name">CODE VED</span> | |
| <span class="brand-edition">Premium</span> | |
| </div> | |
| </a> | |
| <button class="btn-mobile-close" id="btnSidebarClose"> | |
| <svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" stroke-width="2.5" fill="none"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> | |
| </button> | |
| </div> | |
| <div class="sidebar-body"> | |
| <!-- Authentication Widget --> | |
| <div class="auth-widget"> | |
| <button id="loginPromptBtn" class="btn-secure-connect"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg> | |
| Secure Login | |
| </button> | |
| <div id="userProfile" class="user-profile-display"> | |
| <div class="avatar-badge" id="uAvatar">U</div> | |
| <div class="user-details"> | |
| <div class="user-email-id" id="uEmail">user@network.com</div> | |
| <div class="user-clearance-level">Verified Clearance</div> | |
| </div> | |
| <button class="btn-system-logout" id="btnLogout" title="Terminate Session"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path><polyline points="16 17 21 12 16 7"></polyline><line x1="21" y1="12" x2="9" y2="12"></line></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Branding Box --> | |
| <div class="developer-credit-box"> | |
| <img src="https://i.ibb.co/MxKsrXDj/TIRANGA-20260525-172109-0000.png" alt="CODE VED Core Image"> | |
| <h3 class="dev-box-title">CODE VED Core</h3> | |
| <p class="dev-box-subtitle">ENGINEERED BY DIVY PATEL</p> | |
| </div> | |
| <!-- Wipe Memory Button --> | |
| <button class="btn-erase-memory" id="btnClearMemory"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg> | |
| Wipe 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" id="btnSidebarOpen"> | |
| <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2.5" fill="none"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg> | |
| </button> | |
| <div class="system-status-pill"> | |
| <div class="pulse-dot"></div> | |
| System Online | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Scrollable Conversation Area --> | |
| <div class="chat-scroll-area" id="msgs"> | |
| <!-- Internal Welcome / Guest Warning State --> | |
| <div class="chat-hero-section" id="welcomeState"> | |
| <div class="hero-avatar-wrapper"> | |
| <div class="hero-avatar-glow"></div> | |
| <img src="https://i.ibb.co/MxKsrXDj/TIRANGA-20260525-172109-0000.png" alt="CODE VED 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"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path><line x1="12" y1="9" x2="12" y2="13"></line><line x1="12" y1="17" x2="12.01" y2="17"></line></svg> | |
| Guest Mode Active: <span id="guestCountDisplay">0</span>/3 Queries Used. Please login. | |
| </div> | |
| <div class="prompt-suggestions-grid"> | |
| <div class="prompt-card" id="suggCodeBtn"> | |
| <span class="prompt-icon">💻</span> | |
| <div class="prompt-title">Generate Production Code</div> | |
| <div class="prompt-desc">Create secure, workspace-ready architecture instantly.</div> | |
| </div> | |
| <div class="prompt-card" id="suggImgBtn"> | |
| <span class="prompt-icon">🎨</span> | |
| <div class="prompt-title">Render Stunning Visions</div> | |
| <div class="prompt-desc">Utilize advanced AI to paint your imagination.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Floating Scroll Down Button --> | |
| <button class="btn-scroll-trigger" id="scrollTriggerBtn"> | |
| <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"></polyline></svg> | |
| </button> | |
| <!-- Bottom Input Dock --> | |
| <div class="input-dock"> | |
| <div class="input-master-container"> | |
| <!-- File Preview Component --> | |
| <div class="upload-preview-bar" id="filePreviewBar"> | |
| <img class="upload-thumb" id="previewImgThumb" src="" style="display:none;"> | |
| <div class="upload-thumb" id="previewDocIcon" style="display:none;">📄</div> | |
| <div class="upload-meta"> | |
| <div class="upload-filename" id="previewFileName">document.pdf</div> | |
| <div class="upload-status-text"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"><polyline points="20 6 9 17 4 12"></polyline></svg> | |
| File ready to be transmitted | |
| </div> | |
| </div> | |
| <button class="btn-discard-upload" id="btnDiscardFile"> | |
| <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> | |
| </button> | |
| </div> | |
| <!-- Main Tool & Input Row --> | |
| <div class="input-tools-row"> | |
| <!-- Attachment Dropdown Module --> | |
| <div class="attachment-module"> | |
| <button class="btn-tool-icon" id="btnAttachMenuToggle" title="Attach File"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg> | |
| </button> | |
| <div class="attachment-dropdown" id="attachDropdownMenu"> | |
| <div class="dropdown-item" id="opt-image"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><circle cx="8.5" cy="8.5" r="1.5"></circle><polyline points="21 15 16 10 5 21"></polyline></svg> | |
| High-Res Image | |
| </div> | |
| <div class="dropdown-item" id="opt-document"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg> | |
| Document / Code | |
| </div> | |
| </div> | |
| <!-- Hidden File Inputs --> | |
| <input type="file" id="sys-inp-image" class="stealth-input" accept="image/*"> | |
| <input type="file" id="sys-inp-document" class="stealth-input" accept=".pdf,.doc,.docx,.txt,.md,.csv,.json,.py,.js,.html,.css,.cpp,.c,.java"> | |
| </div> | |
| <!-- Expanding Text Area --> | |
| <textarea class="main-textarea" id="mainChatInput" placeholder="Message CODE VED..." rows="1"></textarea> | |
| <!-- Master Send Button --> | |
| <button class="btn-master-send" id="masterSendBtn"> | |
| <svg viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <div class="bottom-branding-text">Secured by CODE VED Architecture • Developed by DIVY PATEL</div> | |
| </div> | |
| </main> | |
| <!-- C. WORKSPACE CODE EDITOR PANEL WITH PREVIEW --> | |
| <aside class="code-workspace-panel" id="workspacePanel"> | |
| <div class="workspace-header-bar"> | |
| <div class="workspace-tabs"> | |
| <div class="ws-tab active" id="ws-tab-code" onclick="CompilerEngine.switchTab('code')"> | |
| <svg viewBox="0 0 24 24" 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> | |
| Code | |
| </div> | |
| <div class="ws-tab" id="ws-tab-preview" onclick="CompilerEngine.switchTab('preview')"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg> | |
| Preview / Run | |
| </div> | |
| </div> | |
| <div class="workspace-tools"> | |
| <button class="btn-workspace-tool" id="btnWsCopy"> | |
| <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg> | |
| Copy | |
| </button> | |
| <button class="btn-workspace-tool close" id="btnWsClose" title="Close Editor"> | |
| <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Code View --> | |
| <div class="workspace-editor-surface" id="workspaceCodeContainer"> | |
| <pre><code id="workspaceCodeBlock" class="hljs"></code></pre> | |
| </div> | |
| <!-- Preview / Execution View --> | |
| <div class="workspace-preview-surface" id="workspacePreviewContainer"> | |
| <!-- Content injected dynamically --> | |
| </div> | |
| </aside> | |
| </div> | |
| <!-- ========================================================================================= | |
| DOM STRUCTURE: SECURE AUTHENTICATION MODAL | |
| ========================================================================================= --> | |
| <div class="secure-modal-backdrop" id="secureAuthModal"> | |
| <div class="secure-modal-surface"> | |
| <button class="btn-modal-dismiss" id="btnAuthClose"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg> | |
| </button> | |
| <div class="modal-brand-header">CODE VED Network</div> | |
| <div class="auth-tab-switch"> | |
| <div class="auth-tab-item active" id="btn-tab-login">Connect</div> | |
| <div class="auth-tab-item" id="btn-tab-register">Enroll</div> | |
| </div> | |
| <!-- Login Flow --> | |
| <div id="auth-flow-login"> | |
| <div class="auth-form-view active" id="auth-log-phase-1"> | |
| <input type="email" class="auth-input-element" id="authLogEmail" placeholder="Authorized Email Address"> | |
| <button class="btn-auth-execute" id="btn-fire-log-otp">Generate Secure Token (OTP)</button> | |
| </div> | |
| <div class="auth-form-view" id="auth-log-phase-2"> | |
| <input type="number" class="auth-input-element" id="authLogOTP" placeholder="Validation Code (OTP)"> | |
| <button class="btn-auth-execute" id="btn-fire-log-verify">Authenticate Session</button> | |
| <button class="btn-auth-return" id="btnLogBack">← Return</button> | |
| </div> | |
| </div> | |
| <!-- Register Flow --> | |
| <div id="auth-flow-register" style="display:none;"> | |
| <div class="auth-form-view active" id="auth-reg-phase-1"> | |
| <input type="text" class="auth-input-element" id="authRegName" placeholder="Full Legal Name"> | |
| <input type="email" class="auth-input-element" id="authRegEmail" placeholder="Communication Email"> | |
| <button class="btn-auth-execute" id="btn-fire-reg-otp">Verify Identity</button> | |
| </div> | |
| <div class="auth-form-view" id="auth-reg-phase-2"> | |
| <input type="number" class="auth-input-element" id="authRegOTP" placeholder="Identity Token (OTP)"> | |
| <button class="btn-auth-execute" id="btn-fire-reg-verify">Initialize Account</button> | |
| <button class="btn-auth-return" id="btnRegBack">← Return</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ========================================================================================= | |
| [3] MASSIVE ENTERPRISE JAVASCRIPT ARCHITECTURE | |
| ========================================================================================= --> | |
| <script> | |
| // ======================================================================================= | |
| // 1. CONFIGURATION & STATE MANAGEMENT | |
| // ======================================================================================= | |
| const Config = { | |
| GAS_URL: "https://script.google.com/macros/s/AKfycbz5vrlB4GrfkfBVYdQ52IQweIXC1cNDwKuTUorxdAiOdSSIrH55mzJlaz9kq1Y94ot5/exec", | |
| LOGO_URL: "https://i.ibb.co/MxKsrXDj/TIRANGA-20260525-172109-0000.png", | |
| PDF_WORKER: 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js', | |
| API_ENDPOINT: '/api/chat', // Backend AI endpoint | |
| }; | |
| pdfjsLib.GlobalWorkerOptions.workerSrc = Config.PDF_WORKER; | |
| const AppState = { | |
| currentUser: localStorage.getItem('codeved_user') || null, | |
| guestCount: parseInt(localStorage.getItem('codeved_guest') || '0', 10), | |
| history: [], | |
| pendingAttachment: null, | |
| isProcessing: false, | |
| isUserScrolling: false, | |
| generatedCodeBlocks: [], | |
| currentWorkspaceId: null, | |
| isStreamingActive: false | |
| }; | |
| // ======================================================================================= | |
| // 2. UTILITY ENGINE | |
| // ======================================================================================= | |
| const 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" stroke-width="2.5"><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,'>'); | |
| }, | |
| executeFallbackCopy: (text, btnElement) => { | |
| const textArea = document.createElement("textarea"); | |
| textArea.value = text; | |
| 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> Copied Successfully`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| } else { | |
| Utils.showToast("Clipboard access denied by browser."); | |
| } | |
| } catch (err) { | |
| Utils.showToast("System error copying text."); | |
| } | |
| document.body.removeChild(textArea); | |
| }, | |
| copyToClipboard: (btnElement, textToCopy) => { | |
| if (!navigator.clipboard) { | |
| Utils.executeFallbackCopy(textToCopy, btnElement); | |
| return; | |
| } | |
| navigator.clipboard.writeText(textToCopy).then(() => { | |
| const originalHTML = btnElement.innerHTML; | |
| btnElement.innerHTML = `<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"></polyline></svg> Copied Successfully`; | |
| setTimeout(() => { btnElement.innerHTML = originalHTML; }, 2500); | |
| }).catch((err) => { | |
| Utils.executeFallbackCopy(textToCopy, btnElement); | |
| }); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 3. AUTHENTICATION & SYNC MANAGER (WITH BUG FIX FOR HISTORY SYNC) | |
| // ======================================================================================= | |
| const AuthManager = { | |
| initUI: () => { | |
| const promptBtn = document.getElementById('loginPromptBtn'); | |
| const profileCard = document.getElementById('userProfile'); | |
| const guestBadge = document.getElementById('guestBadge'); | |
| if (AppState.currentUser) { | |
| promptBtn.style.display = 'none'; | |
| profileCard.style.display = 'flex'; | |
| document.getElementById('uEmail').innerText = AppState.currentUser; | |
| document.getElementById('uAvatar').innerText = AppState.currentUser.charAt(0).toUpperCase(); | |
| if(guestBadge) guestBadge.style.display = 'none'; | |
| } else { | |
| promptBtn.style.display = 'flex'; | |
| profileCard.style.display = 'none'; | |
| if(guestBadge) { | |
| guestBadge.style.display = 'inline-flex'; | |
| document.getElementById('guestCountDisplay').innerText = AppState.guestCount; | |
| } | |
| } | |
| }, | |
| openModal: () => { document.getElementById('secureAuthModal').style.display = 'flex'; }, | |
| closeModal: () => { document.getElementById('secureAuthModal').style.display = 'none'; }, | |
| switchTab: (tabName) => { | |
| document.querySelectorAll('.auth-tab-item').forEach(el => el.classList.remove('active')); | |
| document.getElementById(tabName === 'login' ? 'btn-tab-login' : 'btn-tab-register').classList.add('active'); | |
| document.getElementById('auth-flow-login').style.display = tabName === 'login' ? 'block' : 'none'; | |
| document.getElementById('auth-flow-register').style.display = tabName === 'register' ? 'block' : 'none'; | |
| }, | |
| switchPhase: (currentId, nextId) => { | |
| document.getElementById(currentId).classList.remove('active'); | |
| document.getElementById(nextId).classList.add('active'); | |
| }, | |
| process: async (actionType) => { | |
| 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 = "CODE VED Base"; | |
| if (!payload.email || !payload.name) return 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 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 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', | |
| mode: 'cors', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify(payload) | |
| }); | |
| const result = await response.json(); | |
| if (result.status === 'success') { | |
| Utils.showToast(result.message); | |
| if (actionType === 'register_send_otp') AuthManager.switchPhase('auth-reg-phase-1', 'auth-reg-phase-2'); | |
| else if (actionType === 'login_send_otp') AuthManager.switchPhase('auth-log-phase-1', 'auth-log-phase-2'); | |
| else if (actionType === 'register_verify' || actionType === 'login_verify') { | |
| AppState.currentUser = payload.email; | |
| localStorage.setItem('codeved_user', AppState.currentUser); | |
| AuthManager.closeModal(); | |
| AuthManager.initUI(); | |
| ChatEngine.syncHistoryFromCloud(); // Safely calls the fixed function | |
| } | |
| } else { | |
| Utils.showToast(result.message); | |
| } | |
| } catch (error) { | |
| console.error("Auth Error:", error); | |
| Utils.showToast("Encrypted gateway error. Check network."); | |
| } | |
| triggerBtn.disabled = false; | |
| triggerBtn.innerHTML = originalText; | |
| }, | |
| logout: () => { | |
| localStorage.removeItem('codeved_user'); | |
| location.reload(); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 4. UI & DOM MANAGER | |
| // ======================================================================================= | |
| const UIManager = { | |
| toggleSidebar: () => { document.getElementById('sidebar').classList.toggle('active'); }, | |
| checkScrollState: () => { | |
| const msgArea = document.getElementById('msgs'); | |
| const isAtBottom = Math.abs((msgArea.scrollHeight - msgArea.scrollTop) - msgArea.clientHeight) < 80; | |
| AppState.isUserScrolling = !isAtBottom; | |
| const scrollBtn = document.getElementById('scrollTriggerBtn'); | |
| if (AppState.isUserScrolling) scrollBtn.classList.add('visible'); | |
| else scrollBtn.classList.remove('visible'); | |
| }, | |
| forceScrollDown: () => { | |
| const msgArea = document.getElementById('msgs'); | |
| msgArea.scrollTo({ top: msgArea.scrollHeight, behavior: 'smooth' }); | |
| AppState.isUserScrolling = false; | |
| document.getElementById('scrollTriggerBtn').classList.remove('visible'); | |
| }, | |
| autoScroll: () => { | |
| if (!AppState.isUserScrolling) { | |
| const msgArea = document.getElementById('msgs'); | |
| msgArea.scrollTop = msgArea.scrollHeight; | |
| } | |
| }, | |
| autoGrowTextArea: (element) => { | |
| element.style.height = 'auto'; | |
| element.style.height = Math.min(element.scrollHeight, 200) + 'px'; | |
| }, | |
| toggleAttachMenu: () => { | |
| document.getElementById('attachDropdownMenu').classList.toggle('visible'); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 5. FILE PROCESSOR | |
| // ======================================================================================= | |
| const FileProcessor = { | |
| triggerFileSelector: (type) => { | |
| document.getElementById('attachDropdownMenu').classList.remove('visible'); | |
| document.getElementById('sys-inp-' + type).click(); | |
| }, | |
| processFile: async (inputElement, typeContext) => { | |
| const file = inputElement.files[0]; | |
| if (!file) return; | |
| const fName = file.name.toLowerCase(); | |
| const mime = file.type; | |
| if (typeContext === 'image' && !mime.startsWith('image/')) { Utils.showToast("Visual media required."); inputElement.value=''; return; } | |
| if (typeContext === 'document' && !fName.endsWith('.pdf') && !fName.endsWith('.doc') && !fName.endsWith('.docx') && !fName.endsWith('.txt') && !fName.endsWith('.py') && !fName.endsWith('.js') && !fName.endsWith('.html')) { Utils.showToast("Document/Code format required."); inputElement.value=''; return; } | |
| Utils.showToast(`Uploading your file...`); | |
| const thumbImg = document.getElementById('previewImgThumb'); | |
| const docIcon = document.getElementById('previewDocIcon'); | |
| thumbImg.style.display = 'none'; | |
| docIcon.style.display = 'none'; | |
| document.getElementById('previewFileName').innerText = file.name; | |
| document.getElementById('filePreviewBar').classList.add('visible'); | |
| const fileReader = new FileReader(); | |
| if (typeContext === 'image') { | |
| fileReader.onload = (e) => { | |
| AppState.pendingAttachment = { type: 'image', data: e.target.result.split(',')[1], name: file.name }; | |
| thumbImg.src = e.target.result; | |
| thumbImg.style.display = 'flex'; | |
| }; | |
| fileReader.readAsDataURL(file); | |
| } | |
| else if (typeContext === 'document') { | |
| docIcon.innerText = '📄'; | |
| docIcon.style.display = 'flex'; | |
| if (fName.endsWith('.pdf')) { | |
| fileReader.onload = async function() { | |
| try { | |
| const typedArray = new Uint8Array(this.result); | |
| const pdfDoc = await pdfjsLib.getDocument(typedArray).promise; | |
| let extractedText = ""; | |
| for (let i = 1; i <= pdfDoc.numPages; i++) { | |
| const page = await pdfDoc.getPage(i); | |
| const content = await page.getTextContent(); | |
| extractedText += content.items.map(s => s.str).join(' ') + "\n"; | |
| } | |
| AppState.pendingAttachment = { type: 'text', data: extractedText.trim() || "No readable text found.", name: file.name }; | |
| Utils.showToast("Your PDF is ready!"); | |
| } catch (e) { | |
| Utils.showToast("PDF parsing encountered an error."); | |
| FileProcessor.discardFile(); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(file); | |
| } | |
| else if (fName.endsWith('.docx') || fName.endsWith('.doc')) { | |
| fileReader.onload = async function() { | |
| try { | |
| const buffer = this.result; | |
| const resultData = await mammoth.extractRawText({ arrayBuffer: buffer }); | |
| AppState.pendingAttachment = { type: 'text', data: resultData.value.trim() || "No readable text found.", name: file.name }; | |
| Utils.showToast("Your Word document is ready!"); | |
| } catch(e) { | |
| Utils.showToast("Document parsing encountered an error."); | |
| FileProcessor.discardFile(); | |
| } | |
| }; | |
| fileReader.readAsArrayBuffer(file); | |
| } | |
| else { | |
| fileReader.onload = (e) => { | |
| AppState.pendingAttachment = { type: 'text', data: e.target.result, name: file.name }; | |
| Utils.showToast("Your Code file is ready!"); | |
| }; | |
| fileReader.readAsText(file); | |
| } | |
| } | |
| document.querySelectorAll('.stealth-input').forEach(i => i.value = ''); | |
| }, | |
| discardFile: () => { | |
| AppState.pendingAttachment = null; | |
| document.getElementById('filePreviewBar').classList.remove('visible'); | |
| document.querySelectorAll('.stealth-input').forEach(i => i.value = ''); | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 6. COMPILER & WORKSPACE ENGINE (NEW PREVIEW / CODE LOGIC) | |
| // ======================================================================================= | |
| const CompilerEngine = { | |
| currentMode: 'code', | |
| switchTab: (mode) => { | |
| CompilerEngine.currentMode = mode; | |
| document.getElementById('ws-tab-code').classList.remove('active'); | |
| document.getElementById('ws-tab-preview').classList.remove('active'); | |
| document.getElementById(`ws-tab-${mode}`).classList.add('active'); | |
| document.getElementById('workspaceCodeContainer').style.display = mode === 'code' ? 'block' : 'none'; | |
| document.getElementById('workspacePreviewContainer').style.display = mode === 'preview' ? 'flex' : 'none'; | |
| if (mode === 'preview') { | |
| CompilerEngine.executeCurrentCode(); | |
| } | |
| }, | |
| executeCurrentCode: async () => { | |
| const previewContainer = document.getElementById('workspacePreviewContainer'); | |
| if (AppState.currentWorkspaceId === null) return; | |
| const codeData = AppState.generatedCodeBlocks[AppState.currentWorkspaceId]; | |
| const lang = (codeData.lang || 'plaintext').toLowerCase(); | |
| const code = codeData.code; | |
| previewContainer.innerHTML = '<div class="compiling-loader">Compiling execution context...</div>'; | |
| // Web Based Languages Render in Iframe | |
| if (['html', 'xml', 'javascript', 'js', 'css'].includes(lang)) { | |
| let finalHTML = code; | |
| if (lang === 'javascript' || lang === 'js') finalHTML = `<script>${code}<\/script>`; | |
| if (lang === 'css') finalHTML = `<style>${code}</style><div style="padding:20px; color:#fff; font-family:sans-serif;">CSS Ready. Render HTML to see effect.</div>`; | |
| const iframe = document.createElement('iframe'); | |
| iframe.style.width = '100%'; | |
| iframe.style.height = '100%'; | |
| iframe.style.border = 'none'; | |
| iframe.style.background = '#ffffff'; | |
| previewContainer.innerHTML = ''; | |
| previewContainer.appendChild(iframe); | |
| iframe.contentWindow.document.open(); | |
| iframe.contentWindow.document.write(finalHTML); | |
| iframe.contentWindow.document.close(); | |
| return; | |
| } | |
| // Backend Languages executed via Piston API | |
| const pistonLangs = { | |
| 'python': 'python', 'py': 'python', | |
| 'c': 'c', 'cpp': 'c++', 'c++': 'c++', | |
| 'java': 'java', 'rust': 'rust', | |
| 'go': 'go', 'php': 'php', 'ruby': 'ruby', | |
| 'typescript': 'typescript', 'ts': 'typescript', | |
| 'swift': 'swift', 'csharp': 'csharp', 'cs': 'csharp' | |
| }; | |
| const runLang = pistonLangs[lang]; | |
| if (!runLang) { | |
| previewContainer.innerHTML = `<div class="console-output error">Cannot execute language: ${lang || 'Unknown'}. Live Preview not supported.</div>`; | |
| return; | |
| } | |
| try { | |
| const res = await fetch('https://emkc.org/api/v2/piston/execute', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ | |
| language: runLang, | |
| version: "*", | |
| files: [{ content: code }] | |
| }) | |
| }); | |
| const data = await res.json(); | |
| let output = ""; | |
| if (data.compile && data.compile.output) output += data.compile.output + "\n"; | |
| if (data.run && data.run.output) output += data.run.output; | |
| if (data.run && data.run.stderr) output += "\n" + data.run.stderr; | |
| if (!output.trim()) output = `[Process finished with exit code 0 - No Output generated]`; | |
| previewContainer.innerHTML = `<pre class="console-output">${Utils.escapeHTML(output)}</pre>`; | |
| } catch (e) { | |
| previewContainer.innerHTML = `<div class="console-output error">Compiler Error: Could not connect to remote execution server. Check internet connection.</div>`; | |
| } | |
| }, | |
| launch: (codeBlockId) => { | |
| AppState.currentWorkspaceId = codeBlockId; | |
| const codeData = AppState.generatedCodeBlocks[codeBlockId]; | |
| 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'); | |
| // Always reset to code tab when opening a new workspace | |
| CompilerEngine.switchTab('code'); | |
| if (window.innerWidth <= 1024) { | |
| document.getElementById('sidebar').classList.remove('active'); | |
| } | |
| }, | |
| closePanel: () => { document.getElementById('workspacePanel').classList.remove('expanded'); }, | |
| executeCopy: (btnElement) => { | |
| if (AppState.currentWorkspaceId !== null) { | |
| const srcCode = AppState.generatedCodeBlocks[AppState.currentWorkspaceId].code; | |
| Utils.copyToClipboard(btnElement, srcCode); | |
| } | |
| } | |
| }; | |
| const MD_Renderer = new marked.Renderer(); | |
| MD_Renderer.code = function(token) { | |
| const rawCode = typeof token === 'string' ? token : (token.text || ''); | |
| const langClass = typeof token === 'string' ? arguments[1] : (token.lang || ''); | |
| if (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}">${Utils.escapeHTML(rawCode)}</code></pre> | |
| </div>`; | |
| } | |
| const internalId = AppState.generatedCodeBlocks.length; | |
| AppState.generatedCodeBlocks.push({ code: rawCode, lang: langClass }); | |
| return ` | |
| <div class="workspace-execute-card"> | |
| <div class="ws-card-left"> | |
| <div class="ws-card-icon-box"> | |
| <svg viewBox="0 0 24 24" width="28" height="28" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="16 18 22 12 16 6"></polyline><polyline points="8 6 2 12 8 18"></polyline></svg> | |
| </div> | |
| <div class="ws-card-details"> | |
| <h4>Code Module Compiled</h4> | |
| <p>${langClass || 'Syntax Detected'}</p> | |
| </div> | |
| </div> | |
| <button class="btn-launch-workspace btn-launch-ws" data-id="${internalId}">Open Workspace</button> | |
| </div>`; | |
| }; | |
| marked.use({ renderer: MD_Renderer }); | |
| document.getElementById('msgs').addEventListener('click', function(e) { | |
| if (e.target && e.target.classList.contains('btn-launch-ws')) { | |
| const blockId = e.target.getAttribute('data-id'); | |
| CompilerEngine.launch(blockId); | |
| } | |
| }); | |
| // ======================================================================================= | |
| // 7. CORE CHAT ENGINE & LLM (WITH ROCK SOLID BUG FIXES) | |
| // ======================================================================================= | |
| const ChatEngine = { | |
| handleKeyboard: (e) => { | |
| if (e.key === 'Enter' && !e.shiftKey) { | |
| e.preventDefault(); | |
| ChatEngine.initiateDispatch(); | |
| } | |
| }, | |
| sendExample: (queryText) => { | |
| document.getElementById('mainChatInput').value = queryText; | |
| ChatEngine.initiateDispatch(); | |
| }, | |
| clearMemory: async () => { | |
| if (AppState.currentUser) { | |
| Utils.showToast("Purging neural link memory..."); | |
| try { | |
| await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify({ action: "delete_history", email: AppState.currentUser }) | |
| }); | |
| } catch(e) {} | |
| } | |
| 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(--brand-saffron); font-size:18px;">Decrypting Historic Archives...</div>'; | |
| try { | |
| const response = await fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify({ action: "get_history", email: AppState.currentUser }) | |
| }); | |
| const resData = await response.json(); | |
| messageZone.innerHTML = ''; | |
| if (resData.status === 'success' && resData.historyJSON !== "[]") { | |
| AppState.history = JSON.parse(resData.historyJSON); | |
| AppState.history.forEach(msgObj => { | |
| if (msgObj.role === 'user') { | |
| ChatEngine.renderUserMessage(msgObj.content, msgObj.badge, msgObj.previewHTML); | |
| } else { | |
| AppState.isStreamingActive = false; | |
| ChatEngine.renderBotMessage(msgObj.content, true); | |
| } | |
| }); | |
| setTimeout(UIManager.forceScrollDown, 150); | |
| } else { | |
| document.getElementById('welcomeState').style.display = 'flex'; | |
| } | |
| } catch (err) { | |
| console.error("History Sync Failed:", err); | |
| messageZone.innerHTML = ''; | |
| document.getElementById('welcomeState').style.display = 'flex'; | |
| } | |
| }, | |
| saveHistoryToCloud: () => { | |
| if (AppState.currentUser) { | |
| try { | |
| fetch(Config.GAS_URL, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'text/plain;charset=utf-8' }, | |
| body: JSON.stringify({ action: "save_history", email: AppState.currentUser, historyJSON: JSON.stringify(AppState.history) }) | |
| }).catch(e => console.warn("Background Save Failed")); | |
| } catch(err) {} | |
| } | |
| }, | |
| 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 === 'document') { | |
| return `<div class="chat-file-card"><div class="icon"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg></div><span class="name">${attachmentObj.name}</span></div>`; | |
| } | |
| return ''; | |
| }, | |
| renderUserMessage: (textContent, badgeText, previewHTMLString = '') => { | |
| let badgeNode = badgeText ? `<div class="file-badge"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"></path></svg> ${Utils.escapeHTML(badgeText)}</div>` : ''; | |
| let visibleText = textContent; | |
| if(textContent.includes('---DATA BEGIN---')) { | |
| const parts = textContent.split('User Prompt:'); | |
| if(parts.length > 1) visibleText = parts[1].trim(); | |
| } | |
| const bubbleBox = document.createElement('div'); | |
| bubbleBox.className = 'chat-message-row user-msg'; | |
| bubbleBox.innerHTML = ` | |
| <div class="msg-avatar">U</div> | |
| <div class="msg-content-column"> | |
| ${badgeNode} | |
| <div class="chat-bubble"> | |
| ${previewHTMLString} | |
| ${Utils.escapeHTML(visibleText)} | |
| </div> | |
| </div>`; | |
| document.getElementById('msgs').appendChild(bubbleBox); | |
| }, | |
| renderBotMessage: (textContent, bypassStreamFormatting = false, isError = 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 ${isError ? 'error-bubble' : ''}"></div> | |
| </div>`; | |
| document.getElementById('msgs').appendChild(bubbleBox); | |
| 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 && !contentTarget.classList.contains('error-bubble')) { | |
| const safeRawCopy = strippedMarkup.replace(/"/g, '"').replace(/'/g, "\\'").replace(/\n/g, '\\n').replace(/\r/g, ''); | |
| const actionsHTML = ` | |
| <div class="bot-actions-row"> | |
| <button class="btn-bot-action btn-cpy-action" data-cpy="${safeRawCopy}"> | |
| <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg> | |
| Copy Data | |
| </button> | |
| </div>`; | |
| bubbleDOM.querySelector('.msg-content-column').insertAdjacentHTML('beforeend', actionsHTML); | |
| bubbleDOM.querySelector('.btn-cpy-action').addEventListener('click', function() { Utils.copyToClipboard(this, this.getAttribute('data-cpy')); }); | |
| } | |
| }, | |
| initiateDispatch: async () => { | |
| if (AppState.isProcessing) return; | |
| const inputField = document.getElementById('mainChatInput'); | |
| const rawUserText = inputField.value.trim(); | |
| if (!rawUserText && !AppState.pendingAttachment) return; | |
| if (!AppState.currentUser) { | |
| if (AppState.guestCount >= 3) { | |
| AuthManager.openModal(); | |
| return Utils.showToast("Query limit reached. Secure Login required."); | |
| } | |
| AppState.guestCount++; | |
| localStorage.setItem('codeved_guest', AppState.guestCount.toString()); | |
| document.getElementById('guestCountDisplay').innerText = AppState.guestCount; | |
| } | |
| inputField.value = ''; | |
| inputField.style.height = 'auto'; | |
| document.getElementById('masterSendBtn').disabled = true; | |
| AppState.isProcessing = true; | |
| const wState = document.getElementById('welcomeState'); | |
| if (wState) wState.style.display = 'none'; | |
| let payloadStr = rawUserText; | |
| let historyStr = rawUserText; | |
| let payloadAttachments = []; | |
| let visualBadge = null; | |
| let previewHTMLForChat = ''; | |
| if (AppState.pendingAttachment) { | |
| previewHTMLForChat = ChatEngine.buildPreviewHTML(AppState.pendingAttachment); | |
| if (AppState.pendingAttachment.type === 'text') { | |
| payloadStr = `[Document Analyzed: ${AppState.pendingAttachment.name}]\n\n---DATA BEGIN---\n${AppState.pendingAttachment.data}\n---DATA END---\n\nUser Prompt: ${rawUserText}`; | |
| historyStr = `[Document previously attached: ${AppState.pendingAttachment.name}]\nUser Prompt: ${rawUserText}`; | |
| visualBadge = 'File Appended'; | |
| } else { | |
| payloadAttachments.push({ | |
| type: AppState.pendingAttachment.type, | |
| data: AppState.pendingAttachment.data, | |
| name: AppState.pendingAttachment.name | |
| }); | |
| visualBadge = "Media Appended"; | |
| } | |
| ChatEngine.renderUserMessage(rawUserText || '[Transmitting Media Context]', visualBadge, previewHTMLForChat); | |
| AppState.history.push({ role: 'user', content: historyStr, badge: visualBadge, previewHTML: previewHTMLForChat }); | |
| } else { | |
| ChatEngine.renderUserMessage(rawUserText, null, ''); | |
| AppState.history.push({ role: 'user', content: rawUserText }); | |
| } | |
| FileProcessor.discardFile(); | |
| ChatEngine.saveHistoryToCloud(); | |
| const activeBotBubble = ChatEngine.renderBotMessage('', false); | |
| UIManager.forceScrollDown(); | |
| const cryptographicSeed = Math.floor(Math.random() * 999999999); | |
| let cognitivePrompt = `You are CODE VED, a sophisticated premium enterprise AI system engineered by DIVY PATEL. | |
| LANGUAGE REGULATION: Your default cognitive language is ENGLISH. If the user writes in English, reply in purely professional English. If the user writes in Hindi or Hinglish, reply gracefully in Hindi. Never force Hindi translation if the prompt is English.`; | |
| // BUG FIX: Strictly mapping history roles to 'assistant' to prevent backend crashes | |
| const secureHistory = AppState.history.slice(0, -1).map(h => ({ | |
| role: h.role === 'bot' ? 'assistant' : h.role, | |
| content: h.content | |
| })); | |
| const transmissionPayload = { | |
| message: payloadStr, | |
| attachments: payloadAttachments, | |
| system_prompt: cognitivePrompt, | |
| history: secureHistory, | |
| max_tokens: 4096, | |
| temperature: 0.75 | |
| }; | |
| try { | |
| const fetchOp = await fetch(Config.API_ENDPOINT, { | |
| method: 'POST', | |
| headers: {'Content-Type': 'application/json'}, | |
| body: JSON.stringify(transmissionPayload) | |
| }); | |
| if (!fetchOp.ok) { | |
| throw new Error(`API Disconnected (Status: ${fetchOp.status})`); | |
| } | |
| const networkReader = fetchOp.body.getReader(); | |
| const textDecoder = new TextDecoder(); | |
| let responseBuffer = ""; | |
| let streamChunkBuffer = ""; | |
| AppState.isStreamingActive = true; | |
| while (true) { | |
| const { done, value } = await networkReader.read(); | |
| if (done) break; | |
| streamChunkBuffer += textDecoder.decode(value, { stream: true }); | |
| const fragmentedLines = streamChunkBuffer.split('\n'); | |
| streamChunkBuffer = fragmentedLines.pop(); | |
| for (let line of fragmentedLines) { | |
| line = line.trim(); | |
| if(!line) continue; | |
| if (line.startsWith('data: ')) { | |
| const parseableStr = line.substring(6).trim(); | |
| if (parseableStr === '[DONE]') continue; | |
| try { | |
| const jsonSegment = JSON.parse(parseableStr); | |
| if (jsonSegment.choices && jsonSegment.choices[0].delta && jsonSegment.choices[0].delta.content) { | |
| responseBuffer += jsonSegment.choices[0].delta.content; | |
| ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true); | |
| UIManager.autoScroll(); | |
| } else if (jsonSegment.response) { // Ollama API fallback compatibility | |
| responseBuffer += jsonSegment.response; | |
| ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, true); | |
| UIManager.autoScroll(); | |
| } | |
| } catch (e) { } | |
| } | |
| } | |
| } | |
| // BUG FIX: Handle completely empty responses gracefully | |
| if (!responseBuffer.trim()) { | |
| throw new Error("Received an empty neural transmission."); | |
| } | |
| AppState.isStreamingActive = false; | |
| ChatEngine.updateBotBubble(activeBotBubble, responseBuffer, false); | |
| AppState.history.push({ role: 'bot', content: responseBuffer }); | |
| ChatEngine.saveHistoryToCloud(); | |
| } catch(error) { | |
| console.error("AI Dispatch Error:", error); | |
| AppState.isStreamingActive = false; | |
| // Show actual error in the bubble instead of leaving it empty | |
| activeBotBubble.querySelector('.chat-bubble').classList.add('error-bubble'); | |
| ChatEngine.updateBotBubble(activeBotBubble, `**System Error:** Communication array offline. Verification needed. (${error.message})`, false); | |
| } finally { | |
| AppState.isProcessing = false; | |
| document.getElementById('masterSendBtn').disabled = false; | |
| UIManager.autoScroll(); | |
| } | |
| } | |
| }; | |
| // ======================================================================================= | |
| // 8. EVENT DELEGATION & BOOTSTRAP INVOCATION | |
| // ======================================================================================= | |
| window.startCODEVEDApp = function() { | |
| document.getElementById('welcomeOverlay').classList.add('hidden'); | |
| localStorage.setItem('codeved_welcome_seen', 'true'); | |
| setTimeout(() => { document.getElementById('welcomeOverlay').style.display = 'none'; }, 400); | |
| }; | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Sidebar Controls | |
| document.getElementById('btnSidebarOpen')?.addEventListener('click', UIManager.toggleSidebar); | |
| document.getElementById('btnSidebarClose')?.addEventListener('click', UIManager.toggleSidebar); | |
| document.getElementById('btnLaunchSystem')?.addEventListener('click', window.startCODEVEDApp); | |
| // Auth Flow Controls | |
| document.getElementById('loginPromptBtn')?.addEventListener('click', AuthManager.openModal); | |
| document.getElementById('btnAuthClose')?.addEventListener('click', AuthManager.closeModal); | |
| document.getElementById('btn-tab-login')?.addEventListener('click', () => AuthManager.switchTab('login')); | |
| document.getElementById('btn-tab-register')?.addEventListener('click', () => AuthManager.switchTab('register')); | |
| document.getElementById('btn-fire-log-otp')?.addEventListener('click', () => AuthManager.process('login_send_otp')); | |
| document.getElementById('btn-fire-log-verify')?.addEventListener('click', () => AuthManager.process('login_verify')); | |
| document.getElementById('btn-fire-reg-otp')?.addEventListener('click', () => AuthManager.process('register_send_otp')); | |
| document.getElementById('btn-fire-reg-verify')?.addEventListener('click', () => AuthManager.process('register_verify')); | |
| document.getElementById('btnLogBack')?.addEventListener('click', () => AuthManager.switchPhase('auth-log-phase-2', 'auth-log-phase-1')); | |
| document.getElementById('btnRegBack')?.addEventListener('click', () => AuthManager.switchPhase('auth-reg-phase-2', 'auth-reg-phase-1')); | |
| document.getElementById('btnLogout')?.addEventListener('click', AuthManager.logout); | |
| document.getElementById('btnClearMemory')?.addEventListener('click', ChatEngine.clearMemory); | |
| // File Attachment Routing | |
| document.getElementById('btnAttachMenuToggle')?.addEventListener('click', UIManager.toggleAttachMenu); | |
| document.getElementById('attachDropdownMenu')?.addEventListener('click', (e) => { | |
| const target = e.target.closest('.dropdown-item'); | |
| if(!target) return; | |
| if(target.id === 'opt-image') FileProcessor.triggerFileSelector('image'); | |
| if(target.id === 'opt-document') FileProcessor.triggerFileSelector('document'); | |
| }); | |
| document.getElementById('sys-inp-image')?.addEventListener('change', function() { FileProcessor.processFile(this, 'image'); }); | |
| document.getElementById('sys-inp-document')?.addEventListener('change', function() { FileProcessor.processFile(this, 'document'); }); | |
| document.getElementById('btnDiscardFile')?.addEventListener('click', FileProcessor.discardFile); | |
| // Primary Message Controls | |
| document.getElementById('masterSendBtn')?.addEventListener('click', ChatEngine.initiateDispatch); | |
| document.getElementById('mainChatInput')?.addEventListener('keydown', ChatEngine.handleKeyboard); | |
| document.getElementById('mainChatInput')?.addEventListener('input', function() { UIManager.autoGrowTextArea(this); }); | |
| // Example Prompt Controls | |
| document.getElementById('suggCodeBtn')?.addEventListener('click', () => ChatEngine.sendExample('Write a secure python script for a modern Flask backend server.')); | |
| document.getElementById('suggImgBtn')?.addEventListener('click', () => ChatEngine.sendExample('Create a hyper-realistic 8k image of a futuristic Indian smart city.')); | |
| // Workspace Logic Hooks | |
| document.getElementById('btnWsClose')?.addEventListener('click', CompilerEngine.closePanel); | |
| document.getElementById('btnWsCopy')?.addEventListener('click', function() { CompilerEngine.executeCopy(this); }); | |
| // Interaction Scroll Listeners | |
| document.getElementById('msgs')?.addEventListener('scroll', UIManager.checkScrollState); | |
| document.getElementById('scrollTriggerBtn')?.addEventListener('click', UIManager.forceScrollDown); | |
| // Ensure startup screen displays if memory cleared | |
| if(!localStorage.getItem('codeved_welcome_seen')) { | |
| const overlay = document.getElementById('welcomeOverlay'); | |
| if(overlay) overlay.style.display = 'flex'; | |
| } else { | |
| const overlay = document.getElementById('welcomeOverlay'); | |
| if(overlay) overlay.style.display = 'none'; | |
| } | |
| // Fire Boot Processes | |
| AuthManager.initUI(); | |
| if(AppState.currentUser) { ChatEngine.syncHistoryFromCloud(); } | |
| }); | |
| </script> | |
| </body> | |
| </html> | |