File size: 9,166 Bytes
8f40d24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!DOCTYPE html>
<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>