Gertie01 commited on
Commit
8bd9942
·
verified ·
1 Parent(s): b0f164a

Upload folder using huggingface_hub

Browse files
assets/css/styles.css ADDED
@@ -0,0 +1,473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Basic Reset & Box Sizing */
2
+ *, *::before, *::after {
3
+ box-sizing: border-box;
4
+ margin: 0;
5
+ padding: 0;
6
+ }
7
+
8
+ /* Base Styles */
9
+ :root {
10
+ --primary-color: #6a0dad; /* Dark purple */
11
+ --primary-hover: #5a0ca0;
12
+ --secondary-color: #007bff; /* Blue for highlights */
13
+ --text-color: #333;
14
+ --light-text-color: #f4f4f4;
15
+ --bg-color: #f9f9f9;
16
+ --card-bg: #ffffff;
17
+ --border-color: #e0e0e0;
18
+ --shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
19
+ --border-radius: 8px;
20
+ --spacing-md: 16px;
21
+ --spacing-lg: 24px;
22
+ }
23
+
24
+ body {
25
+ font-family: 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
26
+ line-height: 1.6;
27
+ color: var(--text-color);
28
+ background-color: var(--bg-color);
29
+ min-height: 100vh;
30
+ display: flex;
31
+ flex-direction: column;
32
+ }
33
+
34
+ .container {
35
+ max-width: 1200px;
36
+ margin: 0 auto;
37
+ padding: var(--spacing-md);
38
+ }
39
+
40
+ /* Header */
41
+ .site-header {
42
+ background-color: var(--primary-color);
43
+ color: var(--light-text-color);
44
+ padding: var(--spacing-md) 0;
45
+ box-shadow: var(--shadow);
46
+ }
47
+
48
+ .site-header .container {
49
+ display: flex;
50
+ justify-content: space-between;
51
+ align-items: center;
52
+ flex-wrap: wrap; /* Allow wrapping on smaller screens */
53
+ }
54
+
55
+ .site-header h1 {
56
+ font-size: 1.8em;
57
+ margin: 0;
58
+ padding-bottom: 5px; /* Add some padding below for mobile */
59
+ }
60
+
61
+ .anycoder-link {
62
+ color: var(--light-text-color);
63
+ text-decoration: none;
64
+ font-weight: bold;
65
+ font-size: 0.9em;
66
+ padding: 5px 10px;
67
+ border: 1px solid var(--light-text-color);
68
+ border-radius: 5px;
69
+ transition: background-color 0.3s ease, color 0.3s ease;
70
+ }
71
+
72
+ .anycoder-link:hover {
73
+ background-color: var(--light-text-color);
74
+ color: var(--primary-color);
75
+ }
76
+
77
+ /* Main Content Sections */
78
+ main {
79
+ flex: 1; /* Allows main content to grow and push footer down */
80
+ padding-top: var(--spacing-lg);
81
+ padding-bottom: var(--spacing-lg);
82
+ }
83
+
84
+ section {
85
+ background-color: var(--card-bg);
86
+ padding: var(--spacing-lg);
87
+ margin-bottom: var(--spacing-lg);
88
+ border-radius: var(--border-radius);
89
+ box-shadow: var(--shadow);
90
+ }
91
+
92
+ h2 {
93
+ color: var(--primary-color);
94
+ font-size: 1.5em;
95
+ margin-bottom: var(--spacing-md);
96
+ border-bottom: 2px solid var(--border-color);
97
+ padding-bottom: 10px;
98
+ }
99
+
100
+ /* Upload Section */
101
+ .upload-section {
102
+ text-align: center;
103
+ }
104
+
105
+ .dropzone {
106
+ border: 2px dashed var(--border-color);
107
+ border-radius: var(--border-radius);
108
+ padding: var(--spacing-lg);
109
+ text-align: center;
110
+ cursor: pointer;
111
+ transition: background-color 0.3s ease, border-color 0.3s ease;
112
+ margin-bottom: var(--spacing-md);
113
+ position: relative;
114
+ }
115
+
116
+ .dropzone.drag-over {
117
+ background-color: #f0e6fa; /* Lighter primary color */
118
+ border-color: var(--primary-color);
119
+ }
120
+
121
+ .dropzone p {
122
+ margin-bottom: var(--spacing-md);
123
+ font-size: 1.1em;
124
+ color: #666;
125
+ }
126
+
127
+ .btn {
128
+ display: inline-block;
129
+ background-color: var(--primary-color);
130
+ color: var(--light-text-color);
131
+ padding: 10px 20px;
132
+ border: none;
133
+ border-radius: 5px;
134
+ cursor: pointer;
135
+ font-size: 1em;
136
+ transition: background-color 0.3s ease, transform 0.2s ease;
137
+ }
138
+
139
+ .btn:hover {
140
+ background-color: var(--primary-hover);
141
+ transform: translateY(-2px);
142
+ }
143
+
144
+ .btn-primary {
145
+ background-color: var(--secondary-color);
146
+ }
147
+
148
+ .btn-primary:hover {
149
+ background-color: #0056b3;
150
+ }
151
+
152
+ .uploaded-previews {
153
+ display: flex;
154
+ flex-wrap: wrap;
155
+ gap: var(--spacing-md);
156
+ justify-content: center;
157
+ margin-top: var(--spacing-md);
158
+ }
159
+
160
+ .uploaded-image-wrapper {
161
+ position: relative;
162
+ width: 100px;
163
+ height: 100px;
164
+ border: 1px solid var(--border-color);
165
+ border-radius: var(--border-radius);
166
+ overflow: hidden;
167
+ cursor: grab;
168
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
169
+ }
170
+
171
+ .uploaded-image-wrapper img {
172
+ width: 100%;
173
+ height: 100%;
174
+ object-fit: cover;
175
+ display: block;
176
+ }
177
+
178
+ .remove-image {
179
+ position: absolute;
180
+ top: 5px;
181
+ right: 5px;
182
+ background-color: rgba(255, 0, 0, 0.7);
183
+ color: white;
184
+ border: none;
185
+ border-radius: 50%;
186
+ width: 20px;
187
+ height: 20px;
188
+ font-size: 0.8em;
189
+ display: flex;
190
+ align-items: center;
191
+ justify-content: center;
192
+ cursor: pointer;
193
+ transition: background-color 0.2s ease;
194
+ }
195
+
196
+ .remove-image:hover {
197
+ background-color: rgba(255, 0, 0, 1);
198
+ }
199
+
200
+ /* Remix Spots Section */
201
+ .instruction-text {
202
+ font-style: italic;
203
+ color: #666;
204
+ margin-bottom: var(--spacing-md);
205
+ text-align: center;
206
+ }
207
+
208
+ .remix-spots {
209
+ display: grid;
210
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
211
+ gap: var(--spacing-md);
212
+ margin-top: var(--spacing-md);
213
+ }
214
+
215
+ .image-spot {
216
+ border: 2px dashed var(--border-color);
217
+ border-radius: var(--border-radius);
218
+ min-height: 200px;
219
+ display: flex;
220
+ flex-direction: column;
221
+ justify-content: center;
222
+ align-items: center;
223
+ text-align: center;
224
+ padding: var(--spacing-md);
225
+ transition: background-color 0.3s ease, border-color 0.3s ease;
226
+ background-color: #fefefe;
227
+ position: relative;
228
+ overflow: hidden; /* Ensure image doesn't overflow */
229
+ }
230
+
231
+ .image-spot.drag-over {
232
+ background-color: #e6f0fa; /* Lighter blue for spot drag-over */
233
+ border-color: var(--secondary-color);
234
+ }
235
+
236
+ .image-spot .spot-label {
237
+ position: absolute;
238
+ top: 10px;
239
+ left: 10px;
240
+ background-color: rgba(0, 0, 0, 0.6);
241
+ color: white;
242
+ padding: 3px 8px;
243
+ border-radius: 5px;
244
+ font-size: 0.8em;
245
+ z-index: 10;
246
+ }
247
+
248
+ .image-spot .spot-image {
249
+ max-width: 100%;
250
+ max-height: 180px; /* Constrain image height */
251
+ object-fit: contain;
252
+ display: block;
253
+ margin-top: 20px; /* Space for label */
254
+ filter: grayscale(80%); /* Placeholder initial look */
255
+ transition: filter 0.3s ease;
256
+ }
257
+
258
+ .image-spot.has-image .spot-image {
259
+ filter: grayscale(0%); /* Full color when an image is dropped */
260
+ }
261
+
262
+ /* Prompt & Model Section */
263
+ .prompt-input-group {
264
+ margin-bottom: var(--spacing-lg);
265
+ }
266
+
267
+ .prompt-input-group label {
268
+ display: block;
269
+ font-weight: bold;
270
+ margin-bottom: 8px;
271
+ color: var(--primary-color);
272
+ }
273
+
274
+ textarea#text-prompt {
275
+ width: 100%;
276
+ padding: 12px;
277
+ border: 1px solid var(--border-color);
278
+ border-radius: var(--border-radius);
279
+ font-size: 1em;
280
+ font-family: inherit;
281
+ resize: vertical;
282
+ min-height: 100px;
283
+ transition: border-color 0.3s ease;
284
+ }
285
+
286
+ textarea#text-prompt:focus {
287
+ outline: none;
288
+ border-color: var(--primary-color);
289
+ box-shadow: 0 0 0 3px rgba(106, 13, 173, 0.2);
290
+ }
291
+
292
+ .model-selection h3 {
293
+ font-size: 1.2em;
294
+ color: var(--primary-color);
295
+ margin-bottom: var(--spacing-md);
296
+ }
297
+
298
+ .model-options {
299
+ display: flex;
300
+ gap: var(--spacing-md);
301
+ flex-wrap: wrap;
302
+ margin-bottom: var(--spacing-lg);
303
+ }
304
+
305
+ .model-radio {
306
+ display: flex;
307
+ align-items: center;
308
+ border: 1px solid var(--border-color);
309
+ border-radius: var(--border-radius);
310
+ padding: 10px 15px;
311
+ cursor: pointer;
312
+ transition: background-color 0.3s ease, border-color 0.3s ease;
313
+ background-color: var(--card-bg);
314
+ position: relative;
315
+ overflow: visible; /* Allow tooltip to show */
316
+ }
317
+
318
+ .model-radio:hover {
319
+ background-color: #f0f0f0;
320
+ }
321
+
322
+ .model-radio input[type="radio"] {
323
+ margin-right: 8px;
324
+ accent-color: var(--primary-color); /* Custom color for radio button */
325
+ }
326
+
327
+ .model-radio input[type="radio"]:checked + span {
328
+ font-weight: bold;
329
+ color: var(--primary-color);
330
+ }
331
+
332
+ /* Tooltip for model description */
333
+ .model-radio .tooltip {
334
+ visibility: hidden;
335
+ opacity: 0;
336
+ width: 180px;
337
+ background-color: rgba(0, 0, 0, 0.8);
338
+ color: #fff;
339
+ text-align: center;
340
+ border-radius: 6px;
341
+ padding: 8px 0;
342
+ position: absolute;
343
+ z-index: 1;
344
+ bottom: 125%; /* Position above the text */
345
+ left: 50%;
346
+ margin-left: -90px; /* Center the tooltip */
347
+ font-size: 0.8em;
348
+ transition: opacity 0.3s;
349
+ }
350
+
351
+ .model-radio .tooltip::after {
352
+ content: " ";
353
+ position: absolute;
354
+ top: 100%; /* At the bottom of the tooltip */
355
+ left: 50%;
356
+ margin-left: -5px;
357
+ border-width: 5px;
358
+ border-style: solid;
359
+ border-color: rgba(0, 0, 0, 0.8) transparent transparent transparent;
360
+ }
361
+
362
+ .model-radio:hover .tooltip {
363
+ visibility: visible;
364
+ opacity: 1;
365
+ }
366
+
367
+
368
+ /* Status Message */
369
+ .status-message {
370
+ margin-top: var(--spacing-md);
371
+ padding: 10px 15px;
372
+ border-radius: var(--border-radius);
373
+ font-weight: bold;
374
+ text-align: center;
375
+ display: none; /* Hidden by default */
376
+ }
377
+
378
+ .status-message.loading {
379
+ background-color: #e0f7fa; /* Light blue */
380
+ color: #007bff;
381
+ border: 1px solid #007bff;
382
+ display: block;
383
+ }
384
+
385
+ .status-message.error {
386
+ background-color: #ffebee; /* Light red */
387
+ color: #d32f2f;
388
+ border: 1px solid #d32f2f;
389
+ display: block;
390
+ }
391
+
392
+ /* Result Section */
393
+ .remix-result {
394
+ min-height: 250px;
395
+ display: flex;
396
+ justify-content: center;
397
+ align-items: center;
398
+ border: 2px dashed var(--border-color);
399
+ border-radius: var(--border-radius);
400
+ background-color: #fefefe;
401
+ overflow: hidden;
402
+ padding: var(--spacing-md);
403
+ }
404
+
405
+ .remix-result img#result-image {
406
+ max-width: 100%;
407
+ max-height: 500px; /* Max height for the result image */
408
+ height: auto;
409
+ border-radius: var(--border-radius);
410
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
411
+ }
412
+
413
+ .remix-result p#result-placeholder {
414
+ color: #888;
415
+ font-style: italic;
416
+ }
417
+
418
+ /* Footer */
419
+ .site-footer {
420
+ background-color: var(--text-color);
421
+ color: var(--light-text-color);
422
+ text-align: center;
423
+ padding: var(--spacing-md) 0;
424
+ margin-top: var(--spacing-lg);
425
+ }
426
+
427
+ .site-footer p {
428
+ font-size: 0.9em;
429
+ }
430
+
431
+ /* Responsive Adjustments */
432
+ @media (max-width: 768px) {
433
+ .site-header .container {
434
+ flex-direction: column;
435
+ text-align: center;
436
+ }
437
+
438
+ .site-header h1 {
439
+ margin-bottom: var(--spacing-md);
440
+ }
441
+
442
+ .remix-spots {
443
+ grid-template-columns: 1fr; /* Stack spots vertically */
444
+ }
445
+
446
+ .model-options {
447
+ flex-direction: column; /* Stack model options vertically */
448
+ }
449
+ }
450
+
451
+ @media (max-width: 480px) {
452
+ .container {
453
+ padding: var(--spacing-md);
454
+ }
455
+
456
+ h1 {
457
+ font-size: 1.5em;
458
+ }
459
+
460
+ h2 {
461
+ font-size: 1.3em;
462
+ }
463
+
464
+ .btn {
465
+ width: 100%;
466
+ margin-top: var(--spacing-md);
467
+ }
468
+
469
+ .uploaded-image-wrapper {
470
+ width: 80px;
471
+ height: 80px;
472
+ }
473
+ }
assets/img/initial-result.png ADDED
assets/img/placeholder.png ADDED
assets/js/script.js ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const uploadInput = document.getElementById('image-upload');
3
+ const uploadButton = document.getElementById('upload-button');
4
+ const uploadDropzone = document.getElementById('upload-dropzone');
5
+ const uploadedPreviews = document.getElementById('uploaded-previews');
6
+ const imageSpots = Array.from(document.querySelectorAll('.image-spot'));
7
+ const textPrompt = document.getElementById('text-prompt');
8
+ const remixButton = document.getElementById('remix-button');
9
+ const statusMessage = document.getElementById('status-message');
10
+ const remixResult = document.getElementById('remix-result');
11
+ const resultImage = document.getElementById('result-image');
12
+ const resultPlaceholder = document.getElementById('result-placeholder');
13
+
14
+ // Store base64 data for images in spots
15
+ const imageSpotData = Array(3).fill(null);
16
+ // Store original draggable elements created from uploaded images
17
+ const draggableImages = new Map(); // Map<id, {element, src}>
18
+
19
+ let uploadedImageCounter = 0;
20
+
21
+ // --- Utility Functions ---
22
+ const showStatus = (message, type = 'loading') => {
23
+ statusMessage.textContent = message;
24
+ statusMessage.className = `status-message ${type}`;
25
+ statusMessage.style.display = 'block';
26
+ };
27
+
28
+ const hideStatus = () => {
29
+ statusMessage.style.display = 'none';
30
+ statusMessage.textContent = '';
31
+ };
32
+
33
+ const clearResult = () => {
34
+ resultImage.style.display = 'none';
35
+ resultImage.src = '';
36
+ resultPlaceholder.style.display = 'block';
37
+ };
38
+
39
+ // --- File Upload Logic ---
40
+ uploadButton.addEventListener('click', () => uploadInput.click());
41
+
42
+ uploadInput.addEventListener('change', (event) => {
43
+ handleFiles(event.target.files);
44
+ });
45
+
46
+ uploadDropzone.addEventListener('dragover', (event) => {
47
+ event.preventDefault();
48
+ uploadDropzone.classList.add('drag-over');
49
+ });
50
+
51
+ uploadDropzone.addEventListener('dragleave', () => {
52
+ uploadDropzone.classList.remove('drag-over');
53
+ });
54
+
55
+ uploadDropzone.addEventListener('drop', (event) => {
56
+ event.preventDefault();
57
+ uploadDropzone.classList.remove('drag-over');
58
+ handleFiles(event.dataTransfer.files);
59
+ });
60
+
61
+ function handleFiles(files) {
62
+ if (files.length === 0) return;
63
+
64
+ Array.from(files).forEach(file => {
65
+ if (!file.type.startsWith('image/')) return;
66
+
67
+ const reader = new FileReader();
68
+ reader.onload = (e) => {
69
+ const imgId = `uploaded-img-${uploadedImageCounter++}`;
70
+ createDraggableImage(e.target.result, imgId);
71
+ };
72
+ reader.readAsDataURL(file);
73
+ });
74
+ }
75
+
76
+ function createDraggableImage(src, id) {
77
+ const wrapper = document.createElement('div');
78
+ wrapper.className = 'uploaded-image-wrapper';
79
+ wrapper.draggable = true;
80
+ wrapper.id = id;
81
+
82
+ const img = document.createElement('img');
83
+ img.src = src;
84
+ img.alt = `Uploaded image ${id}`;
85
+
86
+ const removeBtn = document.createElement('button');
87
+ removeBtn.className = 'remove-image';
88
+ removeBtn.textContent = 'x';
89
+ removeBtn.title = 'Remove image';
90
+ removeBtn.addEventListener('click', (e) => {
91
+ e.stopPropagation(); // Prevent drag event from firing
92
+ wrapper.remove();
93
+ draggableImages.delete(id);
94
+ // Also check if this image was in any spot and remove it
95
+ for (let i = 0; i < imageSpotData.length; i++) {
96
+ if (imageSpotData[i] && imageSpotData[i].id === id) {
97
+ clearImageSpot(imageSpots[i], i);
98
+ }
99
+ }
100
+ });
101
+
102
+ wrapper.appendChild(img);
103
+ wrapper.appendChild(removeBtn);
104
+ uploadedPreviews.appendChild(wrapper);
105
+
106
+ draggableImages.set(id, { element: wrapper, src: src });
107
+
108
+ wrapper.addEventListener('dragstart', (e) => {
109
+ e.dataTransfer.setData('text/plain', id);
110
+ e.dataTransfer.effectAllowed = 'copyMove';
111
+ // Optional: add a class to the original to make it transparent or similar
112
+ // e.target.classList.add('dragging');
113
+ });
114
+
115
+ // wrapper.addEventListener('dragend', (e) => {
116
+ // e.target.classList.remove('dragging');
117
+ // });
118
+ }
119
+
120
+ // --- Image Spot Drag & Drop Logic ---
121
+ imageSpots.forEach((spot) => {
122
+ spot.addEventListener('dragover', (event) => {
123
+ event.preventDefault();
124
+ spot.classList.add('drag-over');
125
+ event.dataTransfer.dropEffect = 'copy';
126
+ });
127
+
128
+ spot.addEventListener('dragleave', () => {
129
+ spot.classList.remove('drag-over');
130
+ });
131
+
132
+ spot.addEventListener('drop', (event) => {
133
+ event.preventDefault();
134
+ spot.classList.remove('drag-over');
135
+ const draggedId = event.dataTransfer.getData('text/plain');
136
+ const draggedImageData = draggableImages.get(draggedId);
137
+
138
+ if (draggedImageData) {
139
+ const spotIndex = parseInt(spot.dataset.index);
140
+ renderImageInSpot(spot, draggedImageData.src);
141
+ imageSpotData[spotIndex] = { src: draggedImageData.src, id: draggedId };
142
+ }
143
+ });
144
+ });
145
+
146
+ function renderImageInSpot(spotElement, imgSrc) {
147
+ const imgElement = spotElement.querySelector('.spot-image');
148
+ imgElement.src = imgSrc;
149
+ spotElement.classList.add('has-image');
150
+ imgElement.alt = `Image in spot ${spotElement.dataset.index + 1}`;
151
+ // Remove old image's alt if it exists and wasn't placeholder.
152
+ }
153
+
154
+ function clearImageSpot(spotElement, spotIndex) {
155
+ const imgElement = spotElement.querySelector('.spot-image');
156
+ imgElement.src = 'assets/img/placeholder.png'; // Reset to placeholder
157
+ spotElement.classList.remove('has-image');
158
+ imgElement.alt = `Image spot ${spotIndex + 1}`;
159
+ imageSpotData[spotIndex] = null;
160
+ }
161
+
162
+ // --- Remix Logic ---
163
+ remixButton.addEventListener('click', remixImages);
164
+
165
+ async function remixImages() {
166
+ hideStatus();
167
+ clearResult();
168
+
169
+ const images = imageSpotData.filter(data => data !== null);
170
+ const prompt = textPrompt.value.trim();
171
+ const selectedModel = document.querySelector('input[name="ai-model"]:checked').value;
172
+
173
+ if (images.length === 0) {
174
+ showStatus('Please drag at least one image into a spot.', 'error');
175
+ return;
176
+ }
177
+
178
+ if (!prompt) {
179
+ showStatus('Please enter a text prompt.', 'error');
180
+ return;
181
+ }
182
+
183
+ showStatus(`Remixing with ${selectedModel}... This is a simulation.`, 'loading');
184
+
185
+ try {
186
+ // Simulate API call
187
+ await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate network delay
188
+
189
+ // In a real application, you would send `images` (base64 or URLs), `prompt`, and `selectedModel`
190
+ // to a backend API that integrates with Gemini-2 or GPT Image-1.
191
+ // The backend would then return the generated image's URL or base64.
192
+
193
+ // For simulation, we'll use a placeholder image based on the model
194
+ const placeholderResult = selectedModel === 'gemini-2'
195
+ ? 'https://picsum.photos/seed/gemini/800/600?grayscale' // A bit more abstract
196
+ : 'https://picsum.photos/seed/gpt/800/600'; // Standard realistic
197
+
198
+ resultImage.src = placeholderResult;
199
+ resultImage.style.display = 'block';
200
+ resultPlaceholder.style.display = 'none';
201
+ showStatus('Remix successful! (Simulated)', 'success');
202
+ statusMessage.style.backgroundColor = '#d4edda'; // Light green for success
203
+ statusMessage.style.color = '#155724';
204
+ statusMessage.style.borderColor = '#28a745';
205
+
206
+ } catch (error) {
207
+ console.error('Remix error (simulated):', error);
208
+ showStatus('Failed to remix images. Please try again. (Simulated Error)', 'error');
209
+ }
210
+ }
211
+ });
212
+
213
+ // Initial state for result section
214
+ document.addEventListener('DOMContentLoaded', () => {
215
+ const resultImage = document.getElementById('result-image');
216
+ const resultPlaceholder = document.getElementById('result-placeholder');
217
+ resultImage.style.display = 'none';
218
+ resultPlaceholder.style.display = 'block';
219
+ });
index.html CHANGED
@@ -1,19 +1,97 @@
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
+ <meta name="description" content="Remix images with text prompts using AI models like Gemini and GPT. Drag and drop your images into three spots for creative combinations.">
7
+ <meta name="keywords" content="image remixer, AI art, Gemini, GPT, image generation, drag and drop, creative tool">
8
+ <meta name="author" content="Anycoder">
9
+ <title>AI Image Remixer</title>
10
+ <link rel="stylesheet" href="assets/css/styles.css">
11
+ <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext x='50%' y='50%' style='dominant-baseline:central;text-anchor:middle;font-size:80px;'%3E🎨%3C/text%3E%3C/svg%3E" type="image/svg+xml">
12
+ </head>
13
+ <body>
14
+ <header class="site-header">
15
+ <div class="container">
16
+ <h1>AI Image Remixer 🎨</h1>
17
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" class="anycoder-link" target="_blank" rel="noopener noreferrer">Built with anycoder</a>
18
+ </div>
19
+ </header>
20
+
21
+ <main class="container">
22
+ <section class="upload-section">
23
+ <h2>1. Upload or Drop Images</h2>
24
+ <div id="upload-dropzone" class="dropzone">
25
+ <p>Drag & drop images here, or click to upload</p>
26
+ <input type="file" id="image-upload" accept="image/*" multiple style="display: none;">
27
+ <button id="upload-button" class="btn">Browse Files</button>
28
+ </div>
29
+ <div id="uploaded-previews" class="uploaded-previews">
30
+ <!-- Uploaded image previews will go here -->
31
+ </div>
32
+ </section>
33
+
34
+ <section class="remix-spots-section">
35
+ <h2>2. Place Images in Spots</h2>
36
+ <p class="instruction-text">Drag images from the "Uploads" section into these three blank spots.</p>
37
+ <div class="remix-spots">
38
+ <div class="image-spot" id="spot-1" data-index="0">
39
+ <span class="spot-label">Spot 1</span>
40
+ <img class="spot-image" src="assets/img/placeholder.png" alt="Image spot 1">
41
+ </div>
42
+ <div class="image-spot" id="spot-2" data-index="1">
43
+ <span class="spot-label">Spot 2</span>
44
+ <img class="spot-image" src="assets/img/placeholder.png" alt="Image spot 2">
45
+ </div>
46
+ <div class="image-spot" id="spot-3" data-index="2">
47
+ <span class="spot-label">Spot 3</span>
48
+ <img class="spot-image" src="assets/img/placeholder.png" alt="Image spot 3">
49
+ </div>
50
+ </div>
51
+ </section>
52
+
53
+ <section class="prompt-model-section">
54
+ <h2>3. Add a Prompt & Select Model</h2>
55
+ <div class="prompt-input-group">
56
+ <label for="text-prompt">Text Prompt:</label>
57
+ <textarea id="text-prompt" placeholder="Describe the remix, e.g., 'A surreal landscape with elements of all three images, painted in an impressionistic style.'" rows="4"></textarea>
58
+ </div>
59
+
60
+ <div class="model-selection">
61
+ <h3>Choose AI Model:</h3>
62
+ <div class="model-options">
63
+ <label class="model-radio">
64
+ <input type="radio" name="ai-model" value="gemini-2" checked>
65
+ Gemini-2
66
+ <span class="tooltip">Advanced multimodal reasoning.</span>
67
+ </label>
68
+ <label class="model-radio">
69
+ <input type="radio" name="ai-model" value="gpt-image-1">
70
+ GPT Image-1
71
+ <span class="tooltip">Powerful image generation.</span>
72
+ </label>
73
+ </div>
74
+ </div>
75
+
76
+ <button id="remix-button" class="btn btn-primary">Remix Images</button>
77
+ <div id="status-message" class="status-message" aria-live="polite"></div>
78
+ </section>
79
+
80
+ <section class="result-section">
81
+ <h2>4. Your Remixed Image</h2>
82
+ <div id="remix-result" class="remix-result">
83
+ <img id="result-image" src="assets/img/initial-result.png" alt="Remixed image output" style="display: none;">
84
+ <p id="result-placeholder">Your remixed image will appear here.</p>
85
+ </div>
86
+ </section>
87
+ </main>
88
+
89
+ <footer class="site-footer">
90
+ <div class="container">
91
+ <p>&copy; 2023 AI Image Remixer. All rights reserved.</p>
92
+ </div>
93
+ </footer>
94
+
95
+ <script src="assets/js/script.js"></script>
96
+ </body>
97
+ </html>