HyzeCodeCLI / cli.html
HyzeAI's picture
Upload cli.html
051abd8 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hyze Code</title>
<link rel="icon" type="image/png" href="https://i.imgur.com/f5QyYpV.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=VT323&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg-primary: #151A28;
--bg-secondary: #1e2535;
--bg-tertiary: #252d3f;
--accent-primary: #1C4297;
--accent-secondary: #2d5bc4;
--accent-dim: #0f2a5c;
--text-primary: #e0f0ff;
--text-secondary: #8aa8c2;
--text-muted: #4a6075;
--border-color: #1C4297;
--border-dim: #0f2a5c;
--error: #ff3366;
--success: #00ff88;
--warning: #ffcc00;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
}
body {
font-family: 'VT323', monospace;
background: var(--bg-primary);
color: var(--text-primary);
height: 100vh;
overflow: hidden;
font-size: 18px;
line-height: 1.4;
}
/* CRT Scanline Effect */
body::before {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0.15),
rgba(0, 0, 0, 0.15) 1px,
transparent 1px,
transparent 2px
);
pointer-events: none;
z-index: 9999;
opacity: 0.3;
}
/* Screen Glow */
body::after {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle at center, rgba(28, 66, 151, 0.05) 0%, transparent 70%);
pointer-events: none;
z-index: 9998;
}
.terminal-container {
display: flex;
flex-direction: column;
height: 100vh;
padding: 20px;
gap: 10px;
}
/* Header */
.terminal-header {
border: 2px solid var(--border-color);
background: var(--bg-secondary);
padding: 15px 20px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 0 20px rgba(28, 66, 151, 0.3);
}
.logo-section {
display: flex;
align-items: center;
gap: 15px;
cursor: pointer;
}
.logo-ascii {
color: var(--accent-primary);
font-size: 10px;
line-height: 1;
white-space: pre;
font-family: 'JetBrains Mono', monospace;
text-shadow: 0 0 10px rgba(28, 66, 151, 0.5);
}
.header-status {
display: flex;
align-items: center;
gap: 10px;
color: var(--text-secondary);
font-size: 16px;
}
.status-dot {
width: 12px;
height: 12px;
background: var(--success);
box-shadow: 0 0 10px var(--success);
animation: blink 1s infinite;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0.3; }
}
/* Main Terminal Area */
.terminal-main {
flex: 1;
border: 2px solid var(--border-color);
background: var(--bg-primary);
overflow: hidden;
display: flex;
flex-direction: column;
position: relative;
box-shadow: inset 0 0 30px rgba(28, 66, 151, 0.05);
}
.terminal-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
}
/* Custom Scrollbar */
.terminal-messages::-webkit-scrollbar {
width: 12px;
}
.terminal-messages::-webkit-scrollbar-track {
background: var(--bg-secondary);
border-left: 2px solid var(--border-dim);
}
.terminal-messages::-webkit-scrollbar-thumb {
background: var(--accent-dim);
border: 2px solid var(--bg-secondary);
}
.terminal-messages::-webkit-scrollbar-thumb:hover {
background: var(--accent-primary);
}
/* Welcome Screen */
.welcome-screen {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
height: 100%;
text-align: left;
gap: 20px;
padding: 20px;
animation: flicker 4s infinite;
}
@keyframes flicker {
0%, 100% { opacity: 1; }
50% { opacity: 0.95; }
52% { opacity: 0.8; }
54% { opacity: 0.95; }
}
.welcome-ascii {
color: var(--accent-primary);
font-size: 12px;
line-height: 1.1;
white-space: pre;
text-shadow: 0 0 20px rgba(28, 66, 151, 0.5);
font-family: 'JetBrains Mono', monospace;
letter-spacing: 0;
}
.welcome-text {
color: var(--text-secondary);
font-size: 20px;
max-width: 600px;
}
.command-hints {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: flex-start;
margin-top: 20px;
}
.cmd-hint {
border: 1px solid var(--border-dim);
padding: 8px 16px;
cursor: pointer;
transition: all 0.2s;
color: var(--text-secondary);
font-size: 16px;
}
.cmd-hint:hover {
border-color: var(--accent-primary);
color: var(--accent-primary);
background: rgba(28, 66, 151, 0.1);
box-shadow: 0 0 15px rgba(28, 66, 151, 0.3);
}
/* Messages */
.message {
display: flex;
flex-direction: column;
gap: 5px;
animation: typeIn 0.3s ease;
align-items: flex-start;
}
@keyframes typeIn {
from { opacity: 0; transform: translateX(-10px); }
to { opacity: 1; transform: translateX(0); }
}
.message-header {
display: flex;
align-items: center;
gap: 10px;
color: var(--accent-primary);
font-size: 16px;
}
.message.user .message-header {
color: var(--success);
}
.message-timestamp {
color: var(--text-muted);
font-size: 14px;
}
.message-content {
padding-left: 20px;
color: var(--text-primary);
line-height: 1.5;
white-space: pre-wrap;
text-align: left;
width: 100%;
}
.message-content code {
background: var(--bg-tertiary);
color: var(--accent-primary);
padding: 2px 6px;
border: 1px solid var(--border-dim);
font-family: 'JetBrains Mono', monospace;
font-size: 14px;
}
.message-content pre {
background: var(--bg-secondary);
border: 1px solid var(--border-dim);
padding: 15px;
margin: 10px 0;
overflow-x: auto;
position: relative;
width: 100%;
}
.message-content pre code {
background: transparent;
border: none;
padding: 0;
color: var(--text-primary);
}
/* Code Block Styling */
.code-block-container {
border: 2px solid var(--border-dim);
margin: 15px 0;
background: var(--bg-secondary);
width: 100%;
}
.code-block-header {
background: var(--bg-tertiary);
padding: 10px 15px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border-dim);
}
.code-lang {
color: var(--accent-primary);
font-size: 16px;
text-transform: uppercase;
letter-spacing: 1px;
}
.copy-btn {
background: transparent;
border: 1px solid var(--accent-primary);
color: var(--accent-primary);
padding: 5px 15px;
font-family: 'VT323', monospace;
font-size: 16px;
cursor: pointer;
transition: all 0.2s;
text-transform: uppercase;
}
.copy-btn:hover {
background: var(--accent-primary);
color: var(--bg-primary);
box-shadow: 0 0 15px rgba(28, 66, 151, 0.5);
}
.copy-btn.copied {
background: var(--success);
border-color: var(--success);
color: var(--bg-primary);
}
/* Help Menu */
.help-menu {
border: 2px solid var(--accent-primary);
background: var(--bg-secondary);
padding: 20px;
margin: 10px 0;
max-width: 500px;
}
.help-title {
color: var(--accent-primary);
font-size: 24px;
margin-bottom: 15px;
text-align: left;
border-bottom: 1px solid var(--border-dim);
padding-bottom: 10px;
}
.help-item {
display: flex;
gap: 20px;
margin: 10px 0;
font-size: 16px;
}
.help-cmd {
color: var(--success);
min-width: 100px;
font-family: 'JetBrains Mono', monospace;
}
.help-desc {
color: var(--text-secondary);
}
/* Input Area */
.terminal-input-area {
border-top: 2px solid var(--border-color);
background: var(--bg-secondary);
padding: 15px 20px;
}
.input-wrapper {
display: flex;
align-items: flex-end;
gap: 10px;
max-width: 100%;
}
.input-prompt {
color: var(--accent-primary);
font-size: 20px;
white-space: nowrap;
text-shadow: 0 0 10px rgba(28, 66, 151, 0.5);
}
.terminal-input {
flex: 1;
background: transparent;
border: none;
color: var(--text-primary);
font-family: 'VT323', monospace;
font-size: 20px;
outline: none;
resize: none;
min-height: 30px;
max-height: 150px;
line-height: 1.4;
}
.terminal-input::placeholder {
color: var(--text-muted);
}
.send-btn {
background: transparent;
border: 2px solid var(--accent-primary);
color: var(--accent-primary);
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 20px;
transition: all 0.2s;
}
.send-btn:hover:not(:disabled) {
background: var(--accent-primary);
color: var(--bg-primary);
box-shadow: 0 0 20px rgba(28, 66, 151, 0.5);
}
.send-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
border-color: var(--text-muted);
color: var(--text-muted);
}
.input-footer {
text-align: left;
margin-top: 10px;
color: var(--accent-primary);
font-size: 14px;
letter-spacing: 1px;
font-family: 'JetBrains Mono', monospace;
}
/* Typing Indicator */
.typing-indicator {
display: flex;
align-items: center;
gap: 10px;
color: var(--accent-primary);
padding: 10px 0;
}
.typing-text {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 0.4; }
50% { opacity: 1; }
}
/* Cursor Blink */
.cursor {
display: inline-block;
width: 10px;
height: 20px;
background: var(--accent-primary);
animation: cursorBlink 1s infinite;
vertical-align: middle;
margin-left: 2px;
}
@keyframes cursorBlink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/* Responsive */
@media (max-width: 768px) {
body {
font-size: 16px;
}
.logo-ascii {
font-size: 8px;
}
.welcome-ascii {
font-size: 8px;
}
.terminal-container {
padding: 10px;
}
}
/* Selection Color */
::selection {
background: var(--accent-primary);
color: var(--bg-primary);
}
/* Scrollbar for code blocks */
pre::-webkit-scrollbar {
height: 10px;
}
pre::-webkit-scrollbar-track {
background: var(--bg-tertiary);
}
pre::-webkit-scrollbar-thumb {
background: var(--accent-dim);
}
pre::-webkit-scrollbar-thumb:hover {
background: var(--accent-primary);
}
</style>
</head>
<body>
<div class="terminal-container">
<header class="terminal-header">
<div class="logo-section" title="Double-click to reset">
<img src="https://i.imgur.com/f5QyYpV.png" alt="Hyze Code" class="logo-img">
</div>
<div class="header-status">
<span>SYSTEM:</span>
<div class="status-dot"></div>
<span>ONLINE</span>
</div>
</header>
<main class="terminal-main">
<div class="terminal-messages" id="messagesContainer">
<div class="welcome-screen" id="welcomeScreen">
<div class="welcome-ascii">
██╗ ██╗██╗ ██╗███████╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗
██║ ██║╚██╗ ██╔╝╚══███╔╝██╔════╝ ██╔════╝██╔═══██╗██╔══██╗██╔════╝
███████║ ╚████╔╝ ███╔╝ █████╗ ██║ ██║ ██║██║ ██║█████╗
██╔══██║ ╚██╔╝ ███╔╝ ██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝
██║ ██║ ██║ ███████╗███████╗ ╚██████╗╚██████╔╝██████╔╝███████╗
╚═╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
</div>
<div class="welcome-text">
> Welcome to Hyze Code!<br>
> Powered by Hyze H1 and Kimi K2<br>
> TYPE /help FOR COMMANDS<br>
> TYPE /clear for clearing HISTORY
</div>
<div class="command-hints">
<div class="cmd-hint" onclick="sendSuggestion('Create HTML/CSS layout')">> CREATE_LAYOUT</div>
<div class="cmd-hint" onclick="sendSuggestion('Debug JavaScript code')">> DEBUG_JS</div>
<div class="cmd-hint" onclick="sendSuggestion('Explain Python functions')">> EXPLAIN_PY</div>
<div class="cmd-hint" onclick="sendSuggestion('Optimize SQL query')">> OPTIMIZE_SQL</div>
</div>
</div>
</div>
</main>
<div class="terminal-input-area">
<div class="input-wrapper">
<span class="input-prompt">></span>
<textarea class="terminal-input" id="messageInput" placeholder="Enter command..." rows="1" onkeydown="handleKeyDown(event)" oninput="autoResize(this)"></textarea>
<button class="send-btn" id="sendBtn" onclick="sendMessage()"></button>
</div>
<div class="input-footer">[ HYZE CODE v2.0 | SECURE CONNECTION ]</div>
</div>
</div>
<script>
// --- Configuration ---
const API_KEY = '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';
const MODEL = 'moonshotai/kimi-k2-instruct-0905';
const API_URL = 'https://api.groq.com/openai/v1/chat/completions';
// --- State ---
let messages = [];
let isGenerating = false;
let codeBlockCounter = 0;
// --- Initialization ---
document.addEventListener('DOMContentLoaded', () => {
loadChatHistory();
document.getElementById('messageInput').focus();
});
// --- UI Helpers ---
function autoResize(textarea) {
textarea.style.height = 'auto';
textarea.style.height = Math.min(textarea.scrollHeight, 150) + 'px';
}
function handleKeyDown(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
}
function sendSuggestion(text) {
document.getElementById('messageInput').value = text;
autoResize(document.getElementById('messageInput'));
sendMessage();
}
function getTimestamp() {
const now = new Date();
return now.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' });
}
function scrollToBottom() {
const container = document.getElementById('messagesContainer');
container.scrollTop = container.scrollHeight;
}
// --- Command Handlers ---
function showHelp() {
const container = document.getElementById('messagesContainer');
const helpDiv = document.createElement('div');
helpDiv.className = 'message system';
helpDiv.innerHTML = `
<div class="message-header" style="color: var(--warning)">
<span>SYSTEM</span>
<span class="message-timestamp">[${getTimestamp()}]</span>
</div>
<div class="message-content">
<div class="help-menu">
<div class="help-title">=== HYZE CODE COMMANDS ===</div>
<div class="help-item">
<span class="help-cmd">/clear</span>
<span class="help-desc">Clear all chat history and reset terminal</span>
</div>
<div class="help-item">
<span class="help-cmd">/help</span>
<span class="help-desc">Display this help menu</span>
</div>
<div class="help-item">
<span class="help-cmd">[message]</span>
<span class="help-desc">Send message to AI assistant</span>
</div>
<div style="margin-top: 15px; padding-top: 10px; border-top: 1px solid var(--border-dim); color: var(--text-muted); text-align: left;">
Double-click logo to force reset
</div>
</div>
</div>
`;
container.appendChild(helpDiv);
scrollToBottom();
}
function clearChat() {
messages = [];
codeBlockCounter = 0;
localStorage.removeItem('hyze_code_chats');
const container = document.getElementById('messagesContainer');
container.innerHTML = `
<div class="welcome-screen" id="welcomeScreen">
<div class="welcome-ascii">
██╗ ██╗██╗ ██╗███████╗███████╗ ██████╗ ██████╗ ██████╗ ███████╗
██║ ██║╚██╗ ██╔╝╚══███╔╝██╔════╝ ██╔════╝██╔═══██╗██╔══██╗██╔════╝
███████║ ╚████╔╝ ███╔╝ █████╗ ██║ ██║ ██║██║ ██║█████╗
██╔══██║ ╚██╔╝ ███╔╝ ██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝
██║ ██║ ██║ ███████╗███████╗ ╚██████╗╚██████╔╝██████╔╝███████╗
╚═╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
</div>
<div class="welcome-text">
> TERMINAL INTERFACE INITIALIZED...<br>
> CONNECTED TO NEURAL NETWORK<br>
> TYPE /help FOR COMMANDS<br>
> READY FOR INPUT_
</div>
<div class="command-hints">
<div class="cmd-hint" onclick="sendSuggestion('Create HTML/CSS layout')">> CREATE_LAYOUT</div>
<div class="cmd-hint" onclick="sendSuggestion('Debug JavaScript code')">> DEBUG_JS</div>
<div class="cmd-hint" onclick="sendSuggestion('Explain Python functions')">> EXPLAIN_PY</div>
<div class="cmd-hint" onclick="sendSuggestion('Optimize SQL query')">> OPTIMIZE_SQL</div>
</div>
</div>
`;
// Add system message
const confirmDiv = document.createElement('div');
confirmDiv.className = 'message system';
confirmDiv.innerHTML = `
<div class="message-header" style="color: var(--success)">
<span>SYSTEM</span>
<span class="message-timestamp">[${getTimestamp()}]</span>
</div>
<div class="message-content">> TERMINAL CLEARED. HISTORY RESET.</div>
`;
container.appendChild(confirmDiv);
scrollToBottom();
}
// --- Core Chat Logic ---
async function sendMessage() {
const input = document.getElementById('messageInput');
const text = input.value.trim();
if (!text || isGenerating) return;
// Handle commands
if (text.toLowerCase() === '/clear') {
clearChat();
input.value = '';
input.style.height = 'auto';
return;
}
if (text.toLowerCase() === '/help') {
showHelp();
input.value = '';
input.style.height = 'auto';
return;
}
document.getElementById('welcomeScreen').style.display = 'none';
const timestamp = getTimestamp();
addMessage('user', text, timestamp);
messages.push({ role: 'user', content: text });
input.value = '';
input.style.height = 'auto';
showTypingIndicator();
try {
isGenerating = true;
document.getElementById('sendBtn').disabled = true;
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: MODEL,
messages: [
{
role: 'system',
content: 'You are Hyze Code, a terminal-style AI coding assistant. Provide concise, technical responses. Use code blocks with language specification.'
},
...messages
],
temperature: 0.6,
max_tokens: 3000,
stream: true
})
});
if (!response.ok) throw new Error(`API Error: ${response.status}`);
removeTypingIndicator();
const messageDiv = document.createElement('div');
messageDiv.className = 'message assistant';
const msgTimestamp = getTimestamp();
messageDiv.innerHTML = `
<div class="message-header">
<span>HYZE_AI</span>
<span class="message-timestamp">[${msgTimestamp}]</span>
</div>
<div class="message-content" id="streamingContent"></div>
`;
document.getElementById('messagesContainer').appendChild(messageDiv);
const contentDiv = messageDiv.querySelector('#streamingContent');
const reader = response.body.getReader();
const decoder = new TextDecoder();
let fullContent = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') continue;
try {
const parsed = JSON.parse(data);
const content = parsed.choices?.[0]?.delta?.content || '';
if (content) {
fullContent += content;
contentDiv.innerHTML = formatMessage(fullContent);
scrollToBottom();
}
} catch (e) {}
}
}
}
// Post-processing
contentDiv.innerHTML = formatMessage(fullContent);
// Highlight code
contentDiv.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
});
// Add copy buttons to code blocks
addCopyButtons(contentDiv);
messages.push({ role: 'assistant', content: fullContent });
saveChatHistory();
} catch (error) {
removeTypingIndicator();
addMessage('assistant', `ERROR: ${error.message}`, getTimestamp());
} finally {
isGenerating = false;
document.getElementById('sendBtn').disabled = false;
}
}
function addMessage(role, content, timestamp) {
const container = document.getElementById('messagesContainer');
const messageDiv = document.createElement('div');
messageDiv.className = `message ${role}`;
const sender = role === 'user' ? 'USER' : 'HYZE_AI';
const color = role === 'user' ? 'var(--success)' : 'var(--accent-primary)';
messageDiv.innerHTML = `
<div class="message-header" style="color: ${color}">
<span>${sender}</span>
<span class="message-timestamp">[${timestamp}]</span>
</div>
<div class="message-content">${formatMessage(content)}</div>
`;
container.appendChild(messageDiv);
scrollToBottom();
// Highlight and add copy buttons
messageDiv.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
});
addCopyButtons(messageDiv);
}
function showTypingIndicator() {
const container = document.getElementById('messagesContainer');
const indicator = document.createElement('div');
indicator.className = 'typing-indicator';
indicator.id = 'typingIndicator';
indicator.innerHTML = `
<span>HYZE_AI</span>
<span class="typing-text">PROCESSING</span>
<span class="cursor"></span>
`;
container.appendChild(indicator);
scrollToBottom();
}
function removeTypingIndicator() {
const indicator = document.getElementById('typingIndicator');
if (indicator) indicator.remove();
}
// --- Markdown & Formatting ---
function formatMessage(text) {
let safeText = text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
// Code Blocks
let codeBlocks = [];
safeText = safeText.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
const id = codeBlockCounter++;
const language = lang || 'text';
codeBlocks.push({id, lang: language, code: code});
return `<!--CODEBLOCK_${id}-->`;
});
// Inline Code
safeText = safeText.replace(/`([^`]+)`/g, '<code>$1</code>');
// Bold
safeText = safeText.replace(/\*\*(.*?)\*\*/g, '<strong style="color: var(--accent-primary)">$1</strong>');
// Italic
safeText = safeText.replace(/\*(.*?)\*/g, '<em>$1</em>');
// Lists
safeText = safeText.replace(/^\s*-\s+(.*$)/gim, ' ▸ $1');
safeText = safeText.replace(/^\s*\d+\.\s+(.*$)/gim, ' $1');
// Line Breaks
safeText = safeText.replace(/\n/g, '<br>');
// Restore Code Blocks
safeText = safeText.replace(/<!--CODEBLOCK_(\d+)-->/g, (match, id) => {
const block = codeBlocks.find(b => b.id == id);
if (!block) return match;
return `
<div class="code-block-container" id="code-block-${block.id}">
<div class="code-block-header">
<span class="code-lang">${block.lang.toUpperCase()}</span>
<button class="copy-btn" onclick="copyCode('${block.id}')">COPY</button>
</div>
<pre><code class="language-${block.lang}">${block.code.replace(/</g, '&lt;')}</code></pre>
</div>
`;
});
return safeText;
}
function addCopyButtons(container) {
// Already handled in formatMessage
}
function copyCode(blockId) {
const block = document.querySelector(`#code-block-${blockId} code`);
if (!block) return;
const code = block.textContent;
navigator.clipboard.writeText(code).then(() => {
const btn = document.querySelector(`#code-block-${blockId} .copy-btn`);
const originalText = btn.textContent;
btn.textContent = 'COPIED!';
btn.classList.add('copied');
setTimeout(() => {
btn.textContent = originalText;
btn.classList.remove('copied');
}, 2000);
});
}
// --- History Management ---
function saveChatHistory() {
localStorage.setItem('hyze_code_chats', JSON.stringify(messages));
}
function loadChatHistory() {
const saved = localStorage.getItem('hyze_code_chats');
if (saved) {
try {
messages = JSON.parse(saved);
if (messages.length > 0) {
document.getElementById('welcomeScreen').style.display = 'none';
messages.forEach(msg => {
addMessage(msg.role, msg.content, getTimestamp());
});
}
} catch(e) { console.error("Failed to load history", e); }
}
}
// Clear history on double-click of logo
document.querySelector('.logo-section').addEventListener('dblclick', () => {
if (confirm('RESET TERMINAL?')) {
clearChat();
}
});
</script>
</body>
</html>