Sebastiankay commited on
Commit
2091a7f
·
verified ·
1 Parent(s): f254640

Upload 57 files

Browse files
_res/_custom.css CHANGED
@@ -1,788 +1,764 @@
1
- @font-face {
2
- font-family: "Geist Mono";
3
- src: url("file=_res/assets/webfonts/GeistMono-Thin.woff2") format("woff2");
4
- font-weight: 100;
5
- font-style: normal;
6
- }
7
-
8
- @font-face {
9
- font-family: "Geist Mono";
10
- src: url("file=_res/assets/webfonts/GeistMono-Light.woff2") format("woff2");
11
- font-weight: 300;
12
- font-style: normal;
13
- }
14
-
15
- @font-face {
16
- font-family: "Geist Mono";
17
- src: url("file=_res/assets/webfonts/GeistMono-Regular.woff2") format("woff2");
18
- font-weight: 400;
19
- font-style: normal;
20
- }
21
-
22
- @font-face {
23
- font-family: "Geist Mono";
24
- src: url("file=_res/assets/webfonts/GeistMono-SemiBold.woff2") format("woff2");
25
- font-weight: 600;
26
- font-style: normal;
27
- }
28
-
29
- @font-face {
30
- font-family: "Geist Mono";
31
- src: url("file=_res/assets/webfonts/GeistMono-Bold.woff2") format("woff2");
32
- font-weight: 700;
33
- font-style: normal;
34
- }
35
-
36
- /* width */
37
- ::-webkit-scrollbar {
38
- width: 0px;
39
- }
40
-
41
- body::-webkit-scrollbar {
42
- width: 8px;
43
- }
44
-
45
- /* Track */
46
- ::-webkit-scrollbar-track {
47
- background: var(--neutral-900);
48
- }
49
-
50
- /* Handle */
51
- ::-webkit-scrollbar-thumb {
52
- background: var(--primary-600);
53
- border-radius: 3px;
54
- }
55
-
56
- /* Handle on hover */
57
- ::-webkit-scrollbar-thumb:hover {
58
- background: var(--primary-800);
59
- }
60
-
61
- body {
62
- /* min-height: 101vh; */
63
-
64
- gradio-app {
65
- /* background: var(--primary-950);
66
- background-image: linear-gradient(180deg, color-mix(in srgb, var(--primary-950), transparent 50%) 0%, color-mix(in srgb, var(--primary-950), transparent 50%) 28%, var(--neutral-950) 28%, var(--neutral-950) 100%) !important; */
67
- padding-top: 60px;
68
- /* min-width: 900px; */
69
- transition: opacity 0.4s linear;
70
- position: relative;
71
-
72
- & #alertModal {
73
- position: absolute;
74
- top: 250px;
75
- left: 50%;
76
- width: 400px;
77
- max-width: 80vw !important;
78
- min-height: 140px;
79
- transform: translate(-50%, -50%);
80
- padding: var(--size-4) var(--size-8);
81
- background-color: var(--neutral-900) !important;
82
-
83
- border-top-width: 8px;
84
- border-right-width: 1px;
85
- border-bottom-width: 1px;
86
- border-left-width: 1px;
87
- border-top-style: solid;
88
- border-right-style: solid;
89
- border-bottom-style: solid;
90
- border-left-style: solid;
91
- border-top-color: var(--primary-600);
92
- border-right-color: var(--primary-600);
93
- border-bottom-color: var(--primary-600);
94
- border-left-color: var(--primary-600);
95
-
96
- border-radius: var(--container-radius);
97
-
98
- & #alertModalP {
99
- display: flex;
100
- justify-content: center;
101
-
102
- & span {
103
- color: var(--neutral-50);
104
- margin-top: 0rem;
105
- line-height: 1.4;
106
- }
107
-
108
- & svg {
109
- font-size: 4rem;
110
- margin-right: 1rem;
111
- color: var(--cat-red);
112
- fill: var(--cat-red);
113
- }
114
- }
115
-
116
- & button {
117
- color: var(--text-color-by-luminance) !important;
118
- }
119
- }
120
-
121
- .md-header {
122
- padding: var(--size-2) var(--size-1);
123
-
124
- .flex-wrapper {
125
- display: inline-flex !important;
126
- width: 100% !important;
127
- justify-content: center !important;
128
- align-items: flex-end !important;
129
- }
130
- & h1 {
131
- color: var(--primary-950) !important;
132
- text-shadow:
133
- var(--primary-600) 1px 1px 0px,
134
- var(--primary-600) 1px -1px 0px,
135
- var(--primary-600) -1px 1px 0px,
136
- var(--primary-600) -1px -1px 0px,
137
- var(--primary-600) 1px 0px 0px,
138
- var(--primary-600) 0px 1px 0px,
139
- var(--primary-600) -1px 0px 0px,
140
- var(--primary-600) 0px -1px 0px;
141
- }
142
-
143
- & p,
144
- span {
145
- color: var(--neutral-800) !important;
146
- line-height: 1.5 !important;
147
- font-size: 1.1rem !important;
148
- text-shadow:
149
- var(--primary-600) 1px 1px 0px,
150
- var(--primary-600) 1px -1px 0px,
151
- var(--primary-600) -1px 1px 0px,
152
- var(--primary-600) -1px -1px 0px,
153
- var(--primary-600) 1px 0px 0px,
154
- var(--primary-600) 0px 1px 0px,
155
- var(--primary-600) -1px 0px 0px,
156
- var(--primary-600) 0px -1px 0px;
157
-
158
- & i {
159
- display: inline-flex;
160
- align-items: center;
161
- justify-content: center;
162
-
163
- & svg {
164
- font-size: inherit !important;
165
- width: 16px !important;
166
- height: 16px !important;
167
- }
168
- }
169
- }
170
- p.errorinfo {
171
- color: #e26c5a;
172
- margin-top: 0.3rem;
173
- margin-bottom: 0.3rem;
174
- background: var(--text-color-by-luminance) !important;
175
- padding: 0.25rem 0.5rem;
176
- border: none;
177
- border-radius: 0.4rem;
178
- font-size: 0.9rem !important;
179
- border: none !important;
180
- max-width: 80%;
181
- }
182
- }
183
- }
184
- }
185
-
186
- body>gradio-app::before {
187
- position: absolute;
188
- content: "";
189
- background: var(--primary-800);
190
- width: 100%;
191
- height: 355px;
192
- top: 0;
193
- z-index: 0;
194
- transition: filter 0.4s ease-out;
195
- filter: blur(var(--blur-value));
196
- }
197
-
198
- body>gradio-app.has-bg-image::before {
199
- /* --bg-image-path: none; */
200
- /* --bg-image-path: url("https://image.pollinations.ai/prompt/A%20midnight%20blue%20stallion%20gallops%20across%20a%20misty%2C%20moonlit%20meadow%2C%20its%20mane%20and%20tail%20flowing%20in%20the%20wind%20like%20a%20celestial%20river%2C%20as%20stars%20twinkle%20in%20the%20sky%20above%20-%20Expressionist%20Watercolor%20Painting?model=flux&width=1024&height=683&nologo=true&enhance=false&nofeed=true&seed=42"); */
201
- background-image: var(--bg-image-path);
202
- background-size: cover;
203
- background-position: center;
204
- background-repeat: no-repeat;
205
- filter: blur(12px);
206
-
207
- }
208
-
209
- div.gradio-container {
210
- font-family: "Geist Mono", sans-serif !important;
211
- font-weight: 400;
212
- }
213
-
214
- @media screen and (min-width: 980px) {
215
-
216
- div.gradio-container {
217
- max-width: 80% !important;
218
- }
219
-
220
- }
221
-
222
- div.tabs>div.tab-nav>button.selected {
223
- border-width: 0 !important;
224
- background: var(--primary-600) !important;
225
- font-weight: 600;
226
- }
227
-
228
- div.tabs>div.tab-nav {
229
- border-bottom: none !important;
230
- padding: 0 0.25rem 0 0.25rem !important;
231
- }
232
-
233
- div.tabs div.tabitem {
234
- background-color: var(--neutral-900) !important;
235
- border-width: 0 !important;
236
- border-top: 8px solid var(--primary-600) !important;
237
- border-radius: var(--container-radius) !important;
238
- }
239
-
240
- .top-description h1 {
241
- color: var(--neutral-400);
242
- font-size: 2rem;
243
- }
244
-
245
- .prompt-input textarea {
246
- resize: none;
247
- }
248
-
249
- .ratio_buttons_wrapper {
250
- display: flex !important;
251
- flex-grow: 0 !important;
252
- min-width: min(48px, 30%) !important;
253
- flex: 1 1 0%;
254
- flex-wrap: nowrap;
255
- }
256
-
257
- .image_size_selctor_wrapper {
258
- flex-grow: 2 !important;
259
- min-width: min(120px, 10%) !important;
260
- }
261
-
262
- .info-text-wrapper {
263
- padding: calc(var(--spacing-xl) / 2) calc(var(--spacing-xl) + 2px);
264
- }
265
-
266
- span.info-text {
267
- margin-bottom: var(--spacing-lg);
268
- color: var(--block-info-text-color);
269
- font-weight: var(--block-info-text-weight);
270
- font-size: var(--block-info-text-size);
271
- line-height: var(--line-sm);
272
- }
273
-
274
- .image-input-read-exfi {
275
- max-height: 120px;
276
- }
277
-
278
- .image-input-read-exfi>button {
279
- transform: scale(.8);
280
- }
281
-
282
- .image-ratio-buttons {
283
- height: 120px;
284
-
285
- & label {
286
- width: calc(25% - calc(var(--spacing-xl) + 2px) * 2 / 4);
287
- justify-content: center;
288
- align-items: end;
289
-
290
- & input {
291
- display: none;
292
- }
293
- }
294
-
295
- & label span {
296
- margin-left: 0;
297
- }
298
- }
299
-
300
- span.has-info+div {
301
- margin-top: var(--spacing-lg);
302
- margin-bottom: var(--spacing-lg);
303
- }
304
-
305
- .switch-ratio-btn {
306
- /* max-width: 38px;
307
- min-width: 38px !important;
308
- height: 33px; */
309
- --icon-ratio: 3/2;
310
- aspect-ratio: 1;
311
- min-width: 120px;
312
- max-width: 120px;
313
- display: flex;
314
- justify-content: center;
315
- align-items: center;
316
-
317
- /*
318
- & div#switch_width_height_inner {
319
- fill: var(--text-color-by-luminance);
320
- width: 70%;
321
- transition: transform 0.2s ease-in-out;
322
- }
323
-
324
- & div#switch_width_height_inner.portrait {
325
- transform: rotate(90deg) rotateX(180deg);
326
- }
327
- */
328
-
329
- & #switch_width_height_inner {
330
- width: 100px;
331
- height: 100px;
332
- transition: transform 0.2s ease-in-out, width 0.3s ease-in-out, height 0.38s ease-in-out 0.1s, background-image 0.3s ease-in-out;
333
- border-radius: 0.4rem;
334
- border: 4px solid var(--text-color-by-luminance);
335
- /*background: transparent;*/
336
- background-position: center;
337
-
338
- & div {
339
- width: calc(100% + 20px);
340
- height: calc(100% + 20px);
341
- margin-top: -10px;
342
- margin-left: -10px;
343
- transition: background-image 0.3s ease-in-out;
344
- background-position: center;
345
- }
346
- }
347
-
348
- [data-aspect-ratio="16-9"] {
349
- width: 90px !important;
350
- height: 51px !important;
351
- background-image: url("file=_res/assets/ratio_preview_bgs/90x51px_16zu9.png");
352
- }
353
- [data-aspect-ratio="9-16"] {
354
- width: 51px !important;
355
- height: 90px !important;
356
- background-image: url("file=_res/assets/ratio_preview_bgs/51x90px_9zu16.png");
357
- }
358
- [data-aspect-ratio="4-3"] {
359
- width: 90px !important;
360
- height: 60px !important;
361
- background-image: url("file=_res/assets/ratio_preview_bgs/90x60px_4zu3.png");
362
- }
363
- [data-aspect-ratio="3-4"] {
364
- width: 60px !important;
365
- height: 90px !important;
366
- background-image: url("file=_res/assets/ratio_preview_bgs/60x90px_3zu4.png");
367
- }
368
- [data-aspect-ratio="3-2"] {
369
- width: 90px !important;
370
- height: 67px !important;
371
- background-image: url("file=_res/assets/ratio_preview_bgs/90x67px_3zu2.png");
372
- }
373
- [data-aspect-ratio="2-3"] {
374
- width: 67px !important;
375
- height: 90px !important;
376
- background-image: url("file=_res/assets/ratio_preview_bgs/67x90px_2zu3.png");
377
- }
378
- [data-aspect-ratio="1-1"] {
379
- width: 70px !important;
380
- height: 70px !important;
381
- background-image: url("file=_res/assets/ratio_preview_bgs/70x70px_1zu1.png");
382
- }
383
- }
384
-
385
- .switch-ratio-btn:hover {
386
- & #switch_width_height_inner.querformat {
387
- transform: rotate(20deg);
388
- }
389
-
390
- & #switch_width_height_inner.hochformat {
391
- transform: rotate(-20deg) !important;
392
- }
393
- }
394
-
395
- .output-dominant-image-color {
396
- display: none;
397
- }
398
-
399
- .image-info-wrapper {
400
- transition: opacity 0.4s linear;
401
- }
402
-
403
- .tb-img-width input[type=text],
404
- .tb-img-height input[type=text],
405
- .tb-img-seed input[type=text] {
406
- display: block;
407
- position: relative;
408
- outline: none !important;
409
- box-shadow: var(--input-shadow);
410
- border: var(--input-border-width) solid var(--input-border-color);
411
- border-radius: var(--input-radius);
412
- background: var(--input-background-fill);
413
- padding: var(--size-2) var(--size-2);
414
- height: var(--size-6);
415
- color: var(--body-text-color);
416
- font-size: var(--input-text-size);
417
- line-height: var(--line-sm);
418
- text-align: center;
419
- }
420
-
421
- #output_image {
422
- min-height: 400px;
423
-
424
- &>div.image-container>div.icon-buttons {
425
-
426
-
427
- /* display: flex;
428
- position: absolute;
429
- top: var(--block-label-margin);
430
- right: var(--block-label-margin);
431
- align-items: center; */
432
- & button,
433
- a button {
434
- display: inline-block;
435
- position: relative;
436
- z-index: var(--layer-4);
437
- border: solid var(--block-title-border-width) var(--block-title-border-color);
438
- border-radius: var(--block-title-radius);
439
- background: var(--block-title-background-fill);
440
- padding: var(--block-title-padding);
441
- color: var(--block-title-text-color);
442
- font-weight: var(--block-title-text-weight);
443
- font-size: var(--block-title-text-size);
444
- line-height: var(--line-sm);
445
- }
446
- }
447
- }
448
-
449
- .random-prompt-btn,
450
- .enhance-prompt-btn,
451
- .run-btn {
452
- min-width: 110px;
453
- transition: background 0.2s ease-in-out;
454
-
455
- & svg {
456
- fill: var(--text-color-by-luminance);
457
- width: 1.8rem;
458
- }
459
-
460
- }
461
-
462
- button.secondary {
463
- min-width: 110px;
464
- transition: background 0.2s ease-in-out;
465
-
466
- & svg {
467
- transition: fill 0.2s ease-in-out;
468
- fill: var(--primary-600);
469
- }
470
-
471
- }
472
-
473
- button.secondary:hover {
474
- min-width: 110px;
475
-
476
- & svg {
477
- fill: var(--text-color-by-luminance);
478
- }
479
-
480
- }
481
-
482
- .image-height-selector>label,
483
- .image-width-selector>label {
484
- display: flex;
485
- justify-content: space-between;
486
-
487
- & input {
488
- min-width: 100px;
489
- width: 50%;
490
- height: var(--size-9);
491
- }
492
-
493
- }
494
-
495
-
496
- div.gradio-container.blur-container {
497
- filter: blur(12px);
498
- pointer-events: none;
499
- }
500
-
501
- #image_seed:has(input[disabled].svelte-pc1gm4) {
502
- position: relative;
503
- }
504
-
505
- #image_seed:has(input[disabled].svelte-pc1gm4)::after {
506
- position: absolute;
507
- content: '';
508
- top: 50%;
509
- left: 50%;
510
- transform: translate(-50%, -50%);
511
- width: 100%;
512
- height: 100%;
513
- border-radius: var(--block-radius);
514
- background: var(--block-background-fill);
515
- opacity: 0.5;
516
- cursor: not-allowed;
517
- z-index: var(--layer-5);
518
- }
519
-
520
- /* MARK: Toggle Button Checkbox */
521
- /* INFO: gr.Checkbox elem_classes".toggle-btn" */
522
-
523
- .toggle-btn {
524
- display: flex;
525
- flex-direction: column-reverse;
526
-
527
- &>div.wrap {
528
- display: none;
529
- }
530
-
531
- &>div:not(.wrap) {
532
- margin-top: var(--spacing-lg);
533
- margin-bottom: 0;
534
- }
535
-
536
- &>label {
537
- position: relative;
538
- width: 57px;
539
- height: 27px;
540
- display: inline-block;
541
- border-radius: 13px;
542
- background: var(--neutral-700);
543
- box-shadow: var(--shadow-inset);
544
- transition: background-color 0.3s, cursor 0.3s;
545
- border: solid 0.4px var(--border-color-primary);
546
- cursor: pointer;
547
-
548
- &>input[type="checkbox"] {
549
- width: 0;
550
- height: 0;
551
- opacity: 0;
552
- }
553
-
554
- &>span {
555
- position: absolute;
556
- left: 60px;
557
- height: 27px;
558
- min-width: 140px;
559
- line-height: 27px;
560
- }
561
- }
562
-
563
- &>label:has(input[type="checkbox"])::after {
564
- content: "";
565
- position: absolute;
566
- top: 3px;
567
- left: 3px;
568
- width: 20px;
569
- height: 20px;
570
- border-radius: 50%;
571
- background: var(--neutral-900);
572
- box-shadow: var(--shadow-inset);
573
- transition: left 0.2s ease-in-out, background 0.2s ease-in-out;
574
- }
575
-
576
- &>label:has(input[type="checkbox"]:checked)::after {
577
- content: "";
578
- position: absolute;
579
- background: var(--neutral-900);
580
- opacity: 0.8;
581
- left: 32px;
582
- }
583
-
584
- &>label:has(input[type="checkbox"]:checked) {
585
- background: var(--primary-600);
586
- }
587
- }
588
-
589
-
590
- /* MARK: Range Input */
591
- input[type=range].svelte-pc1gm4 {
592
- accent-color: var(--slider-color);
593
- background: var(--neutral-700) !important;
594
- background-image: linear-gradient(var(--slider-color), var(--slider-color)) !important;
595
- background-size: 0% 100%;
596
- }
597
-
598
- input[type=range].svelte-pc1gm4::-webkit-slider-thumb {
599
- background-color: var(--primary-600);
600
- border-width: 0;
601
- }
602
-
603
- input[type=range].svelte-pc1gm4::-webkit-slider-thumb:hover {
604
- background-color: var(--primary-500);
605
- }
606
-
607
- /* MARK: Text-Color Override */
608
- label.svelte-1b6s6s,
609
- label.svelte-9gxdi0,
610
- span.svelte-1gfkn6j,
611
- span.svelte-1gfkn6j,
612
- .primary.svelte-cmf5ev,
613
- label.selected.svelte-1k4wjf2,
614
- label.selected.svelte-1mhtq7j,
615
- label.svelte-1mhtq7j:hover,
616
- div.tabs>div.tab-nav>button,
617
- .md-header h1,
618
- .md-header p,
619
- .md-header span {
620
- color: var(--text-color-by-luminance) !important;
621
- }
622
-
623
- /* MARK: Hide Progress */
624
- .hide-progress:has(.wrap.default.full) {
625
- pointer-events: none;
626
- }
627
-
628
- .hide-progress:has(.wrap.default.full.hide) {
629
- pointer-events: initial;
630
- }
631
-
632
- .hide-progress .wrap.default.full:not(.hide) {
633
- display: none;
634
- }
635
-
636
- #run_btn {
637
-
638
- svg,
639
- dotlottie-player {
640
- height: 28.8px;
641
- }
642
- }
643
-
644
-
645
- /* KOFI CSS */
646
- img.kofiimg {
647
- display: initial !important;
648
- vertical-align: middle;
649
- height: 13px !important;
650
- width: 20px !important;
651
- padding-top: 0 !important;
652
- padding-bottom: 0 !important;
653
- border: none;
654
- margin-top: 0;
655
- margin-right: 5px !important;
656
- margin-left: 0 !important;
657
- margin-bottom: 3px !important;
658
- content: url('https://storage.ko-fi.com/cdn/cup-border.png')
659
- }
660
-
661
- .kofiimg:after {
662
- vertical-align: middle;
663
- height: 25px;
664
- padding-top: 0;
665
- padding-bottom: 0;
666
- border: none;
667
- margin-top: 0;
668
- margin-right: 6px;
669
- margin-left: 0;
670
- margin-bottom: 4px !important;
671
- content: url('https://storage.ko-fi.com/cdn/whitelogo.svg')
672
- }
673
-
674
- .btn-container {
675
- display: inline-block !important;
676
- white-space: nowrap;
677
- min-width: 230px;
678
- }
679
-
680
- span.kofitext {
681
- color: var(--text-color-by-luminance) !important;
682
- letter-spacing: -0.15px !important;
683
- text-wrap: none;
684
- vertical-align: middle;
685
- line-height: 33px !important;
686
- padding: 0;
687
- text-align: center;
688
- text-decoration: none !important;
689
- text-shadow: 0 1px 1px rgba(34, 34, 34, 0.05);
690
- }
691
-
692
- .kofitext a {
693
- color: #fff !important;
694
- text-decoration: none:important;
695
- }
696
-
697
- .kofitext a:hover {
698
- color: #fff !important;
699
- text-decoration: none
700
- }
701
-
702
- a.kofi-button {
703
- background: var(--primary-600) !important;
704
- box-shadow: 0px -8px 16px -8px rgba(17, 17, 27, 0.7);
705
- border: 4px solid var(--text-color-by-luminance) !important;
706
-
707
- box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.2);
708
- line-height: 36px !important;
709
- min-width: 150px;
710
- display: inline-block !important;
711
- background-color: #29abe0;
712
- padding: 2px 12px !important;
713
- text-align: center !important;
714
- border-radius: 7px;
715
- color: #fff;
716
- cursor: pointer;
717
- overflow-wrap: break-word;
718
- vertical-align: middle;
719
-
720
- border: 4px solid var(--text-color-by-luminance) !important;
721
- font-family: 'Quicksand', Helvetica, Century Gothic, sans-serif !important;
722
- text-decoration: none;
723
- text-shadow: none;
724
- font-weight: 700 !important;
725
- font-size: 14px !important
726
- }
727
-
728
- a.kofi-button:visited {
729
- color: #fff !important;
730
- text-decoration: none !important
731
- }
732
-
733
- a.kofi-button:hover {
734
- opacity: .85;
735
- color: #f5f5f5 !important;
736
- text-decoration: none !important
737
- }
738
-
739
- a.kofi-button:active {
740
- color: #f5f5f5 !important;
741
- text-decoration: none !important
742
- }
743
-
744
- .kofitext img.kofiimg {
745
- height: 15px !important;
746
- width: 22px !important;
747
- display: initial;
748
- animation: kofi-wiggle 3s infinite;
749
- }
750
-
751
- @keyframes kofi-wiggle {
752
- 0% {
753
- transform: rotate(0) scale(1)
754
- }
755
-
756
- 60% {
757
- transform: rotate(0) scale(1)
758
- }
759
-
760
- 75% {
761
- transform: rotate(0) scale(1.12)
762
- }
763
-
764
- 80% {
765
- transform: rotate(0) scale(1.1)
766
- }
767
-
768
- 84% {
769
- transform: rotate(-10deg) scale(1.1)
770
- }
771
-
772
- 88% {
773
- transform: rotate(10deg) scale(1.1)
774
- }
775
-
776
- 92% {
777
- transform: rotate(-10deg) scale(1.1)
778
- }
779
-
780
- 96% {
781
- transform: rotate(10deg) scale(1.1)
782
- }
783
-
784
- 100% {
785
- transform: rotate(0) scale(1)
786
- }
787
- }
788
- /* KOFI CSS END */
 
