anycoder-238ef2c1 / index.html
Erik
Upload folder using huggingface_hub
268159b verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Client-Side AI Code Modifier</title>
<!-- Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root {
--bg-dark: #0f0f11;
--bg-panel: #1a1a1d;
--bg-input: #252529;
--accent: #6366f1;
--accent-hover: #4f46e5;
--text-main: #e4e4e7;
--text-muted: #a1a1aa;
--border: #27272a;
--success: #10b981;
--error: #ef4444;
--code-font: 'JetBrains Mono', monospace;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
background-color: var(--bg-dark);
color: var(--text-main);
height: 100vh;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* --- Header --- */
header {
background-color: var(--bg-panel);
border-bottom: 1px solid var(--border);
padding: 1rem 2rem;
display: flex;
justify-content: space-between;
align-items: center;
height: 64px;
flex-shrink: 0;
}
.brand {
display: flex;
align-items: center;
gap: 10px;
font-weight: 700;
font-size: 1.2rem;
color: var(--text-main);
}
.brand i { color: var(--accent); }
.logo-link {
text-decoration: none;
color: var(--text-muted);
font-size: 0.8rem;
display: flex;
align-items: center;
gap: 5px;
transition: color 0.2s;
}
.logo-link:hover {
color: var(--accent);
}
.status-badge {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.75rem;
background: rgba(16, 185, 129, 0.1);
color: var(--success);
padding: 4px 12px;
border-radius: 20px;
border: 1px solid rgba(16, 185, 129, 0.2);
}
.status-dot {
width: 8px;
height: 8px;
background-color: var(--success);
border-radius: 50%;
box-shadow: 0 0 8px var(--success);
}
/* --- Main Layout --- */
main {
display: grid;
grid-template-columns: 1fr 350px;
flex-grow: 1;
overflow: hidden;
}
/* --- Editor Section --- */
.editor-container {
display: flex;
flex-direction: column;
border-right: 1px solid var(--border);
height: 100%;
}
.toolbar {
padding: 10px 20px;
background: var(--bg-panel);
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
}
.toolbar-title {
font-size: 0.85rem;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 1px;
font-weight: 600;
}
.editor-area {
flex-grow: 1;
display: flex;
flex-direction: column;
}
textarea.code-input {
flex-grow: 1;
background-color: var(--bg-dark);
color: #d4d4d4;
border: none;
resize: none;
padding: 20px;
font-family: var(--code-font);
font-size: 14px;
line-height: 1.6;
outline: none;
white-space: pre;
overflow: auto;
}
textarea.code-input::placeholder {
color: #444;
}
/* --- Sidebar / AI Panel --- */
.ai-panel {
background-color: var(--bg-panel);
display: flex;
flex-direction: column;
height: 100%;
}
.panel-header {
padding: 20px;
border-bottom: 1px solid var(--border);
}
.panel-header h2 {
font-size: 1.1rem;
margin-bottom: 5px;
}
.panel-header p {
font-size: 0.8rem;
color: var(--text-muted);
}
.control-group {
padding: 20px;
border-bottom: 1px solid var(--border);
}
.label {
display: block;
font-size: 0.8rem;
color: var(--text-muted);
margin-bottom: 8px;
font-weight: 500;
}
textarea.prompt-input {
width: 100%;
background-color: var(--bg-input);
border: 1px solid var(--border);
color: var(--text-main);
padding: 10px;
border-radius: 6px;
font-family: 'Inter', sans-serif;
font-size: 0.9rem;
resize: vertical;
min-height: 80px;
outline: none;
transition: border-color 0.2s;
}
textarea.prompt-input:focus {
border-color: var(--accent);
}
.slider-container {
display: flex;
align-items: center;
gap: 10px;
}
input[type="range"] {
flex-grow: 1;
accent-color: var(--accent);
cursor: pointer;
}
.slider-value {
font-size: 0.8rem;
font-family: var(--code-font);
color: var(--accent);
min-width: 40px;
text-align: right;
}
.action-btn {
width: 100%;
padding: 14px;
margin-top: auto; /* Push to bottom if needed, but here we stack */
background-color: var(--accent);
color: white;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
transition: all 0.2s;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
}
.action-btn:hover {
background-color: var(--accent-hover);
transform: translateY(-1px);
}
.action-btn:active {
transform: translateY(0);
}
.action-btn:disabled {
background-color: var(--border);
color: var(--text-muted);
cursor: not-allowed;
transform: none;
}
/* --- Console / Output Log --- */
.console-log {
height: 150px;
background-color: #000;
padding: 15px;
overflow-y: auto;
font-family: var(--code-font);
font-size: 0.8rem;
border-top: 1px solid var(--border);
}
.log-entry {
margin-bottom: 6px;
padding-bottom: 6px;
border-bottom: 1px solid #222;
}
.log-time {
color: var(--text-muted);
margin-right: 8px;
}
.log-info { color: #60a5fa; }
.log-success { color: var(--success); }
.log-warn { color: #fbbf24; }
/* --- Responsive Design --- */
@media (max-width: 768px) {
main {
grid-template-columns: 1fr;
grid-template-rows: 1fr 1fr;
overflow-y: auto;
}
.editor-container {
border-right: none;
border-bottom: 1px solid var(--border);
}
.ai-panel {
height: 500px;
}
body {
overflow: auto;
}
header {
padding: 1rem;
}
}
/* Loading Animation */
.loader {
width: 18px;
height: 18px;
border: 3px solid #ffffff;
border-bottom-color: transparent;
border-radius: 50%;
display: inline-block;
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<header>
<div class="brand">
<i class="fa-solid fa-brain"></i>
<span>Client-Side AI Studio</span>
</div>
<div style="display: flex; align-items: center; gap: 20px;">
<div class="status-badge">
<div class="status-dot"></div>
<span>WebLLM (Transformers.js)</span>
</div>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="logo-link">
<i class="fa-solid fa-code"></i> Built with anycoder
</a>
</div>
</header>
<main>
<!-- Left Side: Code Editor -->
<section class="editor-container">
<div class="toolbar">
<span class="toolbar-title"><i class="fa-solid fa-file-code"></i> main.js</span>
<div style="font-size: 0.75rem; color: var(--text-muted);">
<i class="fa-solid fa-terminal"></i> Ready
</div>
</div>
<div class="editor-area">
<textarea id="codeEditor" class="code-input" spellcheck="false" placeholder="// Existing code appears here...&#10;const server = require('express')();&#10;&#10;// TODO: Optimize database connection&#10;function legacyFunction(data) {&#10; // messy logic here&#10; return data;&#10;}">
// --- EXISTING CODE BASE ---
// You can modify this code using the AI panel on the right.
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
// Middleware to parse JSON bodies
app.use(express.json());
// Database connection simulation (Needs optimization)
let database = {
users: [],
items: []
};
/**
* Legacy function to handle user creation
* @param {Object} userData
*/
function createUser(userData) {
if (!userData.email) {
throw new Error('Email is required');
}
const newUser = {
id: Date.now(),
...userData,
createdAt: new Date().toISOString()
};
database.users.push(newUser);
return newUser;
}
// Endpoint: Get all users
app.get('/api/users', (req, res) => {
res.json({ success: true, data: database.users });
});
// Endpoint: Create User
app.post('/api/users', (req, res) => {
try {
const user = createUser(req.body);
res.status(201).json({ success: true, data: user });
} catch (error) {
res.status(400).json({ success: false, error: error.message });
}
});
// Start Server
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
console.log("Ready to accept requests.");
});
</textarea>
</div>
</section>
<!-- Right Side: AI Controls -->
<aside class="ai-panel">
<div class="panel-header">
<h2><i class="fa-solid fa-robot"></i> AI Assistant</h2>
<p>Running DistilGPT-2 locally in your browser</p>
</div>
<div class="control-group">
<label class="label">Modification Request</label>
<textarea id="promptInput" class="prompt-input" placeholder="Describe what you want to change...&#10;Example: 'Add input validation to the email field' or 'Refactor createUser to use async/await'"></textarea>
</div>
<div class="control-group">
<label class="label">Creativity (Temperature) <span id="tempValue" class="slider-value">0.7</span></label>
<div class="slider-container">
<input type="range" id="temperature" min="0" max="1" step="0.1" value="0.7">
</div>
<div style="margin-top: 10px;">
<label class="label">Max New Tokens</label>
<div class="slider-container">
<input type="range" id="maxTokens" min="50" max="500" step="50" value="200">
<span class="slider-value" id="tokensValue">200</span>
</div>
</div>
</div>
<button id="generateBtn" class="action-btn">
<span id="btnText"><i class="fa-solid fa-play"></i> Generate Code</span>
<div id="btnLoader" class="loader" style="display: none;"></div>
</button>
<div class="console-log" id="consoleLog">
<div class="log-entry">
<span class="log-time">[System]</span>
<span class="log-info">Transformers.js initialized. Model loaded: distilgpt2</span>
</div>
<div class="log-entry">
<span class="log-time">[System]</span>
<span class="log-info">Client-side environment ready.</span>
</div>
</div>
</aside>
</main>
<!-- Transformers.js Library -->
<script src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.13.0/dist/transformers.min.js"></script>
<script>
// --- Configuration & State ---
const CONFIG = {
modelId: 'Xenova/distilgpt2', // Lightweight GPT model for the browser
progressCallback: (data) => {
logToConsole(`Downloading model: ${(data.progress * 100).toFixed(2)}%`, 'info');
}
};
let generator = null;
let isModelLoaded = false;
// --- DOM Elements ---
const codeEditor = document.getElementById('codeEditor');
const promptInput = document.getElementById('promptInput');
const generateBtn = document.getElementById('generateBtn');
const btnText = document.getElementById('btnText');
const btnLoader = document.getElementById('btnLoader');
const consoleLog = document.getElementById('consoleLog');
const tempInput = document.getElementById('temperature');
const tempValueDisplay = document.getElementById('tempValue');
const tokensInput = document.getElementById('maxTokens');
const tokensValueDisplay = document.getElementById('tokensValue');
// --- Helper Functions ---
// Logger for the Console Panel
function logToConsole(message, type = 'info') {
const entry = document.createElement('div');
entry.className = 'log-entry';
const time = new Date().toLocaleTimeString([], { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
let typeClass = 'log-info';
if (type === 'success') typeClass = 'log-success';
if (type === 'warn') typeClass = 'log-warn';
entry.innerHTML = `<span class="log-time">[${time}]</span> <span class="${typeClass}">${message}</span>`;
consoleLog.appendChild(entry);
consoleLog.scrollTop = consoleLog.scrollHeight;
}
// Initialize Transformers.js
async function initAI() {
try {
logToConsole('Initializing Transformers.js environment...', 'info');
// Create the text generation pipeline
generator = await pipeline('text-generation', CONFIG.modelId, {
progress_callback: CONFIG.progressCallback,
dtype: 'int8', // Use int8 quantization to save memory
device: 'cpu' // Explicitly force CPU for free tier stability
});
isModelLoaded = true;
logToConsole('Model loaded successfully: Xenova/distilgpt2', 'success');
logToConsole('System Ready. Enter a request below.', 'info');
} catch (error) {
console.error(error);
logToConsole(`Error loading model: ${error.message}`, 'warn');
alert("Failed to load AI model. Please check your internet connection and try again.");
}
}
// Process the code generation
async function handleCodeGeneration() {
if (!isModelLoaded) {
logToConsole('Model is still loading. Please wait...', 'warn');
return;
}
const userPrompt = promptInput.value.trim();
const currentCode = codeEditor.value;
const temperature = parseFloat(tempInput.value);
const maxNewTokens = parseInt(tokensInput.value);
if (!userPrompt) {
logToConsole('Please enter a modification request.', 'warn');
promptInput.focus();
return;
}
// UI State: Loading
generateBtn.disabled = true;
btnText.innerHTML = '<span class="loader" style="width:16px; height:16px; border-width:2px; margin-right:10px;"></span> Generating...';
logToConsole(`Processing request: "${userPrompt}"`, 'info');
// Construct the Prompt
// We provide the context (existing code) and the instruction (prompt)
const fullPrompt = `
<CODE>
${currentCode}
</CODE>
<INSTRUCTION>
${userPrompt}
</INSTRUCTION>
Please modify the code inside <CODE> tags to fulfill the instruction.
Return only the full updated code block.
`;
try {
// Run inference
const output = await generator(fullPrompt, {
max_new_tokens: maxNewTokens,
temperature: temperature,
do_sample: true,
top_k: 50,
return_full_text: false, // We want just the generated part
pad_token_id: 50256 // EOS token for GPT-2
});
const generatedText = output[0].generated_text;
// Parse logic: In a real app we might parse XML/Markdown.
// Since GPT-2 is small, it often just continues the code stream.
// We will attempt to extract just the new code block if formatted,
// or append/replace intelligently.
// For this demo, we will replace the editor content with the result
// or append it if it looks like a function addition.
logToConsole('Code generated successfully.', 'success');
// Simple cleanup for GPT-2 (it often adds quotes or extra text)
let cleanCode = generatedText.trim();
// If the model returns a code block wrapper, strip it
if (cleanCode.startsWith('```')) {
cleanCode = cleanCode.replace(/```(javascript|js|html|css)?\n?/, '').replace(/```$/, '');
}
codeEditor.value = cleanCode;
logToConsole('Editor updated with new code.', 'success');
} catch (error) {
console.error(error);
logToConsole(`Generation error: ${error.message}`, 'warn');
} finally {
// UI State: Reset
generateBtn.disabled = false;
btnText.innerHTML = '<i class="fa-solid fa-play"></i> Generate Code';
}
}
// --- Event Listeners ---
// Temperature Slider
tempInput.addEventListener('input', (e) => {
tempValueDisplay.textContent = e.target.value;
});
// Max Tokens Slider
tokensInput.addEventListener('input', (e) => {
tokensValueDisplay.textContent = e.target.value;
});
// Generate Button
generateBtn.addEventListener('click', handleCodeGeneration);
// Initialize on Load
window.addEventListener('DOMContentLoaded', () => {
// Small delay to allow UI to paint first
setTimeout(() => {
initAI();
}, 500);
});
</script>
</body>
</html>