Hmrishav commited on
Commit
ca282ad
·
1 Parent(s): 259f45b

resolve deps

Browse files
Files changed (1) hide show
  1. templates/index.html +421 -0
templates/index.html ADDED
@@ -0,0 +1,421 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>FlipSketch - GIF Generator</title>
5
+ <script src="https://cdn.tailwindcss.com"></script>
6
+ <style>
7
+ @keyframes shimmer {
8
+ 0% { transform: translateX(-100%); }
9
+ 100% { transform: translateX(100%); }
10
+ }
11
+
12
+ .loading-bar {
13
+ display: none;
14
+ position: relative;
15
+ overflow: hidden;
16
+ background: #f3f4f6;
17
+ height: 4px;
18
+ width: 100%;
19
+ }
20
+
21
+ .loading-bar::after {
22
+ content: '';
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ width: 50%;
27
+ height: 100%;
28
+ background: linear-gradient(90deg, transparent, #4f46e5, transparent);
29
+ animation: shimmer 1.5s infinite;
30
+ }
31
+
32
+ .loading-bar.active {
33
+ display: block;
34
+ }
35
+
36
+ .results {
37
+ display: none;
38
+ }
39
+
40
+ .results.active {
41
+ display: block;
42
+ }
43
+
44
+ .preview-container {
45
+ max-width: 300px;
46
+ margin: 10px 0;
47
+ }
48
+
49
+ .preview-image {
50
+ max-width: 100%;
51
+ height: auto;
52
+ border-radius: 0.5rem;
53
+ }
54
+
55
+ /* Updated styles to display multiple GIFs in a grid */
56
+ .results-grid {
57
+ display: grid;
58
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
59
+ grid-gap: 20px;
60
+ justify-items: center;
61
+ }
62
+
63
+ .results-grid img {
64
+ width: 100%;
65
+ height: auto;
66
+ border-radius: 0.5rem;
67
+ }
68
+
69
+ .examples-grid {
70
+ display: grid;
71
+ grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); /* Increased minmax to 150px */
72
+ grid-gap: 15px; /* Increased gap between images */
73
+ margin-top: 10px;
74
+ }
75
+
76
+ .example-item {
77
+ cursor: pointer;
78
+ border: 2px solid transparent;
79
+ border-radius: 0.25rem;
80
+ overflow: hidden;
81
+ }
82
+
83
+ .example-item.selected {
84
+ border-color: #4f46e5; /* Indigo border when selected */
85
+ }
86
+
87
+ .example-item img {
88
+ width: 100%;
89
+ height: auto;
90
+ display: block;
91
+ }
92
+
93
+
94
+ .example-item img {
95
+ width: 100%;
96
+ height: auto;
97
+ display: block;
98
+ }
99
+ .tab-buttons {
100
+ display: flex;
101
+ border-bottom: 1px solid #e5e7eb;
102
+ margin-bottom: 1rem;
103
+ }
104
+
105
+ .tab-button {
106
+ flex: 1;
107
+ padding: 0.75rem 1rem;
108
+ text-align: center;
109
+ cursor: pointer;
110
+ border: 1px solid transparent;
111
+ border-bottom: none;
112
+ background-color: #f9fafb;
113
+ font-weight: 500;
114
+ color: #6b7280;
115
+ }
116
+
117
+ .tab-button.active {
118
+ background-color: #ffffff;
119
+ border-top-left-radius: 0.5rem;
120
+ border-top-right-radius: 0.5rem;
121
+ border-color: #e5e7eb;
122
+ color: #4f46e5;
123
+ border-bottom: 1px solid #ffffff;
124
+ }
125
+
126
+ .tab-content {
127
+ display: none;
128
+ }
129
+
130
+ .tab-content.active {
131
+ display: block;
132
+ }
133
+
134
+ </style>
135
+ </head>
136
+ <body class="bg-gray-100 min-h-screen">
137
+ <div class="container mx-auto px-4 py-8">
138
+ <h1 class="text-4xl font-bold text-center mb-8 text-indigo-600">FlipSketch</h1>
139
+
140
+ <div class="max-w-2xl mx-auto bg-white rounded-lg shadow-lg p-6">
141
+ <form id="generatorForm" class="space-y-6">
142
+ <div>
143
+ <label class="block text-sm font-medium text-gray-700 mb-2">Enter your prompt</label>
144
+ <input type="text" name="prompt" required
145
+ class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-indigo-500 focus:border-indigo-500">
146
+ </div>
147
+
148
+ <div>
149
+ <div class="tab-buttons">
150
+ <div class="tab-button active" data-tab="examplesTab">Sketch</div>
151
+ <div class="tab-button" data-tab="uploadTab">Upload</div>
152
+ </div>
153
+ <div id="examplesTab" class="tab-content active">
154
+ <div id="exampleSketches" class="examples-grid">
155
+ </div>
156
+ </div>
157
+
158
+
159
+ <div id="uploadTab" class="tab-content">
160
+ <input type="file" id="imageInput" name="image" accept="image/*"
161
+ class="w-full px-4 py-2 border border-gray-300 rounded-md">
162
+ <div id="imagePreview" class="preview-container"></div>
163
+ </div>
164
+
165
+ </div>
166
+
167
+ <!-- Seeds input remains unchanged -->
168
+ <div>
169
+ <label class="block text-sm font-medium text-gray-700 mb-2">Seeds (1-10)</label>
170
+ <input type="number" name="seeds" min="1" max="10" value="5"
171
+ class="w-full px-4 py-2 border border-gray-300 rounded-md">
172
+ </div>
173
+
174
+ <div>
175
+ <label class="block text-sm font-medium text-gray-700 mb-2">Motion (0.0 - 1.0) [Reduce when the animation changes the input sketch]</label>
176
+ <input type="range" name="lambda" min="0" max="1" step="0.05" value="0.5" class="w-full">
177
+ <div class="text-sm text-gray-600 mt-1">Value (1-Lambda) : <span id="lambdaValue">0.5</span></div>
178
+ </div>
179
+
180
+ <button type="submit"
181
+ class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition duration-200">
182
+ Generate GIF
183
+ </button>
184
+ </form>
185
+
186
+ <div id="loadingBar" class="loading-bar mt-6"></div>
187
+ <div id="progressText" class="text-center mt-4 text-gray-600 hidden">Generating your GIF...
188
+ <span id="progressPercent">0%</span>
189
+ </div>
190
+
191
+ <div class="results mt-8">
192
+ <h2 class="text-2xl font-semibold mb-4 text-center">Generated GIFs</h2>
193
+ <div class="results-grid" id="resultsGrid"></div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <script>
199
+ // Lambda Slider Update
200
+ const lambdaSlider = document.querySelector('input[name="lambda"]');
201
+ const lambdaValue = document.getElementById('lambdaValue');
202
+ lambdaSlider.addEventListener('input', () => {
203
+ lambdaValue.textContent = lambdaSlider.value;
204
+ });
205
+ const examplePrompts = {
206
+ 'sketch1.png': 'The camel walks slowly',
207
+ 'sketch2.png': 'The wine in the wine glass sways from side to side',
208
+ 'sketch3.png': 'The squirrel is eating a nut',
209
+ 'sketch4.png': 'The surfer surfs on the waves',
210
+ 'sketch5.png': 'A galloping horse',
211
+ 'sketch6.png': 'The cat walks forward',
212
+ 'sketch7.png': 'The eagle flies in the sky',
213
+ 'sketch8.png': 'The flower is blooming slowly',
214
+ 'sketch9.png': 'The reindeer looks around',
215
+ 'sketch10.png': 'The cloud floats in the sky',
216
+ 'sketch11.png': 'The jazz saxophonist performs on stage with a rhythmic sway, his upper body sways subtly to the rhythm of the music.',
217
+ 'sketch12.png': 'The biker rides on the road',
218
+ };
219
+
220
+ const tabButtons = document.querySelectorAll('.tab-button');
221
+ const tabContents = document.querySelectorAll('.tab-content');
222
+ let selectedExample = null;
223
+
224
+ tabButtons.forEach(button => {
225
+ button.addEventListener('click', () => {
226
+ // Remove active class from all buttons
227
+ tabButtons.forEach(btn => btn.classList.remove('active'));
228
+ // Hide all tab contents
229
+ tabContents.forEach(content => content.classList.remove('active'));
230
+
231
+ // Add active class to clicked button
232
+ button.classList.add('active');
233
+ // Show corresponding tab content
234
+ const tabId = button.getAttribute('data-tab');
235
+ document.getElementById(tabId).classList.add('active');
236
+
237
+ // Reset inputs when switching tabs
238
+ if (tabId === 'uploadTab') {
239
+ // Clear selected example
240
+ selectedExample = null;
241
+ const exampleItems = document.querySelectorAll('.example-item');
242
+ exampleItems.forEach(item => item.classList.remove('selected'));
243
+ // Enable image input
244
+ document.getElementById('imageInput').disabled = false;
245
+
246
+ // Clear the prompt input field
247
+ const promptInput = document.querySelector('input[name="prompt"]');
248
+ promptInput.value = '';
249
+ } else if (tabId === 'examplesTab') {
250
+ // Clear uploaded image
251
+ const imageInput = document.getElementById('imageInput');
252
+ imageInput.value = '';
253
+ document.getElementById('imagePreview').innerHTML = '';
254
+ // Disable image input
255
+ imageInput.disabled = true;
256
+
257
+ // Clear the prompt input field
258
+ const promptInput = document.querySelector('input[name="prompt"]');
259
+ promptInput.value = '';
260
+ }
261
+ });
262
+ });
263
+
264
+ // Load example sketches when the page loads
265
+ document.addEventListener('DOMContentLoaded', () => {
266
+ const exampleSketches = document.getElementById('exampleSketches');
267
+ const numExamples = 12; // Number of example sketches
268
+ for (let i = 1; i <= numExamples; i++) {
269
+ const filename = `sketch${i}.png`;
270
+ const prompt = examplePrompts[filename] || ''; // Get the default prompt, or empty string if not defined
271
+
272
+ const exampleItem = document.createElement('div');
273
+ exampleItem.className = 'example-item';
274
+ exampleItem.dataset.prompt = prompt; // Store the prompt as a data attribute
275
+
276
+ const img = document.createElement('img');
277
+ img.src = `static/examples/${filename}`; // Adjust the path to your examples
278
+ img.alt = `Sketch ${i}`;
279
+ img.dataset.filename = filename; // Store the filename
280
+
281
+ exampleItem.appendChild(img);
282
+ exampleSketches.appendChild(exampleItem);
283
+ }
284
+ });
285
+ // Handle selection of an example sketch
286
+ document.getElementById('exampleSketches').addEventListener('click', (e) => {
287
+ if (e.target.tagName === 'IMG') {
288
+ const clickedItem = e.target.parentElement;
289
+ const isSelected = clickedItem.classList.contains('selected');
290
+
291
+ // Deselect all items
292
+ const exampleItems = document.querySelectorAll('.example-item');
293
+ exampleItems.forEach(item => item.classList.remove('selected'));
294
+
295
+ if (!isSelected) {
296
+ // Select the clicked item
297
+ clickedItem.classList.add('selected');
298
+ selectedExample = e.target.dataset.filename;
299
+
300
+ // Retrieve and set the default prompt
301
+ const defaultPrompt = clickedItem.dataset.prompt || '';
302
+ const promptInput = document.querySelector('input[name="prompt"]');
303
+ promptInput.value = defaultPrompt;
304
+ } else {
305
+ // Deselecting the item
306
+ selectedExample = null;
307
+ const promptInput = document.querySelector('input[name="prompt"]');
308
+ promptInput.value = '';
309
+ }
310
+ }
311
+ });
312
+
313
+ // Image upload preview (optional)
314
+ document.getElementById('imageInput').addEventListener('change', (e) => {
315
+ const previewContainer = document.getElementById('imagePreview');
316
+ previewContainer.innerHTML = '';
317
+ if (e.target.files.length > 0) {
318
+ const file = e.target.files[0];
319
+ const img = document.createElement('img');
320
+ img.className = 'preview-image';
321
+ img.src = URL.createObjectURL(file);
322
+ previewContainer.appendChild(img);
323
+ }
324
+ });
325
+
326
+ document.getElementById('generatorForm').addEventListener('submit', async (e) => {
327
+ e.preventDefault();
328
+
329
+ const form = e.target;
330
+ const formData = new FormData(form);
331
+
332
+ // Determine which tab is active
333
+ const activeTab = document.querySelector('.tab-content.active').id;
334
+
335
+ if (activeTab === 'uploadTab') {
336
+ // Ensure a file is uploaded
337
+ const imageInput = document.getElementById('imageInput');
338
+ if (!imageInput.files.length) {
339
+ alert('Please upload an image before submitting!');
340
+ return; // Stop form submission
341
+ }
342
+ // No need to append selected_example
343
+ } else if (activeTab === 'examplesTab') {
344
+ // Ensure an example is selected
345
+ if (!selectedExample) {
346
+ alert('Please select an example sketch before submitting!');
347
+ return; // Stop form submission
348
+ }
349
+ // Append selected_example to form data
350
+ formData.append('selected_example', selectedExample);
351
+ }
352
+
353
+ // Show Loading Bar
354
+ const loadingBar = document.getElementById('loadingBar');
355
+ const progressText = document.getElementById('progressText');
356
+ const progressPercent = document.getElementById('progressPercent');
357
+ loadingBar.classList.add('active');
358
+ progressText.classList.remove('hidden');
359
+ document.querySelector('.results').classList.remove('active');
360
+
361
+ // Simulate Loading Progress
362
+ let progress = 0;
363
+ const totalDuration = 65000; // 30 seconds
364
+ const updateInterval = 100; // Update every 100ms
365
+ const increment = 100 / (totalDuration / updateInterval);
366
+
367
+ const progressInterval = setInterval(() => {
368
+ progress += increment;
369
+ if (progress >= 100) {
370
+ progress = 100;
371
+ clearInterval(progressInterval);
372
+ }
373
+ progressPercent.textContent = `${Math.floor(progress)}%`;
374
+ }, updateInterval);
375
+
376
+ try {
377
+ const response = await fetch('/generate', {
378
+ method: 'POST',
379
+ body: formData,
380
+ });
381
+
382
+ const data = await response.json();
383
+
384
+ if (response.ok) {
385
+ // Complete the Progress Bar
386
+ progress = 100;
387
+ progressPercent.textContent = '100%';
388
+
389
+ const resultsGrid = document.getElementById('resultsGrid');
390
+ resultsGrid.innerHTML = '';
391
+
392
+ // Display all GIFs returned by the server
393
+ data.gifs.forEach((gifUrl) => {
394
+ const gifElement = document.createElement('div');
395
+ gifElement.className = 'gif-container';
396
+ gifElement.innerHTML = `
397
+ <img src="${gifUrl}" alt="Generated GIF">
398
+ `;
399
+ resultsGrid.appendChild(gifElement);
400
+ });
401
+
402
+ document.querySelector('.results').classList.add('active');
403
+ } else {
404
+ alert(data.error || 'An error occurred');
405
+ }
406
+ } catch (error) {
407
+ console.error('Error:', error);
408
+ alert('An error occurred while generating the GIFs');
409
+ } finally {
410
+ clearInterval(progressInterval);
411
+ setTimeout(() => {
412
+ loadingBar.classList.remove('active');
413
+ progressText.classList.add('hidden');
414
+ }, 500);
415
+ }
416
+ });
417
+
418
+
419
+ </script>
420
+ </body>
421
+ </html>`