1
+ @font-face {
2
+ font-family: "Geist Mono";
3
+ src: url("file=_res/assets/webfonts/GeistMono-Thin.woff2") format("woff2");
4
+ font-weight: 100;
5
+ font-style: normal;
6
+ }
7
+
8
+ @font-face {
9
+ font-family: "Geist Mono";
10
+ src: url("file=_res/assets/webfonts/GeistMono-Light.woff2") format("woff2");
11
+ font-weight: 300;
12
+ font-style: normal;
13
+ }
14
+
15
+ @font-face {
16
+ font-family: "Geist Mono";
17
+ src: url("file=_res/assets/webfonts/GeistMono-Regular.woff2") format("woff2");
18
+ font-weight: 400;
19
+ font-style: normal;
20
+ }
21
+
22
+ @font-face {
23
+ font-family: "Geist Mono";
24
+ src: url("file=_res/assets/webfonts/GeistMono-SemiBold.woff2") format("woff2");
25
+ font-weight: 600;
26
+ font-style: normal;
27
+ }
28
+
29
+ @font-face {
30
+ font-family: "Geist Mono";
31
+ src: url("file=_res/assets/webfonts/GeistMono-Bold.woff2") format("woff2");
32
+ font-weight: 700;
33
+ font-style: normal;
34
+ }
35
+
36
+ /* width */
37
+ ::-webkit-scrollbar {
38
+ width: 0px;
39
+ }
40
+
41
+ body::-webkit-scrollbar {
42
+ width: 8px;
43
+ }
44
+
45
+ /* Track */
46
+ ::-webkit-scrollbar-track {
47
+ background: var(--neutral-900);
48
+ }
49
+
50
+ /* Handle */
51
+ ::-webkit-scrollbar-thumb {
52
+ background: var(--primary-600);
53
+ border-radius: 3px;
54
+ }
55
+
56
+ /* Handle on hover */
57
+ ::-webkit-scrollbar-thumb:hover {
58
+ background: var(--primary-800);
59
+ }
60
+
61
+ body {
62
+ /* min-height: 101vh; */
63
+
64
+ gradio-app {
65
+ /* background: var(--primary-950);
66
+ background-image: linear-gradient(180deg, color-mix(in srgb, var(--primary-950), transparent 50%) 0%, color-mix(in srgb, var(--primary-950), transparent 50%) 28%, var(--neutral-950) 28%, var(--neutral-950) 100%) !important; */
67
+ padding-top: 60px;
68
+ /* min-width: 900px; */
69
+ transition: opacity 0.4s linear;
70
+ position: relative;
71
+
72
+ & #alertModal {
73
+ position: absolute;
74
+ top: 250px;
75
+ left: 50%;
76
+ width: 400px;
77
+ max-width: 80vw !important;
78
+ min-height: 140px;
79
+ transform: translate(-50%, -50%);
80
+ padding: var(--size-4) var(--size-8);
81
+ background-color: var(--neutral-900) !important;
82
+
83
+ border-top-width: 8px;
84
+ border-right-width: 1px;
85
+ border-bottom-width: 1px;
86
+ border-left-width: 1px;
87
+ border-top-style: solid;
88
+ border-right-style: solid;
89
+ border-bottom-style: solid;
90
+ border-left-style: solid;
91
+ border-top-color: var(--primary-600);
92
+ border-right-color: var(--primary-600);
93
+ border-bottom-color: var(--primary-600);
94
+ border-left-color: var(--primary-600);
95
+
96
+ border-radius: var(--container-radius);
97
+
98
+ & #alertModalP {
99
+ display: flex;
100
+ justify-content: center;
101
+
102
+ & span {
103
+ color: var(--neutral-50);
104
+ margin-top: 0rem;
105
+ line-height: 1.4;
106
+ }
107
+
108
+ & svg {
109
+ font-size: 4rem;
110
+ margin-right: 1rem;
111
+ color: var(--cat-red);
112
+ fill: var(--cat-red);
113
+ }
114
+ }
115
+
116
+ & button {
117
+ color: var(--text-color-by-luminance) !important;
118
+ }
119
+ }
120
+
121
+ .md-header {
122
+ padding: var(--size-2) var(--size-1);
123
+
124
+ .flex-wrapper {
125
+ display: inline-flex !important;
126
+ width: 100% !important;
127
+ justify-content: center !important;
128
+ align-items: flex-end !important;
129
+ }
130
+ & h1 {
131
+ color: var(--primary-950) !important;
132
+ text-shadow: var(--primary-600) 1px 1px 0px, var(--primary-600) 1px -1px 0px, var(--primary-600) -1px 1px 0px, var(--primary-600) -1px -1px 0px, var(--primary-600) 1px 0px 0px, var(--primary-600) 0px 1px 0px, var(--primary-600) -1px 0px 0px, var(--primary-600) 0px -1px 0px;
133
+ }
134
+
135
+ & p,
136
+ span {
137
+ color: var(--neutral-800) !important;
138
+ line-height: 1.5 !important;
139
+ font-size: 1.1rem !important;
140
+ text-shadow: var(--primary-600) 1px 1px 0px, var(--primary-600) 1px -1px 0px, var(--primary-600) -1px 1px 0px, var(--primary-600) -1px -1px 0px, var(--primary-600) 1px 0px 0px, var(--primary-600) 0px 1px 0px, var(--primary-600) -1px 0px 0px, var(--primary-600) 0px -1px 0px;
141
+
142
+ & i {
143
+ display: inline-flex;
144
+ align-items: center;
145
+ justify-content: center;
146
+
147
+ & svg {
148
+ font-size: inherit !important;
149
+ width: 16px !important;
150
+ height: 16px !important;
151
+ }
152
+ }
153
+ }
154
+ p.errorinfo {
155
+ display: none !important;
156
+ color: #e26c5a;
157
+ margin-top: 0.3rem;
158
+ margin-bottom: 0.3rem;
159
+ background: var(--text-color-by-luminance) !important;
160
+ padding: 0.25rem 0.5rem;
161
+ border: none;
162
+ border-radius: 0.4rem;
163
+ font-size: 0.9rem !important;
164
+ border: none !important;
165
+ max-width: 80%;
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ body > gradio-app::before {
172
+ position: absolute;
173
+ content: "";
174
+ background: var(--primary-800);
175
+ width: 100%;
176
+ height: 355px;
177
+ top: 0;
178
+ z-index: 0;
179
+ transition: filter 0.4s ease-out;
180
+ filter: blur(var(--blur-value));
181
+ }
182
+
183
+ body > gradio-app.has-bg-image::before {
184
+ /* --bg-image-path: none; */
185
+ /* --bg-image-path: url("https://image.pollinations.ai/prompt/A%20midnight%20blue%20stallion%20gallops%20across%20a%20misty%2C%20moonlit%20meadow%2C%20its%20mane%20and%20tail%20flowing%20in%20the%20wind%20like%20a%20celestial%20river%2C%20as%20stars%20twinkle%20in%20the%20sky%20above%20-%20Expressionist%20Watercolor%20Painting?model=flux&width=1024&height=683&nologo=true&enhance=false&nofeed=true&seed=42"); */
186
+ background-image: var(--bg-image-path);
187
+ background-size: cover;
188
+ background-position: center;
189
+ background-repeat: no-repeat;
190
+ filter: blur(12px);
191
+ }
192
+
193
+ div.gradio-container {
194
+ font-family: "Geist Mono", sans-serif !important;
195
+ font-weight: 400;
196
+ }
197
+
198
+ @media screen and (min-width: 980px) {
199
+ div.gradio-container {
200
+ max-width: 80% !important;
201
+ }
202
+ }
203
+
204
+ div.tabs > div.tab-nav > button.selected {
205
+ border-width: 0 !important;
206
+ background: var(--primary-600) !important;
207
+ font-weight: 600;
208
+ }
209
+
210
+ div.tabs > div.tab-nav {
211
+ border-bottom: none !important;
212
+ padding: 0 0.25rem 0 0.25rem !important;
213
+ }
214
+
215
+ div.tabs div.tabitem {
216
+ background-color: var(--neutral-900) !important;
217
+ border-width: 0 !important;
218
+ border-top: 8px solid var(--primary-600) !important;
219
+ border-radius: var(--container-radius) !important;
220
+ }
221
+
222
+ .top-description h1 {
223
+ color: var(--neutral-400);
224
+ font-size: 2rem;
225
+ }
226
+
227
+ .prompt-input textarea {
228
+ resize: none;
229
+ }
230
+
231
+ .ratio_buttons_wrapper {
232
+ display: flex !important;
233
+ flex-grow: 0 !important;
234
+ min-width: min(48px, 30%) !important;
235
+ flex: 1 1 0%;
236
+ flex-wrap: nowrap;
237
+ }
238
+
239
+ .image_size_selctor_wrapper {
240
+ flex-grow: 2 !important;
241
+ min-width: min(120px, 10%) !important;
242
+ }
243
+
244
+ .info-text-wrapper {
245
+ padding: calc(var(--spacing-xl) / 2) calc(var(--spacing-xl) + 2px);
246
+ }
247
+
248
+ span.info-text {
249
+ margin-bottom: var(--spacing-lg);
250
+ color: var(--block-info-text-color);
251
+ font-weight: var(--block-info-text-weight);
252
+ font-size: var(--block-info-text-size);
253
+ line-height: var(--line-sm);
254
+ }
255
+
256
+ .image-input-read-exfi {
257
+ max-height: 120px;
258
+ }
259
+
260
+ .image-input-read-exfi > button {
261
+ transform: scale(0.8);
262
+ }
263
+
264
+ .image-ratio-buttons {
265
+ height: 120px;
266
+
267
+ & label {
268
+ width: calc(25% - calc(var(--spacing-xl) + 2px) * 2 / 4);
269
+ justify-content: center;
270
+ align-items: end;
271
+
272
+ & input {
273
+ display: none;
274
+ }
275
+ }
276
+
277
+ & label span {
278
+ margin-left: 0;
279
+ }
280
+ }
281
+
282
+ span.has-info + div {
283
+ margin-top: var(--spacing-lg);
284
+ margin-bottom: var(--spacing-lg);
285
+ }
286
+
287
+ .switch-ratio-btn {
288
+ /* max-width: 38px;
289
+ min-width: 38px !important;
290
+ height: 33px; */
291
+ --icon-ratio: 3/2;
292
+ aspect-ratio: 1;
293
+ min-width: 120px;
294
+ max-width: 120px;
295
+ display: flex;
296
+ justify-content: center;
297
+ align-items: center;
298
+
299
+ /*
300
+ & div#switch_width_height_inner {
301
+ fill: var(--text-color-by-luminance);
302
+ width: 70%;
303
+ transition: transform 0.2s ease-in-out;
304
+ }
305
+
306
+ & div#switch_width_height_inner.portrait {
307
+ transform: rotate(90deg) rotateX(180deg);
308
+ }
309
+ */
310
+
311
+ & #switch_width_height_inner {
312
+ width: 100px;
313
+ height: 100px;
314
+ transition: transform 0.2s ease-in-out, width 0.3s ease-in-out, height 0.38s ease-in-out 0.1s, background-image 0.3s ease-in-out;
315
+ border-radius: 0.4rem;
316
+ border: 4px solid var(--text-color-by-luminance);
317
+ /*background: transparent;*/
318
+ background-position: center;
319
+
320
+ & div {
321
+ width: calc(100% + 20px);
322
+ height: calc(100% + 20px);
323
+ margin-top: -10px;
324
+ margin-left: -10px;
325
+ transition: background-image 0.3s ease-in-out;
326
+ background-position: center;
327
+ }
328
+ }
329
+
330
+ [data-aspect-ratio="16-9"] {
331
+ width: 90px !important;
332
+ height: 51px !important;
333
+ background-image: url("file=_res/assets/ratio_preview_bgs/90x51px_16zu9.png");
334
+ }
335
+ [data-aspect-ratio="9-16"] {
336
+ width: 51px !important;
337
+ height: 90px !important;
338
+ background-image: url("file=_res/assets/ratio_preview_bgs/51x90px_9zu16.png");
339
+ }
340
+ [data-aspect-ratio="4-3"] {
341
+ width: 90px !important;
342
+ height: 60px !important;
343
+ background-image: url("file=_res/assets/ratio_preview_bgs/90x60px_4zu3.png");
344
+ }
345
+ [data-aspect-ratio="3-4"] {
346
+ width: 60px !important;
347
+ height: 90px !important;
348
+ background-image: url("file=_res/assets/ratio_preview_bgs/60x90px_3zu4.png");
349
+ }
350
+ [data-aspect-ratio="3-2"] {
351
+ width: 90px !important;
352
+ height: 67px !important;
353
+ background-image: url("file=_res/assets/ratio_preview_bgs/90x67px_3zu2.png");
354
+ }
355
+ [data-aspect-ratio="2-3"] {
356
+ width: 67px !important;
357
+ height: 90px !important;
358
+ background-image: url("file=_res/assets/ratio_preview_bgs/67x90px_2zu3.png");
359
+ }
360
+ [data-aspect-ratio="1-1"] {
361
+ width: 70px !important;
362
+ height: 70px !important;
363
+ background-image: url("file=_res/assets/ratio_preview_bgs/70x70px_1zu1.png");
364
+ }
365
+ }
366
+
367
+ .switch-ratio-btn:hover {
368
+ & #switch_width_height_inner.querformat {
369
+ transform: rotate(20deg);
370
+ }
371
+
372
+ & #switch_width_height_inner.hochformat {
373
+ transform: rotate(-20deg) !important;
374
+ }
375
+ }
376
+
377
+ .output-dominant-image-color {
378
+ display: none;
379
+ }
380
+
381
+ .image-info-wrapper {
382
+ transition: opacity 0.4s linear;
383
+ }
384
+
385
+ .tb-img-width input[type="text"],
386
+ .tb-img-height input[type="text"],
387
+ .tb-img-seed input[type="text"] {
388
+ display: block;
389
+ position: relative;
390
+ outline: none !important;
391
+ box-shadow: var(--input-shadow);
392
+ border: var(--input-border-width) solid var(--input-border-color);
393
+ border-radius: var(--input-radius);
394
+ background: var(--input-background-fill);
395
+ padding: var(--size-2) var(--size-2);
396
+ height: var(--size-6);
397
+ color: var(--body-text-color);
398
+ font-size: var(--input-text-size);
399
+ line-height: var(--line-sm);
400
+ text-align: center;
401
+ }
402
+
403
+ #output_image {
404
+ min-height: 400px;
405
+
406
+ & > div.image-container > div.icon-buttons {
407
+ /* display: flex;
408
+ position: absolute;
409
+ top: var(--block-label-margin);
410
+ right: var(--block-label-margin);
411
+ align-items: center; */
412
+ & button,
413
+ a button {
414
+ display: inline-block;
415
+ position: relative;
416
+ z-index: var(--layer-4);
417
+ border: solid var(--block-title-border-width) var(--block-title-border-color);
418
+ border-radius: var(--block-title-radius);
419
+ background: var(--block-title-background-fill);
420
+ padding: var(--block-title-padding);
421
+ color: var(--block-title-text-color);
422
+ font-weight: var(--block-title-text-weight);
423
+ font-size: var(--block-title-text-size);
424
+ line-height: var(--line-sm);
425
+ }
426
+ }
427
+ }
428
+
429
+ #gallery {
430
+ min-height: 800px;
431
+ }
432
+
433
+ .random-prompt-btn,
434
+ .enhance-prompt-btn,
435
+ .run-btn {
436
+ min-width: 110px;
437
+ transition: background 0.2s ease-in-out;
438
+
439
+ & svg {
440
+ fill: var(--text-color-by-luminance);
441
+ width: 1.8rem;
442
+ }
443
+ }
444
+
445
+ button.secondary {
446
+ min-width: 110px;
447
+ transition: background 0.2s ease-in-out;
448
+
449
+ & svg {
450
+ transition: fill 0.2s ease-in-out;
451
+ fill: var(--primary-600);
452
+ }
453
+ }
454
+
455
+ button.secondary:hover {
456
+ min-width: 110px;
457
+
458
+ & svg {
459
+ fill: var(--text-color-by-luminance);
460
+ }
461
+ }
462
+
463
+ .image-height-selector > label,
464
+ .image-width-selector > label {
465
+ display: flex;
466
+ justify-content: space-between;
467
+
468
+ & input {
469
+ min-width: 100px;
470
+ width: 50%;
471
+ height: var(--size-9);
472
+ }
473
+ }
474
+
475
+ div.gradio-container.blur-container {
476
+ filter: blur(12px);
477
+ pointer-events: none;
478
+ }
479
+
480
+ #image_seed:has(input[disabled].svelte-pc1gm4) {
481
+ position: relative;
482
+ }
483
+
484
+ #image_seed:has(input[disabled].svelte-pc1gm4)::after {
485
+ position: absolute;
486
+ content: "";
487
+ top: 50%;
488
+ left: 50%;
489
+ transform: translate(-50%, -50%);
490
+ width: 100%;
491
+ height: 100%;
492
+ border-radius: var(--block-radius);
493
+ background: var(--block-background-fill);
494
+ opacity: 0.5;
495
+ cursor: not-allowed;
496
+ z-index: var(--layer-5);
497
+ }
498
+
499
+ /* MARK: Toggle Button Checkbox */
500
+ /* INFO: gr.Checkbox elem_classes".toggle-btn" */
501
+
502
+ .toggle-btn {
503
+ display: flex;
504
+ flex-direction: column-reverse;
505
+
506
+ & > div.wrap {
507
+ display: none;
508
+ }
509
+
510
+ & > div:not(.wrap) {
511
+ margin-top: var(--spacing-lg);
512
+ margin-bottom: 0;
513
+ }
514
+
515
+ & > label {
516
+ position: relative;
517
+ width: 57px;
518
+ height: 27px;
519
+ display: inline-block;
520
+ border-radius: 13px;
521
+ background: var(--neutral-700);
522
+ box-shadow: var(--shadow-inset);
523
+ transition: background-color 0.3s, cursor 0.3s;
524
+ border: solid 0.4px var(--border-color-primary);
525
+ cursor: pointer;
526
+
527
+ & > input[type="checkbox"] {
528
+ width: 0;
529
+ height: 0;
530
+ opacity: 0;
531
+ }
532
+
533
+ & > span {
534
+ position: absolute;
535
+ left: 60px;
536
+ height: 27px;
537
+ min-width: 140px;
538
+ line-height: 27px;
539
+ }
540
+ }
541
+
542
+ & > label:has(input[type="checkbox"])::after {
543
+ content: "";
544
+ position: absolute;
545
+ top: 3px;
546
+ left: 3px;
547
+ width: 20px;
548
+ height: 20px;
549
+ border-radius: 50%;
550
+ background: var(--neutral-900);
551
+ box-shadow: var(--shadow-inset);
552
+ transition: left 0.2s ease-in-out, background 0.2s ease-in-out;
553
+ }
554
+
555
+ & > label:has(input[type="checkbox"]:checked)::after {
556
+ content: "";
557
+ position: absolute;
558
+ background: var(--neutral-900);
559
+ opacity: 0.8;
560
+ left: 32px;
561
+ }
562
+
563
+ & > label:has(input[type="checkbox"]:checked) {
564
+ background: var(--primary-600);
565
+ }
566
+ }
567
+
568
+ /* MARK: Range Input */
569
+ input[type="range"].svelte-pc1gm4 {
570
+ accent-color: var(--slider-color);
571
+ background: var(--neutral-700) !important;
572
+ background-image: linear-gradient(var(--slider-color), var(--slider-color)) !important;
573
+ background-size: 0% 100%;
574
+ }
575
+
576
+ input[type="range"].svelte-pc1gm4::-webkit-slider-thumb {
577
+ background-color: var(--primary-600);
578
+ border-width: 0;
579
+ }
580
+
581
+ input[type="range"].svelte-pc1gm4::-webkit-slider-thumb:hover {
582
+ background-color: var(--primary-500);
583
+ }
584
+
585
+ /* MARK: Text-Color Override */
586
+ label.svelte-1b6s6s,
587
+ label.svelte-9gxdi0,
588
+ span.svelte-1gfkn6j,
589
+ span.svelte-1gfkn6j,
590
+ .primary.svelte-cmf5ev,
591
+ label.selected.svelte-1k4wjf2,
592
+ label.selected.svelte-1mhtq7j,
593
+ label.svelte-1mhtq7j:hover,
594
+ div.tabs > div.tab-nav > button,
595
+ .md-header h1,
596
+ .md-header p,
597
+ .md-header span {
598
+ color: var(--text-color-by-luminance) !important;
599
+ }
600
+
601
+ /* MARK: Hide Progress */
602
+ .hide-progress:has(.wrap.default.full) {
603
+ pointer-events: none;
604
+ }
605
+
606
+ .hide-progress:has(.wrap.default.full.hide) {
607
+ pointer-events: initial;
608
+ }
609
+
610
+ .hide-progress .wrap.default.full:not(.hide) {
611
+ display: none;
612
+ }
613
+
614
+ #run_btn {
615
+ svg,
616
+ dotlottie-player {
617
+ height: 28.8px;
618
+ }
619
+ }
620
+
621
+ /* KOFI CSS */
622
+ img.kofiimg {
623
+ display: initial !important;
624
+ vertical-align: middle;
625
+ height: 13px !important;
626
+ width: 20px !important;
627
+ padding-top: 0 !important;
628
+ padding-bottom: 0 !important;
629
+ border: none;
630
+ margin-top: 0;
631
+ margin-right: 5px !important;
632
+ margin-left: 0 !important;
633
+ margin-bottom: 3px !important;
634
+ content: url("https://storage.ko-fi.com/cdn/cup-border.png");
635
+ }
636
+
637
+ .kofiimg:after {
638
+ vertical-align: middle;
639
+ height: 25px;
640
+ padding-top: 0;
641
+ padding-bottom: 0;
642
+ border: none;
643
+ margin-top: 0;
644
+ margin-right: 6px;
645
+ margin-left: 0;
646
+ margin-bottom: 4px !important;
647
+ content: url("https://storage.ko-fi.com/cdn/whitelogo.svg");
648
+ }
649
+
650
+ .btn-container {
651
+ display: inline-block !important;
652
+ white-space: nowrap;
653
+ min-width: 230px;
654
+ }
655
+
656
+ span.kofitext {
657
+ color: var(--text-color-by-luminance) !important;
658
+ letter-spacing: -0.15px !important;
659
+ text-wrap: none;
660
+ vertical-align: middle;
661
+ line-height: 33px !important;
662
+ padding: 0;
663
+ text-align: center;
664
+ text-decoration: none !important;
665
+ text-shadow: 0 1px 1px rgba(34, 34, 34, 0.05);
666
+ }
667
+
668
+ .kofitext a {
669
+ color: #fff !important;
670
+ text-decoration: none !important;
671
+ }
672
+
673
+ .kofitext a:hover {
674
+ color: #fff !important;
675
+ text-decoration: none;
676
+ }
677
+
678
+ a.kofi-button {
679
+ background: var(--primary-600) !important;
680
+ box-shadow: 0px -8px 16px -8px rgba(17, 17, 27, 0.7);
681
+ border: 4px solid var(--text-color-by-luminance) !important;
682
+
683
+ box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.2);
684
+ line-height: 36px !important;
685
+ min-width: 150px;
686
+ display: inline-block !important;
687
+ background-color: #29abe0;
688
+ padding: 2px 12px !important;
689
+ text-align: center !important;
690
+ border-radius: 7px;
691
+ color: #fff;
692
+ cursor: pointer;
693
+ overflow-wrap: break-word;
694
+ vertical-align: middle;
695
+
696
+ border: 4px solid var(--text-color-by-luminance) !important;
697
+ font-family: "Quicksand", Helvetica, Century Gothic, sans-serif !important;
698
+ text-decoration: none;
699
+ text-shadow: none;
700
+ font-weight: 700 !important;
701
+ font-size: 14px !important;
702
+ }
703
+
704
+ a.kofi-button:visited {
705
+ color: #fff !important;
706
+ text-decoration: none !important;
707
+ }
708
+
709
+ a.kofi-button:hover {
710
+ opacity: 0.85;
711
+ color: #f5f5f5 !important;
712
+ text-decoration: none !important;
713
+ }
714
+
715
+ a.kofi-button:active {
716
+ color: #f5f5f5 !important;
717
+ text-decoration: none !important;
718
+ }
719
+
720
+ .kofitext img.kofiimg {
721
+ height: 15px !important;
722
+ width: 22px !important;
723
+ display: initial;
724
+ animation: kofi-wiggle 3s infinite;
725
+ }
726
+
727
+ @keyframes kofi-wiggle {
728
+ 0% {
729
+ transform: rotate(0) scale(1);
730
+ }
731
+
732
+ 60% {
733
+ transform: rotate(0) scale(1);
734
+ }
735
+
736
+ 75% {
737
+ transform: rotate(0) scale(1.12);
738
+ }
739
+
740
+ 80% {
741
+ transform: rotate(0) scale(1.1);
742
+ }
743
+
744
+ 84% {
745
+ transform: rotate(-10deg) scale(1.1);
746
+ }
747
+
748
+ 88% {
749
+ transform: rotate(10deg) scale(1.1);
750
+ }
751
+
752
+ 92% {
753
+ transform: rotate(-10deg) scale(1.1);
754
+ }
755
+
756
+ 96% {
757
+ transform: rotate(10deg) scale(1.1);
758
+ }
759
+
760
+ 100% {
761
+ transform: rotate(0) scale(1);
762
+ }
763
+ }
764
+ /* KOFI CSS END */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
_res/_custom.js CHANGED
@@ -1,315 +1,315 @@
1
- function gradioCustomJS() {
2
- console.log("gradioCustomJS Started")
3
-
4
- // MARK: berechne Helligkeit der Akzentfarbe
5
- function berechneHelligkeit(rgb) {
6
- const match = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
7
- if (!match) {
8
- throw new Error("Ungültiges Farbformat")
9
- }
10
-
11
- const r = parseInt(match[1]) / 255
12
- const g = parseInt(match[2]) / 255
13
- const b = parseInt(match[3]) / 255
14
-
15
- const rLin = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4)
16
- const gLin = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4)
17
- const bLin = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4)
18
-
19
- const luminanz = 0.2126 * rLin + 0.7152 * gLin + 0.0722 * bLin
20
-
21
- return luminanz
22
- }
23
-
24
- // MARK: Textfarbe bestimmen
25
- function anpasseTextfarbe(farbe) {
26
- const luminanz = berechneHelligkeit(farbe)
27
- const textFarbe = luminanz > 0.4 ? "var(--neutral-950)" : "var(--neutral-50)"
28
- console.log("Luminanz: " + luminanz + " Text-Farbe: " + textFarbe)
29
-
30
- return textFarbe
31
- }
32
-
33
- const body = document.querySelector("body")
34
- body.className = "dark"
35
-
36
- // Catppuccin colors
37
- const rosewater = "245, 224, 220"
38
- const flamingo = "242, 205, 205"
39
- const pink = "245, 194, 231"
40
- const mauve = "203, 166, 247"
41
- const red = "243, 139, 168"
42
- const maroon = "235, 160, 172"
43
- const peach = "250, 179, 135"
44
- const yellow = "249, 226, 175"
45
- const green = "166, 227, 161"
46
- const teal = "148, 226, 213"
47
- const sky = "137, 220, 235"
48
- const sapphire = "116, 199, 236"
49
- const blue = "137, 180, 250"
50
-
51
- let colors = [rosewater, flamingo, pink, mauve, red, maroon, peach, yellow, green, teal, sky, sapphire, blue]
52
- let usedColor = `rgb(${colors[Math.floor(Math.random() * colors.length)]})`
53
-
54
- body.style.setProperty("--cat-rosewater", "rgb(" + rosewater + ")")
55
- body.style.setProperty("--cat-flamingo", "rgb(" + flamingo + ")")
56
- body.style.setProperty("--cat-pink", "rgb(" + pink + ")")
57
- body.style.setProperty("--cat-mauve", "rgb(" + mauve + ")")
58
- body.style.setProperty("--cat-red", "rgb(" + red + ")")
59
- body.style.setProperty("--cat-maroon", "rgb(" + maroon + ")")
60
- body.style.setProperty("--cat-peach", "rgb(" + peach + ")")
61
- body.style.setProperty("--cat-yellow", "rgb(" + yellow + ")")
62
- body.style.setProperty("--cat-green", "rgb(" + green + ")")
63
- body.style.setProperty("--cat-teal", "rgb(" + teal + ")")
64
- body.style.setProperty("--cat-sky", "rgb(" + sky + ")")
65
- body.style.setProperty("--cat-sapphire", "rgb(" + sapphire + ")")
66
- body.style.setProperty("--cat-blue", "rgb(" + blue + ")")
67
-
68
- body.style.setProperty("--primary-600", usedColor)
69
- body.style.setProperty("--primary-50", "color-mix(in srgb, var(--primary-600) 5%, white)")
70
- body.style.setProperty("--primary-100", "color-mix(in srgb, var(--primary-600) 10%, white)")
71
- body.style.setProperty("--primary-200", "color-mix(in srgb, var(--primary-600) 20%, white)")
72
- body.style.setProperty("--primary-300", "color-mix(in srgb, var(--primary-600) 60%, white)")
73
- body.style.setProperty("--primary-400", "color-mix(in srgb, var(--primary-600) 70%, white)")
74
- body.style.setProperty("--primary-500", "color-mix(in srgb, var(--primary-600) 80%, white)")
75
- body.style.setProperty("--primary-700", "color-mix(in srgb, var(--primary-600) 80%, black)")
76
- body.style.setProperty("--primary-800", "color-mix(in srgb, var(--primary-600) 65%, black)")
77
- body.style.setProperty("--primary-900", "color-mix(in srgb, var(--primary-600) 40%, black)")
78
- body.style.setProperty("--primary-950", "color-mix(in srgb, var(--primary-600) 30%, black)")
79
-
80
- body.style.setProperty("--button-primary-background-fill", "var(--primary-600)")
81
- body.style.setProperty("--button-primary-background-fill-hover", "var(--primary-500)")
82
- body.style.setProperty("--blur-value", "0px")
83
- body.style.setProperty("--text-color-by-luminance", anpasseTextfarbe(usedColor))
84
-
85
- // MARK: Selectors & Elements
86
- const gradioApp = document.querySelector("gradio-app")
87
- const gradioContainer = document.querySelector("body > gradio-app > div.gradio-container")
88
- const dominantColorField = document.querySelector("#dominant_image_color > label > textarea")
89
- const outputImageElem = document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img")
90
- const alertModalElem = document.createElement("div")
91
- const alertModalElemP = document.createElement("p")
92
- const alertModalElemI = document.createElement("i")
93
- alertModalElemI.className = "fas fa-exclamation-circle"
94
- const alertModalElemSpan = document.createElement("span")
95
- alertModalElemSpan.id = "alertModalText"
96
- const alertModalElemButton = document.createElement("button")
97
- alertModalElemButton.className = "lg primary run-btn svelte-cmf5ev"
98
- alertModalElemButton.id = "alertModalBtn"
99
- alertModalElemButton.textContent = "Ok"
100
- alertModalElemP.id = "alertModalP"
101
- alertModalElemP.append(alertModalElemI, alertModalElemSpan)
102
- alertModalElem.id = "alertModal"
103
- alertModalElem.style.display = "none"
104
- alertModalElem.append(alertModalElemP, alertModalElemButton)
105
- //alertModalElem.innerHTML = '<p></p>'
106
- gradioApp.appendChild(alertModalElem)
107
-
108
- alertModalElemButton.addEventListener("click", () => {
109
- oldText = alertModalElemSpan.textContent
110
- alertModalElemButton.disabled = true
111
- if (alertModalElemButton.textContent == "Noch mal?") {
112
- alertModalElemSpan.innerHTML = 'Na gut, noch mal. <br/>Der "Ok" ... ne, der "Noch mal?" Button ändert nur diesen Text. 😉 In 10 Sekunden wird wieder die ursprüngliche Meldung gezeigt. Cool oder?'
113
- setTimeout(() => {
114
- alertModalElemSpan.textContent = oldText
115
- alertModalElemButton.disabled = false
116
- alertModalElemButton.textContent = "Noch mal?"
117
- }, 10000)
118
- } else if (alertModalElemButton.textContent == "Ok") {
119
- alertModalElemSpan.innerHTML = 'Der "Ok" Button ändert nur diesen Text. 🫢<br/>In 6 Sekunden wird wieder die ursprüngliche Meldung gezeigt. Cool oder?'
120
- setTimeout(() => {
121
- alertModalElemSpan.textContent = oldText
122
- alertModalElemButton.disabled = false
123
- alertModalElemButton.textContent = "Noch mal?"
124
- }, 6000)
125
- }
126
- })
127
-
128
- const prompt_input = document.querySelector("#prompt_input")
129
- prompt_input.setAttribute("autocomplete", "off")
130
- prompt_input.setAttribute("autocorrect", "off")
131
- prompt_input.setAttribute("autocapitalize", "off")
132
- prompt_input.setAttribute("spellcheck", "false")
133
-
134
- const switch_width_height = document.querySelector("#switch_width_height")
135
- const random_prompt_btn = document.querySelector("#random_prompt_btn")
136
- const switch_ratio_btns = document.querySelectorAll("#image_ratio_buttons label")
137
-
138
- // MARK: DOM Change Detection
139
- function onDominantImageColorChange(callback) {
140
- const observer = new MutationObserver(callback)
141
- observer.observe(document.querySelector("#dominant_image_color"), {
142
- childList: true,
143
- subtree: true,
144
- })
145
- }
146
-
147
- function onImageRatioButtonsChange(callback) {
148
- const observer = new MutationObserver(callback)
149
- observer.observe(document.querySelector("#image_ratio_buttons"), {
150
- childList: true,
151
- subtree: true,
152
- })
153
- }
154
-
155
- function onDomElemChange(selector) {
156
- return new Promise((resolve) => {
157
- const element = document.querySelector(selector)
158
- if (!element) {
159
- console.error(`Element nicht gefunden: ${selector}`)
160
- return
161
- }
162
-
163
- const observer = new MutationObserver((mutations) => {
164
- mutations.forEach((mutation) => {
165
- if (mutation.type === "childList" || mutation.type === "attributes") {
166
- resolve(element)
167
- }
168
- })
169
- })
170
-
171
- observer.observe(element, {
172
- childList: true,
173
- subtree: true,
174
- attributes: true,
175
- })
176
-
177
- // Wiederholt aufgerufen werden
178
- function watch() {
179
- observer.disconnect()
180
- observer.observe(element, {
181
- childList: true,
182
- subtree: true,
183
- attributes: true,
184
- })
185
- setTimeout(watch, 100)
186
- }
187
- watch()
188
- })
189
- }
190
-
191
- onDominantImageColorChange(() => {
192
- console.log("changed: " + document.querySelector("#dominant_image_color > label > textarea").value)
193
- if (document.querySelector("#dominant_image_color > label > textarea").value.match(/^rgb\((\d{1,3}),(\s\d{1,3}),(\s\d{1,3})\)$/) && document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").src) {
194
- document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").style.opacity = "0"
195
- document.querySelector("body > gradio-app > div").classList.add("fade-bg")
196
- document.querySelector("gradio-app").style.opacity = "0"
197
- setTimeout(() => {
198
- usedColor = document.querySelector("#dominant_image_color > label > textarea").value
199
- body.style.setProperty("--primary-600", document.querySelector("#dominant_image_color > label > textarea").value)
200
- body.style.setProperty("--text-color-by-luminance", anpasseTextfarbe(document.querySelector("#dominant_image_color > label > textarea").value))
201
- gradioApp.classList.add("has-bg-image")
202
- body.style.setProperty("--bg-image-path", `url("${document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").src}")`)
203
- }, 400)
204
- setTimeout(() => {
205
- gradioApp.style.opacity = "1"
206
- document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").style.opacity = "1"
207
- document.querySelector("#dominant_image_color > label > textarea").value = ""
208
- }, 800)
209
- setTimeout(() => {
210
- //document.querySelector("body > gradio-app > div").classList.remove("fade-bg")
211
- }, 2000)
212
- }
213
- })
214
-
215
- // MARK: SVGs
216
- document.querySelector(".row-header i.winking-hand-emoji").innerHTML =
217
- '<svg aria-hidden="true" style="height: 16px;" preserveAspectRatio="xMidYMid meet" role="img" viewBox="0 0 128 128"><style> @keyframes wink{0%, 60%, 100%{transform: rotate(0deg);}10%, 30%, 70%, 90%{transform: rotate(14deg);}20%, 80%{transform: rotate(-8deg);}40%{transform: rotate(-4deg);}50%{transform: rotate(10deg);}}</style><g style="animation: wink 3s ease-in-out infinite; transform-origin: 50% 50%;"><radialGradient id="a" cx="-779.868" cy="686.689" r="91.008" gradientTransform="scale(1 -1) rotate(45 506.867 1318.897)" gradientUnits="userSpaceOnUse"><stop offset=".353" stop-color="#ffca28"/><stop offset=".872" stop-color="#ffb300"/></radialGradient><path fill="url(#a)" d="M59.53 107.44c-3.95-3.17-40.63-38.84-41.04-39.23-1.62-1.62-2.64-3.3-2.92-4.84-.29-1.6.2-3 1.5-4.3 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.59l16.63 15.98c.29.28.67.42 1.04.42a1.494 1.494 0 0 0 1.07-2.54L19.13 46.25c-2.66-2.66-3.91-6.73-.75-9.89 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.59l27.16 26.48c.29.28.67.43 1.05.43s.77-.15 1.06-.44c.58-.58.59-1.52.01-2.11L24.91 28.02c-1.51-1.51-2.42-3.32-2.58-5.08-.15-1.79.48-3.45 1.83-4.8 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.58L67.3 51.31c.29.28.67.43 1.05.43s.77-.15 1.06-.44c.58-.58.59-1.52.01-2.11L45.26 24.36c-1.52-1.52-2.43-3.32-2.58-5.08-.15-1.79.48-3.45 1.83-4.8 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.59 8.86 8.7 31.99 31.45 32.77 32.29 2.97 2.05 3.57-1.05 3.72-3.06.17-2.34-2.51-10.51-.95-17.86 2.62-9.77 10.17-8.17 10.34-8.09 4.14 1.94 3.35 4.84 1.88 10.67l-.15 1.15c-1.54 7.62 9.04 30.2 9.82 31.89 4.15 9.08 8.93 27.49-6.9 43.32-17.35 17.35-38.83 8.46-45.38 1.91z"/><path fill="#eda600" d="M81.79 117.18c-10.64 0-19.69-5.09-23.26-8.62-3.21-2.62-23.47-22.18-39.97-38.19-.67-.65-1.06-1.02-1.1-1.07-1.87-1.87-3.03-3.82-3.36-5.66-.38-2.09.27-3.98 1.91-5.63 1.5-1.5 3.34-2.29 5.34-2.29 2.35 0 4.71 1.08 6.65 3.03l16.61 15.96-26.56-27.42c-3.06-3.06-4.6-8.13-.73-11.99 1.5-1.5 3.34-2.29 5.34-2.29 2.35 0 4.71 1.08 6.65 3.03L56.45 62.5 23.84 29.07c-1.74-1.74-2.81-3.87-3-5.99-.19-2.26.59-4.33 2.26-6 1.5-1.5 3.34-2.29 5.34-2.29 2.34 0 4.7 1.07 6.65 3.02l33.26 32.43-24.16-24.83c-1.75-1.75-2.82-3.88-3-6-.19-2.25.59-4.32 2.26-5.99 1.5-1.5 3.34-2.29 5.34-2.29 2.35 0 4.71 1.08 6.65 3.03l7.21 7.07c12.85 12.6 23.59 23.15 24.74 24.33.56.45 1.29.62 1.6.47.2-.1.42-.56.38-1.53-.06-1.7-.3-3.81-.55-6.04-.5-4.48-1.02-9.12-.37-12.18 1.42-5.31 4.21-7.56 6.29-8.53 2.86-1.32 5.63-.86 6.16-.61 5.2 2.44 4.17 6.52 2.75 12.18l-.03.14-.16 1.17c-1.04 5.12 4.3 19.27 9.64 30.8l.08.16c3.57 7.8 10 27.81-7.2 45.01-7.91 7.89-16.47 10.58-24.19 10.58zM21.35 58.72c-1.18 0-2.3.49-3.22 1.41-.95.95-1.28 1.87-1.08 2.97.22 1.21 1.11 2.65 2.5 4.05.01.01.41.4 1.1 1.06 23.42 22.73 37.56 36.24 39.82 38.06l.12.11c5.52 5.52 26.03 15.32 43.26-1.91 15.87-15.87 9.9-34.4 6.59-41.64l-.07-.15c-3.44-7.42-11.26-25.42-9.87-32.6l.23-1.5c1.54-6.12 1.63-7.4-.98-8.66-.77-.14-6.29-.81-8.4 7.06-.53 2.51-.02 7.1.43 11.15.26 2.29.5 4.46.56 6.27.1 2.85-1.25 3.94-2.07 4.34-1.67.81-3.66.12-4.9-.92l-.13-.12c-.61-.66-15.12-14.89-24.72-24.31L53.3 16.3c-2.46-2.47-5.63-2.88-7.76-.75-1.04 1.04-1.51 2.26-1.4 3.61.12 1.41.88 2.88 2.15 4.15L70.5 48.14a3.012 3.012 0 0 1-.02 4.22c-1.11 1.11-3.07 1.13-4.21.03L32.98 19.94c-2.46-2.46-5.64-2.87-7.76-.74-1.04 1.04-1.51 2.26-1.4 3.61.13 1.41.89 2.89 2.15 4.14L58.6 60.41c1.15 1.16 1.14 3.06-.02 4.22-1.11 1.11-3.07 1.13-4.21.03L27.2 38.17c-2.46-2.48-5.64-2.88-7.76-.75-2.59 2.59-1.21 5.8.75 7.77l26.57 27.44a2.988 2.988 0 0 1-.03 4.2c-1.12 1.12-3.06 1.13-4.2.04L25.9 60.89c-1.4-1.41-3.01-2.17-4.55-2.17z"/><path fill="#eda600" d="M84.76 46.54c-5.49 11.21-4.78 26.9 3.46 39.49.93 1.7 2.52.87 1.71-.88-9.95-21.29.48-36.63.48-36.63l-5.65-1.98z"/><path fill="#b0bec5" d="M63.17 4.5c3.02-.79 6.24-.72 9.37.01 3.11.75 6.22 2.33 8.53 4.91 2.26 2.56 3.65 5.67 4.12 8.93.44 3.23.03 6.56-1.5 9.32-.18-3.1-.72-5.95-1.63-8.58-.47-1.31-1.02-2.56-1.69-3.74-.66-1.17-1.44-2.33-2.27-3.28-1.69-1.95-3.98-3.47-6.55-4.65-2.58-1.22-5.39-2.12-8.38-2.92z"/><path fill="#90a4ae" d="M64 13.98c1.67-1.06 3.76-1.28 5.73-.93 1.99.35 3.89 1.34 5.39 2.71 1.49 1.39 2.55 3.14 3.21 4.96.32.91.48 1.87.63 2.8.05.96.05 1.92-.1 2.88-.69-.73-1.23-1.46-1.74-2.17-.59-.67-1.05-1.38-1.58-2.03-1.04-1.29-2.05-2.46-3.14-3.5-1.12-1.01-2.3-1.9-3.67-2.67-1.36-.79-2.89-1.45-4.73-2.05z"/><path fill="#b0bec5" d="M6.83 77.34c1.41 2.76 2.88 5.32 4.59 7.58 1.7 2.26 3.65 4.18 5.92 5.43 1.1.61 2.41 1.14 3.69 1.54 1.29.41 2.63.69 4.01.88 2.76.34 5.66.28 8.73-.19-2.38 2.07-5.56 3.17-8.8 3.41-3.28.22-6.61-.49-9.59-2.17-3-1.71-5.2-4.43-6.58-7.32-1.38-2.91-2.12-6.04-1.97-9.16z"/><path fill="#90a4ae" d="M16.28 76.17c.97 1.68 1.93 3.03 2.98 4.21 1.04 1.18 2.16 2.15 3.38 3.03 1.24.85 2.6 1.6 4.08 2.35.74.38 1.53.68 2.31 1.12.81.35 1.63.72 2.49 1.25-.91.34-1.84.54-2.79.69-.94.04-1.91.09-2.87-.04-1.92-.26-3.84-.93-5.52-2.1-1.65-1.19-3.02-2.84-3.77-4.71-.76-1.86-.98-3.94-.29-5.8z"/></g></svg>'
218
- document.querySelector(".row-header i.heart-beat-emoji").innerHTML =
219
- '<svg xmlns="http://www.w3.org/2000/svg" style="height: 16px;" viewBox="0 0 512 512"><defs><style> @keyframes beat{0%{transform: scale(1);}5%{transform: scale(0.75);}20%{transform: scale(1);}30%{transform: scale(1);}35%{transform: scale(0.75);}50%{transform: scale(1);}55%{transform: scale(0.75);}70%{transform: scale(1);}}</style></defs><g style="animation: beat 2s ease-in-out infinite; transform-origin: 50% 50%;"><path fill="#bd0a0a" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></g></svg>'
220
- random_prompt_btn.innerHTML =
221
- '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><g data-name="Ebene_1"><path fill="none" d="M0 48V0h48v48z"/><path d="M42.15 9.85C41.58 9.28 40.9 9 40.12 9H7.88c-.78 0-1.46.28-2.03.85S5 11.1 5 11.88v24.23c0 .78.28 1.46.85 2.03s1.25.85 2.03.85h32.23c.78 0 1.46-.28 2.03-.85s.85-1.25.85-2.03V11.88c0-.78-.28-1.46-.85-2.03ZM13.66 30.78c-.68 0-1.24-.55-1.24-1.24s.55-1.24 1.24-1.24 1.24.55 1.24 1.24-.55 1.24-1.24 1.24Zm2.8-7.78-1.3 1.8c-.32.45-.41.76-.48 1.23-.04.26-.13.48-.28.64-.17.19-.42.29-.73.29s-.56-.12-.73-.31c-.16-.18-.25-.42-.25-.73 0-.68.12-1.09.65-1.8l1.48-2c.33-.45.58-.87.58-1.47 0-1.04-.75-1.83-1.83-1.83-.52 0-.99.15-1.36.52-.29.29-.43.65-.55 1.12-.06.22-.16.47-.27.58-.15.17-.39.29-.7.29-.26 0-.49-.1-.66-.29-.18-.2-.23-.42-.23-.71 0-.67.35-1.58 1.03-2.22.68-.65 1.62-1.03 2.73-1.03 2.11 0 3.79 1.4 3.79 3.57 0 1-.35 1.62-.89 2.36Zm7.28 7.78c-.68 0-1.24-.55-1.24-1.24s.55-1.24 1.24-1.24 1.24.55 1.24 1.24-.55 1.24-1.24 1.24Zm2.8-7.78-1.3 1.8c-.32.45-.41.76-.48 1.23-.04.26-.13.48-.28.64-.17.19-.42.29-.73.29s-.56-.12-.73-.31c-.16-.18-.25-.42-.25-.73 0-.68.12-1.09.65-1.8l1.48-2c.33-.45.58-.87.58-1.47 0-1.04-.75-1.83-1.83-1.83-.52 0-.99.15-1.36.52-.29.29-.43.65-.55 1.12-.06.22-.16.47-.27.58-.15.17-.39.29-.7.29-.26 0-.49-.1-.66-.29-.18-.2-.23-.42-.23-.71 0-.67.35-1.58 1.03-2.22.68-.65 1.62-1.03 2.73-1.03 2.11 0 3.79 1.4 3.79 3.57 0 1-.35 1.62-.89 2.36Zm7.28 7.78c-.68 0-1.24-.55-1.24-1.24s.55-1.24 1.24-1.24 1.24.55 1.24 1.24-.55 1.24-1.24 1.24Zm2.8-7.78-1.3 1.8c-.32.45-.41.76-.48 1.23-.04.26-.13.48-.28.64-.17.19-.42.29-.73.29s-.56-.12-.73-.31c-.16-.18-.25-.42-.25-.73 0-.68.12-1.09.65-1.8l1.48-2c.33-.45.58-.87.58-1.47 0-1.04-.75-1.83-1.83-1.83-.52 0-.99.15-1.36.52-.29.29-.43.65-.55 1.12-.06.22-.16.47-.27.58-.15.17-.39.29-.7.29-.26 0-.49-.1-.66-.29-.18-.2-.23-.42-.23-.71 0-.67.35-1.58 1.03-2.22.68-.65 1.62-1.03 2.73-1.03 2.11 0 3.79 1.4 3.79 3.57 0 1-.35 1.62-.89 2.36Z"/></g></svg>'
222
- const enhance_prompt_btn = document.querySelector("#enhance_prompt_btn")
223
- enhance_prompt_btn.innerHTML =
224
- '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><g data-name="Ebene_1"><path fill="none" d="M0 48V0h48v48z"/><path d="m33.91 29.59 9.37-8.07h.38c.4.05.72.21.95.49.23.28.35.59.35.91 0 .18-.05.37-.14.55-.09.18-.22.35-.37.5l-7.55 6.48 2.31 10s.04.1.04.17v.14c0 .41-.14.73-.42.98-.28.24-.6.37-.97.37-.12 0-.24-.01-.37-.04s-.25-.07-.37-.13l-.4-.27-2.8-12.09Zm-4.95-15.31-3-7.1.16-.33c.1-.27.26-.47.5-.63.24-.15.49-.23.75-.23.24 0 .49.07.74.22s.43.36.55.65l3.25 7.67-2.95-.26ZM12.1 37.29l8.69-5.23 8.69 5.29-2.3-9.9 7.65-6.64-10.09-.89-3.95-9.31-3.95 9.25-10.09.89 7.65 6.66-2.3 9.88Zm-3.09 1.65 2.44-10.56-8.16-7.13c-.2-.18-.35-.38-.46-.59-.11-.22-.16-.42-.16-.63 0-.41.14-.79.43-1.14.29-.34.67-.53 1.14-.55l10.8-.96 4.18-9.96c.13-.34.34-.59.64-.76.3-.17.6-.25.91-.25s.62.08.93.25c.31.17.53.42.66.76l4.18 9.96 10.8.96c.48.02.86.21 1.15.55.29.34.44.72.44 1.13 0 .22-.06.44-.18.65-.12.21-.27.4-.47.58l-8.16 7.13 2.47 10.56c.03.09.05.21.05.36 0 .48-.17.89-.51 1.22-.34.33-.73.49-1.16.49-.09 0-.4-.09-.93-.27l-9.26-5.59-9.26 5.59c-.14.08-.29.14-.46.19-.16.05-.31.08-.44.08-.5 0-.94-.21-1.31-.62-.37-.41-.48-.9-.32-1.45Z"/></g></svg>'
225
- document.querySelector("#run_btn").innerHTML =
226
- //'<dotlottie-player src="https://lottie.host/07f9842b-03a8-46dc-a45f-684d4cf57429/2amWXB96uz.lottie" background="transparent" speed="1" loop></dotlottie-player>'
227
- '<dotlottie-player src="https://lottie.host/e3515e09-f615-49f0-a63d-a421b45ceb45/XEuKdFRH19.lottie" background="transparent" speed="1" loop></dotlottie-player>'
228
-
229
-
230
- const switch_width_height_inner = document.createElement("div")
231
- //const switch_width_height_inner_image = document.createElement("div")
232
- //switch_width_height_inner_image.id = "switch_width_height_inner_image"
233
- switch_width_height_inner.id = "switch_width_height_inner"
234
- switch_width_height_inner.setAttribute("data-aspect-ratio", "9-16")
235
- switch_width_height_inner.className = "hochformat"
236
- switch_width_height_inner.innerHTML = `<div></div>`
237
- //switch_width_height_inner.append(switch_width_height_inner_image)
238
- switch_width_height.append(switch_width_height_inner)
239
- const switch_width_height_btn_inner = document.querySelector("div#switch_width_height_inner")
240
-
241
- switch_width_height.addEventListener("click", () => {
242
- //switch_width_height_btn_inner.className = document.querySelector("#image_ratio_buttons > span").textContent.toLocaleLowerCase()
243
- })
244
-
245
- switch_ratio_btns.forEach((_) => {
246
- _.querySelector("input").addEventListener("click", (e) => {
247
- switch_width_height_btn_inner.setAttribute("data-aspect-ratio", e.target.value.replace(":", "-").trim())
248
- })
249
- })
250
-
251
- onImageRatioButtonsChange(() => {
252
- switch_width_height_btn_inner.className = document.querySelector("#image_ratio_buttons > span").textContent.toLocaleLowerCase()
253
- const selected_ratio = document.querySelector("#image_ratio_buttons label.selected input").value.replace(":", "-").trim()
254
- if (switch_width_height_btn_inner.getAttribute("data-aspect-ratio") != selected_ratio) {
255
- switch_width_height_btn_inner.setAttribute("data-aspect-ratio", selected_ratio)
256
- }
257
- })
258
-
259
- // MARK: Element-Ready function
260
- function elementReady(selector) {
261
- return new Promise((resolve, reject) => {
262
- const el = document.querySelector(selector)
263
- if (el) {
264
- resolve(el)
265
- }
266
-
267
- new MutationObserver((mutationRecords, observer) => {
268
- Array.from(document.querySelectorAll(selector)).forEach((element) => {
269
- resolve(element)
270
- observer.disconnect()
271
- })
272
- }).observe(document.documentElement, {
273
- childList: true,
274
- subtree: true,
275
- })
276
- })
277
- }
278
-
279
- // MARK: Mobile Check
280
- function istMobile() {
281
- // Überprüfen, ob das Gerät ein Touchscreen hat
282
- if ("ontouchstart" in window || (navigator.maxTouchPoints && window.innerWidth < 768)) {
283
- gradioContainer.classList.add("blur-container")
284
- body.style.setProperty("--blur-value", "12px")
285
- gradioApp.style.height = "calc(100vh - 120px)"
286
- alertModalElem.style.display = ""
287
- alertModalElemSpan.textContent = "Diese Seite ist nicht für mobile Geräte optimiert. Bitte besuche diese Seite von einem Desktop-Computer aus."
288
- } else if (window.innerWidth < 1024) {
289
- gradioContainer.classList.add("blur-container")
290
- body.style.setProperty("--blur-value", "12px")
291
- gradioApp.style.height = "calc(100vh - 120px)"
292
- alertModalElem.style.display = ""
293
- alertModalElemSpan.textContent = "Bildschirm Auflösung oder Fensterbreite zu gering. Bitte besuche diese Seite von einem Desktop-Computer aus."
294
- } else {
295
- gradioContainer.classList.remove("blur-container")
296
- body.style.setProperty("--blur-value", "0px")
297
- gradioApp.style.height = ""
298
- alertModalElem.style.display = "none"
299
- alertModalElemSpan.textContent = ""
300
- }
301
- }
302
-
303
- // MARK: Event Listeners
304
- window.addEventListener("resize", () => {
305
- console.log("Event Window resize.")
306
- istMobile()
307
- })
308
-
309
- elementReady("body > gradio-app > div.gradio-container").then((element) => {
310
- console.log("Element exist: " + element)
311
- istMobile()
312
- })
313
-
314
- return "Custom Gradio JS"
315
- }
 
