Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"/> | |
| <title>DeepShell Chat</title> | |
| <!-- Optional: Prism for code highlighting inside responses --> | |
| <link rel="stylesheet" id="prism-theme" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" /> | |
| <link rel="stylesheet" id="prism-light-theme" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css" disabled /> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-bash.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-python.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-docker.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-yaml.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-hcl.min.js"></script> | |
| <!-- Optional: marked for Markdown rendering --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/12.0.2/marked.min.js"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg: #0a0a0a; | |
| --panel: #161616; | |
| --border: #2a2a2a; | |
| --text: #e0e0e0; | |
| --muted: #888888; | |
| --accent: #00a832; | |
| --accent-2: #0e7a9a; | |
| } | |
| :root.light { | |
| --bg: #f8fafc; | |
| --panel: #ffffff; | |
| --border: #e2e8f0; | |
| --text: #1e293b; | |
| --muted: #64748b; | |
| --accent: #16a34a; | |
| --accent-2: #2563eb; | |
| } | |
| * { transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease; } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: 'JetBrains Mono', 'Courier New', monospace; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| padding: 24px 40px; | |
| } | |
| header { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| margin-bottom: 16px; | |
| } | |
| .brand { | |
| font-weight: 700; | |
| font-size: 18px; | |
| letter-spacing: 1px; | |
| font-family: 'Courier New', monospace; | |
| color: var(--accent); | |
| text-shadow: 0 0 10px #00ff4155; | |
| } | |
| .status { | |
| font-size: 13px; | |
| color: var(--muted); | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| } | |
| .status-dot { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: #ef4444; | |
| display: inline-block; | |
| } | |
| .status-dot.ok { | |
| background: #00a832; | |
| box-shadow: none; | |
| } | |
| .header-btn { | |
| padding: 6px 12px; | |
| font-size: 12px; | |
| background: var(--panel); | |
| color: var(--text); | |
| border: 1px solid var(--border); | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.2s; | |
| } | |
| .theme-btn { | |
| padding: 4px 10px; | |
| font-size: 13px; | |
| background: var(--panel); | |
| color: var(--muted); | |
| border: 1px solid var(--border); | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.2s; | |
| } | |
| .theme-btn:hover { | |
| background: var(--border); | |
| color: var(--text); | |
| } | |
| .tts-btn { | |
| padding: 4px 12px; | |
| font-size: 12px; | |
| background: #1a1a1a; | |
| color: #aaaaaa; | |
| border: 1px solid #333333; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| font-family: 'JetBrains Mono', monospace; | |
| transition: all 0.2s; | |
| } | |
| .tts-btn.tts-active { | |
| background: #22c55e; | |
| color: white; | |
| border-color: #16a34a; | |
| box-shadow: 0 0 8px #22c55e55; | |
| } | |
| .mode-toggle { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| background: transparent; | |
| border: none; | |
| padding: 0; | |
| } | |
| .mode-btn { | |
| padding: 5px 14px; | |
| font-size: 12px; | |
| border: 1px solid #333333; | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| font-family: 'JetBrains Mono', monospace; | |
| transition: all 0.2s; | |
| background: #1a1a1a; | |
| color: #aaaaaa; | |
| letter-spacing: 0.5px; | |
| } | |
| .mode-btn:hover { | |
| color: var(--accent); | |
| border-color: var(--accent); | |
| } | |
| .mode-btn.active { | |
| background: #00a832; | |
| color: #000000; | |
| box-shadow: none; | |
| } | |
| .mode-btn.trainer-active { | |
| background: #f59e0b; | |
| color: white; | |
| } | |
| .header-btn:hover { | |
| background: #334155; | |
| border-color: #475569; | |
| transform: translateY(-1px); | |
| } | |
| .panel { | |
| background: var(--panel); | |
| border: 1px solid var(--border); | |
| border-radius: 10px; | |
| padding: 12px; | |
| } | |
| #chat-output { | |
| height: 70vh; | |
| overflow-y: auto; | |
| padding: 16px; | |
| background: var(--bg); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| } | |
| .message { | |
| margin: 12px 0; | |
| padding: 14px 18px; | |
| background: var(--panel); | |
| border: 1px solid var(--border); | |
| border-radius: 10px; | |
| line-height: 1.7; | |
| font-size: 15px; | |
| } | |
| .message.user-msg { | |
| background: var(--panel); | |
| border-color: #1e2a3a; | |
| border-left: 2px solid #1e3a5a; | |
| } | |
| .message strong { | |
| display: inline-block; | |
| color: #00a832; | |
| margin-bottom: 6px; | |
| } | |
| .message.error { | |
| border-color: #ef4444; | |
| background: var(--bg); | |
| } | |
| .message.error strong { | |
| color: #ef4444; | |
| } | |
| .message.loading { | |
| border-color: #f59e0b; | |
| background: var(--bg); | |
| } | |
| .message.loading strong { | |
| color: #f59e0b; | |
| } | |
| pre { | |
| margin: 6px 0 0; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| } | |
| .composer { | |
| margin-top: 16px; | |
| display: grid; | |
| grid-template-columns: 1fr auto; | |
| gap: 12px; | |
| align-items: start; | |
| } | |
| #chat-input { | |
| width: 100%; | |
| resize: vertical; | |
| min-height: 80px; | |
| max-height: 240px; | |
| padding: 14px 16px; | |
| border-radius: 10px; | |
| border: 1px solid var(--border); | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: inherit; | |
| font-size: 15px; | |
| } | |
| #chat-input:focus { | |
| outline: none; | |
| border-color: #1e3a4a; | |
| box-shadow: none; | |
| } | |
| #chat-send { | |
| height: 40px; | |
| padding: 0 20px; | |
| border: 1px solid var(--accent); | |
| background: transparent; | |
| color: var(--accent); | |
| border-radius: 4px; | |
| cursor: pointer; | |
| font-weight: 700; | |
| font-family: 'Courier New', monospace; | |
| transition: all 0.2s; | |
| letter-spacing: 1px; | |
| } | |
| #chat-send:hover:not(:disabled) { | |
| background: #00a832; | |
| color: #000000; | |
| box-shadow: none; | |
| } | |
| #chat-send:hover:not(:disabled) { | |
| border-color: #334155; | |
| } | |
| #chat-send:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| background: #1a1a1a; | |
| } | |
| .hint { | |
| margin-top: 8px; | |
| color: var(--muted); | |
| font-size: 12px; | |
| } | |
| a { color: var(--accent); text-decoration: none; } | |
| a:hover { text-decoration: underline; } | |
| /* Copy button styles */ | |
| .code-wrapper { | |
| position: relative; | |
| margin: 6px 0 0; | |
| } | |
| .copy-btn { | |
| position: absolute; | |
| top: 8px; | |
| right: 8px; | |
| padding: 4px 10px; | |
| font-size: 11px; | |
| background: var(--panel); | |
| color: var(--text); | |
| border: 1px solid var(--border); | |
| border-radius: 4px; | |
| cursor: pointer; | |
| z-index: 10; | |
| font-weight: 600; | |
| } | |
| .copy-btn:hover { | |
| background: #334155; | |
| border-color: #475569; | |
| } | |
| /* Loading spinner */ | |
| .spinner { | |
| display: inline-block; | |
| width: 12px; | |
| height: 12px; | |
| border: 2px solid var(--border); | |
| border-top-color: var(--accent); | |
| border-radius: 50%; | |
| animation: spin 0.8s linear infinite; | |
| margin-left: 8px; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| } | |
| /* Command execution styles */ | |
| .command-wrapper { | |
| margin: 10px 0; | |
| background: var(--bg); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| padding: 12px; | |
| } | |
| .command-block { | |
| background: var(--panel); | |
| padding: 12px; | |
| border-radius: 6px; | |
| margin: 0 0 8px 0; | |
| font-family: 'Courier New', monospace; | |
| color: #22c55e; | |
| border-left: 3px solid #22c55e; | |
| } | |
| .command-buttons { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .execute-btn { | |
| padding: 6px 16px; | |
| font-size: 13px; | |
| background: linear-gradient(180deg, #22c55e, #16a34a); | |
| color: white; | |
| border: 1px solid #16a34a; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| transition: all 0.2s; | |
| } | |
| .execute-btn:hover:not(:disabled) { | |
| background: linear-gradient(180deg, #16a34a, #15803d); | |
| transform: translateY(-1px); | |
| } | |
| .execute-btn:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="brand">>_ DeepShell <span id="mode-label" style="font-size:11px;color:var(--muted);font-weight:400;margin-left:6px;"></span></div> | |
| <div style="display: flex; align-items: center; gap: 12px;"> | |
| <div class="mode-toggle"> | |
| <button class="mode-btn active" id="btn-assistant" onclick="setMode('assistant')">๐ค Assistant</button> | |
| <button class="mode-btn" id="btn-trainer" onclick="setMode('trainer')">๐ Trainer</button> | |
| </div> | |
| <button class="theme-btn" id="theme-btn" onclick="toggleTheme()" title="Toggle light/dark theme">๐</button> | |
| <button id="tts-btn" class="tts-btn" onclick="toggleTTS()" title="Voice OFF โ click to enable">๐ Voice OFF</button> | |
| <button class="tts-btn" onclick="replayLast()" title="Replay last response">๐ Replay</button> | |
| <select id="lang-select" class="header-btn" onchange="setLang(this.value)" title="TTS Language"> | |
| <option value="en-US">๐บ๐ธ EN</option> | |
| <option value="hi-IN">๐ฎ๐ณ HI</option> | |
| <option value="ta-IN">๐ฎ๐ณ TA (soon)</option> | |
| <option value="te-IN">๐ฎ๐ณ TE (soon)</option> | |
| <option value="ar-SA">๐ธ๐ฆ AR (soon)</option> | |
| </select> | |
| <button id="export-btn" class="header-btn" title="Export chat as Markdown"> | |
| ๐ฅ Export | |
| </button> | |
| <button id="clear-btn" class="header-btn" title="Clear conversation"> | |
| ๐๏ธ Clear | |
| </button> | |
| <a href="/about.html" class="header-btn" style="text-decoration:none;">About</a> | |
| <a href="/contact.html" class="header-btn" style="text-decoration:none;">Contact</a> | |
| <div class="status"><span class="status-dot" id="status-dot"></span>Backend: <span id="status">checkingโฆ</span></div> | |
| </div> | |
| </header> | |
| <div class="panel"> | |
| <div id="chat-output" class="panel"> | |
| <div id="welcome-msg" style=" | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| height: 100%; | |
| text-align: center; | |
| padding: 40px 20px; | |
| opacity: 0.85; | |
| "> | |
| <div style="font-size: 48px; margin-bottom: 16px;">๐ฅ๏ธ</div> | |
| <div style="font-size: 22px; font-weight: 700; color: var(--accent); margin-bottom: 8px;">>_ DeepShell</div> | |
| <div style="font-size: 13px; color: var(--muted); margin-bottom: 24px; letter-spacing: 1px;">AI-POWERED DEVOPS ASSISTANT & TRAINER</div> | |
| <div style="display: flex; gap: 16px; flex-wrap: wrap; justify-content: center; margin-bottom: 24px;"> | |
| <div style="background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 12px 20px; min-width: 140px;"> | |
| <div style="font-size: 20px;">๐ค</div> | |
| <div style="font-size: 13px; font-weight: 600; color: var(--accent); margin: 4px 0;">Assistant</div> | |
| <div style="font-size: 11px; color: var(--muted);">Fast DevOps answers</div> | |
| </div> | |
| <div style="background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 12px 20px; min-width: 140px;"> | |
| <div style="font-size: 20px;">๐</div> | |
| <div style="font-size: 13px; font-weight: 600; color: var(--accent); margin: 4px 0;">Trainer</div> | |
| <div style="font-size: 11px; color: var(--muted);">Learn with examples</div> | |
| </div> | |
| </div> | |
| <div style="font-size: 11px; color: var(--muted); max-width: 900px; line-height: 1.6; text-align: center; white-space: nowrap;"> | |
| Linux โข Docker โข Kubernetes โข Terraform โข AWS โข Ansible โข Bash | |
| </div> | |
| <div style="margin-top: 20px; font-size: 11px; color: var(--muted);"> | |
| ๐ Voice TTS in English & Hindi | โก Powered by Groq | ๐ DevOps-only scope | |
| </div> | |
| </div> | |
| </div> | |
| <form id="chat-form" class="composer" autocomplete="off"> | |
| <textarea id="chat-input" placeholder="Type your promptโฆ e.g., Show me all running Docker containers."></textarea> | |
| <button id="chat-send" type="submit">Send</button> | |
| </form> | |
| <div class="hint" style="font-size: 13px; text-align:center;"> | |
| ๐ก Tip: All code blocks have copy buttons. | Use <b>Trainer mode</b> for structured learning. | |
| </div> | |
| </div> | |
| </div> | |
| <script src="./app.js"></script> | |
| <script> | |
| // simple readiness check | |
| (async () => { | |
| const el = document.getElementById('status'); | |
| try { | |
| const r = await fetch('/chat/ready'); | |
| const j = await r.json().catch(() => ({})); | |
| const isOk = r.ok && j.status === 'ok'; | |
| el.textContent = isOk ? 'ok' : 'error'; | |
| document.getElementById('status-dot').classList.toggle('ok', isOk); | |
| } catch { | |
| el.textContent = 'offline'; | |
| } | |
| })(); | |
| </script> | |
| </body> | |
| </html> | |