Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Code Completion AI</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); | |
| html { | |
| scroll-behavior: smooth; | |
| } | |
| body { | |
| font-family: 'Inter', sans-serif; | |
| background-color: #0f172a; /* slate-900 */ | |
| background-image: radial-gradient(circle at 1px 1px, rgba(255,255,255,0.05) 1px, transparent 0); | |
| background-size: 2rem 2rem; | |
| } | |
| .suggestion-item { | |
| transition: all 0.2s ease-in-out; | |
| } | |
| .info-card-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); | |
| gap: 1rem; | |
| } | |
| </style> | |
| </head> | |
| <body class="text-gray-200 min-h-screen flex flex-col items-center justify-center p-4"> | |
| <main class="w-full max-w-5xl mx-auto grid grid-cols-1 lg:grid-cols-5 gap-8 lg:gap-12"> | |
| <!-- Left Column: Interaction --> | |
| <div class="lg:col-span-3 bg-slate-900/50 backdrop-blur-sm border border-slate-700 rounded-2xl shadow-2xl p-6 md:p-8"> | |
| <div class="text-left mb-8"> | |
| <h1 class="text-4xl font-bold text-white tracking-tight">Code Completion AI</h1> | |
| <p class="text-slate-400 mt-2">Enter a Python code snippet to get AI-powered suggestions.</p> | |
| </div> | |
| <div> | |
| <label for="code-input" class="block text-sm font-medium text-slate-300 mb-2">Python Snippet</label> | |
| <textarea id="code-input" | |
| class="w-full h-48 p-4 bg-slate-900 border border-slate-700 rounded-lg text-slate-200 focus:ring-2 focus:ring-sky-500 focus:border-sky-500 transition duration-200 resize-none font-mono text-sm" | |
| placeholder="e.g., import numpy as"></textarea> | |
| </div> | |
| <div class="mt-6 text-left"> | |
| <button id="predict-btn" | |
| class="bg-sky-600 hover:bg-sky-700 text-white font-bold py-3 px-6 rounded-lg transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-slate-900 focus:ring-sky-500 flex items-center justify-center"> | |
| <span id="btn-text">Get Suggestions</span> | |
| <span id="spinner" class="hidden"> | |
| <svg class="animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> | |
| <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle> | |
| <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path> | |
| </svg> | |
| </span> | |
| </button> | |
| </div> | |
| <div id="results-container" class="mt-8"> | |
| <h2 class="text-lg font-semibold text-white mb-3">Top 5 Suggestions</h2> | |
| <div id="suggestions" class="bg-slate-900 p-3 rounded-lg min-h-[160px] border border-slate-700 space-y-1"> | |
| <p id="placeholder-text" class="text-slate-500 p-2">Suggestions will appear here...</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Right Column: Model Info --> | |
| <div class="lg:col-span-2 space-y-6"> | |
| <div class="bg-slate-900/50 backdrop-blur-sm border border-slate-700 rounded-2xl shadow-xl p-6"> | |
| <h3 class="text-2xl font-bold text-white mb-4">Model Details</h3> | |
| <p class="text-slate-400 mb-6"> | |
| This app uses a <span class="text-sky-400 font-semibold">Residual LSTM</span> model with two LSTM layers and a skip connection. It was trained on the Python subset of the <span class="text-sky-400">CodeXGlue</span> dataset to predict the next token in a sequence. | |
| </p> | |
| <div class="info-card-grid"> | |
| <div class="bg-slate-800 p-4 rounded-lg border border-slate-700"> | |
| <p class="text-sm text-slate-400">Top-5 Accuracy</p> | |
| <p class="text-xl font-semibold text-white">86.82%</p> | |
| </div> | |
| <div class="bg-slate-800 p-4 rounded-lg border border-slate-700"> | |
| <p class="text-sm text-slate-400">Perplexity</p> | |
| <p class="text-xl font-semibold text-white">4.19</p> | |
| </div> | |
| <div class="bg-slate-800 p-4 rounded-lg border border-slate-700"> | |
| <p class="text-sm text-slate-400">Embedding Dim</p> | |
| <p class="text-xl font-semibold text-white">256</p> | |
| </div> | |
| <div class="bg-slate-800 p-4 rounded-lg border border-slate-700"> | |
| <p class="text-sm text-slate-400">Hidden Units</p> | |
| <p class="text-xl font-semibold text-white">512</p> | |
| </div> | |
| <div class="bg-slate-800 p-4 rounded-lg border border-slate-700"> | |
| <p class="text-sm text-slate-400">Vocab Size</p> | |
| <p class="text-xl font-semibold text-white">10,002</p> | |
| </div> | |
| <div class="bg-slate-800 p-4 rounded-lg border border-slate-700"> | |
| <p class="text-sm text-slate-400">Parameters</p> | |
| <p class="text-xl font-semibold text-white">~15.5 M</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <footer class="w-full max-w-5xl mx-auto text-center text-slate-500 py-8 mt-4"> | |
| <p>Made with ❤️ by Ayush</p> | |
| </footer> | |
| <script> | |
| const codeInput = document.getElementById('code-input'); | |
| const predictBtn = document.getElementById('predict-btn'); | |
| const suggestionsDiv = document.getElementById('suggestions'); | |
| const placeholderText = document.getElementById('placeholder-text'); | |
| const btnText = document.getElementById('btn-text'); | |
| const spinner = document.getElementById('spinner'); | |
| let debounceTimer; | |
| const getPredictions = async () => { | |
| const code = codeInput.value; | |
| if (code.trim() === '') { | |
| suggestionsDiv.innerHTML = '<p id="placeholder-text" class="text-slate-500 p-2">Suggestions will appear here...</p>'; | |
| return; | |
| } | |
| btnText.classList.add('hidden'); | |
| spinner.classList.remove('hidden'); | |
| predictBtn.disabled = true; | |
| try { | |
| const response = await fetch('/predict', { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ code: code }), | |
| }); | |
| if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); | |
| const data = await response.json(); | |
| if (data.error) { | |
| suggestionsDiv.innerHTML = `<p class="text-red-400 p-2">${data.error}</p>`; | |
| return; | |
| } | |
| if (data.suggestions && data.suggestions.length > 0) { | |
| suggestionsDiv.innerHTML = ''; | |
| data.suggestions.forEach(suggestion => { | |
| const p = document.createElement('p'); | |
| p.textContent = suggestion; | |
| p.className = 'suggestion-item p-2 rounded hover:bg-slate-700 cursor-pointer text-slate-300'; | |
| p.onclick = () => { | |
| const lastCharIsSpace = codeInput.value.slice(-1) === ' '; | |
| codeInput.value += (lastCharIsSpace ? '' : ' ') + suggestion; | |
| codeInput.focus(); | |
| getPredictions(); | |
| }; | |
| suggestionsDiv.appendChild(p); | |
| }); | |
| } else { | |
| suggestionsDiv.innerHTML = '<p class="text-slate-500 p-2">No suggestions found.</p>'; | |
| } | |
| } catch (error) { | |
| console.error('Error:', error); | |
| suggestionsDiv.innerHTML = '<p class="text-red-400 p-2">An error occurred. Check server logs.</p>'; | |
| } finally { | |
| btnText.classList.remove('hidden'); | |
| spinner.classList.add('hidden'); | |
| predictBtn.disabled = false; | |
| } | |
| }; | |
| predictBtn.addEventListener('click', getPredictions); | |
| codeInput.addEventListener('input', () => { | |
| clearTimeout(debounceTimer); | |
| debounceTimer = setTimeout(getPredictions, 500); // 500ms debounce | |
| }); | |
| </script> | |
| </body> | |
| </html> | |