1
+ function gradioCustomJS() {
2
+ console.log("gradioCustomJS Started")
3
+
4
+ // MARK: berechne Helligkeit der Akzentfarbe
5
+ function berechneHelligkeit(rgb) {
6
+ const match = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
7
+ if (!match) {
8
+ throw new Error("Ungültiges Farbformat")
9
+ }
10
+
11
+ const r = parseInt(match[1]) / 255
12
+ const g = parseInt(match[2]) / 255
13
+ const b = parseInt(match[3]) / 255
14
+
15
+ const rLin = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4)
16
+ const gLin = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4)
17
+ const bLin = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4)
18
+
19
+ const luminanz = 0.2126 * rLin + 0.7152 * gLin + 0.0722 * bLin
20
+
21
+ return luminanz
22
+ }
23
+
24
+ // MARK: Textfarbe bestimmen
25
+ function anpasseTextfarbe(farbe) {
26
+ const luminanz = berechneHelligkeit(farbe)
27
+ const textFarbe = luminanz > 0.4 ? "var(--neutral-950)" : "var(--neutral-50)"
28
+ console.log("Luminanz: " + luminanz + " Text-Farbe: " + textFarbe)
29
+
30
+ return textFarbe
31
+ }
32
+
33
+ const body = document.querySelector("body")
34
+ body.className = "dark"
35
+
36
+ // Catppuccin colors
37
+ const rosewater = "245, 224, 220"
38
+ const flamingo = "242, 205, 205"
39
+ const pink = "245, 194, 231"
40
+ const mauve = "203, 166, 247"
41
+ const red = "243, 139, 168"
42
+ const maroon = "235, 160, 172"
43
+ const peach = "250, 179, 135"
44
+ const yellow = "249, 226, 175"
45
+ const green = "166, 227, 161"
46
+ const teal = "148, 226, 213"
47
+ const sky = "137, 220, 235"
48
+ const sapphire = "116, 199, 236"
49
+ const blue = "137, 180, 250"
50
+
51
+ let colors = [rosewater, flamingo, pink, mauve, red, maroon, peach, yellow, green, teal, sky, sapphire, blue]
52
+ let usedColor = `rgb(${colors[Math.floor(Math.random() * colors.length)]})`
53
+
54
+ body.style.setProperty("--cat-rosewater", "rgb(" + rosewater + ")")
55
+ body.style.setProperty("--cat-flamingo", "rgb(" + flamingo + ")")
56
+ body.style.setProperty("--cat-pink", "rgb(" + pink + ")")
57
+ body.style.setProperty("--cat-mauve", "rgb(" + mauve + ")")
58
+ body.style.setProperty("--cat-red", "rgb(" + red + ")")
59
+ body.style.setProperty("--cat-maroon", "rgb(" + maroon + ")")
60
+ body.style.setProperty("--cat-peach", "rgb(" + peach + ")")
61
+ body.style.setProperty("--cat-yellow", "rgb(" + yellow + ")")
62
+ body.style.setProperty("--cat-green", "rgb(" + green + ")")
63
+ body.style.setProperty("--cat-teal", "rgb(" + teal + ")")
64
+ body.style.setProperty("--cat-sky", "rgb(" + sky + ")")
65
+ body.style.setProperty("--cat-sapphire", "rgb(" + sapphire + ")")
66
+ body.style.setProperty("--cat-blue", "rgb(" + blue + ")")
67
+
68
+ body.style.setProperty("--primary-600", usedColor)
69
+ body.style.setProperty("--primary-50", "color-mix(in srgb, var(--primary-600) 5%, white)")
70
+ body.style.setProperty("--primary-100", "color-mix(in srgb, var(--primary-600) 10%, white)")
71
+ body.style.setProperty("--primary-200", "color-mix(in srgb, var(--primary-600) 20%, white)")
72
+ body.style.setProperty("--primary-300", "color-mix(in srgb, var(--primary-600) 60%, white)")
73
+ body.style.setProperty("--primary-400", "color-mix(in srgb, var(--primary-600) 70%, white)")
74
+ body.style.setProperty("--primary-500", "color-mix(in srgb, var(--primary-600) 80%, white)")
75
+ body.style.setProperty("--primary-700", "color-mix(in srgb, var(--primary-600) 80%, black)")
76
+ body.style.setProperty("--primary-800", "color-mix(in srgb, var(--primary-600) 65%, black)")
77
+ body.style.setProperty("--primary-900", "color-mix(in srgb, var(--primary-600) 40%, black)")
78
+ body.style.setProperty("--primary-950", "color-mix(in srgb, var(--primary-600) 30%, black)")
79
+
80
+ body.style.setProperty("--button-primary-background-fill", "var(--primary-600)")
81
+ body.style.setProperty("--button-primary-background-fill-hover", "var(--primary-500)")
82
+ body.style.setProperty("--blur-value", "0px")
83
+ body.style.setProperty("--text-color-by-luminance", anpasseTextfarbe(usedColor))
84
+
85
+ // MARK: Selectors & Elements
86
+ const gradioApp = document.querySelector("gradio-app")
87
+ const gradioContainer = document.querySelector("body > gradio-app > div.gradio-container")
88
+ const dominantColorField = document.querySelector("#dominant_image_color > label > textarea")
89
+ const outputImageElem = document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img")
90
+ const alertModalElem = document.createElement("div")
91
+ const alertModalElemP = document.createElement("p")
92
+ const alertModalElemI = document.createElement("i")
93
+ alertModalElemI.className = "fas fa-exclamation-circle"
94
+ const alertModalElemSpan = document.createElement("span")
95
+ alertModalElemSpan.id = "alertModalText"
96
+ const alertModalElemButton = document.createElement("button")
97
+ alertModalElemButton.className = "lg primary run-btn svelte-cmf5ev"
98
+ alertModalElemButton.id = "alertModalBtn"
99
+ alertModalElemButton.textContent = "Ok"
100
+ alertModalElemP.id = "alertModalP"
101
+ alertModalElemP.append(alertModalElemI, alertModalElemSpan)
102
+ alertModalElem.id = "alertModal"
103
+ alertModalElem.style.display = "none"
104
+ alertModalElem.append(alertModalElemP, alertModalElemButton)
105
+ //alertModalElem.innerHTML = '<p></p>'
106
+ gradioApp.appendChild(alertModalElem)
107
+
108
+ alertModalElemButton.addEventListener("click", () => {
109
+ oldText = alertModalElemSpan.textContent
110
+ alertModalElemButton.disabled = true
111
+ if (alertModalElemButton.textContent == "Noch mal?") {
112
+ alertModalElemSpan.innerHTML = 'Na gut, noch mal. <br/>Der "Ok" ... ne, der "Noch mal?" Button ändert nur diesen Text. 😉 In 10 Sekunden wird wieder die ursprüngliche Meldung gezeigt. Cool oder?'
113
+ setTimeout(() => {
114
+ alertModalElemSpan.textContent = oldText
115
+ alertModalElemButton.disabled = false
116
+ alertModalElemButton.textContent = "Noch mal?"
117
+ }, 10000)
118
+ } else if (alertModalElemButton.textContent == "Ok") {
119
+ alertModalElemSpan.innerHTML = 'Der "Ok" Button ändert nur diesen Text. 🫢<br/>In 6 Sekunden wird wieder die ursprüngliche Meldung gezeigt. Cool oder?'
120
+ setTimeout(() => {
121
+ alertModalElemSpan.textContent = oldText
122
+ alertModalElemButton.disabled = false
123
+ alertModalElemButton.textContent = "Noch mal?"
124
+ }, 6000)
125
+ }
126
+ })
127
+
128
+ const prompt_input = document.querySelector("#prompt_input")
129
+ prompt_input.setAttribute("autocomplete", "off")
130
+ prompt_input.setAttribute("autocorrect", "off")
131
+ prompt_input.setAttribute("autocapitalize", "off")
132
+ prompt_input.setAttribute("spellcheck", "false")
133
+
134
+ const switch_width_height = document.querySelector("#switch_width_height")
135
+ const random_prompt_btn = document.querySelector("#random_prompt_btn")
136
+ const switch_ratio_btns = document.querySelectorAll("#image_ratio_buttons label")
137
+
138
+ // MARK: DOM Change Detection
139
+ function onDominantImageColorChange(callback) {
140
+ const observer = new MutationObserver(callback)
141
+ observer.observe(document.querySelector("#dominant_image_color"), {
142
+ childList: true,
143
+ subtree: true,
144
+ })
145
+ }
146
+
147
+ function onImageRatioButtonsChange(callback) {
148
+ const observer = new MutationObserver(callback)
149
+ observer.observe(document.querySelector("#image_ratio_buttons"), {
150
+ childList: true,
151
+ subtree: true,
152
+ })
153
+ }
154
+
155
+ function onDomElemChange(selector) {
156
+ return new Promise((resolve) => {
157
+ const element = document.querySelector(selector)
158
+ if (!element) {
159
+ console.error(`Element nicht gefunden: ${selector}`)
160
+ return
161
+ }
162
+
163
+ const observer = new MutationObserver((mutations) => {
164
+ mutations.forEach((mutation) => {
165
+ if (mutation.type === "childList" || mutation.type === "attributes") {
166
+ resolve(element)
167
+ }
168
+ })
169
+ })
170
+
171
+ observer.observe(element, {
172
+ childList: true,
173
+ subtree: true,
174
+ attributes: true,
175
+ })
176
+
177
+ // Wiederholt aufgerufen werden
178
+ function watch() {
179
+ observer.disconnect()
180
+ observer.observe(element, {
181
+ childList: true,
182
+ subtree: true,
183
+ attributes: true,
184
+ })
185
+ setTimeout(watch, 100)
186
+ }
187
+ watch()
188
+ })
189
+ }
190
+
191
+ onDominantImageColorChange(() => {
192
+ console.log("changed: " + document.querySelector("#dominant_image_color > label > textarea").value)
193
+ if (document.querySelector("#dominant_image_color > label > textarea").value.match(/^rgb\((\d{1,3}),(\s\d{1,3}),(\s\d{1,3})\)$/) && document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").src) {
194
+ document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").style.opacity = "0"
195
+ document.querySelector("body > gradio-app > div").classList.add("fade-bg")
196
+ document.querySelector("gradio-app").style.opacity = "0"
197
+ setTimeout(() => {
198
+ usedColor = document.querySelector("#dominant_image_color > label > textarea").value
199
+ body.style.setProperty("--primary-600", document.querySelector("#dominant_image_color > label > textarea").value)
200
+ body.style.setProperty("--text-color-by-luminance", anpasseTextfarbe(document.querySelector("#dominant_image_color > label > textarea").value))
201
+ gradioApp.classList.add("has-bg-image")
202
+ body.style.setProperty("--bg-image-path", `url("${document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").src}")`)
203
+ }, 400)
204
+ setTimeout(() => {
205
+ gradioApp.style.opacity = "1"
206
+ document.querySelector("#output_image > div.image-container.svelte-1p15vfy > button > div > img").style.opacity = "1"
207
+ document.querySelector("#dominant_image_color > label > textarea").value = ""
208
+ }, 800)
209
+ setTimeout(() => {
210
+ //document.querySelector("body > gradio-app > div").classList.remove("fade-bg")
211
+ }, 2000)
212
+ }
213
+ })
214
+
215
+ // MARK: SVGs
216
+ document.querySelector(".row-header i.winking-hand-emoji").innerHTML =
217
+ '<svg aria-hidden="true" style="height: 16px;" preserveAspectRatio="xMidYMid meet" role="img" viewBox="0 0 128 128"><style> @keyframes wink{0%, 60%, 100%{transform: rotate(0deg);}10%, 30%, 70%, 90%{transform: rotate(14deg);}20%, 80%{transform: rotate(-8deg);}40%{transform: rotate(-4deg);}50%{transform: rotate(10deg);}}</style><g style="animation: wink 3s ease-in-out infinite; transform-origin: 50% 50%;"><radialGradient id="a" cx="-779.868" cy="686.689" r="91.008" gradientTransform="scale(1 -1) rotate(45 506.867 1318.897)" gradientUnits="userSpaceOnUse"><stop offset=".353" stop-color="#ffca28"/><stop offset=".872" stop-color="#ffb300"/></radialGradient><path fill="url(#a)" d="M59.53 107.44c-3.95-3.17-40.63-38.84-41.04-39.23-1.62-1.62-2.64-3.3-2.92-4.84-.29-1.6.2-3 1.5-4.3 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.59l16.63 15.98c.29.28.67.42 1.04.42a1.494 1.494 0 0 0 1.07-2.54L19.13 46.25c-2.66-2.66-3.91-6.73-.75-9.89 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.59l27.16 26.48c.29.28.67.43 1.05.43s.77-.15 1.06-.44c.58-.58.59-1.52.01-2.11L24.91 28.02c-1.51-1.51-2.42-3.32-2.58-5.08-.15-1.79.48-3.45 1.83-4.8 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.58L67.3 51.31c.29.28.67.43 1.05.43s.77-.15 1.06-.44c.58-.58.59-1.52.01-2.11L45.26 24.36c-1.52-1.52-2.43-3.32-2.58-5.08-.15-1.79.48-3.45 1.83-4.8 1.21-1.21 2.69-1.85 4.28-1.85 1.94 0 3.93.92 5.59 2.59 8.86 8.7 31.99 31.45 32.77 32.29 2.97 2.05 3.57-1.05 3.72-3.06.17-2.34-2.51-10.51-.95-17.86 2.62-9.77 10.17-8.17 10.34-8.09 4.14 1.94 3.35 4.84 1.88 10.67l-.15 1.15c-1.54 7.62 9.04 30.2 9.82 31.89 4.15 9.08 8.93 27.49-6.9 43.32-17.35 17.35-38.83 8.46-45.38 1.91z"/><path fill="#eda600" d="M81.79 117.18c-10.64 0-19.69-5.09-23.26-8.62-3.21-2.62-23.47-22.18-39.97-38.19-.67-.65-1.06-1.02-1.1-1.07-1.87-1.87-3.03-3.82-3.36-5.66-.38-2.09.27-3.98 1.91-5.63 1.5-1.5 3.34-2.29 5.34-2.29 2.35 0 4.71 1.08 6.65 3.03l16.61 15.96-26.56-27.42c-3.06-3.06-4.6-8.13-.73-11.99 1.5-1.5 3.34-2.29 5.34-2.29 2.35 0 4.71 1.08 6.65 3.03L56.45 62.5 23.84 29.07c-1.74-1.74-2.81-3.87-3-5.99-.19-2.26.59-4.33 2.26-6 1.5-1.5 3.34-2.29 5.34-2.29 2.34 0 4.7 1.07 6.65 3.02l33.26 32.43-24.16-24.83c-1.75-1.75-2.82-3.88-3-6-.19-2.25.59-4.32 2.26-5.99 1.5-1.5 3.34-2.29 5.34-2.29 2.35 0 4.71 1.08 6.65 3.03l7.21 7.07c12.85 12.6 23.59 23.15 24.74 24.33.56.45 1.29.62 1.6.47.2-.1.42-.56.38-1.53-.06-1.7-.3-3.81-.55-6.04-.5-4.48-1.02-9.12-.37-12.18 1.42-5.31 4.21-7.56 6.29-8.53 2.86-1.32 5.63-.86 6.16-.61 5.2 2.44 4.17 6.52 2.75 12.18l-.03.14-.16 1.17c-1.04 5.12 4.3 19.27 9.64 30.8l.08.16c3.57 7.8 10 27.81-7.2 45.01-7.91 7.89-16.47 10.58-24.19 10.58zM21.35 58.72c-1.18 0-2.3.49-3.22 1.41-.95.95-1.28 1.87-1.08 2.97.22 1.21 1.11 2.65 2.5 4.05.01.01.41.4 1.1 1.06 23.42 22.73 37.56 36.24 39.82 38.06l.12.11c5.52 5.52 26.03 15.32 43.26-1.91 15.87-15.87 9.9-34.4 6.59-41.64l-.07-.15c-3.44-7.42-11.26-25.42-9.87-32.6l.23-1.5c1.54-6.12 1.63-7.4-.98-8.66-.77-.14-6.29-.81-8.4 7.06-.53 2.51-.02 7.1.43 11.15.26 2.29.5 4.46.56 6.27.1 2.85-1.25 3.94-2.07 4.34-1.67.81-3.66.12-4.9-.92l-.13-.12c-.61-.66-15.12-14.89-24.72-24.31L53.3 16.3c-2.46-2.47-5.63-2.88-7.76-.75-1.04 1.04-1.51 2.26-1.4 3.61.12 1.41.88 2.88 2.15 4.15L70.5 48.14a3.012 3.012 0 0 1-.02 4.22c-1.11 1.11-3.07 1.13-4.21.03L32.98 19.94c-2.46-2.46-5.64-2.87-7.76-.74-1.04 1.04-1.51 2.26-1.4 3.61.13 1.41.89 2.89 2.15 4.14L58.6 60.41c1.15 1.16 1.14 3.06-.02 4.22-1.11 1.11-3.07 1.13-4.21.03L27.2 38.17c-2.46-2.48-5.64-2.88-7.76-.75-2.59 2.59-1.21 5.8.75 7.77l26.57 27.44a2.988 2.988 0 0 1-.03 4.2c-1.12 1.12-3.06 1.13-4.2.04L25.9 60.89c-1.4-1.41-3.01-2.17-4.55-2.17z"/><path fill="#eda600" d="M84.76 46.54c-5.49 11.21-4.78 26.9 3.46 39.49.93 1.7 2.52.87 1.71-.88-9.95-21.29.48-36.63.48-36.63l-5.65-1.98z"/><path fill="#b0bec5" d="M63.17 4.5c3.02-.79 6.24-.72 9.37.01 3.11.75 6.22 2.33 8.53 4.91 2.26 2.56 3.65 5.67 4.12 8.93.44 3.23.03 6.56-1.5 9.32-.18-3.1-.72-5.95-1.63-8.58-.47-1.31-1.02-2.56-1.69-3.74-.66-1.17-1.44-2.33-2.27-3.28-1.69-1.95-3.98-3.47-6.55-4.65-2.58-1.22-5.39-2.12-8.38-2.92z"/><path fill="#90a4ae" d="M64 13.98c1.67-1.06 3.76-1.28 5.73-.93 1.99.35 3.89 1.34 5.39 2.71 1.49 1.39 2.55 3.14 3.21 4.96.32.91.48 1.87.63 2.8.05.96.05 1.92-.1 2.88-.69-.73-1.23-1.46-1.74-2.17-.59-.67-1.05-1.38-1.58-2.03-1.04-1.29-2.05-2.46-3.14-3.5-1.12-1.01-2.3-1.9-3.67-2.67-1.36-.79-2.89-1.45-4.73-2.05z"/><path fill="#b0bec5" d="M6.83 77.34c1.41 2.76 2.88 5.32 4.59 7.58 1.7 2.26 3.65 4.18 5.92 5.43 1.1.61 2.41 1.14 3.69 1.54 1.29.41 2.63.69 4.01.88 2.76.34 5.66.28 8.73-.19-2.38 2.07-5.56 3.17-8.8 3.41-3.28.22-6.61-.49-9.59-2.17-3-1.71-5.2-4.43-6.58-7.32-1.38-2.91-2.12-6.04-1.97-9.16z"/><path fill="#90a4ae" d="M16.28 76.17c.97 1.68 1.93 3.03 2.98 4.21 1.04 1.18 2.16 2.15 3.38 3.03 1.24.85 2.6 1.6 4.08 2.35.74.38 1.53.68 2.31 1.12.81.35 1.63.72 2.49 1.25-.91.34-1.84.54-2.79.69-.94.04-1.91.09-2.87-.04-1.92-.26-3.84-.93-5.52-2.1-1.65-1.19-3.02-2.84-3.77-4.71-.76-1.86-.98-3.94-.29-5.8z"/></g></svg>'
218
+ document.querySelector(".row-header i.heart-beat-emoji").innerHTML =
219
+ '<svg xmlns="http://www.w3.org/2000/svg" style="height: 16px;" viewBox="0 0 512 512"><defs><style> @keyframes beat{0%{transform: scale(1);}5%{transform: scale(0.75);}20%{transform: scale(1);}30%{transform: scale(1);}35%{transform: scale(0.75);}50%{transform: scale(1);}55%{transform: scale(0.75);}70%{transform: scale(1);}}</style></defs><g style="animation: beat 2s ease-in-out infinite; transform-origin: 50% 50%;"><path fill="#bd0a0a" d="M47.6 300.4L228.3 469.1c7.5 7 17.4 10.9 27.7 10.9s20.2-3.9 27.7-10.9L464.4 300.4c30.4-28.3 47.6-68 47.6-109.5v-5.8c0-69.9-50.5-129.5-119.4-141C347 36.5 300.6 51.4 268 84L256 96 244 84c-32.6-32.6-79-47.5-124.6-39.9C50.5 55.6 0 115.2 0 185.1v5.8c0 41.5 17.2 81.2 47.6 109.5z"/></g></svg>'
220
+ random_prompt_btn.innerHTML =
221
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><g data-name="Ebene_1"><path fill="none" d="M0 48V0h48v48z"/><path d="M42.15 9.85C41.58 9.28 40.9 9 40.12 9H7.88c-.78 0-1.46.28-2.03.85S5 11.1 5 11.88v24.23c0 .78.28 1.46.85 2.03s1.25.85 2.03.85h32.23c.78 0 1.46-.28 2.03-.85s.85-1.25.85-2.03V11.88c0-.78-.28-1.46-.85-2.03ZM13.66 30.78c-.68 0-1.24-.55-1.24-1.24s.55-1.24 1.24-1.24 1.24.55 1.24 1.24-.55 1.24-1.24 1.24Zm2.8-7.78-1.3 1.8c-.32.45-.41.76-.48 1.23-.04.26-.13.48-.28.64-.17.19-.42.29-.73.29s-.56-.12-.73-.31c-.16-.18-.25-.42-.25-.73 0-.68.12-1.09.65-1.8l1.48-2c.33-.45.58-.87.58-1.47 0-1.04-.75-1.83-1.83-1.83-.52 0-.99.15-1.36.52-.29.29-.43.65-.55 1.12-.06.22-.16.47-.27.58-.15.17-.39.29-.7.29-.26 0-.49-.1-.66-.29-.18-.2-.23-.42-.23-.71 0-.67.35-1.58 1.03-2.22.68-.65 1.62-1.03 2.73-1.03 2.11 0 3.79 1.4 3.79 3.57 0 1-.35 1.62-.89 2.36Zm7.28 7.78c-.68 0-1.24-.55-1.24-1.24s.55-1.24 1.24-1.24 1.24.55 1.24 1.24-.55 1.24-1.24 1.24Zm2.8-7.78-1.3 1.8c-.32.45-.41.76-.48 1.23-.04.26-.13.48-.28.64-.17.19-.42.29-.73.29s-.56-.12-.73-.31c-.16-.18-.25-.42-.25-.73 0-.68.12-1.09.65-1.8l1.48-2c.33-.45.58-.87.58-1.47 0-1.04-.75-1.83-1.83-1.83-.52 0-.99.15-1.36.52-.29.29-.43.65-.55 1.12-.06.22-.16.47-.27.58-.15.17-.39.29-.7.29-.26 0-.49-.1-.66-.29-.18-.2-.23-.42-.23-.71 0-.67.35-1.58 1.03-2.22.68-.65 1.62-1.03 2.73-1.03 2.11 0 3.79 1.4 3.79 3.57 0 1-.35 1.62-.89 2.36Zm7.28 7.78c-.68 0-1.24-.55-1.24-1.24s.55-1.24 1.24-1.24 1.24.55 1.24 1.24-.55 1.24-1.24 1.24Zm2.8-7.78-1.3 1.8c-.32.45-.41.76-.48 1.23-.04.26-.13.48-.28.64-.17.19-.42.29-.73.29s-.56-.12-.73-.31c-.16-.18-.25-.42-.25-.73 0-.68.12-1.09.65-1.8l1.48-2c.33-.45.58-.87.58-1.47 0-1.04-.75-1.83-1.83-1.83-.52 0-.99.15-1.36.52-.29.29-.43.65-.55 1.12-.06.22-.16.47-.27.58-.15.17-.39.29-.7.29-.26 0-.49-.1-.66-.29-.18-.2-.23-.42-.23-.71 0-.67.35-1.58 1.03-2.22.68-.65 1.62-1.03 2.73-1.03 2.11 0 3.79 1.4 3.79 3.57 0 1-.35 1.62-.89 2.36Z"/></g></svg>'
222
+ const enhance_prompt_btn = document.querySelector("#enhance_prompt_btn")
223
+ enhance_prompt_btn.innerHTML =
224
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><g data-name="Ebene_1"><path fill="none" d="M0 48V0h48v48z"/><path d="m33.91 29.59 9.37-8.07h.38c.4.05.72.21.95.49.23.28.35.59.35.91 0 .18-.05.37-.14.55-.09.18-.22.35-.37.5l-7.55 6.48 2.31 10s.04.1.04.17v.14c0 .41-.14.73-.42.98-.28.24-.6.37-.97.37-.12 0-.24-.01-.37-.04s-.25-.07-.37-.13l-.4-.27-2.8-12.09Zm-4.95-15.31-3-7.1.16-.33c.1-.27.26-.47.5-.63.24-.15.49-.23.75-.23.24 0 .49.07.74.22s.43.36.55.65l3.25 7.67-2.95-.26ZM12.1 37.29l8.69-5.23 8.69 5.29-2.3-9.9 7.65-6.64-10.09-.89-3.95-9.31-3.95 9.25-10.09.89 7.65 6.66-2.3 9.88Zm-3.09 1.65 2.44-10.56-8.16-7.13c-.2-.18-.35-.38-.46-.59-.11-.22-.16-.42-.16-.63 0-.41.14-.79.43-1.14.29-.34.67-.53 1.14-.55l10.8-.96 4.18-9.96c.13-.34.34-.59.64-.76.3-.17.6-.25.91-.25s.62.08.93.25c.31.17.53.42.66.76l4.18 9.96 10.8.96c.48.02.86.21 1.15.55.29.34.44.72.44 1.13 0 .22-.06.44-.18.65-.12.21-.27.4-.47.58l-8.16 7.13 2.47 10.56c.03.09.05.21.05.36 0 .48-.17.89-.51 1.22-.34.33-.73.49-1.16.49-.09 0-.4-.09-.93-.27l-9.26-5.59-9.26 5.59c-.14.08-.29.14-.46.19-.16.05-.31.08-.44.08-.5 0-.94-.21-1.31-.62-.37-.41-.48-.9-.32-1.45Z"/></g></svg>'
225
+ document.querySelector("#run_btn").innerHTML =
226
+ //'<dotlottie-player src="https://lottie.host/07f9842b-03a8-46dc-a45f-684d4cf57429/2amWXB96uz.lottie" background="transparent" speed="1" loop></dotlottie-player>'
227
+ '<dotlottie-player src="https://lottie.host/e3515e09-f615-49f0-a63d-a421b45ceb45/XEuKdFRH19.lottie" background="transparent" speed="1" loop></dotlottie-player>'
228
+
229
+
230
+ const switch_width_height_inner = document.createElement("div")
231
+ //const switch_width_height_inner_image = document.createElement("div")
232
+ //switch_width_height_inner_image.id = "switch_width_height_inner_image"
233
+ switch_width_height_inner.id = "switch_width_height_inner"
234
+ switch_width_height_inner.setAttribute("data-aspect-ratio", "9-16")
235
+ switch_width_height_inner.className = "hochformat"
236
+ switch_width_height_inner.innerHTML = `<div></div>`
237
+ //switch_width_height_inner.append(switch_width_height_inner_image)
238
+ switch_width_height.append(switch_width_height_inner)
239
+ const switch_width_height_btn_inner = document.querySelector("div#switch_width_height_inner")
240
+
241
+ switch_width_height.addEventListener("click", () => {
242
+ //switch_width_height_btn_inner.className = document.querySelector("#image_ratio_buttons > span").textContent.toLocaleLowerCase()
243
+ })
244
+
245
+ switch_ratio_btns.forEach((_) => {
246
+ _.querySelector("input").addEventListener("click", (e) => {
247
+ switch_width_height_btn_inner.setAttribute("data-aspect-ratio", e.target.value.replace(":", "-").trim())
248
+ })
249
+ })
250
+
251
+ onImageRatioButtonsChange(() => {
252
+ switch_width_height_btn_inner.className = document.querySelector("#image_ratio_buttons > span").textContent.toLocaleLowerCase()
253
+ const selected_ratio = document.querySelector("#image_ratio_buttons label.selected input").value.replace(":", "-").trim()
254
+ if (switch_width_height_btn_inner.getAttribute("data-aspect-ratio") != selected_ratio) {
255
+ switch_width_height_btn_inner.setAttribute("data-aspect-ratio", selected_ratio)
256
+ }
257
+ })
258
+
259
+ // MARK: Element-Ready function
260
+ function elementReady(selector) {
261
+ return new Promise((resolve, reject) => {
262
+ const el = document.querySelector(selector)
263
+ if (el) {
264
+ resolve(el)
265
+ }
266
+
267
+ new MutationObserver((mutationRecords, observer) => {
268
+ Array.from(document.querySelectorAll(selector)).forEach((element) => {
269
+ resolve(element)
270
+ observer.disconnect()
271
+ })
272
+ }).observe(document.documentElement, {
273
+ childList: true,
274
+ subtree: true,
275
+ })
276
+ })
277
+ }
278
+
279
+ // MARK: Mobile Check
280
+ function istMobile() {
281
+ // Überprüfen, ob das Gerät ein Touchscreen hat
282
+ if ("ontouchstart" in window || (navigator.maxTouchPoints && window.innerWidth < 768)) {
283
+ gradioContainer.classList.add("blur-container")
284
+ body.style.setProperty("--blur-value", "12px")
285
+ gradioApp.style.height = "calc(100vh - 120px)"
286
+ alertModalElem.style.display = ""
287
+ alertModalElemSpan.textContent = "Diese Seite ist nicht für mobile Geräte optimiert. Bitte besuche diese Seite von einem Desktop-Computer aus."
288
+ } else if (window.innerWidth < 1024) {
289
+ gradioContainer.classList.add("blur-container")
290
+ body.style.setProperty("--blur-value", "12px")
291
+ gradioApp.style.height = "calc(100vh - 120px)"
292
+ alertModalElem.style.display = ""
293
+ alertModalElemSpan.textContent = "Bildschirm Auflösung oder Fensterbreite zu gering. Bitte besuche diese Seite von einem Desktop-Computer aus."
294
+ } else {
295
+ gradioContainer.classList.remove("blur-container")
296
+ body.style.setProperty("--blur-value", "0px")
297
+ gradioApp.style.height = ""
298
+ alertModalElem.style.display = "none"
299
+ alertModalElemSpan.textContent = ""
300
+ }
301
+ }
302
+
303
+ // MARK: Event Listeners
304
+ window.addEventListener("resize", () => {
305
+ console.log("Event Window resize.")
306
+ istMobile()
307
+ })
308
+
309
+ elementReady("body > gradio-app > div.gradio-container").then((element) => {
310
+ console.log("Element exist: " + element)
311
+ istMobile()
312
+ })
313
+
314
+ return "Custom Gradio JS"
315
+ }
_res/assets/bootstrap-catppuccin-mocha.min.css CHANGED
The diff for this file is too large to render. See raw diff
 
