Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Gradio Context & Dockerizer</title> | |
| <!-- Importing Phosphor Icons for modern UI iconography --> | |
| <script src="https://unpkg.com/@phosphor-icons/web"></script> | |
| <style> | |
| /* --- CSS VARIABLES & RESET --- */ | |
| :root { | |
| --bg-body: #0f1115; | |
| --bg-panel: #161b22; | |
| --bg-input: #0d1117; | |
| --border-color: #30363d; | |
| --primary: #238636; | |
| --primary-hover: #2ea043; | |
| --accent: #58a6ff; | |
| --text-main: #c9d1d9; | |
| --text-muted: #8b949e; | |
| --font-stack: 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif; | |
| --font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; | |
| --radius-md: 8px; | |
| --radius-lg: 12px; | |
| --shadow: 0 4px 12px rgba(0,0,0,0.5); | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| body { | |
| background-color: var(--bg-body); | |
| color: var(--text-main); | |
| font-family: var(--font-stack); | |
| height: 100vh; | |
| display: flex; | |
| flex-direction: column; | |
| overflow: hidden; | |
| } | |
| /* --- HEADER --- */ | |
| header { | |
| height: 60px; | |
| background-color: var(--bg-panel); | |
| border-bottom: 1px solid var(--border-color); | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0 20px; | |
| flex-shrink: 0; | |
| } | |
| .brand { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| font-weight: 600; | |
| font-size: 1.1rem; | |
| } | |
| .brand i { | |
| color: var(--accent); | |
| font-size: 1.4rem; | |
| } | |
| .anycoder-link { | |
| font-size: 0.85rem; | |
| color: var(--text-muted); | |
| text-decoration: none; | |
| background: rgba(255,255,255,0.05); | |
| padding: 6px 12px; | |
| border-radius: 20px; | |
| transition: all 0.2s; | |
| border: 1px solid transparent; | |
| } | |
| .anycoder-link:hover { | |
| color: var(--accent); | |
| border-color: var(--border-color); | |
| background: rgba(255,255,255,0.1); | |
| } | |
| /* --- LAYOUT --- */ | |
| .layout { | |
| display: grid; | |
| grid-template-columns: 320px 1fr; | |
| flex: 1; | |
| overflow: hidden; | |
| } | |
| /* --- SIDEBAR (CONFIGURATION) --- */ | |
| aside { | |
| background-color: var(--bg-panel); | |
| border-right: 1px solid var(--border-color); | |
| padding: 20px; | |
| overflow-y: auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 24px; | |
| } | |
| .config-group h3 { | |
| font-size: 0.8rem; | |
| text-transform: uppercase; | |
| letter-spacing: 0.5px; | |
| color: var(--text-muted); | |
| margin-bottom: 12px; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| .form-control { | |
| margin-bottom: 16px; | |
| } | |
| .form-control label { | |
| display: block; | |
| font-size: 0.9rem; | |
| margin-bottom: 6px; | |
| color: var(--text-main); | |
| } | |
| .form-control input[type="text"], | |
| .form-control select, | |
| .form-control textarea { | |
| width: 100%; | |
| background-color: var(--bg-input); | |
| border: 1px solid var(--border-color); | |
| color: var(--text-main); | |
| padding: 8px 12px; | |
| border-radius: var(--radius-md); | |
| font-family: inherit; | |
| font-size: 0.9rem; | |
| transition: border-color 0.2s; | |
| } | |
| .form-control input:focus, | |
| .form-control select:focus, | |
| .form-control textarea:focus { | |
| outline: none; | |
| border-color: var(--accent); | |
| } | |
| .range-wrapper { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .range-wrapper input { | |
| flex: 1; | |
| } | |
| .range-value { | |
| font-family: var(--font-mono); | |
| font-size: 0.85rem; | |
| color: var(--accent); | |
| width: 30px; | |
| text-align: right; | |
| } | |
| /* --- MAIN CONTENT AREA --- */ | |
| main { | |
| padding: 20px; | |
| overflow-y: auto; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| background-image: radial-gradient(var(--border-color) 1px, transparent 1px); | |
| background-size: 24px 24px; | |
| } | |
| .card { | |
| background-color: var(--bg-panel); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-lg); | |
| padding: 20px; | |
| box-shadow: var(--shadow); | |
| } | |
| .card-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 16px; | |
| border-bottom: 1px solid var(--border-color); | |
| padding-bottom: 12px; | |
| } | |
| .card-title { | |
| font-weight: 600; | |
| display: flex; | |
| align-items: center; | |
| gap: 8px; | |
| } | |
| /* --- DOCKERFILE PREVIEW --- */ | |
| .code-block { | |
| background-color: #0d1117; | |
| border-radius: var(--radius-md); | |
| padding: 16px; | |
| font-family: var(--font-mono); | |
| font-size: 0.85rem; | |
| color: #a5d6ff; | |
| overflow-x: auto; | |
| white-space: pre; | |
| position: relative; | |
| } | |
| .copy-btn { | |
| position: absolute; | |
| top: 10px; | |
| right: 10px; | |
| background: rgba(255,255,255,0.1); | |
| border: none; | |
| color: var(--text-main); | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 0.75rem; | |
| cursor: pointer; | |
| opacity: 0; | |
| transition: opacity 0.2s; | |
| } | |
| .code-block:hover .copy-btn { | |
| opacity: 1; | |
| } | |
| /* --- TERMINAL / LOGS --- */ | |
| .terminal { | |
| background-color: #000; | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--radius-md); | |
| padding: 12px; | |
| font-family: var(--font-mono); | |
| font-size: 0.85rem; | |
| height: 200px; | |
| overflow-y: auto; | |
| color: #d2a8ff; | |
| } | |
| .log-line { | |
| margin-bottom: 4px; | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .log-time { | |
| color: var(--text-muted); | |
| } | |
| .log-success { color: var(--primary); } | |
| .log-info { color: var(--accent); } | |
| .log-warn { color: #d29922; } | |
| /* --- ACTION BUTTONS --- */ | |
| .btn { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| padding: 10px 20px; | |
| border-radius: var(--radius-md); | |
| font-weight: 600; | |
| cursor: pointer; | |
| border: none; | |
| transition: all 0.2s; | |
| font-size: 0.95rem; | |
| } | |
| .btn-primary { | |
| background-color: var(--primary); | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background-color: var(--primary-hover); | |
| } | |
| .btn-primary:disabled { | |
| background-color: #23863680; | |
| cursor: not-allowed; | |
| } | |
| .btn-secondary { | |
| background-color: transparent; | |
| border: 1px solid var(--border-color); | |
| color: var(--text-main); | |
| } | |
| .btn-secondary:hover { | |
| border-color: var(--text-muted); | |
| background-color: rgba(255,255,255,0.05); | |
| } | |
| /* --- GRADIO PREVIEW --- */ | |
| .gradio-sim { | |
| border: 2px dashed var(--border-color); | |
| border-radius: var(--radius-lg); | |
| padding: 30px; | |
| text-align: center; | |
| color: var(--text-muted); | |
| position: relative; | |
| background: rgba(255,255,255,0.02); | |
| } | |
| .gradio-active { | |
| border-style: solid; | |
| border-color: var(--accent); | |
| background: rgba(88, 166, 255, 0.05); | |
| color: var(--text-main); | |
| } | |
| .status-badge { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| padding: 4px 10px; | |
| border-radius: 12px; | |
| font-size: 0.75rem; | |
| font-weight: 600; | |
| background: rgba(110, 118, 129, 0.2); | |
| } | |
| .status-running { | |
| background: rgba(46, 160, 67, 0.2); | |
| color: #3fb950; | |
| } | |
| /* --- RESPONSIVE --- */ | |
| @media (max-width: 768px) { | |
| .layout { | |
| grid-template-columns: 1fr; | |
| grid-template-rows: auto 1fr; | |
| } | |
| aside { | |
| border-right: none; | |
| border-bottom: 1px solid var(--border-color); | |
| max-height: 300px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="brand"> | |
| <i class="ph ph-cube-transparent"></i> | |
| <span>AutoDockerizer</span> | |
| </div> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> | |
| Built with anycoder <i class="ph ph-arrow-up-right"></i> | |
| </a> | |
| </header> | |
| <div class="layout"> | |
| <!-- SIDEBAR: CONFIGURATION --> | |
| <aside> | |
| <div class="config-group"> | |
| <h3><i class="ph ph-gear"></i> Environment</h3> | |
| <div class="form-control"> | |
| <label>Python Version</label> | |
| <select id="pythonVersion"> | |
| <option value="3.10">Python 3.10</option> | |
| <option value="3.11" selected>Python 3.11</option> | |
| <option value="3.12">Python 3.12</option> | |
| </select> | |
| </div> | |
| <div class="form-control"> | |
| <label>Base Image</label> | |
| <select id="baseImage"> | |
| <option value="python/slim">Python Slim</option> | |
| <option value="nvidia/cuda">CUDA (GPU)</option> | |
| <option value="ubuntu">Ubuntu Latest</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="config-group"> | |
| <h3><i class="ph ph-brackets-curly"></i> Gradio Config</h3> | |
| <div class="form-control"> | |
| <label>App Title</label> | |
| <input type="text" id="appTitle" value="My AI Demo"> | |
| </div> | |
| <div class="form-control"> | |
| <label>Model ID (Hugging Face)</label> | |
| <input type="text" id="modelId" placeholder="e.g. gpt2"> | |
| </div> | |
| </div> | |
| <div class="config-group"> | |
| <h3><i class="ph ph-sliders"></i> Parameters</h3> | |
| <div class="form-control"> | |
| <label>Max Tokens</label> | |
| <div class="range-wrapper"> | |
| <input type="range" min="64" max="4096" value="512" id="maxTokens"> | |
| <span class="range-value" id="val-maxTokens">512</span> | |
| </div> | |
| </div> | |
| <div class="form-control"> | |
| <label>Temperature</label> | |
| <div class="range-wrapper"> | |
| <input type="range" min="0" max="1" step="0.1" value="0.7" id="temperature"> | |
| <span class="range-value" id="val-temperature">0.7</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="config-group"> | |
| <h3><i class="ph ph-file-code"></i> Actions</h3> | |
| <button class="btn btn-primary" style="width: 100%" onclick="runDeployment()"> | |
| <i class="ph ph-rocket-launch"></i> Build & Deploy | |
| </button> | |
| </div> | |
| </aside> | |
| <!-- MAIN CONTENT --> | |
| <main> | |
| <!-- Dockerfile Preview --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="ph ph-docker-logo"></i> Generated Dockerfile | |
| </div> | |
| <div class="status-badge">Auto-generated</div> | |
| </div> | |
| <div class="code-block" id="dockerfileOutput"> | |
| <button class="copy-btn" onclick="copyDockerfile()">Copy</button> | |
| <!-- Content injected via JS --> | |
| </div> | |
| </section> | |
| <!-- Terminal & Status --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="ph ph-terminal-window"></i> Build Terminal | |
| </div> | |
| <div id="buildStatus" class="status-badge">Waiting for input...</div> | |
| </div> | |
| <div class="terminal" id="terminalOutput"> | |
| <div class="log-line"><span class="log-time">[System]</span> Ready to initialize build process.</div> | |
| </div> | |
| </section> | |
| <!-- Gradio Simulation --> | |
| <section class="card"> | |
| <div class="card-header"> | |
| <div class="card-title"> | |
| <i class="ph ph-monitor-play"></i> Gradio Live Preview | |
| </div> | |
| </div> | |
| <div class="gradio-sim" id="gradioPreview"> | |
| <i class="ph ph-cloud-arrow-up" style="font-size: 3rem; margin-bottom: 10px; display: block;"></i> | |
| <p>Click "Build & Deploy" to start the container and launch the Gradio interface.</p> | |
| <div style="margin-top: 15px; opacity: 0.5; font-size: 0.8rem;"> | |
| Running on http://127.0.0.1:7860 | |
| </div> | |
| </div> | |
| </section> | |
| </main> | |
| </div> | |
| <script> | |
| // --- DOM ELEMENTS --- | |
| const inputs = { | |
| python: document.getElementById('pythonVersion'), | |
| base: document.getElementById('baseImage'), | |
| title: document.getElementById('appTitle'), | |
| model: document.getElementById('modelId'), | |
| tokens: document.getElementById('maxTokens'), | |
| temp: document.getElementById('temperature') | |
| }; | |
| const displays = { | |
| tokens: document.getElementById('val-maxTokens'), | |
| temp: document.getElementById('val-temperature') | |
| }; | |
| const outputs = { | |
| dockerfile: document.getElementById('dockerfileOutput'), | |
| terminal: document.getElementById('terminalOutput'), | |
| status: document.getElementById('buildStatus'), | |
| preview: document.getElementById('gradioPreview') | |
| }; | |
| // --- EVENT LISTENERS FOR LIVE UPDATES --- | |
| Object.values(inputs).forEach(input => { | |
| input.addEventListener('input', updateDockerfile); | |
| }); | |
| // Update slider values immediately | |
| inputs.tokens.addEventListener('input', (e) => displays.tokens.textContent = e.target.value); | |
| inputs.temp.addEventListener('input', (e) => displays.temp.textContent = e.target.value); | |
| // --- CORE FUNCTIONS --- | |
| function updateDockerfile() { | |
| const pyVer = inputs.python.value; | |
| const base = inputs.base.value; | |
| const title = inputs.title.value || 'My AI Demo'; | |
| const model = inputs.model.value || 'gpt2'; | |
| // Logic to select appropriate base image string | |
| let fromString = `python:${pyVer}-slim`; | |
| if (base.includes('cuda')) fromString = `nvidia/cuda:11.8.0-runtime-ubuntu${pyVer > 11 ? '22.04' : '20.04'}`; | |
| if (base.includes('ubuntu')) fromString = `ubuntu:latest`; | |
| const dockerfileContent = `# Auto-generated Dockerfile for Gradio App | |
| FROM ${fromString} | |
| # Set working directory | |
| WORKDIR /app | |
| # Install system dependencies | |
| RUN apt-get update && apt-get install -y \\ | |
| git \\ | |
| git-lfs \\ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Copy requirements file (simulated) | |
| RUN pip install --no-cache-dir -U pip | |
| RUN pip install gradio torch transformers accelerate | |
| # Set environment variables | |
| ENV MODEL_ID="${model}" | |
| ENV MAX_TOKENS=${inputs.tokens.value} | |
| ENV TEMPERATURE=${inputs.temp.value} | |
| APP_TITLE="${title}" | |
| # Copy application code | |
| COPY app.py . | |
| # Expose port | |
| EXPOSE 7860 | |
| # Run Gradio app | |
| CMD ["python", "app.py"] | |
| `; | |
| // Preserve the copy button, replace text content | |
| const btn = outputs.dockerfile.querySelector('.copy-btn'); | |
| outputs.dockerfile.innerHTML = ''; | |
| outputs.dockerfile.appendChild(btn); | |
| outputs.dockerfile.appendChild(document.createTextNode(dockerfileContent)); | |
| } | |
| function copyDockerfile() { | |
| const text = outputs.dockerfile.textContent.replace('Copy', '').trim(); | |
| navigator.clipboard.writeText(text).then(() => { | |
| const btn = outputs.dockerfile.querySelector('.copy-btn'); | |
| const originalText = btn.textContent; | |
| btn.textContent = 'Copied!'; | |
| setTimeout(() => btn.textContent = originalText, 2000); | |
| }); | |
| } | |
| function addLog(message, type = 'info') { | |
| const line = document.createElement('div'); | |
| line.className = 'log-line'; | |
| const time = new Date().toLocaleTimeString('en-US', { 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'; | |
| line.innerHTML = `<span class="log-time">[${time}]</span> <span class="${typeClass}">${message}</span>`; | |
| outputs.terminal.appendChild(line); | |
| outputs.terminal.scrollTop = outputs.terminal.scrollHeight; | |
| } | |
| async function runDeployment() { | |
| // Reset state | |
| outputs.terminal.innerHTML = ''; | |
| outputs.status.textContent = 'Building...'; | |
| outputs.status.className = 'status-badge'; | |
| outputs.preview.classList.remove('gradio-active'); | |
| outputs.preview.innerHTML = ` | |
| <i class="ph ph-spinner ph-spin" style="font-size: 3rem; margin-bottom: 10px; display: block;"></i> | |
| <p>Initializing Container...</p> | |
| `; | |
| const steps = [ | |
| { msg: "Pulling base image...", delay: 800 }, | |
| { msg: "Installing system dependencies (git, lfs)...", delay: 1500 }, | |
| { msg: "Upgrading pip...", delay: 1000 }, | |
| { msg: "Installing Python packages (gradio, torch)...", delay: 2500 }, | |
| { msg: "Downloading model weights...", delay: 2000 }, | |
| { msg: "Exposing port 7860...", delay: 500 }, | |
| { msg: "Starting Gradio interface...", delay: 800, type: 'success' } | |
| ]; | |
| for (let step of steps) { | |
| await new Promise(r => setTimeout(r, step.delay)); | |
| addLog(step.msg, step.type || 'info'); | |
| } | |
| // Final State | |
| outputs.status.textContent = 'Running'; | |
| outputs.status.className = 'status-badge status-running'; | |
| // Update Preview UI | |
| const title = inputs.title.value; | |
| outputs.preview.classList.add('gradio-active'); | |
| outputs.preview.innerHTML = ` | |
| <div style="text-align: left; max-width: 600px; margin: 0 auto;"> | |
| <h2 style="margin-bottom: 20px; color: var(--accent);">${title}</h2> | |
| <div style="background: var(--bg-input); padding: 15px; border-radius: 8px; border: 1px solid var(--border-color); margin-bottom: 15px;"> | |
| <label style="display:block; margin-bottom:5px; font-size:0.8rem;">Input Prompt</label> | |
| <input type="text" placeholder="Type something here..." style="width:100%; background:transparent; border:none; color:white; outline:none;"> | |
| </div> | |
| <button class="btn btn-secondary" style="width:100%;">Submit</button> | |
| <div style="margin-top: 20px; padding: 15px; background: rgba(46, 160, 67, 0.1); border: 1px solid var(--primary); border-radius: 8px; color: var(--primary);"> | |
| <i class="ph ph-check-circle"></i> Output will appear here. | |
| </div> | |
| </div> | |
| <div style="margin-top: 20px; font-size: 0.8rem; color: var(--text-muted);"> | |
| <i class="ph ph-share-network"></i> Public URL: https://huggingface.co/spaces/user/${title.replace(/\s+/g, '-').toLowerCase()} | |
| </div> | |
| `; | |
| addLog("Application successfully deployed.", "success"); | |
| } | |
| // Initialize on load | |
| updateDockerfile(); | |
| </script> | |
| </body> | |
| </html> |