arpit13 commited on
Commit
c56c2a0
·
verified ·
1 Parent(s): 6a21df7

Create ui_components.py

Browse files
Files changed (1) hide show
  1. ui_components.py +1135 -0
ui_components.py ADDED
@@ -0,0 +1,1135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # AI Image Creator: Enhanced UI and UX
2
+ # Part 2: Enhanced UI Components and Styling
3
+
4
+ # CSS for styling the interface - Comprehensive styling for modern UI
5
+ css = """
6
+ /* Main theme colors with CSS variables for better customization */
7
+ :root {
8
+ --primary-color: #4F46E5;
9
+ --primary-hover: #4338CA;
10
+ --secondary-color: #7C3AED;
11
+ --secondary-hover: #6D28D9;
12
+ --background-color: #F8FAFC;
13
+ --card-color: #FFFFFF;
14
+ --text-color: #1E293B;
15
+ --text-muted: #64748B;
16
+ --accent-color: #3B82F6;
17
+ --success-color: #10B981;
18
+ --success-hover: #059669;
19
+ --warning-color: #F59E0B;
20
+ --error-color: #EF4444;
21
+ --error-hover: #DC2626;
22
+ --border-color: #E2E8F0;
23
+ --border-hover: #CBD5E1;
24
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
25
+ --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
26
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
27
+ --radius-sm: 0.375rem;
28
+ --radius: 0.5rem;
29
+ --radius-lg: 0.75rem;
30
+ --radius-xl: 1rem;
31
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
32
+ }
33
+
34
+ /* Global styles and resets */
35
+ body, html {
36
+ font-family: var(--font-sans);
37
+ color: var(--text-color);
38
+ background-color: var(--background-color);
39
+ line-height: 1.5;
40
+ margin: 0;
41
+ padding: 0;
42
+ }
43
+
44
+ /* Container with responsive padding */
45
+ .container {
46
+ max-width: 1400px;
47
+ margin: 0 auto;
48
+ padding: 1rem;
49
+ }
50
+
51
+ @media (max-width: 640px) {
52
+ .container {
53
+ padding: 0.5rem;
54
+ }
55
+ }
56
+
57
+ /* Card styling with elevation and hover effects */
58
+ .gr-panel {
59
+ border-radius: var(--radius) !important;
60
+ border: 1px solid var(--border-color) !important;
61
+ box-shadow: var(--shadow) !important;
62
+ overflow: hidden;
63
+ transition: transform 0.2s, box-shadow 0.2s;
64
+ background-color: var(--card-color) !important;
65
+ }
66
+
67
+ .gr-panel:hover {
68
+ transform: translateY(-2px);
69
+ box-shadow: var(--shadow-lg) !important;
70
+ }
71
+
72
+ /* Button styling with gradient and hover states */
73
+ button.primary {
74
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)) !important;
75
+ color: white !important;
76
+ border: none !important;
77
+ border-radius: var(--radius) !important;
78
+ font-weight: 600 !important;
79
+ letter-spacing: 0.025em !important;
80
+ padding: 0.75rem 1.5rem !important;
81
+ transition: all 0.3s ease !important;
82
+ box-shadow: var(--shadow-sm) !important;
83
+ outline: none !important;
84
+ text-transform: none !important;
85
+ }
86
+
87
+ button.primary:hover {
88
+ transform: translateY(-1px);
89
+ box-shadow: var(--shadow) !important;
90
+ opacity: 0.9;
91
+ }
92
+
93
+ button.primary:active {
94
+ transform: translateY(0);
95
+ opacity: 0.8;
96
+ }
97
+
98
+ button.primary[disabled], button.primary[disabled]:hover {
99
+ opacity: 0.5;
100
+ cursor: not-allowed;
101
+ transform: none;
102
+ }
103
+
104
+ /* Secondary button styling */
105
+ button.secondary {
106
+ background-color: transparent !important;
107
+ color: var(--primary-color) !important;
108
+ border: 1px solid var(--primary-color) !important;
109
+ border-radius: var(--radius) !important;
110
+ font-weight: 500 !important;
111
+ padding: 0.625rem 1.25rem !important;
112
+ transition: all 0.2s ease !important;
113
+ text-transform: none !important;
114
+ }
115
+
116
+ button.secondary:hover {
117
+ background-color: rgba(79, 70, 229, 0.05) !important;
118
+ border-color: var(--primary-hover) !important;
119
+ }
120
+
121
+ /* Style for the example buttons */
122
+ .example-button {
123
+ font-size: 0.875rem !important;
124
+ padding: 0.5rem 0.75rem !important;
125
+ background-color: transparent !important;
126
+ border: 1px solid var(--border-color) !important;
127
+ border-radius: var(--radius) !important;
128
+ transition: all 0.2s !important;
129
+ text-align: left !important;
130
+ justify-content: flex-start !important;
131
+ height: auto !important;
132
+ text-overflow: ellipsis;
133
+ overflow: hidden;
134
+ white-space: nowrap;
135
+ width: 100%;
136
+ color: var(--text-color) !important;
137
+ }
138
+
139
+ .example-button:hover {
140
+ background-color: rgba(79, 70, 229, 0.05) !important;
141
+ border-color: var(--primary-color) !important;
142
+ transform: translateY(-1px);
143
+ }
144
+
145
+ /* Form controls styling */
146
+ .gr-input, .gr-textarea, .gr-dropdown {
147
+ border-radius: var(--radius) !important;
148
+ border: 1px solid var(--border-color) !important;
149
+ transition: border-color 0.2s, box-shadow 0.2s !important;
150
+ font-family: var(--font-sans) !important;
151
+ color: var(--text-color) !important;
152
+ }
153
+
154
+ .gr-input:focus, .gr-textarea:focus, .gr-dropdown:focus-within {
155
+ border-color: var(--primary-color) !important;
156
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2) !important;
157
+ outline: none !important;
158
+ }
159
+
160
+ .gr-form {
161
+ gap: 1rem !important;
162
+ }
163
+
164
+ .gr-input-label, .gr-dropdown-label, .gr-textarea-label, .gr-checkbox-label, .gr-radio-label {
165
+ font-size: 0.875rem !important;
166
+ font-weight: 500 !important;
167
+ color: var(--text-color) !important;
168
+ margin-bottom: 0.25rem !important;
169
+ }
170
+
171
+ /* Input placeholder styling */
172
+ .gr-input::placeholder, .gr-textarea::placeholder {
173
+ color: var(--text-muted) !important;
174
+ opacity: 0.7;
175
+ }
176
+
177
+ /* Input and textarea styling */
178
+ textarea, input[type="text"] {
179
+ border-radius: var(--radius) !important;
180
+ border: 1px solid var(--border-color) !important;
181
+ padding: 0.75rem 1rem !important;
182
+ transition: border-color 0.2s, box-shadow 0.2s !important;
183
+ font-family: var(--font-sans) !important;
184
+ }
185
+
186
+ textarea:focus, input[type="text"]:focus {
187
+ border-color: var(--primary-color) !important;
188
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2) !important;
189
+ outline: none !important;
190
+ }
191
+
192
+ /* Dropdown styling */
193
+ .gr-dropdown {
194
+ border-radius: var(--radius) !important;
195
+ border: 1px solid var(--border-color) !important;
196
+ background-color: var(--card-color) !important;
197
+ }
198
+
199
+ .gr-dropdown > div {
200
+ border-radius: var(--radius) !important;
201
+ min-height: 38px !important;
202
+ }
203
+
204
+ .gr-dropdown > div > span {
205
+ font-size: 0.9375rem !important;
206
+ }
207
+
208
+ /* Dropdown menu styling */
209
+ .gr-dropdown ul {
210
+ background-color: var(--card-color) !important;
211
+ border: 1px solid var(--border-color) !important;
212
+ border-radius: var(--radius) !important;
213
+ box-shadow: var(--shadow) !important;
214
+ }
215
+
216
+ .gr-dropdown ul li {
217
+ padding: 0.5rem 0.75rem !important;
218
+ }
219
+
220
+ .gr-dropdown ul li:hover {
221
+ background-color: rgba(79, 70, 229, 0.05) !important;
222
+ }
223
+
224
+ /* Custom header with gradient background */
225
+ .app-header {
226
+ text-align: center;
227
+ padding: 1.75rem 1rem;
228
+ margin-bottom: 2rem;
229
+ background: linear-gradient(135deg, rgba(79, 70, 229, 0.08), rgba(124, 58, 237, 0.08));
230
+ border-radius: var(--radius-lg);
231
+ border-bottom: 3px solid var(--primary-color);
232
+ position: relative;
233
+ overflow: hidden;
234
+ }
235
+
236
+ .app-header::before {
237
+ content: '';
238
+ position: absolute;
239
+ top: -50px;
240
+ left: -50px;
241
+ right: -50px;
242
+ height: 100px;
243
+ background: linear-gradient(135deg, rgba(79, 70, 229, 0.2), rgba(124, 58, 237, 0.2));
244
+ transform: rotate(-5deg);
245
+ z-index: 0;
246
+ }
247
+
248
+ .app-header h1 {
249
+ font-size: 2.5rem !important;
250
+ font-weight: 800 !important;
251
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
252
+ -webkit-background-clip: text;
253
+ -webkit-text-fill-color: transparent;
254
+ margin-bottom: 0.5rem !important;
255
+ position: relative;
256
+ z-index: 1;
257
+ }
258
+
259
+ .app-header p {
260
+ font-size: 1.25rem !important;
261
+ color: var(--text-color);
262
+ opacity: 0.8;
263
+ max-width: 40rem;
264
+ margin: 0 auto;
265
+ position: relative;
266
+ z-index: 1;
267
+ }
268
+
269
+ /* Responsive header */
270
+ @media (max-width: 640px) {
271
+ .app-header h1 {
272
+ font-size: 2rem !important;
273
+ }
274
+
275
+ .app-header p {
276
+ font-size: 1rem !important;
277
+ }
278
+ }
279
+
280
+ /* Examples gallery with grid layout */
281
+ .example-gallery {
282
+ display: grid;
283
+ grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
284
+ gap: 1rem;
285
+ margin: 1rem 0;
286
+ }
287
+
288
+ .example-item {
289
+ border-radius: var(--radius);
290
+ overflow: hidden;
291
+ cursor: pointer;
292
+ border: 2px solid transparent;
293
+ transition: all 0.2s;
294
+ display: flex;
295
+ flex-direction: column;
296
+ background-color: var(--card-color);
297
+ }
298
+
299
+ .example-item:hover {
300
+ transform: translateY(-2px);
301
+ border-color: var(--accent-color);
302
+ box-shadow: var(--shadow);
303
+ }
304
+
305
+ .example-item:active {
306
+ transform: translateY(0);
307
+ }
308
+
309
+ .example-item-image {
310
+ width: 100%;
311
+ aspect-ratio: 1;
312
+ background-color: #f0f0f0;
313
+ display: flex;
314
+ align-items: center;
315
+ justify-content: center;
316
+ color: var(--text-muted);
317
+ font-size: 1.5rem;
318
+ border-bottom: 1px solid var(--border-color);
319
+ }
320
+
321
+ .example-item-caption {
322
+ padding: 0.5rem;
323
+ font-size: 0.75rem;
324
+ line-height: 1.25;
325
+ color: var(--text-color);
326
+ overflow: hidden;
327
+ display: -webkit-box;
328
+ -webkit-line-clamp: 2;
329
+ -webkit-box-orient: vertical;
330
+ }
331
+
332
+ /* Loading indicator with animation */
333
+ .loading-indicator {
334
+ display: flex;
335
+ align-items: center;
336
+ justify-content: center;
337
+ height: 100%;
338
+ width: 100%;
339
+ position: absolute;
340
+ top: 0;
341
+ left: 0;
342
+ background-color: rgba(255, 255, 255, 0.8);
343
+ z-index: 1000;
344
+ backdrop-filter: blur(2px);
345
+ border-radius: var(--radius);
346
+ }
347
+
348
+ .spinner {
349
+ width: 40px;
350
+ height: 40px;
351
+ border: 4px solid rgba(79, 70, 229, 0.2);
352
+ border-radius: 50%;
353
+ border-top-color: var(--primary-color);
354
+ animation: spin 1s linear infinite;
355
+ }
356
+
357
+ @keyframes spin {
358
+ to {
359
+ transform: rotate(360deg);
360
+ }
361
+ }
362
+
363
+ /* Info cards with subtle styling */
364
+ .info-card {
365
+ background-color: var(--card-color);
366
+ border-radius: var(--radius);
367
+ padding: 1rem;
368
+ border: 1px solid var(--border-color);
369
+ margin-bottom: 1rem;
370
+ transition: all 0.2s;
371
+ }
372
+
373
+ .info-card:hover {
374
+ border-color: var(--border-hover);
375
+ box-shadow: var(--shadow-sm);
376
+ }
377
+
378
+ .info-card h3 {
379
+ margin-top: 0;
380
+ margin-bottom: 0.5rem;
381
+ font-size: 1rem;
382
+ font-weight: 600;
383
+ color: var(--primary-color);
384
+ display: flex;
385
+ align-items: center;
386
+ gap: 0.5rem;
387
+ }
388
+
389
+ .info-card p {
390
+ margin: 0;
391
+ font-size: 0.875rem;
392
+ color: var(--text-muted);
393
+ line-height: 1.5;
394
+ }
395
+
396
+ /* Model info panel with branded styling */
397
+ .model-info {
398
+ background-color: rgba(79, 70, 229, 0.05);
399
+ border-left: 3px solid var(--primary-color);
400
+ padding: 0.75rem 1rem;
401
+ border-radius: 0 var(--radius) var(--radius) 0;
402
+ margin: 1rem 0;
403
+ }
404
+
405
+ .model-info h3 {
406
+ display: flex;
407
+ align-items: center;
408
+ gap: 0.5rem;
409
+ margin-top: 0;
410
+ margin-bottom: 0.5rem;
411
+ font-size: 1rem;
412
+ font-weight: 600;
413
+ color: var(--primary-color);
414
+ }
415
+
416
+ .model-info p {
417
+ margin: 0 0 0.5rem 0;
418
+ font-size: 0.875rem;
419
+ color: var(--text-color);
420
+ }
421
+
422
+ .model-info .model-id {
423
+ font-size: 0.75rem;
424
+ color: var(--text-muted);
425
+ font-family: monospace;
426
+ background-color: rgba(0, 0, 0, 0.03);
427
+ padding: 0.25rem 0.5rem;
428
+ border-radius: 4px;
429
+ margin-top: 0.5rem;
430
+ word-break: break-all;
431
+ }
432
+
433
+ /* Parameter pills for displaying selections */
434
+ .parameter-pill {
435
+ display: inline-flex;
436
+ align-items: center;
437
+ background-color: rgba(79, 70, 229, 0.1);
438
+ color: var(--primary-color);
439
+ border-radius: 16px;
440
+ padding: 0.25rem 0.75rem;
441
+ margin-right: 0.5rem;
442
+ margin-bottom: 0.5rem;
443
+ font-size: 0.75rem;
444
+ font-weight: 500;
445
+ user-select: none;
446
+ }
447
+
448
+ .parameter-pill .icon {
449
+ margin-right: 0.25rem;
450
+ }
451
+
452
+ /* Badge for showing model speed/quality */
453
+ .badge {
454
+ display: inline-flex;
455
+ align-items: center;
456
+ justify-content: center;
457
+ border-radius: 9999px;
458
+ padding: 0.125rem 0.5rem;
459
+ font-size: 0.75rem;
460
+ font-weight: 500;
461
+ margin-left: 0.5rem;
462
+ }
463
+
464
+ .badge-success {
465
+ background-color: rgba(16, 185, 129, 0.1);
466
+ color: var(--success-color);
467
+ }
468
+
469
+ .badge-warning {
470
+ background-color: rgba(245, 158, 11, 0.1);
471
+ color: var(--warning-color);
472
+ }
473
+
474
+ .badge-error {
475
+ background-color: rgba(239, 68, 68, 0.1);
476
+ color: var(--error-color);
477
+ }
478
+
479
+ .badge-info {
480
+ background-color: rgba(59, 130, 246, 0.1);
481
+ color: var(--accent-color);
482
+ }
483
+
484
+ /* Enhanced accordion styling */
485
+ .gr-accordion {
486
+ border: 1px solid var(--border-color) !important;
487
+ border-radius: var(--radius) !important;
488
+ margin-bottom: 1rem !important;
489
+ overflow: hidden;
490
+ }
491
+
492
+ .gr-accordion > div:first-child {
493
+ padding: 0.75rem 1rem !important;
494
+ background-color: rgba(0, 0, 0, 0.02) !important;
495
+ font-weight: 600 !important;
496
+ color: var(--text-color) !important;
497
+ font-size: 0.9375rem !important;
498
+ }
499
+
500
+ .gr-accordion > div:last-child {
501
+ padding: 1rem !important;
502
+ }
503
+
504
+ /* Tooltip styling */
505
+ .tooltip {
506
+ position: relative;
507
+ display: inline-block;
508
+ cursor: help;
509
+ }
510
+
511
+ .tooltip .tooltiptext {
512
+ visibility: hidden;
513
+ width: 200px;
514
+ background-color: var(--text-color);
515
+ color: white;
516
+ text-align: center;
517
+ border-radius: var(--radius-sm);
518
+ padding: 0.5rem 0.75rem;
519
+ position: absolute;
520
+ z-index: 1000;
521
+ bottom: 125%;
522
+ left: 50%;
523
+ transform: translateX(-50%);
524
+ opacity: 0;
525
+ transition: opacity 0.3s;
526
+ font-size: 0.75rem;
527
+ box-shadow: var(--shadow);
528
+ pointer-events: none;
529
+ }
530
+
531
+ .tooltip .tooltiptext::after {
532
+ content: "";
533
+ position: absolute;
534
+ top: 100%;
535
+ left: 50%;
536
+ margin-left: -5px;
537
+ border-width: 5px;
538
+ border-style: solid;
539
+ border-color: var(--text-color) transparent transparent transparent;
540
+ }
541
+
542
+ .tooltip:hover .tooltiptext {
543
+ visibility: visible;
544
+ opacity: 1;
545
+ }
546
+
547
+ /* History item styling */
548
+ .history-item {
549
+ display: flex;
550
+ align-items: center;
551
+ padding: 0.75rem;
552
+ border-radius: var(--radius);
553
+ margin-bottom: 0.75rem;
554
+ background-color: var(--card-color);
555
+ border: 1px solid var(--border-color);
556
+ cursor: pointer;
557
+ transition: all 0.2s;
558
+ }
559
+
560
+ .history-item:hover {
561
+ background-color: rgba(79, 70, 229, 0.05);
562
+ transform: translateY(-1px);
563
+ }
564
+
565
+ .history-item-image {
566
+ width: 48px;
567
+ height: 48px;
568
+ border-radius: var(--radius-sm);
569
+ object-fit: cover;
570
+ margin-right: 0.75rem;
571
+ background-color: #f0f0f0;
572
+ display: flex;
573
+ align-items: center;
574
+ justify-content: center;
575
+ color: var(--text-muted);
576
+ font-size: 1.25rem;
577
+ }
578
+
579
+ .history-item-content {
580
+ flex: 1;
581
+ overflow: hidden;
582
+ }
583
+
584
+ .history-item-title {
585
+ margin: 0;
586
+ font-size: 0.875rem;
587
+ font-weight: 500;
588
+ white-space: nowrap;
589
+ overflow: hidden;
590
+ text-overflow: ellipsis;
591
+ color: var(--text-color);
592
+ }
593
+
594
+ .history-item-subtitle {
595
+ margin: 0;
596
+ font-size: 0.75rem;
597
+ color: var(--text-muted);
598
+ margin-top: 0.25rem;
599
+ }
600
+
601
+ /* Tabs styling */
602
+ .tabs {
603
+ display: flex;
604
+ border-bottom: 1px solid var(--border-color);
605
+ margin-bottom: 1rem;
606
+ }
607
+
608
+ .tab {
609
+ padding: 0.75rem 1rem;
610
+ cursor: pointer;
611
+ border-bottom: 2px solid transparent;
612
+ font-weight: 500;
613
+ font-size: 0.9375rem;
614
+ color: var(--text-muted);
615
+ transition: all 0.2s;
616
+ }
617
+
618
+ .tab:hover {
619
+ color: var(--primary-color);
620
+ }
621
+
622
+ .tab.active {
623
+ color: var(--primary-color);
624
+ border-bottom-color: var(--primary-color);
625
+ }
626
+
627
+ /* Progress bar */
628
+ .progress-container {
629
+ width: 100%;
630
+ height: 8px;
631
+ background-color: rgba(79, 70, 229, 0.1);
632
+ border-radius: 4px;
633
+ overflow: hidden;
634
+ margin: 0.5rem 0;
635
+ }
636
+
637
+ .progress-bar {
638
+ height: 100%;
639
+ background: linear-gradient(to right, var(--primary-color), var(--secondary-color));
640
+ width: 0%;
641
+ transition: width 0.3s ease;
642
+ border-radius: 4px;
643
+ }
644
+
645
+ /* Image output container */
646
+ .image-output-container {
647
+ position: relative;
648
+ border-radius: var(--radius);
649
+ overflow: hidden;
650
+ transition: all 0.2s;
651
+ background-color: #f5f5f5;
652
+ min-height: 300px;
653
+ }
654
+
655
+ .image-output-container img {
656
+ width: 100%;
657
+ display: block;
658
+ border-radius: var(--radius);
659
+ }
660
+
661
+ .image-placeholder {
662
+ position: absolute;
663
+ top: 0;
664
+ left: 0;
665
+ width: 100%;
666
+ height: 100%;
667
+ display: flex;
668
+ flex-direction: column;
669
+ align-items: center;
670
+ justify-content: center;
671
+ color: var(--text-muted);
672
+ font-size: 1rem;
673
+ text-align: center;
674
+ padding: 1rem;
675
+ }
676
+
677
+ .image-placeholder .icon {
678
+ font-size: 3rem;
679
+ margin-bottom: 1rem;
680
+ opacity: 0.6;
681
+ }
682
+
683
+ /* Image controls overlay */
684
+ .image-controls {
685
+ position: absolute;
686
+ bottom: 0;
687
+ left: 0;
688
+ right: 0;
689
+ padding: 0.75rem;
690
+ background: linear-gradient(to top, rgba(0,0,0,0.7), rgba(0,0,0,0));
691
+ display: flex;
692
+ justify-content: flex-end;
693
+ opacity: 0;
694
+ transition: opacity 0.2s;
695
+ }
696
+
697
+ .image-output-container:hover .image-controls {
698
+ opacity: 1;
699
+ }
700
+
701
+ .image-control-button {
702
+ background-color: rgba(255, 255, 255, 0.9);
703
+ border: none;
704
+ border-radius: 50%;
705
+ width: 36px;
706
+ height: 36px;
707
+ display: flex;
708
+ align-items: center;
709
+ justify-content: center;
710
+ cursor: pointer;
711
+ margin-left: 0.5rem;
712
+ color: var(--text-color);
713
+ transition: all 0.2s;
714
+ }
715
+
716
+ .image-control-button:hover {
717
+ background-color: white;
718
+ transform: translateY(-2px);
719
+ box-shadow: var(--shadow);
720
+ }
721
+
722
+ /* Character counter */
723
+ .character-counter {
724
+ text-align: right;
725
+ font-size: 0.75rem;
726
+ color: var(--text-muted);
727
+ margin-top: 0.25rem;
728
+ transition: color 0.2s;
729
+ }
730
+
731
+ .character-counter.warning {
732
+ color: var(--warning-color);
733
+ }
734
+
735
+ .character-counter.error {
736
+ color: var(--error-color);
737
+ }
738
+
739
+ /* Status message */
740
+ .status-message {
741
+ padding: 0.75rem 1rem;
742
+ border-radius: var(--radius);
743
+ margin: 1rem 0;
744
+ font-size: 0.875rem;
745
+ display: flex;
746
+ align-items: center;
747
+ }
748
+
749
+ .status-message .icon {
750
+ margin-right: 0.75rem;
751
+ font-size: 1.25rem;
752
+ }
753
+
754
+ .status-success {
755
+ background-color: rgba(16, 185, 129, 0.1);
756
+ color: var(--success-color);
757
+ border-left: 3px solid var(--success-color);
758
+ }
759
+
760
+ .status-error {
761
+ background-color: rgba(239, 68, 68, 0.1);
762
+ color: var(--error-color);
763
+ border-left: 3px solid var(--error-color);
764
+ }
765
+
766
+ .status-warning {
767
+ background-color: rgba(245, 158, 11, 0.1);
768
+ color: var(--warning-color);
769
+ border-left: 3px solid var(--warning-color);
770
+ }
771
+
772
+ .status-info {
773
+ background-color: rgba(59, 130, 246, 0.1);
774
+ color: var(--accent-color);
775
+ border-left: 3px solid var(--accent-color);
776
+ }
777
+
778
+ /* Responsive adjustments */
779
+ @media (max-width: 768px) {
780
+ .example-gallery {
781
+ grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
782
+ }
783
+
784
+ .gr-panel {
785
+ padding: 0.75rem !important;
786
+ }
787
+
788
+ .gr-accordion > div:first-child {
789
+ padding: 0.625rem 0.75rem !important;
790
+ }
791
+
792
+ .gr-accordion > div:last-child {
793
+ padding: 0.75rem !important;
794
+ }
795
+
796
+ button.primary {
797
+ padding: 0.625rem 1.25rem !important;
798
+ }
799
+ }
800
+ """
801
+
802
+ # =============== ENHANCED UI COMPONENTS ===============
803
+
804
+ # Function to create and show application UI
805
+ def create_ui():
806
+ with gr.Blocks(title="AI Image Creator", css=css) as interface:
807
+ # Custom header with branding
808
+ with gr.Row(elem_classes="app-header"):
809
+ with gr.Column():
810
+ gr.HTML("""
811
+ <h1>🎨 AI Image Creator</h1>
812
+ <p>Transform your ideas into stunning images with AI-powered text-to-image generation</p>
813
+ """)
814
+
815
+ # Main content area
816
+ with gr.Row(equal_height=False):
817
+ # Left column - Input controls
818
+ with gr.Column(scale=1, min_width=380):
819
+ # Description input with character counter
820
+ with gr.Group(elem_classes="input-group"):
821
+ description_input = gr.Textbox(
822
+ label="Describe what you want to see",
823
+ placeholder="Be detailed and specific about colors, composition, lighting, and subject...",
824
+ lines=4,
825
+ max_lines=8,
826
+ elem_id="description-input"
827
+ )
828
+
829
+ # Character counter with dynamic updates
830
+ char_counter = gr.HTML(
831
+ value="<div class='character-counter'>0 characters</div>",
832
+ elem_classes="char-counter-container"
833
+ )
834
+
835
+ # Examples gallery with clear visual structure
836
+ with gr.Group(elem_classes="examples-group"):
837
+ gr.HTML("<h3 style='margin-top: 0; font-size: 1rem; margin-bottom: 0.75rem;'>🌟 Try an example:</h3>")
838
+
839
+ # Gallery of examples
840
+ with gr.Row(elem_classes="example-gallery"):
841
+ for i, example in enumerate(EXAMPLE_PROMPTS):
842
+ with gr.Column(elem_classes="example-item"):
843
+ # Example card with visual element and caption
844
+ example_card = gr.Button(
845
+ example["thumbnail_desc"],
846
+ elem_classes="example-button"
847
+ )
848
+
849
+ # Event handler for example selection
850
+ example_card.click(
851
+ fn=lambda idx=i: load_example(idx),
852
+ outputs=[description_input, creation_type, art_style, mood_dropdown]
853
+ )
854
+
855
+ # Creation settings with enhanced dropdowns
856
+ with gr.Group(elem_classes="settings-group"):
857
+ gr.HTML("<h3 style='margin-top: 0; font-size: 1rem; margin-bottom: 0.75rem;'>🛠️ Image Settings</h3>")
858
+
859
+ # Creation Type and Art Style in one row
860
+ with gr.Row():
861
+ # Creation type dropdown with icons
862
+ creation_type = gr.Dropdown(
863
+ choices=format_dropdown_choices(CREATION_TYPES),
864
+ value=f"{CREATION_TYPES['Digital Art']['icon']} Digital Art",
865
+ label="Creation Type",
866
+ elem_classes="enhanced-dropdown"
867
+ )
868
+
869
+ # Art style dropdown with icons
870
+ art_style = gr.Dropdown(
871
+ choices=format_dropdown_choices(ART_STYLES),
872
+ value=f"{ART_STYLES['Photorealistic']['icon']} Photorealistic",
873
+ label="Art Style",
874
+ elem_classes="enhanced-dropdown"
875
+ )
876
+
877
+ # Mood and Model in one row
878
+ with gr.Row():
879
+ # Mood dropdown with icons
880
+ mood_dropdown = gr.Dropdown(
881
+ choices=format_dropdown_choices(MOODS),
882
+ value=f"{MOODS['Peaceful']['icon']} Peaceful",
883
+ label="Mood",
884
+ elem_classes="enhanced-dropdown"
885
+ )
886
+
887
+ # Model selector with display names
888
+ formatted_models = [f"{info['icon']} {info['display_name']}" for model_key, info in IMAGE_MODELS.items()]
889
+ model_selector = gr.Dropdown(
890
+ choices=formatted_models,
891
+ value=f"{IMAGE_MODELS['stabilityai/stable-diffusion-xl-base-1.0']['icon']} {IMAGE_MODELS['stabilityai/stable-diffusion-xl-base-1.0']['display_name']}",
892
+ label="Model",
893
+ elem_classes="enhanced-dropdown"
894
+ )
895
+
896
+ # Information panels for selected options
897
+ with gr.Group(elem_classes="info-panels"):
898
+ # Creation type info
899
+ creation_info = gr.HTML(value="", elem_classes="option-info")
900
+
901
+ # Art style info
902
+ art_info = gr.HTML(value="", elem_classes="option-info")
903
+
904
+ # Model info panel
905
+ model_info = gr.HTML(value="", elem_classes="option-info")
906
+
907
+ # Generate button with clear call to action
908
+ with gr.Group(elem_classes="action-group"):
909
+ # Generate button with progress indicator
910
+ generate_button = gr.Button(
911
+ "✨ Generate Image",
912
+ variant="primary",
913
+ elem_classes="primary",
914
+ elem_id="generate-button"
915
+ )
916
+
917
+ # Generation status message
918
+ generation_status = gr.HTML(value="", elem_classes="generation-status")
919
+
920
+ # Tips section in collapsible accordion
921
+ with gr.Accordion("📝 Tips for better results", open=True):
922
+ gr.HTML("""
923
+ <div class="tips-container">
924
+ <h3>Tips for better results:</h3>
925
+ <ul>
926
+ <li><strong>Be specific and detailed</strong> - Include information about subjects, environment, lighting, colors, perspective, time of day, etc.</li>
927
+ <li><strong>Use descriptive adjectives</strong> - Words like "vibrant", "moody", "ethereal", "weathered" help set the tone.</li>
928
+ <li><strong>Experiment with art styles</strong> - Different styles can dramatically change the look and feel.</li>
929
+ <li><strong>Combine with the right model</strong> - SDXL provides the highest quality but takes longer.</li>
930
+ <li><strong>Think about composition</strong> - Mention foreground/background elements and their relationships.</li>
931
+ </ul>
932
+ </div>
933
+ """)
934
+
935
+ # Right column - Output display
936
+ with gr.Column(scale=1, min_width=480):
937
+ # Image display area with placeholder
938
+ with gr.Group(elem_classes="output-container"):
939
+ # Output image with interactive elements
940
+ image_output = gr.Image(
941
+ label="Generated Image",
942
+ elem_id="image-output",
943
+ type="pil",
944
+ height=512
945
+ )
946
+
947
+ # Image generation details
948
+ with gr.Accordion("Image Details", open=True):
949
+ parameters_display = gr.HTML(value="")
950
+
951
+ # Enhanced prompt display
952
+ with gr.Accordion("Enhanced Prompt", open=False):
953
+ prompt_output = gr.Textbox(
954
+ label="AI-Enhanced Prompt Used",
955
+ lines=5,
956
+ elem_id="prompt-output",
957
+ elem_classes="prompt-display"
958
+ )
959
+
960
+ # Technical details for advanced users
961
+ with gr.Accordion("Technical Details", open=False):
962
+ technical_info = gr.HTML("""
963
+ <div class="technical-info">
964
+ <h4>How Image Generation Works</h4>
965
+ <p>Images are generated using Stable Diffusion, a latent text-to-image diffusion model. Your text prompt is:
966
+ <ol>
967
+ <li>Enhanced with AI to add descriptive details and quality terms</li>
968
+ <li>Processed through a neural network that gradually transforms random noise into an image</li>
969
+ <li>Refined based on the parameters you select (model, style, mood)</li>
970
+ </ol>
971
+ </p>
972
+ <p>Different models have different strengths:
973
+ <ul>
974
+ <li><strong>SDXL 1.0</strong>: Highest quality, best composition and details</li>
975
+ <li><strong>SD 1.5</strong>: Faster generation, good for general purpose</li>
976
+ <li><strong>SD 2.1</strong>: Better with human faces, improved consistency</li>
977
+ <li><strong>OpenJourney</strong>: Midjourney-like stylized artistic results</li>
978
+ <li><strong>Dreamlike</strong>: Dreamy, ethereal aesthetic with artistic flair</li>
979
+ </ul>
980
+ </p>
981
+ </div>
982
+ """)
983
+
984
+ # Return all the UI components that need event handlers
985
+ return interface, description_input, creation_type, art_style, mood_dropdown, model_selector, generate_button, image_output, generation_status, prompt_output, parameters_display, char_counter, creation_info, art_info, model_info
986
+
987
+ # Helper function to update character count with color coding
988
+ def update_char_count(text):
989
+ count = len(text)
990
+ if count == 0:
991
+ color_class = ""
992
+ elif count < 20:
993
+ color_class = "warning"
994
+ elif count > 300:
995
+ color_class = "warning"
996
+ elif count > 500:
997
+ color_class = "error"
998
+ else:
999
+ color_class = ""
1000
+
1001
+ return f"<div class='character-counter {color_class}'>{count} characters</div>"
1002
+
1003
+ # Helper function to update creation type info
1004
+ def update_creation_info(choice):
1005
+ key = extract_key(choice)
1006
+ if key in CREATION_TYPES:
1007
+ info = CREATION_TYPES[key]
1008
+ return f"""<div class="info-card">
1009
+ <h3>{info['icon']} {key}</h3>
1010
+ <p>{info['description']}</p>
1011
+ <p style="margin-top: 0.5rem; font-style: italic; opacity: 0.8;">💡 {info['prompt_hint']}</p>
1012
+ </div>"""
1013
+ return ""
1014
+
1015
+ # Helper function to update art style info
1016
+ def update_art_style_info(choice):
1017
+ key = extract_key(choice)
1018
+ if key in ART_STYLES:
1019
+ info = ART_STYLES[key]
1020
+ return f"""<div class="info-card">
1021
+ <h3>{info['icon']} {key}</h3>
1022
+ <p>{info['description']}</p>
1023
+ <p style="margin-top: 0.5rem; font-style: italic; opacity: 0.8;">🎨 Examples: {info['examples']}</p>
1024
+ </div>"""
1025
+ return ""
1026
+
1027
+ # Helper function to update model info
1028
+ def update_model_info(formatted_choice):
1029
+ # Extract display name without the icon
1030
+ if ' ' in formatted_choice:
1031
+ display_name = formatted_choice.split(' ', 1)[1]
1032
+ # Find the corresponding key and info
1033
+ for key, info in IMAGE_MODELS.items():
1034
+ if info['display_name'] == display_name:
1035
+ # Create speed badge
1036
+ speed_badge = ""
1037
+ if info.get('speed') == 'fast':
1038
+ speed_badge = '<span class="badge badge-success">Fast</span>'
1039
+ elif info.get('speed') == 'medium':
1040
+ speed_badge = '<span class="badge badge-warning">Medium</span>'
1041
+ elif info.get('speed') == 'slow':
1042
+ speed_badge = '<span class="badge badge-error">Slower</span>'
1043
+
1044
+ # Create quality badge
1045
+ quality_badge = ""
1046
+ if info.get('quality') == 'excellent':
1047
+ quality_badge = '<span class="badge badge-success">Excellent Quality</span>'
1048
+ elif info.get('quality') == 'very good':
1049
+ quality_badge = '<span class="badge badge-success">Very Good Quality</span>'
1050
+ elif info.get('quality') == 'good':
1051
+ quality_badge = '<span class="badge badge-info">Good Quality</span>'
1052
+ elif info.get('quality') == 'stylized':
1053
+ quality_badge = '<span class="badge badge-info">Stylized</span>'
1054
+ elif info.get('quality') == 'artistic':
1055
+ quality_badge = '<span class="badge badge-info">Artistic</span>'
1056
+
1057
+ return f"""<div class="model-info">
1058
+ <h3>{info['icon']} {info['display_name']} {speed_badge} {quality_badge}</h3>
1059
+ <p>{info['description']}</p>
1060
+ <div class="model-id">{key}</div>
1061
+ </div>"""
1062
+ return ""
1063
+
1064
+ # Helper function to update status message
1065
+ def update_status(message, is_error=False, is_warning=False, is_info=False):
1066
+ if is_error:
1067
+ status_class = "status-error"
1068
+ icon = "❌"
1069
+ elif is_warning:
1070
+ status_class = "status-warning"
1071
+ icon = "⚠️"
1072
+ elif is_info:
1073
+ status_class = "status-info"
1074
+ icon = "ℹ️"
1075
+ else:
1076
+ status_class = "status-success"
1077
+ icon = "✅"
1078
+
1079
+ return f"""<div class="status-message {status_class}">
1080
+ <span class="icon">{icon}</span>
1081
+ <span>{message}</span>
1082
+ </div>"""
1083
+
1084
+ # Helper function to format parameters display as pills
1085
+ def format_parameters(creation_type_val, art_style_val, mood_val, model_name):
1086
+ creation_key = extract_key(creation_type_val)
1087
+ art_key = extract_key(art_style_val)
1088
+ mood_key = extract_key(mood_val)
1089
+
1090
+ # Get model info
1091
+ model_display_name = "Unknown Model"
1092
+ model_id = ""
1093
+ model_icon = "🤖"
1094
+ for key, info in IMAGE_MODELS.items():
1095
+ if f"{info['icon']} {info['display_name']}" == model_name:
1096
+ model_display_name = info['display_name']
1097
+ model_id = key
1098
+ model_icon = info['icon']
1099
+ break
1100
+
1101
+ html = """<div style="margin-bottom: 1rem;">
1102
+ <div style="font-weight: 500; margin-bottom: 0.75rem;">Generated with these parameters:</div>
1103
+ <div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">"""
1104
+
1105
+ # Add creation type pill
1106
+ if creation_key in CREATION_TYPES:
1107
+ html += f"""<div class="parameter-pill">
1108
+ <span class="icon">{CREATION_TYPES[creation_key]['icon']}</span> {creation_key}
1109
+ </div>"""
1110
+
1111
+ # Add art style pill
1112
+ if art_key in ART_STYLES:
1113
+ html += f"""<div class="parameter-pill">
1114
+ <span class="icon">{ART_STYLES[art_key]['icon']}</span> {art_key}
1115
+ </div>"""
1116
+
1117
+ # Add mood pill
1118
+ if mood_key in MOODS:
1119
+ html += f"""<div class="parameter-pill">
1120
+ <span class="icon">{MOODS[mood_key]['icon']}</span> {mood_key}
1121
+ </div>"""
1122
+
1123
+ # Add model pill
1124
+ html += f"""<div class="parameter-pill">
1125
+ <span class="icon">{model_icon}</span> {model_display_name}
1126
+ </div>"""
1127
+
1128
+ # Close container
1129
+ html += """</div>
1130
+ <div style="margin-top: 1rem; font-size: 0.75rem; color: var(--text-muted);">
1131
+ Image generated on {timestamp}
1132
+ </div>
1133
+ </div>""".replace("{timestamp}", time.strftime("%Y-%m-%d at %H:%M:%S"))
1134
+
1135
+ return html