_res/assets/fontawesome.all.min.css CHANGED
The diff for this file is too large to render. See raw diff
 
_res/assets/random_dark.svg CHANGED
_res/assets/random_light.svg CHANGED
_res/assets/run_1_dark.svg CHANGED
_res/assets/run_1_light.svg CHANGED
_res/assets/star_dark.svg CHANGED
_res/assets/star_light.svg CHANGED
_res/groq_systemmessage_prompt_enhance.json CHANGED
@@ -1,4 +1,4 @@
1
- {
2
- "role": "system",
3
- "content": "You are an AI assistant specialized in improving and diversifying image generation prompts. Your primary function is to take user-provided prompts and enhance them, ensuring they are in English and follow specific guidelines. Here's how you should operate:\n\n1. Language Processing:\n - If the user's prompt is not in English, translate it to English first.\n\n2. Prompt Analysis:\n - Analyze the original image prompt from the user.\n - Identify core elements: main subject, setting, colors, lighting, mood, and any temporal aspects.\n - Determine relevance of specific languages or cultures to the subject matter.\n\n3. Prompt Generation:\n - Create one distinctive new prompt describing the same image from a different perspective.\n - Maintain a clear, vivid description while using varied vocabulary and sentence structures.\n - Avoid reusing adjectives, nouns, verbs, or phrases from the original prompt.\n - The prompt should not be longer than 60 words.\n\n4. Style and Artistic References:\n - If a visual style or artist is referenced, expand with more details about the style or artist.\n - If no style is given, suggest a fitting style typical for that type of image.\n\n5. Technical and Abstract Concepts:\n - For technical content (e.g., spreadsheets, diagrams), rewrite into figurative prompts.\n - Example: Transform a spreadsheet into an intricate isometric technical drawing representing the data.\n - Provide guidance on visualizing abstract concepts or ideas.\n\n6. Emotional Depth:\n - Emphasize emotional nuances and moods in the prompt.\n\n7. Interactive Elements:\n - Suggest ways to imply movement or interaction in static images.\n\n8. Random Prompt Generation:\n - When requested, create an evocative and surprising prompt within user constraints.\n - Provide any unspecified details to complete the image concept.\n\n9. Output Format:\n Ensure the prompt is in English, then respond only with the new prompt in the following format:\n [detailed prompt] - [style artist medium art movement photo style]\n\nAlways strive to create prompts that are imaginative, detailed, and aligned with the user's original intent while offering a fresh perspective or interpretation."
4
- }
 
