dauksza123 commited on
Commit
2d08aab
·
verified ·
1 Parent(s): b17279b

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +352 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Local Ai
3
- emoji: 🚀
4
- colorFrom: purple
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: local-ai
3
+ emoji: 🐳
4
+ colorFrom: gray
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,352 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Transformers.js Text Generator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/@xenova/[email protected]"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ .typewriter {
12
+ border-right: 3px solid #4f46e5;
13
+ white-space: nowrap;
14
+ overflow: hidden;
15
+ animation: blink-caret 0.75s step-end infinite;
16
+ }
17
+
18
+ @keyframes blink-caret {
19
+ from, to { border-color: transparent }
20
+ 50% { border-color: #4f46e5; }
21
+ }
22
+
23
+ .fade-in {
24
+ animation: fadeIn 0.5s ease-in;
25
+ }
26
+
27
+ @keyframes fadeIn {
28
+ from { opacity: 0; }
29
+ to { opacity: 1; }
30
+ }
31
+
32
+ .scrollbar-hide::-webkit-scrollbar {
33
+ display: none;
34
+ }
35
+
36
+ .scrollbar-hide {
37
+ -ms-overflow-style: none;
38
+ scrollbar-width: none;
39
+ }
40
+ </style>
41
+ </head>
42
+ <body class="bg-gray-50 min-h-screen">
43
+ <div class="container mx-auto px-4 py-8 max-w-4xl">
44
+ <header class="mb-10 text-center">
45
+ <h1 class="text-4xl font-bold text-indigo-600 mb-2">Transformers.js</h1>
46
+ <h2 class="text-2xl font-semibold text-gray-700">GPT-2 Text Generator</h2>
47
+ <p class="text-gray-500 mt-2">Powered by the browser with no server required</p>
48
+ </header>
49
+
50
+ <div class="bg-white rounded-xl shadow-lg overflow-hidden mb-8">
51
+ <div class="p-6">
52
+ <div class="flex items-center justify-between mb-4">
53
+ <h3 class="text-lg font-medium text-gray-900">Text Generation</h3>
54
+ <div class="flex items-center space-x-2">
55
+ <span id="model-status" class="px-3 py-1 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">
56
+ Model: Loading...
57
+ </span>
58
+ <button id="info-btn" class="text-gray-400 hover:text-indigo-600 transition-colors">
59
+ <i class="fas fa-info-circle"></i>
60
+ </button>
61
+ </div>
62
+ </div>
63
+
64
+ <div class="mb-4">
65
+ <label for="prompt" class="block text-sm font-medium text-gray-700 mb-2">Prompt</label>
66
+ <div class="relative">
67
+ <textarea
68
+ id="prompt"
69
+ rows="4"
70
+ class="block w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-indigo-500 focus:border-indigo-500"
71
+ placeholder="Start typing your prompt here..."></textarea>
72
+ <div class="absolute bottom-3 right-3 flex space-x-2">
73
+ <button id="clear-btn" class="p-1 text-gray-400 hover:text-indigo-600 transition-colors">
74
+ <i class="fas fa-trash-alt"></i>
75
+ </button>
76
+ </div>
77
+ </div>
78
+ </div>
79
+
80
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
81
+ <div>
82
+ <label for="max-length" class="block text-sm font-medium text-gray-700 mb-1">Max Length</label>
83
+ <input type="range" id="max-length" min="10" max="500" value="50" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
84
+ <div class="flex justify-between text-xs text-gray-500">
85
+ <span>10</span>
86
+ <span id="max-length-value">50</span>
87
+ <span>500</span>
88
+ </div>
89
+ </div>
90
+
91
+ <div>
92
+ <label for="temperature" class="block text-sm font-medium text-gray-700 mb-1">Temperature</label>
93
+ <input type="range" id="temperature" min="0.1" max="1.5" step="0.1" value="0.7" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer">
94
+ <div class="flex justify-between text-xs text-gray-500">
95
+ <span>0.1</span>
96
+ <span id="temperature-value">0.7</span>
97
+ <span>1.5</span>
98
+ </div>
99
+ </div>
100
+ </div>
101
+
102
+ <div class="flex justify-end space-x-3">
103
+ <button id="stop-btn" class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 bg-white hover:bg-gray-50 hidden">
104
+ <i class="fas fa-stop mr-2"></i> Stop
105
+ </button>
106
+ <button id="generate-btn" class="px-6 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors flex items-center">
107
+ <i class="fas fa-bolt mr-2"></i> Generate
108
+ </button>
109
+ </div>
110
+ </div>
111
+ </div>
112
+
113
+ <div id="output-container" class="bg-white rounded-xl shadow-lg overflow-hidden hidden">
114
+ <div class="p-6">
115
+ <div class="flex items-center justify-between mb-4">
116
+ <h3 class="text-lg font-medium text-gray-900">Generated Text</h3>
117
+ <button id="copy-btn" class="px-3 py-1 text-sm text-indigo-600 hover:text-indigo-800 transition-colors flex items-center">
118
+ <i class="fas fa-copy mr-2"></i> Copy
119
+ </button>
120
+ </div>
121
+
122
+ <div id="output" class="bg-gray-50 p-4 rounded-lg min-h-32 max-h-96 overflow-y-auto scrollbar-hide">
123
+ <p class="text-gray-500 italic">Generated text will appear here...</p>
124
+ </div>
125
+
126
+ <div class="mt-4 flex justify-between items-center text-sm text-gray-500">
127
+ <div id="stats" class="flex space-x-4">
128
+ <span id="time-taken"><i class="fas fa-stopwatch mr-1"></i> --</span>
129
+ <span id="tokens-generated"><i class="fas fa-key mr-1"></i> -- tokens</span>
130
+ </div>
131
+ <button id="regenerate-btn" class="text-indigo-600 hover:text-indigo-800 transition-colors flex items-center">
132
+ <i class="fas fa-sync-alt mr-2"></i> Regenerate
133
+ </button>
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ <div id="info-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
139
+ <div class="bg-white rounded-xl max-w-md w-full mx-4 p-6">
140
+ <div class="flex justify-between items-center mb-4">
141
+ <h3 class="text-lg font-medium text-gray-900">About This Demo</h3>
142
+ <button id="close-modal" class="text-gray-400 hover:text-gray-500">
143
+ <i class="fas fa-times"></i>
144
+ </button>
145
+ </div>
146
+ <div class="space-y-3 text-gray-600">
147
+ <p>This demo uses <span class="font-semibold">Transformers.js</span> to run a GPT-2 model directly in your browser with WebAssembly.</p>
148
+ <p>The model is quantized to reduce size and runs entirely client-side - no server processing required!</p>
149
+ <p><span class="font-semibold">Parameters:</span></p>
150
+ <ul class="list-disc pl-5 space-y-1">
151
+ <li><span class="font-medium">Max Length:</span> Controls how many tokens to generate</li>
152
+ <li><span class="font-medium">Temperature:</span> Higher values make output more random</li>
153
+ </ul>
154
+ <p class="pt-2 text-sm text-indigo-600"><i class="fas fa-info-circle mr-2"></i> First generation may take longer as the model loads.</p>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+
160
+ <script>
161
+ // DOM Elements
162
+ const promptInput = document.getElementById('prompt');
163
+ const generateBtn = document.getElementById('generate-btn');
164
+ const stopBtn = document.getElementById('stop-btn');
165
+ const clearBtn = document.getElementById('clear-btn');
166
+ const copyBtn = document.getElementById('copy-btn');
167
+ const regenerateBtn = document.getElementById('regenerate-btn');
168
+ const outputContainer = document.getElementById('output-container');
169
+ const outputDiv = document.getElementById('output');
170
+ const maxLengthSlider = document.getElementById('max-length');
171
+ const maxLengthValue = document.getElementById('max-length-value');
172
+ const temperatureSlider = document.getElementById('temperature');
173
+ const temperatureValue = document.getElementById('temperature-value');
174
+ const timeTaken = document.getElementById('time-taken');
175
+ const tokensGenerated = document.getElementById('tokens-generated');
176
+ const modelStatus = document.getElementById('model-status');
177
+ const infoBtn = document.getElementById('info-btn');
178
+ const infoModal = document.getElementById('info-modal');
179
+ const closeModal = document.getElementById('close-modal');
180
+
181
+ // App State
182
+ let pipeline = null;
183
+ let controller = null;
184
+ let isGenerating = false;
185
+ let modelLoaded = false;
186
+
187
+ // Initialize the model
188
+ async function initializeModel() {
189
+ try {
190
+ modelStatus.textContent = 'Model: Loading...';
191
+
192
+ // Load the GPT-2 model (quantized version for better performance)
193
+ pipeline = await transformers.AutoModelForCausalLM.from_pretrained('Xenova/gpt2', {
194
+ quantized: true,
195
+ progress_callback: (progress) => {
196
+ const percent = Math.floor(progress * 100);
197
+ modelStatus.textContent = `Model: Loading ${percent}%`;
198
+ }
199
+ });
200
+
201
+ modelStatus.textContent = 'Model: Ready';
202
+ modelStatus.className = 'px-3 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800';
203
+ modelLoaded = true;
204
+
205
+ console.log('Model loaded successfully');
206
+ } catch (error) {
207
+ console.error('Error loading model:', error);
208
+ modelStatus.textContent = 'Model: Failed to load';
209
+ modelStatus.className = 'px-3 py-1 rounded-full text-xs font-medium bg-red-100 text-red-800';
210
+ }
211
+ }
212
+
213
+ // Generate text function
214
+ async function generateText() {
215
+ if (!modelLoaded) {
216
+ alert('Model is still loading. Please wait...');
217
+ return;
218
+ }
219
+
220
+ const prompt = promptInput.value.trim();
221
+ if (!prompt) {
222
+ alert('Please enter a prompt');
223
+ return;
224
+ }
225
+
226
+ isGenerating = true;
227
+ generateBtn.disabled = true;
228
+ stopBtn.classList.remove('hidden');
229
+ outputContainer.classList.remove('hidden');
230
+
231
+ // Clear previous output
232
+ outputDiv.innerHTML = '<p class="typewriter">Generating...</p>';
233
+
234
+ const maxLength = parseInt(maxLengthSlider.value);
235
+ const temperature = parseFloat(temperatureSlider.value);
236
+
237
+ // Start timing
238
+ const startTime = performance.now();
239
+
240
+ try {
241
+ // Create a new AbortController for this generation
242
+ controller = new AbortController();
243
+
244
+ // Generate text
245
+ const output = await pipeline(prompt, {
246
+ max_length: maxLength,
247
+ temperature: temperature,
248
+ do_sample: true,
249
+ signal: controller.signal,
250
+ callback_function: (text) => {
251
+ // Update output as it's being generated
252
+ outputDiv.innerHTML = `<p class="fade-in">${text}</p>`;
253
+ }
254
+ });
255
+
256
+ // Calculate stats
257
+ const endTime = performance.now();
258
+ const duration = ((endTime - startTime) / 1000).toFixed(2);
259
+ const tokens = output.length;
260
+
261
+ // Update stats
262
+ timeTaken.innerHTML = `<i class="fas fa-stopwatch mr-1"></i> ${duration}s`;
263
+ tokensGenerated.innerHTML = `<i class="fas fa-key mr-1"></i> ${tokens} tokens`;
264
+
265
+ // Final output
266
+ outputDiv.innerHTML = `<p class="fade-in">${output}</p>`;
267
+
268
+ } catch (error) {
269
+ if (error.name === 'AbortError') {
270
+ console.log('Generation stopped by user');
271
+ outputDiv.innerHTML = '<p class="text-gray-500 italic">Generation stopped.</p>';
272
+ } else {
273
+ console.error('Error during generation:', error);
274
+ outputDiv.innerHTML = `<p class="text-red-500">Error: ${error.message}</p>`;
275
+ }
276
+ } finally {
277
+ isGenerating = false;
278
+ generateBtn.disabled = false;
279
+ stopBtn.classList.add('hidden');
280
+ controller = null;
281
+ }
282
+ }
283
+
284
+ // Stop generation
285
+ function stopGeneration() {
286
+ if (controller && isGenerating) {
287
+ controller.abort();
288
+ isGenerating = false;
289
+ generateBtn.disabled = false;
290
+ stopBtn.classList.add('hidden');
291
+ }
292
+ }
293
+
294
+ // Event Listeners
295
+ generateBtn.addEventListener('click', generateText);
296
+ stopBtn.addEventListener('click', stopGeneration);
297
+
298
+ clearBtn.addEventListener('click', () => {
299
+ promptInput.value = '';
300
+ promptInput.focus();
301
+ });
302
+
303
+ copyBtn.addEventListener('click', () => {
304
+ const textToCopy = outputDiv.textContent;
305
+ navigator.clipboard.writeText(textToCopy).then(() => {
306
+ // Show feedback
307
+ const originalText = copyBtn.innerHTML;
308
+ copyBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Copied!';
309
+ setTimeout(() => {
310
+ copyBtn.innerHTML = originalText;
311
+ }, 2000);
312
+ });
313
+ });
314
+
315
+ regenerateBtn.addEventListener('click', () => {
316
+ if (promptInput.value.trim()) {
317
+ generateText();
318
+ }
319
+ });
320
+
321
+ maxLengthSlider.addEventListener('input', () => {
322
+ maxLengthValue.textContent = maxLengthSlider.value;
323
+ });
324
+
325
+ temperatureSlider.addEventListener('input', () => {
326
+ temperatureValue.textContent = temperatureSlider.value;
327
+ });
328
+
329
+ infoBtn.addEventListener('click', () => {
330
+ infoModal.classList.remove('hidden');
331
+ });
332
+
333
+ closeModal.addEventListener('click', () => {
334
+ infoModal.classList.add('hidden');
335
+ });
336
+
337
+ infoModal.addEventListener('click', (e) => {
338
+ if (e.target === infoModal) {
339
+ infoModal.classList.add('hidden');
340
+ }
341
+ });
342
+
343
+ // Initialize the app
344
+ document.addEventListener('DOMContentLoaded', () => {
345
+ initializeModel();
346
+
347
+ // Focus the prompt input on page load
348
+ promptInput.focus();
349
+ });
350
+ </script>
351
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=dauksza123/local-ai" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
352
+ </html>