codellama / templates /index.html
soxogvv's picture
Update templates/index.html
1181319 verified
Raw
History Blame Contribute Delete
31 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CodeLlama Pro - AI Code Assistant</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: #333;
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
min-height: 100vh;
}
.header {
text-align: center;
margin-bottom: 30px;
color: white;
}
.header h1 {
font-size: 3rem;
margin-bottom: 10px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.header p {
font-size: 1.2rem;
opacity: 0.9;
}
.main-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
height: calc(100vh - 200px);
}
.panel {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
padding: 30px;
display: flex;
flex-direction: column;
}
.panel-header {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #eee;
}
.panel-header i {
font-size: 1.5rem;
margin-right: 15px;
color: #667eea;
}
.panel-header h2 {
font-size: 1.5rem;
color: #333;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #555;
}
.textarea-wrapper {
position: relative;
flex: 1;
}
textarea, .code-output {
width: 100%;
padding: 15px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
font-size: 14px;
resize: vertical;
transition: all 0.3s ease;
background: #fafafa;
}
textarea:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.code-output {
background: #2d3748;
color: #e2e8f0;
min-height: 200px;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-all;
}
.btn {
padding: 12px 30px;
border: none;
border-radius: 25px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
text-decoration: none;
}
.btn-primary {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.4);
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-secondary:hover {
background: #5a6268;
transform: translateY(-2px);
}
.btn-danger {
background: #dc3545;
color: white;
}
.btn-danger:hover {
background: #c82333;
transform: translateY(-2px);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none !important;
}
.action-buttons {
display: flex;
gap: 15px;
margin-top: 20px;
flex-wrap: wrap;
}
.status-bar {
background: rgba(255, 255, 255, 0.9);
padding: 15px 30px;
border-radius: 15px;
margin-bottom: 20px;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.status-indicator {
display: flex;
align-items: center;
gap: 10px;
}
.status-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background: #dc3545;
animation: pulse 2s infinite;
}
.status-dot.loading {
background: #ffc107;
}
.status-dot.ready {
background: #28a745;
animation: none;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.explanation-panel {
background: linear-gradient(145deg, #f8f9ff, #e6f3ff);
border: 1px solid #d0e7ff;
border-radius: 12px;
padding: 20px;
margin-top: 15px;
}
.explanation-panel h3 {
color: #2563eb;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 8px;
}
.copy-btn {
position: absolute;
top: 10px;
right: 10px;
background: rgba(0,0,0,0.7);
color: white;
border: none;
padding: 8px 12px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
opacity: 0;
transition: opacity 0.3s ease;
}
.textarea-wrapper:hover .copy-btn,
.code-output-wrapper:hover .copy-btn {
opacity: 1;
}
.code-output-wrapper {
position: relative;
flex: 1;
}
.toast {
position: fixed;
top: 20px;
right: 20px;
background: #28a745;
color: white;
padding: 15px 25px;
border-radius: 8px;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
z-index: 1000;
opacity: 0;
transform: translateX(100px);
transition: all 0.3s ease;
}
.toast.show {
opacity: 1;
transform: translateX(0);
}
.toast.error {
background: #dc3545;
}
.toast.info {
background: #17a2b8;
}
.session-info {
position: absolute;
top: 10px;
left: 10px;
background: rgba(255, 255, 255, 0.9);
padding: 5px 10px;
border-radius: 15px;
font-size: 12px;
color: #666;
display: flex;
align-items: center;
gap: 5px;
}
.user-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background: #28a745;
}
@media (max-width: 768px) {
.main-content {
grid-template-columns: 1fr;
gap: 20px;
}
.header h1 {
font-size: 2rem;
}
.container {
padding: 10px;
}
.action-buttons {
flex-direction: column;
}
}
.char-counter {
position: absolute;
bottom: 10px;
right: 15px;
font-size: 12px;
color: #666;
background: rgba(255,255,255,0.9);
padding: 2px 6px;
border-radius: 4px;
}
.session-controls {
display: flex;
gap: 10px;
align-items: center;
}
</style>
</head>
<body>
<div class="container">
<div class="session-info">
<div class="user-indicator"></div>
<span id="sessionInfo">Session Active</span>
</div>
<div class="header">
<h1><i class="fas fa-code"></i> CodeLlama Pro</h1>
<p>Advanced AI-Powered Code Assistant & Editor</p>
</div>
<div class="status-bar">
<div class="status-indicator">
<div class="status-dot" id="statusDot"></div>
<span id="statusText">Initializing model...</span>
</div>
<div class="session-controls">
<button class="btn btn-danger" id="clearSessionBtn" onclick="clearSession()">
<i class="fas fa-trash"></i> Clear Session
</button>
<button class="btn btn-secondary" id="loadModelBtn" onclick="loadModel()">
<i class="fas fa-download"></i> Load Model
</button>
</div>
</div>
<div class="main-content">
<div class="panel">
<div class="panel-header">
<i class="fas fa-edit"></i>
<h2>Code Input & Instructions</h2>
</div>
<div class="form-group">
<label for="existingCode">Existing Code (Optional)</label>
<div class="textarea-wrapper">
<textarea id="existingCode" placeholder="Paste your existing code here (optional)..." rows="10"></textarea>
<button class="copy-btn" onclick="copyToClipboard('existingCode')">
<i class="fas fa-copy"></i> Copy
</button>
<div class="char-counter" id="codeCounter">0 characters</div>
</div>
</div>
<div class="form-group">
<label for="instruction">Instructions (Required) *</label>
<div class="textarea-wrapper">
<textarea id="instruction" placeholder="Describe what you want me to do with the code..." rows="6" required></textarea>
<div class="char-counter" id="instructionCounter">0 characters</div>
</div>
</div>
<div class="action-buttons">
<button class="btn btn-primary" id="generateBtn" onclick="generateCode()" disabled>
<i class="fas fa-magic"></i> Generate Code
</button>
<button class="btn btn-secondary" id="explainBtn" onclick="explainCode()">
<i class="fas fa-lightbulb"></i> Explain Code
</button>
</div>
</div>
<div class="panel">
<div class="panel-header">
<i class="fas fa-code"></i>
<h2>Generated Code</h2>
</div>
<div class="code-output-wrapper">
<div class="code-output" id="codeOutput">
<div style="color: #a0aec0; font-style: italic; text-align: center; margin-top: 80px;">
<i class="fas fa-rocket" style="font-size: 3rem; margin-bottom: 20px; display: block;"></i>
Generated code will appear here...
<br><br>
Load the model first, then provide instructions to get started!
</div>
</div>
<button class="copy-btn" onclick="copyToClipboard('codeOutput')">
<i class="fas fa-copy"></i> Copy Code
</button>
</div>
<div class="explanation-panel" id="explanationPanel" style="display: none;">
<h3><i class="fas fa-info-circle"></i> Explanation</h3>
<div id="explanationText"></div>
</div>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script>
let modelLoaded = false;
let isGenerating = false;
let sessionId = null;
let lastSaveTime = null;
// Session Management
function generateSessionId() {
return 'session_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
}
function initializeSession() {
// Try to get existing session ID from localStorage
sessionId = localStorage.getItem('codellama_session_id');
if (!sessionId) {
// Create new session for new user
sessionId = generateSessionId();
localStorage.setItem('codellama_session_id', sessionId);
localStorage.setItem('codellama_session_created', new Date().toISOString());
showToast('Welcome! New session created.', 'info');
} else {
// Existing user - restore their session
restoreSession();
showToast('Welcome back! Session restored.', 'success');
}
updateSessionInfo();
}
function saveSession() {
if (!sessionId) return;
const sessionData = {
existingCode: document.getElementById('existingCode').value,
instruction: document.getElementById('instruction').value,
codeOutput: document.getElementById('codeOutput').textContent,
explanationText: document.getElementById('explanationText').textContent,
explanationVisible: document.getElementById('explanationPanel').style.display !== 'none',
timestamp: new Date().toISOString()
};
localStorage.setItem(`codellama_session_${sessionId}`, JSON.stringify(sessionData));
lastSaveTime = new Date();
updateSessionInfo();
}
function restoreSession() {
if (!sessionId) return;
const savedData = localStorage.getItem(`codellama_session_${sessionId}`);
if (!savedData) return;
try {
const sessionData = JSON.parse(savedData);
// Restore form data
document.getElementById('existingCode').value = sessionData.existingCode || '';
document.getElementById('instruction').value = sessionData.instruction || '';
// Restore code output
const codeOutput = document.getElementById('codeOutput');
if (sessionData.codeOutput && !sessionData.codeOutput.includes('Generated code will appear here')) {
codeOutput.textContent = sessionData.codeOutput;
// Apply syntax highlighting
Prism.highlightElement(codeOutput);
}
// Restore explanation
if (sessionData.explanationText && sessionData.explanationVisible) {
document.getElementById('explanationText').textContent = sessionData.explanationText;
document.getElementById('explanationPanel').style.display = 'block';
}
// Update character counters
updateCharCounters();
lastSaveTime = new Date(sessionData.timestamp);
} catch (error) {
console.error('Error restoring session:', error);
showToast('Error restoring session data.', 'error');
}
}
function clearSession() {
if (confirm('Are you sure you want to clear your session? This will remove all your work and start fresh.')) {
// Clear localStorage
if (sessionId) {
localStorage.removeItem(`codellama_session_${sessionId}`);
}
localStorage.removeItem('codellama_session_id');
localStorage.removeItem('codellama_session_created');
// Reset form
document.getElementById('existingCode').value = '';
document.getElementById('instruction').value = '';
document.getElementById('codeOutput').innerHTML = `
<div style="color: #a0aec0; font-style: italic; text-align: center; margin-top: 80px;">
<i class="fas fa-rocket" style="font-size: 3rem; margin-bottom: 20px; display: block;"></i>
Generated code will appear here...
<br><br>
Load the model first, then provide instructions to get started!
</div>
`;
document.getElementById('explanationPanel').style.display = 'none';
// Create new session
sessionId = generateSessionId();
localStorage.setItem('codellama_session_id', sessionId);
localStorage.setItem('codellama_session_created', new Date().toISOString());
updateCharCounters();
updateSessionInfo();
showToast('Session cleared! Starting fresh.', 'success');
}
}
function updateSessionInfo() {
const sessionInfo = document.getElementById('sessionInfo');
const createdTime = localStorage.getItem('codellama_session_created');
if (createdTime) {
const created = new Date(createdTime);
const now = new Date();
const diffHours = Math.floor((now - created) / (1000 * 60 * 60));
if (diffHours < 1) {
sessionInfo.textContent = 'Active (New)';
} else if (diffHours < 24) {
sessionInfo.textContent = `Active (${diffHours}h ago)`;
} else {
const diffDays = Math.floor(diffHours / 24);
sessionInfo.textContent = `Active (${diffDays}d ago)`;
}
}
}
function updateCharCounters() {
const codeTextarea = document.getElementById('existingCode');
const instructionTextarea = document.getElementById('instruction');
document.getElementById('codeCounter').textContent = codeTextarea.value.length + ' characters';
document.getElementById('instructionCounter').textContent = instructionTextarea.value.length + ' characters';
}
// Auto-save functionality
function setupAutoSave() {
const elements = ['existingCode', 'instruction'];
elements.forEach(id => {
const element = document.getElementById(id);
element.addEventListener('input', () => {
clearTimeout(window.autoSaveTimeout);
window.autoSaveTimeout = setTimeout(saveSession, 2000); // Save after 2 seconds of inactivity
});
});
}
// Initialize
document.addEventListener('DOMContentLoaded', function() {
initializeSession();
checkModelStatus();
setupCharCounters();
setupAutoResize();
setupAutoSave();
// Check status every 5 seconds
setInterval(checkModelStatus, 5000);
// Save session every 30 seconds
setInterval(saveSession, 30000);
// Save before page unload
window.addEventListener('beforeunload', saveSession);
});
// Character counters
function setupCharCounters() {
const codeTextarea = document.getElementById('existingCode');
const instructionTextarea = document.getElementById('instruction');
codeTextarea.addEventListener('input', updateCharCounters);
instructionTextarea.addEventListener('input', updateCharCounters);
// Initial count
updateCharCounters();
}
// Auto-resize textareas
function setupAutoResize() {
const textareas = document.querySelectorAll('textarea');
textareas.forEach(textarea => {
textarea.addEventListener('input', function() {
this.style.height = 'auto';
this.style.height = (this.scrollHeight) + 'px';
});
});
}
// Check model status
async function checkModelStatus() {
try {
const response = await fetch('/api/status');
const data = await response.json();
const statusDot = document.getElementById('statusDot');
const statusText = document.getElementById('statusText');
const generateBtn = document.getElementById('generateBtn');
const loadModelBtn = document.getElementById('loadModelBtn');
if (data.is_loaded) {
statusDot.className = 'status-dot ready';
statusText.textContent = 'Model Ready';
generateBtn.disabled = false;
loadModelBtn.style.display = 'none';
modelLoaded = true;
} else if (data.is_loading) {
statusDot.className = 'status-dot loading';
statusText.innerHTML = '<span class="loading-spinner"></span> Loading Model...';
generateBtn.disabled = true;
loadModelBtn.disabled = true;
} else {
statusDot.className = 'status-dot';
statusText.textContent = 'Model Not Loaded';
generateBtn.disabled = true;
loadModelBtn.disabled = false;
loadModelBtn.style.display = 'inline-flex';
}
} catch (error) {
console.error('Error checking status:', error);
}
}
// Load model
async function loadModel() {
try {
const response = await fetch('/api/load_model', { method: 'POST' });
const data = await response.json();
if (data.status === 'loading') {
showToast('Model loading started...', 'info');
} else if (data.status === 'loaded') {
showToast('Model already loaded!', 'success');
}
checkModelStatus();
} catch (error) {
showToast('Error loading model: ' + error.message, 'error');
}
}
// Generate code
async function generateCode() {
if (!modelLoaded || isGenerating) return;
const existingCode = document.getElementById('existingCode').value;
const instruction = document.getElementById('instruction').value.trim();
if (!instruction) {
showToast('Please provide instructions!', 'error');
return;
}
isGenerating = true;
const generateBtn = document.getElementById('generateBtn');
const originalText = generateBtn.innerHTML;
generateBtn.innerHTML = '<span class="loading-spinner"></span> Generating...';
generateBtn.disabled = true;
try {
const response = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
existing_code: existingCode,
instruction: instruction
})
});
const data = await response.json();
if (data.error) {
showToast('Error: ' + data.error, 'error');
return;
}
// Display code
const codeOutput = document.getElementById('codeOutput');
codeOutput.textContent = data.code || data.full_response;
// Apply syntax highlighting
Prism.highlightElement(codeOutput);
// Display explanation
if (data.explanation) {
const explanationPanel = document.getElementById('explanationPanel');
const explanationText = document.getElementById('explanationText');
explanationText.textContent = data.explanation;
explanationPanel.style.display = 'block';
}
// Save session with new data
saveSession();
showToast('Code generated successfully!', 'success');
} catch (error) {
showToast('Error generating code: ' + error.message, 'error');
} finally {
isGenerating = false;
generateBtn.innerHTML = originalText;
generateBtn.disabled = false;
}
}
// Explain code
async function explainCode() {
if (!modelLoaded) {
showToast('Please load the model first!', 'error');
return;
}
const existingCode = document.getElementById('existingCode').value.trim();
const codeOutput = document.getElementById('codeOutput').textContent.trim();
const codeToExplain = existingCode || codeOutput;
if (!codeToExplain || codeToExplain.includes('Generated code will appear here')) {
showToast('Please provide code to explain!', 'error');
return;
}
const explainBtn = document.getElementById('explainBtn');
const originalText = explainBtn.innerHTML;
explainBtn.innerHTML = '<span class="loading-spinner"></span> Explaining...';
explainBtn.disabled = true;
try {
const response = await fetch('/api/explain', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code: codeToExplain })
});
const data = await response.json();
if (data.error) {
showToast('Error: ' + data.error, 'error');
return;
}
// Display explanation
const explanationPanel = document.getElementById('explanationPanel');
const explanationText = document.getElementById('explanationText');
explanationText.textContent = data.explanation;
explanationPanel.style.display = 'block';
// Save session with new data
saveSession();
showToast('Code explanation generated!', 'success');
} catch (error) {
showToast('Error explaining code: ' + error.message, 'error');
} finally {
explainBtn.innerHTML = originalText;
explainBtn.disabled = false;
}
}
// Copy to clipboard
async function copyToClipboard(elementId) {
const element = document.getElementById(elementId);
const text = element.value || element.textContent;
try {
await navigator.clipboard.writeText(text);
showToast('Copied to clipboard!', 'success');
} catch (error) {
// Fallback for older browsers
const textArea = document.createElement('textarea');
textArea.value = text;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
showToast('Copied to clipboard!', 'success');
}
}
// Show toast notification
function showToast(message, type = 'success') {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = `toast show ${type}`;
setTimeout(() => {
toast.className = 'toast';
}, 3000);
}
// Keyboard shortcuts
document.addEventListener('keydown', function(e) {
if (e.ctrlKey || e.metaKey) {
if (e.key === 'Enter') {
e.preventDefault();
generateCode();
} else if (e.key === 'e') {
e.preventDefault();
explainCode();
} else if (e.key === 's') {
e.preventDefault();
saveSession();
showToast('Session saved manually!', 'success');
}
}
});
</script>
</body>
</html>