1
+ {
2
+ "role": "system",
3
+ "content": "You are an AI assistant specialized in improving and diversifying image generation prompts. Your primary function is to take user-provided prompts and enhance them, ensuring they are in English and follow specific guidelines. Here's how you should operate:\n\n1. Language Processing:\n - If the user's prompt is not in English, translate it to English first.\n\n2. Prompt Analysis:\n - Analyze the original image prompt from the user.\n - Identify core elements: main subject, setting, colors, lighting, mood, and any temporal aspects.\n - Determine relevance of specific languages or cultures to the subject matter.\n\n3. Prompt Generation:\n - Create one distinctive new prompt describing the same image from a different perspective.\n - Maintain a clear, vivid description while using varied vocabulary and sentence structures.\n - Avoid reusing adjectives, nouns, verbs, or phrases from the original prompt.\n - The prompt should not be longer than 60 words.\n\n4. Style and Artistic References:\n - If a visual style or artist is referenced, expand with more details about the style or artist.\n - If no style is given, suggest a fitting style typical for that type of image.\n\n5. Technical and Abstract Concepts:\n - For technical content (e.g., spreadsheets, diagrams), rewrite into figurative prompts.\n - Example: Transform a spreadsheet into an intricate isometric technical drawing representing the data.\n - Provide guidance on visualizing abstract concepts or ideas.\n\n6. Emotional Depth:\n - Emphasize emotional nuances and moods in the prompt.\n\n7. Interactive Elements:\n - Suggest ways to imply movement or interaction in static images.\n\n8. Random Prompt Generation:\n - When requested, create an evocative and surprising prompt within user constraints.\n - Provide any unspecified details to complete the image concept.\n\n9. Output Format:\n Ensure the prompt is in English, then respond only with the new prompt in the following format:\n [detailed prompt] - [style artist medium art movement photo style]\n\nAlways strive to create prompts that are imaginative, detailed, and aligned with the user's original intent while offering a fresh perspective or interpretation."
4
+ }
app.py CHANGED
@@ -1,364 +1,502 @@
1
- import os, sys, json, re, time, base64, random, shutil
2
- import gradio as gr
3
- import numpy as np
4
- import requests
5
- from requests import Session
6
- from requests.adapters import HTTPAdapter
7
- from requests.packages.urllib3.util.retry import Retry
8
- from datetime import datetime
9
- import urllib.parse
10
- from groq import Groq
11
- from exif import Image
12
- from PIL import Image as PILImage, ExifTags as PILExifTags
13
- from io import BytesIO
14
- import colorsys
15
-
16
- # MARK: INIT
17
- MAX_SEED = np.iinfo(np.int32).max
18
- # MAX_SEED = 9999
19
- MAX_IMAGE_SIZE = 2048
20
-
21
- GROQ_APIKEY_PROMPTENHANCE = os.getenv("GROQ_APIKEY_PROMPTENHANCE")
22
- API2 = os.getenv("API2")
23
- API2_MODELS = urllib.parse.unquote(API2 + "/models")
24
- API2_IMAGE = urllib.parse.unquote(API2 + "/imagine")
25
- API1 = urllib.parse.unquote(os.getenv("API1"))
26
-
27
-
28
- CACHE_DIR = os.path.join(os.path.dirname(__file__), "cache")
29
- IMAGE_DIR = "cache/images/"
30
- if not os.path.exists(CACHE_DIR):
31
- os.makedirs(CACHE_DIR)
32
- print(f"Created cache dir on path {CACHE_DIR}")
33
- os.makedirs(os.path.join(CACHE_DIR, "images"))
34
- print(f"Created images dir on path {IMAGE_DIR}")
35
-
36
- RES = os.path.join(os.path.dirname(__file__), "_res")
37
-
38
- gr.set_static_paths(paths=["_res/", "_res/assets/", "_res/assets/emojis/", "_res/assets/favicons/", IMAGE_DIR])
39
-
40
- custom_css = RES + "/_custom.css"
41
- custom_js = RES + "/_custom.js"
42
-
43
- custom_head = f"""
44
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css"/>
45
- <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/js/all.min.js"></script>
46
- <link rel="apple-touch-icon" sizes="180x180" href="file=_res/assets/favicons/apple-touch-icon.png">
47
- <link rel="icon" type="image/png" sizes="32x32" href="file=_res/assets/favicons/favicon-32x32.png">
48
- <link rel="icon" type="image/png" sizes="16x16" href="file=_res/assets/favicons/favicon-16x16.png">
49
- <link rel="icon" type="image/x-icon" href="file=_res/assets/favicons/favicon.ico">
50
- <link rel="manifest" href="file=_res/assets/favicons/site.webmanifest">
51
- <script src="https://unpkg.com/@dotlottie/player-component@latest/dist/dotlottie-player.mjs" type="module"></script>
52
- <script src='https://storage.ko-fi.com/cdn/widget/Widget_2.js'></script>
53
- """
54
-
55
- theme = gr.themes.Soft(
56
- # primary_hue="orange",
57
- radius_size="sm",
58
- neutral_hue=gr.themes.Color(c100="#a6adc8", c200="#9399b2", c300="#7f849c", c400="#6c7086", c50="#cdd6f4", c500="#585b70", c600="#45475a", c700="#313244", c800="#1e1e2e", c900="#181825", c950="#11111b"),
59
- )
60
-
61
- title = "Bilder Builder"
62
-
63
-
64
- # MARK: GET PREV. IMAGES
65
- def get_gallery_images(dirpath):
66
- gallery_images = [dirpath + "/" + s for s in os.listdir(dirpath) if os.path.isfile(os.path.join(dirpath, s))]
67
- gallery_images.sort(key=lambda s: os.path.getmtime(s), reverse=True)
68
- return gallery_images
69
-
70
-
71
- # MARK: READ EXIF
72
- def read_exif(image_path):
73
- with open(image_path, "rb") as src:
74
- img = Image(src)
75
- img_comment = json.loads(img.user_comment)
76
-
77
- # checking if the key exists before removing
78
- if "concept" in img_comment:
79
- img_comment.pop("concept")
80
-
81
- return img_comment
82
-
83
-
84
- def read_image_exfi_data(image_path):
85
- print("Imagepath:", image_path)
86
- img_exif_make, img_exif_comment = read_exif(image_path)
87
- return None, image_path, img_exif_comment
88
-
89
-
90
- # MARK: GROQ PROMPT ENHANCE
91
- def groq_enhance_process(Prompt=""):
92
- client = Groq(api_key=GROQ_APIKEY_PROMPTENHANCE)
93
- Prompt = "random prompt" if Prompt == "" else Prompt
94
- SYSTEMPROMPT = os.path.join(RES, "groq_systemmessage_prompt_enhance.json")
95
- with open(SYSTEMPROMPT, "r") as f:
96
- SYSTEMPROMPT = json.load(f)
97
-
98
- completion = client.chat.completions.create(
99
- model="llama-3.1-70b-versatile",
100
- messages=[SYSTEMPROMPT, {"role": "user", "content": Prompt}],
101
- temperature=0.8,
102
- max_tokens=512,
103
- top_p=0.9,
104
- stream=False,
105
- seed=random.randint(0, MAX_SEED),
106
- stop=None,
107
- )
108
-
109
- if completion.choices[0].message.content != "":
110
- enhanced_prompt = completion.choices[0].message.content
111
- enhanced_prompt = re.sub(r"[\.\"]+", "", enhanced_prompt)
112
-
113
- return enhanced_prompt
114
-
115
-
116
- def image_get_size(image_path):
117
- img = PILImage.open(image_path)
118
- # print("Image size:", img.size)
119
- width, height = img.size
120
- return width, height
121
-
122
-
123
- # MARK: DOMINANT COLOR
124
- def image_get_dominant_color(image_path):
125
- img = PILImage.open(image_path)
126
- img = img.convert("RGB")
127
- img = img.resize((100, 100), resample=0)
128
- pixels = list(img.getdata())
129
-
130
- # Erzeuge eine Liste mit den Häufigkeiten der Farben
131
- colors = []
132
- for pixel in pixels:
133
- r, g, b = pixel
134
- h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255)
135
- if v > 0.5: # Filteriere hellere Farben aus
136
- continue
137
- if v > 0.99: # Filteriere Weiß aus
138
- continue
139
- colors.append((h, s, v))
140
-
141
- # Ermittle die dominante Farbe
142
- dominant_color = max(colors, key=lambda x: x[2])
143
- dominant_color_rgb = colorsys.hsv_to_rgb(dominant_color[0], dominant_color[1], dominant_color[2])
144
- dominant_color_rgb = [int(c * 255) for c in dominant_color_rgb]
145
- dominant_color_rgb = f"rgb({dominant_color_rgb[0]}, {dominant_color_rgb[1]}, {dominant_color_rgb[2]})"
146
- # print(dominant_color_rgb)
147
-
148
- return dominant_color_rgb
149
-
150
-
151
- # MARK: CLEAR COMPONENTS
152
- def clear_components():
153
- return None
154
-
155
-
156
- def process(Prompt, used_model, image_width, image_height, image_ratio, image_seed, randomize_seed):
157
- if Prompt == "":
158
- gr.Info("Kein Prompt angegeben, es wird ein zufälliger Prompt generiert.", duration=12)
159
- Prompt = groq_enhance_process("random prompt")
160
-
161
- image_ratio = "9:16" if image_ratio == "" else image_ratio
162
- used_seed = random.randint(0, MAX_SEED) if image_seed == 0 or randomize_seed else image_seed
163
- # used_model = "turbo" if int(image_width) > 1024 or int(image_height) > 1024 else "flux" # turbo, flux
164
-
165
- timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
166
- filename_prompt = re.sub(r"[^\w\s-]", "", Prompt).strip().replace(" ", "_")
167
- filename = timestamp + "_" + filename_prompt[:100] + ".png"
168
- file_path = IMAGE_DIR + filename
169
-
170
- # Retry-Logik mit requests und Retry
171
- session = Session()
172
- retries = Retry(total=3, status_forcelist=[429, 500, 502, 503, 504], backoff_factor=0.3, respect_retry_after_header=True) # Max 3 Versuche # Codes, die wiederholt werden # Exponential Backoff # Retry-Header beachten
173
- adapter = HTTPAdapter(max_retries=retries)
174
- session.mount("https://", adapter)
175
- session.mount("http://", adapter)
176
-
177
- u_model = re.sub('api\d-', '', used_model.lower())
178
- API1_REQUEST_URL = f"{API1}{urllib.parse.quote(Prompt)}?model={u_model}&width={image_width}&height={image_height}&nologo=true&enhance=false&nofeed=true&seed={used_seed}"
179
- API2_REQUEST_URL = f"{API2_IMAGE}?prompt={urllib.parse.quote(Prompt)}&size={urllib.parse.quote(image_ratio)}&seed={used_seed}&model={u_model}"
180
- REQUEST_URL = API2_REQUEST_URL if used_model.lower().startswith("api1-") else API1_REQUEST_URL
181
-
182
- try:
183
- response = session.get(REQUEST_URL, timeout=60)
184
- if response.status_code == 200:
185
- print("REQUEST URL:\n" + REQUEST_URL + "\n\nImagine API Request solved")
186
- img = PILImage.open(BytesIO(response.content))
187
- img.save(file_path, "png")
188
- print("Save image to: ")
189
- print(file_path)
190
-
191
- # img_exif_comment = "" # read_exif(file_path)
192
- img_dominant_color = image_get_dominant_color(file_path)
193
- img_width, img_height = image_get_size(file_path)
194
-
195
- return ({"value": Prompt, "__type__": "update"}, {"value": file_path, "__type__": "update"}, {"value": None, "visible": False, "__type__": "update"}, {"visible": True, "__type__": "update"}, {"value": Prompt, "visible": True, "__type__": "update"}, img_width, img_height, used_seed, {"value": file_path, "visible": True, "__type__": "update"}, img_dominant_color, used_seed)
196
- else:
197
- print("Imagine API Request ERROR")
198
- raise gr.Error("Imagine API-Aufruf fehlgeschlagen 💥!", duration=15)
199
- except requests.exceptions.Timeout:
200
- raise gr.Error("⏰ Zeitüberschreitung beim API-Aufruf", duration=15)
201
- except requests.exceptions.RequestException as e:
202
- print(f"Unbekannter Fehler beim API-Aufruf: {e}")
203
- raise gr.Error("Unbekannter Fehler beim API-Aufruf! 🤷‍♂️", duration=15)
204
-
205
- def check_api(url):
206
- try:
207
- response = requests.get(url, timeout=8)
208
- print(f"Checking Status for: {url}, it returns statuscode {response.status_code}")
209
- return response.status_code
210
- except requests.exceptions.RequestException as e:
211
- print(f"An error occurred: {e}")
212
- return int(999)
213
-
214
-
215
- def get_inference_models():
216
-
217
- status_api_1 = check_api(API1)
218
- status_api_2 = check_api(API2)
219
-
220
- info_api_1 = "🟢API1👍" if status_api_1 == 200 else "🔴API1👎🔌"
221
- info_api_2 = "🟢API2👍" if status_api_2 == 200 else "🔴API2👎🔌"
222
-
223
- api_models_1 = ["API1-FLUX", "API1-FLUX-Pro", "API1-FLUX-CablyAI", "API1-Turbo"]
224
- api_models_2 = ["API2-FLUX-Realism", "API2-FLUX-Pixel", "API2-FLUX-Anime", "API2-FLUX-3D", "API2-FLUX-Disney", "API2-ANY-DARK"]
225
-
226
- models = [model for model in api_models_1 if status_api_1 == 200] + [model for model in api_models_2 if status_api_2 == 200]
227
- info_api_status = f"Status: {info_api_1} & {info_api_2}"
228
-
229
- return gr.update(choices=models, value=models[0], interactive=True, info=info_api_status)
230
-
231
-
232
- # MARK: Gradio BLOCKS UI
233
- with gr.Blocks(theme=theme, head=custom_head, css=custom_css, js=custom_js, title=title) as demo:
234
- with gr.Row(elem_classes="row-header"):
235
- gr.Markdown(f"""
236
- <div class="flex-wrapper">
237
- <div style="width: 100%">
238
- <h1>{title}</h1>
239
- <p class="errorinfo" style="color: #e26c5a; margin-top: 0.3rem; margin-bottom: 0.3rem;">Aktuell funktioniert die APP nicht, da ich heute wenig Zeit habe werde ich es erst morgen schaffen die Probleme zu beheben.</p>
240
- <p>
241
- <span style="font-weight: 600">LG Sebastian</span>
242
- <i class="winking-hand-emoji"></i> gib dem Space gerne ein
243
- <i class="heart-beat-emoji"></i>
244
- </p>
245
- </div>
246
- <div style="">
247
- <div class="btn-container">
248
- <a title="Support me on ko-fi.com" class="kofi-button" style="background-color: #72a4f2" href="https://ko-fi.com/Z8Z316DSO4" target="_blank" >
249
- <span class="kofitext"><img src="https://storage.ko-fi.com/cdn/cup-border.png" alt="Ko-fi donations" class="kofiimg"/>Support me on Ko-fi</span>
250
- </a>
251
- </div>
252
- </div>
253
- </div>
254
- """, elem_classes="md-header")
255
-
256
- with gr.Tab("Bilder Builder"):
257
- with gr.Row():
258
- with gr.Column(scale=2): # min_width=420,
259
- with gr.Row():
260
- placeholder_text = "[???] Generiert dir einen zufälligen Prompt.\n[STERN] optimiert deinen eignen Prompt.\n[RUN] generiert dein Bild."
261
- text_prompt = gr.Textbox(label="Prompt", show_label=False, lines=12, max_lines=18, placeholder=placeholder_text, elem_id="prompt_input", elem_classes="prompt-input hide-progress", autofocus=True)
262
- with gr.Row():
263
- random_prompt_button = gr.Button("", variant="secondary", elem_id="random_prompt_btn", elem_classes="random-prompt-btn", icon="_res/assets/star_light_48.png")
264
- enhance_prompt_button = gr.Button("", variant="secondary", elem_id="enhance_prompt_btn", elem_classes="enhance-prompt-btn", icon="_res/assets/star_light_48.png")
265
- run_button = gr.Button("Erstellen", variant="primary", elem_id="run_btn", elem_classes="run-btn")
266
- with gr.Row(elem_classes="image_size_selctor_wrapper"):
267
- with gr.Column(scale=1):
268
- with gr.Row():
269
- # inference_models, selected_model = get_inference_models()
270
- # select_model = gr.Dropdown(choices=inference_models, value=selected_model, label="Model", elem_id="select_model", elem_classes="select-model")
271
- select_model = gr.Dropdown(label="Model", elem_id="select_model", elem_classes="select-model")
272
- # with gr.Row():
273
- image_width = gr.Number(label="Breite", minimum=256, maximum=MAX_IMAGE_SIZE, value=576, step=32, elem_id="image_width_selector", elem_classes="image-width-selector", scale=1, visible=False)
274
- image_height = gr.Number(label="Höhe", minimum=256, maximum=MAX_IMAGE_SIZE, value=1024, step=32, elem_id="image_height_selector", elem_classes="image-height-selector", scale=1, visible=False)
275
- with gr.Row():
276
- image_ratio_buttons = gr.Radio(["9:16", "3:4", "2:3", "1:1"], value="9:16", label="Hochformat", show_label=True, info="Seitenverhältniss drehen", interactive=True, elem_id="image_ratio_buttons", elem_classes="image-ratio-buttons", container=True, scale=2)
277
- switch_width_height = gr.Button("", size="sm", elem_id="switch_width_height", elem_classes="switch-ratio-btn", variant="primary", scale=1)
278
- with gr.Column():
279
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True, elem_classes="random-seed-cb toggle-btn")
280
- image_seed = gr.Slider(label="Seed", info="Jeder Seed generiert ein anderes Bild mit dem selben Prompt", minimum=0, step=1, value=42, maximum=MAX_SEED, elem_id="image_seed", elem_classes="image-seed hide-progress", interactive=False)
281
-
282
- with gr.Column(scale=4): # min_width=600,
283
- with gr.Row():
284
- with gr.Column(scale=1):
285
- with gr.Row():
286
- output_image = gr.Image(show_label=False, min_width=320, scale=3, elem_id="output_image", elem_classes="output-image", type="filepath", format="webp")
287
- # gallery = gr.Gallery(label="Bisher erstellte Bilder", show_label=True, value=get_gallery_images(IMAGE_DIR), elem_id="gallery", columns=[4], object_fit="cover", height="auto", interactive=False, format="webp")
288
- with gr.Column(scale=1, visible=False, elem_classes="image-info-wrapper") as image_info_wrapper:
289
- with gr.Group():
290
- image_informations = gr.Markdown("""## Bildinformationen""", visible=True)
291
- with gr.Row(elem_classes="img-size-wrapper"):
292
- image_info_tb_width = gr.Textbox(label="Breite", lines=1, max_lines=1, interactive=False, show_copy_button=True, elem_classes="image-info-tb-width")
293
- image_info_tb_height = gr.Textbox(label="Höhe", lines=1, max_lines=1, interactive=False, show_copy_button=True, elem_classes="image-info-tb-height")
294
- with gr.Row(elem_classes="img-seed-wrapper"):
295
- image_info_tb_seed = gr.Textbox(label="Seed", lines=1, max_lines=1, interactive=False, show_copy_button=True, elem_classes="image-info-tb-seed")
296
- image_info_tb_prompt = gr.Textbox("Bild Prompt", lines=4, max_lines=8, interactive=False, elem_classes="hide-progress", show_copy_button=True, visible=False)
297
- image_download_button = gr.DownloadButton("Bild herunterladen", value=None, elem_classes="download-button", variant="primary", visible=False)
298
-
299
- output_url = gr.Textbox(label="Output URL", show_label=True, interactive=False, visible=False)
300
- outpu_image_comment = gr.Json(visible=False)
301
- output_dominant_image_color = gr.Textbox(show_label=False, elem_id="dominant_image_color", visible=True, elem_classes="output-dominant-image-color")
302
-
303
- demo.load(get_inference_models, outputs=[select_model])
304
-
305
- def switch_image_size_values(image_width, image_height):
306
- return image_height, image_width
307
-
308
- def switch_image_ratio_buttons(ratio_value):
309
- ratio_value = ratio_value.split(":")
310
- ratio_value_new = f"{int(ratio_value[1])}:{int(ratio_value[0])}"
311
-
312
- if int(ratio_value[1]) > int(ratio_value[0]):
313
- # Querformat
314
- new_choises = ["16:9", "4:3", "3:2", "1:1"]
315
- new_label = "Querformat"
316
- elif int(ratio_value[1]) < int(ratio_value[0]):
317
- # Hochformat
318
- new_choises = ["9:16", "3:4", "2:3", "1:1"]
319
- new_label = "Hochformat"
320
- elif int(ratio_value[1]) == int(ratio_value[0]):
321
- new_choises = image_ratio_buttons.choices
322
- new_label = "Quadratisch"
323
-
324
- return {"choices": new_choises, "value": ratio_value_new, "label": new_label, "__type__": "update"}
325
-
326
- def calculate_ratio_values(image_ratio_buttons):
327
- ratio_value = image_ratio_buttons.split(":")
328
- if int(ratio_value[0]) > int(ratio_value[1]):
329
- a = 1024
330
- b = int(a * int(ratio_value[1]) / int(ratio_value[0]))
331
- b = round(b / 8) * 8
332
- new_width = a
333
- new_height = b
334
- new_label = "Querformat"
335
- elif int(ratio_value[0]) < int(ratio_value[1]):
336
- b = 1024
337
- a = int(b * int(ratio_value[0]) / int(ratio_value[1]))
338
- a = round(a / 8) * 8
339
- new_width = a
340
- new_height = b
341
- new_label = "Hochformat"
342
- elif int(ratio_value[0]) == int(ratio_value[1]):
343
- new_width = 1024
344
- new_height = 1024
345
- new_label = "Quadratisch"
346
-
347
- return {"label": new_label, "__type__": "update"}, new_width, new_height
348
-
349
- switch_width_height.click(fn=switch_image_size_values, inputs=[image_width, image_height], outputs=[image_width, image_height], show_progress="hidden", show_api=False)
350
- switch_width_height.click(fn=switch_image_ratio_buttons, inputs=[image_ratio_buttons], outputs=[image_ratio_buttons], show_progress="hidden", show_api=False)
351
-
352
- image_ratio_buttons.input(fn=calculate_ratio_values, inputs=[image_ratio_buttons], outputs=[image_ratio_buttons, image_width, image_height], show_progress="hidden", show_api=False)
353
-
354
- run_button.click(fn=lambda: ({"interactive": False, "__type__": "update"}, {"interactive": False, "__type__": "update"}, {"interactive": False, "__type__": "update"}), outputs=[run_button, enhance_prompt_button, random_prompt_button], show_api=False, js="() => document.querySelector('dotlottie-player').play()").then(fn=clear_components, outputs=[output_image], show_api=False).then(
355
- fn=process, inputs=[text_prompt, select_model, image_width, image_height, image_ratio_buttons, image_seed, randomize_seed], outputs=[text_prompt, output_image, output_url, image_informations, image_info_tb_prompt, image_info_tb_width, image_info_tb_height, image_info_tb_seed, image_download_button, output_dominant_image_color, image_seed]
356
- ).then(fn=lambda: ({"interactive": True, "__type__": "update"}, {"interactive": True, "__type__": "update"}, {"interactive": True, "__type__": "update"}), outputs=[run_button, enhance_prompt_button, random_prompt_button], show_api=False, js="() => document.querySelector('dotlottie-player').stop()")
357
-
358
- randomize_seed.input(lambda x: {"interactive": False if x == True else True, "__type__": "update"}, inputs=[randomize_seed], outputs=[image_seed], show_api=False)
359
-
360
- enhance_prompt_button.click(fn=groq_enhance_process, inputs=[text_prompt], outputs=[text_prompt], show_api=False)
361
- random_prompt_button.click(fn=groq_enhance_process, inputs=None, outputs=[text_prompt], show_api=False)
362
-
363
- # MARK: Gradio LAUNCH
364
- demo.launch(show_api=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, sys, json, re, time, base64, random, shutil
2
+ import gradio as gr
3
+ import numpy as np
4
+ import requests
5
+ from requests import Session
6
+ from requests.adapters import HTTPAdapter
7
+ from requests.packages.urllib3.util.retry import Retry
8
+ from datetime import datetime
9
+ import urllib.parse
10
+ from groq import Groq
11
+ from exif import Image
12
+ from PIL import Image as PILImage, ExifTags as PILExifTags
13
+ from io import BytesIO
14
+ import colorsys
15
+ import spaces
16
+
17
+ if not "SPACE" in os.environ:
18
+ from dotenv import load_dotenv
19
+
20
+ load_dotenv()
21
+
22
+ # MARK: INIT
23
+ MAX_SEED = np.iinfo(np.int32).max
24
+ MAX_IMAGE_SIZE = 2048
25
+
26
+ GROQ_APIKEY_PROMPTENHANCE = os.getenv("GROQ_APIKEY_PROMPTENHANCE")
27
+ API1 = urllib.parse.unquote(os.getenv("API1"))
28
+ API2 = os.getenv("API2")
29
+ API2_MODELS = urllib.parse.unquote(API2 + "/models")
30
+ API2_IMAGE = urllib.parse.unquote(API2 + "/imagine")
31
+
32
+
33
+ CACHE_DIR = os.path.join(os.path.dirname(__file__), "cache")
34
+ IMAGE_DIR = "cache/images/"
35
+ if not os.path.exists(CACHE_DIR):
36
+ os.makedirs(CACHE_DIR)
37
+ print(f"Created cache dir on path {CACHE_DIR}")
38
+ os.makedirs(os.path.join(CACHE_DIR, "images"))
39
+ print(f"Created images dir on path {IMAGE_DIR}")
40
+
41
+ RES = os.path.join(os.path.dirname(__file__), "_res")
42
+
43
+ gr.set_static_paths(paths=["_res/", "_res/assets/", "_res/assets/emojis/", "_res/assets/favicons/", IMAGE_DIR])
44
+
45
+ custom_css = RES + "/_custom.css"
46
+ custom_js = RES + "/_custom.js"
47
+
48
+ custom_head = f"""
49
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css"/>
50
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/js/all.min.js"></script>
51
+ <link rel="apple-touch-icon" sizes="180x180" href="file=_res/assets/favicons/apple-touch-icon.png">
52
+ <link rel="icon" type="image/png" sizes="32x32" href="file=_res/assets/favicons/favicon-32x32.png">
53
+ <link rel="icon" type="image/png" sizes="16x16" href="file=_res/assets/favicons/favicon-16x16.png">
54
+ <link rel="icon" type="image/x-icon" href="file=_res/assets/favicons/favicon.ico">
55
+ <link rel="manifest" href="file=_res/assets/favicons/site.webmanifest">
56
+ <script src="https://unpkg.com/@dotlottie/player-component@latest/dist/dotlottie-player.mjs" type="module"></script>
57
+ <script src='https://storage.ko-fi.com/cdn/widget/Widget_2.js'></script>
58
+ """
59
+
60
+ theme = gr.themes.Soft(
61
+ # primary_hue="orange",
62
+ radius_size="sm",
63
+ neutral_hue=gr.themes.Color(
64
+ c100="#a6adc8",
65
+ c200="#9399b2",
66
+ c300="#7f849c",
67
+ c400="#6c7086",
68
+ c50="#cdd6f4",
69
+ c500="#585b70",
70
+ c600="#45475a",
71
+ c700="#313244",
72
+ c800="#1e1e2e",
73
+ c900="#181825",
74
+ c950="#11111b",
75
+ ),
76
+ )
77
+
78
+ title = "Bilder Builder"
79
+
80
+
81
+ # MARK: READ EXIF
82
+ def read_exif(image_path):
83
+ with open(image_path, "rb") as src:
84
+ img = Image(src)
85
+ img_comment = json.loads(img.user_comment)
86
+
87
+ # checking if the key exists before removing
88
+ if "concept" in img_comment:
89
+ img_comment.pop("concept")
90
+
91
+ return img_comment
92
+
93
+
94
+ def read_image_exfi_data(image_path):
95
+ print("Imagepath:", image_path)
96
+ img_exif_make, img_exif_comment = read_exif(image_path)
97
+ return None, image_path, img_exif_comment
98
+
99
+
100
+ # MARK: GROQ PROMPT ENHANCE
101
+ def groq_enhance_process(Prompt=""):
102
+ client = Groq(api_key=GROQ_APIKEY_PROMPTENHANCE)
103
+ Prompt = "random prompt" if Prompt == "" else Prompt
104
+ SYSTEMPROMPT = os.path.join(RES, "groq_systemmessage_prompt_enhance.json")
105
+ with open(SYSTEMPROMPT, "r") as f:
106
+ SYSTEMPROMPT = json.load(f)
107
+
108
+ completion = client.chat.completions.create(
109
+ model="llama-3.1-70b-versatile",
110
+ messages=[SYSTEMPROMPT, {"role": "user", "content": Prompt}],
111
+ temperature=0.8,
112
+ max_tokens=512,
113
+ top_p=0.9,
114
+ stream=False,
115
+ seed=random.randint(0, MAX_SEED),
116
+ stop=None,
117
+ )
118
+
119
+ if completion.choices[0].message.content != "":
120
+ enhanced_prompt = completion.choices[0].message.content
121
+ enhanced_prompt = re.sub(r"[\.\"]+", "", enhanced_prompt)
122
+
123
+ return enhanced_prompt
124
+
125
+
126
+ def image_get_size(image_path):
127
+ img = PILImage.open(image_path)
128
+ # print("Image size:", img.size)
129
+ width, height = img.size
130
+ return width, height
131
+
132
+
133
+ # MARK: DOMINANT COLOR
134
+ def image_get_dominant_color(image_path):
135
+ img = PILImage.open(image_path)
136
+ img = img.convert("RGB")
137
+ img = img.resize((100, 100), resample=0)
138
+ pixels = list(img.getdata())
139
+
140
+ # Erzeuge eine Liste mit den Häufigkeiten der Farben
141
+ colors = []
142
+ for pixel in pixels:
143
+ r, g, b = pixel
144
+ h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255)
145
+ if v > 0.5: # Filteriere hellere Farben aus
146
+ continue
147
+ if v > 0.99: # Filteriere Weiß aus
148
+ continue
149
+ colors.append((h, s, v))
150
+
151
+ # Ermittle die dominante Farbe
152
+ dominant_color = max(colors, key=lambda x: x[2])
153
+ dominant_color_rgb = colorsys.hsv_to_rgb(dominant_color[0], dominant_color[1], dominant_color[2])
154
+ dominant_color_rgb = [int(c * 255) for c in dominant_color_rgb]
155
+ dominant_color_rgb = f"rgb({dominant_color_rgb[0]}, {dominant_color_rgb[1]}, {dominant_color_rgb[2]})"
156
+ # print(dominant_color_rgb)
157
+
158
+ return dominant_color_rgb
159
+
160
+
161
+ # MARK: CLEAR COMPONENTS
162
+ def clear_components():
163
+ return None
164
+
165
+
166
+ def process(Prompt, used_model, image_width, image_height, image_ratio, image_seed, randomize_seed, gallery):
167
+ if Prompt == "":
168
+ gr.Info("Kein Prompt angegeben, es wird ein zufälliger Prompt generiert.", duration=12)
169
+ Prompt = groq_enhance_process("random prompt")
170
+
171
+ image_ratio = "9:16" if image_ratio == "" else image_ratio
172
+ used_seed = random.randint(0, MAX_SEED) if image_seed == 0 or randomize_seed else image_seed
173
+ # used_model = "turbo" if int(image_width) > 1024 or int(image_height) > 1024 else "flux" # turbo, flux
174
+
175
+ timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
176
+ filename_prompt = re.sub(r"[^\w\s-]", "", Prompt).strip().replace(" ", "_")
177
+ filename = timestamp + "_" + filename_prompt[:100] + ".png"
178
+ file_path = IMAGE_DIR + filename
179
+
180
+ # Retry-Logik mit requests und Retry
181
+ session = Session()
182
+ retries = Retry(
183
+ total=3, status_forcelist=[429, 500, 502, 503, 504], backoff_factor=0.3, respect_retry_after_header=True
184
+ ) # Max 3 Versuche # Codes, die wiederholt werden # Exponential Backoff # Retry-Header beachten
185
+ adapter = HTTPAdapter(max_retries=retries)
186
+ session.mount("https://", adapter)
187
+ session.mount("http://", adapter)
188
+
189
+ u_model = re.sub("api\d-", "", used_model.lower())
190
+ API1_REQUEST_URL = f"{API1}{urllib.parse.quote(Prompt)}?model={u_model}&width={image_width}&height={image_height}&nologo=true&enhance=false&nofeed=true&seed={used_seed}"
191
+ API2_REQUEST_URL = f"{API2_IMAGE}?prompt={urllib.parse.quote(Prompt)}&size={urllib.parse.quote(image_ratio)}&seed={used_seed}&model={u_model}"
192
+ REQUEST_URL = API1_REQUEST_URL if used_model.lower().startswith("api1-") else API2_REQUEST_URL
193
+ print("REQUEST URL:\n" + REQUEST_URL + "\n\nImagine API Request started")
194
+
195
+ try:
196
+ response = session.get(REQUEST_URL, timeout=60)
197
+ if response.status_code == 200:
198
+ print("REQUEST URL:\n" + REQUEST_URL + "\n\nImagine API Request solved")
199
+ img = PILImage.open(BytesIO(response.content))
200
+ img.save(file_path, "png")
201
+ print("Save image to: ")
202
+ print(file_path)
203
+
204
+ # img_exif_comment = "" # read_exif(file_path)
205
+ img_dominant_color = image_get_dominant_color(file_path)
206
+ img_width, img_height = image_get_size(file_path)
207
+
208
+ new_gallery = [i for i in gallery] if gallery else []
209
+ new_gallery.append(file_path)
210
+ gallery = new_gallery
211
+
212
+ return (
213
+ {"value": Prompt, "__type__": "update"},
214
+ {"value": file_path, "__type__": "update"},
215
+ {"value": gallery, "selected_index": len(gallery) - 1, "__type__": "update"},
216
+ {"value": None, "visible": False, "__type__": "update"},
217
+ {"visible": True, "__type__": "update"},
218
+ {"value": Prompt, "visible": True, "__type__": "update"},
219
+ img_width,
220
+ img_height,
221
+ used_seed,
222
+ {"value": file_path, "visible": True, "__type__": "update"},
223
+ img_dominant_color,
224
+ used_seed,
225
+ )
226
+ else:
227
+ print("Imagine API Request ERROR")
228
+ raise gr.Error("Imagine API-Aufruf fehlgeschlagen 💥!", duration=15)
229
+ except requests.exceptions.Timeout:
230
+ raise gr.Error("⏰ Zeitüberschreitung beim API-Aufruf", duration=15)
231
+ except requests.exceptions.RequestException as e:
232
+ print(f"Unbekannter Fehler beim API-Aufruf: {e}")
233
+ raise gr.Error("Unbekannter Fehler beim API-Aufruf! 🤷‍♂️", duration=15)
234
+
235
+
236
+ def check_api(url):
237
+ try:
238
+ response = requests.get(url, timeout=8)
239
+ print(f"Checking Status for: {url}, it returns statuscode {response.status_code}")
240
+ return response.status_code
241
+ except requests.exceptions.RequestException as e:
242
+ print(f"An error occurred: {e}")
243
+ return int(999)
244
+
245
+
246
+ def get_inference_models():
247
+
248
+ status_api_1 = check_api(API1)
249
+ status_api_2 = check_api(API2)
250
+
251
+ info_api_1 = "🟢API1👍" if status_api_1 == 200 else "🔴API1👎🔌"
252
+ info_api_2 = "🟢API2👍" if status_api_2 == 200 else "🔴API2👎🔌"
253
+
254
+ api_models_1 = ["API1-FLUX", "API1-FLUX-Pro", "API1-FLUX-CablyAI", "API1-Turbo"]
255
+ api_models_2 = ["API2-FLUX-Realism", "API2-FLUX-Pixel", "API2-FLUX-Anime", "API2-FLUX-3D", "API2-FLUX-Disney", "API2-ANY-DARK"]
256
+
257
+ models = [model for model in api_models_1 if status_api_1 == 200] + [model for model in api_models_2 if status_api_2 == 200]
258
+ info_api_status = f"Status: {info_api_1} & {info_api_2}"
259
+
260
+ return gr.update(choices=models, value=models[0], interactive=True, info=info_api_status)
261
+
262
+
263
+ # MARK: Gradio BLOCKS UI
264
+ with gr.Blocks(theme=theme, head=custom_head, css=custom_css, js=custom_js, title=title) as demo:
265
+ with gr.Row(elem_classes="row-header"):
266
+ gr.Markdown(
267
+ f"""
268
+ <div class="flex-wrapper">
269
+ <div style="width: 100%">
270
+ <h1>{title}</h1>
271
+ <p class="errorinfo" style="color: #e26c5a; margin-top: 0.3rem; margin-bottom: 0.3rem;">Aktuell funktioniert die APP nicht, da ich heute wenig Zeit habe werde ich es erst morgen schaffen die Probleme zu beheben.</p>
272
+ <p>
273
+ <span style="font-weight: 600">LG Sebastian</span>
274
+ <i class="winking-hand-emoji"></i> gib dem Space gerne ein
275
+ <i class="heart-beat-emoji"></i>
276
+ </p>
277
+ </div>
278
+ <div style="">
279
+ <div class="btn-container">
280
+ <a title="Support me on ko-fi.com" class="kofi-button" style="background-color: #72a4f2" href="https://ko-fi.com/Z8Z316DSO4" target="_blank" >
281
+ <span class="kofitext"><img src="https://storage.ko-fi.com/cdn/cup-border.png" alt="Ko-fi donations" class="kofiimg"/>Support me on Ko-fi</span>
282
+ </a>
283
+ </div>
284
+ </div>
285
+ </div>
286
+ """,
287
+ elem_classes="md-header",
288
+ )
289
+
290
+ with gr.Tab("Bilder Builder"):
291
+ with gr.Row():
292
+ with gr.Column(scale=2): # min_width=420,
293
+ with gr.Row():
294
+ placeholder_text = "[???] Generiert dir einen zufälligen Prompt.\n[STERN] optimiert deinen eignen Prompt.\n[RUN] generiert dein Bild."
295
+ text_prompt = gr.Textbox(
296
+ label="Prompt",
297
+ show_label=False,
298
+ lines=12,
299
+ max_lines=18,
300
+ placeholder=placeholder_text,
301
+ elem_id="prompt_input",
302
+ elem_classes="prompt-input hide-progress",
303
+ autofocus=True,
304
+ )
305
+ with gr.Row():
306
+ random_prompt_button = gr.Button("", variant="secondary", elem_id="random_prompt_btn", elem_classes="random-prompt-btn", icon="_res/assets/star_light_48.png")
307
+ enhance_prompt_button = gr.Button(
308
+ "", variant="secondary", elem_id="enhance_prompt_btn", elem_classes="enhance-prompt-btn", icon="_res/assets/star_light_48.png"
309
+ )
310
+ run_button = gr.Button("Erstellen", variant="primary", elem_id="run_btn", elem_classes="run-btn", interactive=False)
311
+ with gr.Row(elem_classes="image_size_selctor_wrapper"):
312
+ with gr.Column(scale=1):
313
+ with gr.Row():
314
+ # inference_models, selected_model = get_inference_models()
315
+ # select_model = gr.Dropdown(choices=inference_models, value=selected_model, label="Model", elem_id="select_model", elem_classes="select-model")
316
+ select_model = gr.Dropdown(label="Model", elem_id="select_model", elem_classes="select-model")
317
+ # with gr.Row():
318
+ image_width = gr.Number(
319
+ label="Breite",
320
+ minimum=256,
321
+ maximum=MAX_IMAGE_SIZE,
322
+ value=576,
323
+ step=32,
324
+ elem_id="image_width_selector",
325
+ elem_classes="image-width-selector",
326
+ scale=1,
327
+ visible=False,
328
+ )
329
+ image_height = gr.Number(
330
+ label="Höhe",
331
+ minimum=256,
332
+ maximum=MAX_IMAGE_SIZE,
333
+ value=1024,
334
+ step=32,
335
+ elem_id="image_height_selector",
336
+ elem_classes="image-height-selector",
337
+ scale=1,
338
+ visible=False,
339
+ )
340
+ with gr.Row():
341
+ image_ratio_buttons = gr.Radio(
342
+ ["9:16", "3:4", "2:3", "1:1"],
343
+ value="9:16",
344
+ label="Hochformat",
345
+ show_label=True,
346
+ info="Seitenverhältniss drehen",
347
+ interactive=True,
348
+ elem_id="image_ratio_buttons",
349
+ elem_classes="image-ratio-buttons",
350
+ container=True,
351
+ scale=2,
352
+ )
353
+ switch_width_height = gr.Button("", size="sm", elem_id="switch_width_height", elem_classes="switch-ratio-btn", variant="primary", scale=1)
354
+ with gr.Column():
355
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True, elem_classes="random-seed-cb toggle-btn")
356
+ image_seed = gr.Slider(
357
+ label="Seed",
358
+ info="Jeder Seed generiert ein anderes Bild mit dem selben Prompt",
359
+ minimum=0,
360
+ step=1,
361
+ value=42,
362
+ maximum=MAX_SEED,
363
+ elem_id="image_seed",
364
+ elem_classes="image-seed hide-progress",
365
+ interactive=False,
366
+ )
367
+
368
+ with gr.Column(scale=4): # min_width=600,
369
+ with gr.Row():
370
+ with gr.Column(scale=1):
371
+ with gr.Row():
372
+ with gr.Column():
373
+ output_image = gr.Image(
374
+ show_label=False, min_width=320, elem_id="output_image", elem_classes="output-image", type="filepath", format="webp", visible=False
375
+ )
376
+ gallery = gr.Gallery(
377
+ label="Bisher erstellte Bilder",
378
+ show_label=True,
379
+ elem_id="gallery",
380
+ columns=[4],
381
+ object_fit="cover",
382
+ height="auto",
383
+ interactive=False,
384
+ type="filepath",
385
+ format="webp",
386
+ )
387
+ with gr.Column(scale=1, visible=False, elem_classes="image-info-wrapper") as image_info_wrapper:
388
+ with gr.Group():
389
+ image_informations = gr.Markdown("""## Bildinformationen""", visible=True)
390
+ with gr.Row(elem_classes="img-size-wrapper"):
391
+ image_info_tb_width = gr.Textbox(
392
+ label="Breite", lines=1, max_lines=1, interactive=False, show_copy_button=True, elem_classes="image-info-tb-width"
393
+ )
394
+ image_info_tb_height = gr.Textbox(
395
+ label="Höhe", lines=1, max_lines=1, interactive=False, show_copy_button=True, elem_classes="image-info-tb-height"
396
+ )
397
+ with gr.Row(elem_classes="img-seed-wrapper"):
398
+ image_info_tb_seed = gr.Textbox(label="Seed", lines=1, max_lines=1, interactive=False, show_copy_button=True, elem_classes="image-info-tb-seed")
399
+ image_info_tb_prompt = gr.Textbox(
400
+ "Bild Prompt", lines=4, max_lines=8, interactive=False, elem_classes="hide-progress", show_copy_button=True, visible=False
401
+ )
402
+ image_download_button = gr.DownloadButton("Bild herunterladen", value=None, elem_classes="download-button", variant="primary", visible=False)
403
+
404
+ output_url = gr.Textbox(label="Output URL", show_label=True, interactive=False, visible=False)
405
+ outpu_image_comment = gr.Json(visible=False)
406
+ output_dominant_image_color = gr.Textbox(show_label=False, elem_id="dominant_image_color", visible=True, elem_classes="output-dominant-image-color")
407
+
408
+ demo.load(
409
+ lambda x: ({"interactive": False, "__type__": "update"}, {"interactive": False, "__type__": "update"}, {"interactive": False, "__type__": "update"}),
410
+ outputs=[run_button, enhance_prompt_button, random_prompt_button],
411
+ ).then(get_inference_models, outputs=[select_model]).then(
412
+ lambda x: ({"interactive": True, "__type__": "update"}, {"interactive": True, "__type__": "update"}, {"interactive": True, "__type__": "update"}),
413
+ outputs=[run_button, enhance_prompt_button, random_prompt_button],
414
+ )
415
+
416
+ def switch_image_size_values(image_width, image_height):
417
+ return image_height, image_width
418
+
419
+ def switch_image_ratio_buttons(ratio_value):
420
+ ratio_value = ratio_value.split(":")
421
+ ratio_value_new = f"{int(ratio_value[1])}:{int(ratio_value[0])}"
422
+
423
+ if int(ratio_value[1]) > int(ratio_value[0]):
424
+ # Querformat
425
+ new_choises = ["16:9", "4:3", "3:2", "1:1"]
426
+ new_label = "Querformat"
427
+ elif int(ratio_value[1]) < int(ratio_value[0]):
428
+ # Hochformat
429
+ new_choises = ["9:16", "3:4", "2:3", "1:1"]
430
+ new_label = "Hochformat"
431
+ elif int(ratio_value[1]) == int(ratio_value[0]):
432
+ new_choises = image_ratio_buttons.choices
433
+ new_label = "Quadratisch"
434
+
435
+ return {"choices": new_choises, "value": ratio_value_new, "label": new_label, "__type__": "update"}
436
+
437
+ def calculate_ratio_values(image_ratio_buttons):
438
+ ratio_value = image_ratio_buttons.split(":")
439
+ if int(ratio_value[0]) > int(ratio_value[1]):
440
+ a = 1024
441
+ b = int(a * int(ratio_value[1]) / int(ratio_value[0]))
442
+ b = round(b / 8) * 8
443
+ new_width = a
444
+ new_height = b
445
+ new_label = "Querformat"
446
+ elif int(ratio_value[0]) < int(ratio_value[1]):
447
+ b = 1024
448
+ a = int(b * int(ratio_value[0]) / int(ratio_value[1]))
449
+ a = round(a / 8) * 8
450
+ new_width = a
451
+ new_height = b
452
+ new_label = "Hochformat"
453
+ elif int(ratio_value[0]) == int(ratio_value[1]):
454
+ new_width = 1024
455
+ new_height = 1024
456
+ new_label = "Quadratisch"
457
+
458
+ return {"label": new_label, "__type__": "update"}, new_width, new_height
459
+
460
+ switch_width_height.click(fn=switch_image_size_values, inputs=[image_width, image_height], outputs=[image_width, image_height], show_progress="hidden", show_api=False)
461
+ switch_width_height.click(fn=switch_image_ratio_buttons, inputs=[image_ratio_buttons], outputs=[image_ratio_buttons], show_progress="hidden", show_api=False)
462
+
463
+ image_ratio_buttons.input(
464
+ fn=calculate_ratio_values, inputs=[image_ratio_buttons], outputs=[image_ratio_buttons, image_width, image_height], show_progress="hidden", show_api=False
465
+ )
466
+
467
+ run_button.click(
468
+ fn=lambda: ({"interactive": False, "__type__": "update"}, {"interactive": False, "__type__": "update"}, {"interactive": False, "__type__": "update"}),
469
+ outputs=[run_button, enhance_prompt_button, random_prompt_button],
470
+ show_api=False,
471
+ js="() => document.querySelector('dotlottie-player').play()",
472
+ ).then(fn=clear_components, outputs=[output_image], show_api=False).then(
473
+ fn=process,
474
+ inputs=[text_prompt, select_model, image_width, image_height, image_ratio_buttons, image_seed, randomize_seed, gallery],
475
+ outputs=[
476
+ text_prompt,
477
+ output_image,
478
+ gallery,
479
+ output_url,
480
+ image_informations,
481
+ image_info_tb_prompt,
482
+ image_info_tb_width,
483
+ image_info_tb_height,
484
+ image_info_tb_seed,
485
+ image_download_button,
486
+ output_dominant_image_color,
487
+ image_seed,
488
+ ],
489
+ ).then(
490
+ fn=lambda: ({"interactive": True, "__type__": "update"}, {"interactive": True, "__type__": "update"}, {"interactive": True, "__type__": "update"}),
491
+ outputs=[run_button, enhance_prompt_button, random_prompt_button],
492
+ show_api=False,
493
+ js="() => document.querySelector('dotlottie-player').stop()",
494
+ )
495
+
496
+ randomize_seed.input(lambda x: {"interactive": False if x == True else True, "__type__": "update"}, inputs=[randomize_seed], outputs=[image_seed], show_api=False)
497
+
498
+ enhance_prompt_button.click(fn=groq_enhance_process, inputs=[text_prompt], outputs=[text_prompt], show_api=False)
499
+ random_prompt_button.click(fn=groq_enhance_process, inputs=None, outputs=[text_prompt], show_api=False)
500
+
501
+ # MARK: Gradio LAUNCH
502
+ demo.launch(show_api=True)
requirements.txt CHANGED
@@ -1,4 +1,6 @@
1
- gradio
2
- numpy
3
- groq
4
- exif
 
 
 
1
+ gradio
2
+ numpy
3
+ groq
4
+ exif
5
+ spaces
6
+ huggingface-hub