Diodaa commited on
Commit
2bb79e8
·
verified ·
1 Parent(s): f5de1ca

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +42 -0
  2. cuur.html +531 -0
  3. lorasdata.py +115 -0
  4. main.py +221 -0
Dockerfile ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.12-slim
2
+
3
+ RUN apt-get update && apt-get install -y --no-install-recommends libgomp1 wget unzip gnupg curl
4
+ RUN curl -fsSL https://pgp.mongodb.com/server-8.0.asc | gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg
5
+ RUN echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] http://repo.mongodb.org/apt/debian bookworm/mongodb-org/8.0 main" | tee /etc/apt/sources.list.d/mongodb-org-8.0.list
6
+ RUN apt-get update && apt-get install -y --no-install-recommends mongodb-org
7
+
8
+
9
+ RUN mkdir -p /app/sd && \
10
+ wget -q https://github.com/leejet/stable-diffusion.cpp/releases/download/master-564-fd35047/sd-master-fd35047-bin-Linux-Ubuntu-24.04-x86_64.zip -O /tmp/sd.zip && \
11
+ unzip /tmp/sd.zip -d /app/sd && \
12
+ chmod +x /app/sd/* && \
13
+ rm /tmp/sd.zip
14
+
15
+ RUN ls -aR /app
16
+ RUN pip install --no-cache-dir uvicorn[standard] fastapi requests pymongo huggingface_hub python-multipart
17
+
18
+ ENV LD_LIBRARY_PATH=/app/sd:$LD_LIBRARY_PATH
19
+ WORKDIR /app
20
+
21
+ COPY ./main.py /app/main.py
22
+ COPY ./cuur.html /app/cuur.html
23
+ COPY ./lorasdata.py /app/lorasdata.py
24
+ RUN mkdir -p /data/db && mkdir -p /var/log/mongodb
25
+
26
+ RUN wget -nv -c \
27
+ https://huggingface.co/leejet/Z-Image-Turbo-GGUF/resolve/main/z_image_turbo-Q4_0.gguf \
28
+ -P ./models/diffusion_models/
29
+
30
+ RUN wget -nv -c \
31
+ https://huggingface.co/unsloth/Qwen3-4B-Instruct-2507-GGUF/resolve/main/Qwen3-4B-Instruct-2507-Q4_0.gguf \
32
+ -P ./models/text_encoders/
33
+
34
+ RUN wget -nv -c \
35
+ https://huggingface.co/calcuis/pig-vae/resolve/main/pig_flux_vae_fp32-f16.gguf \
36
+ -P ./models/vae/
37
+ RUN ls -aR
38
+ EXPOSE 7860 27017
39
+ # CMD ["sh","mongod --fork --logpath /var/log/mongodb/mongod.log --bind_ip_all & uvicorn main:app --host 0.0.0.0 --port 7860"]
40
+ CMD mongod --fork --logpath /var/log/mongodb/mongod.log --bind_ip_all && \
41
+ until mongosh >/dev/null 2>&1; do sleep 1; done && \
42
+ exec uvicorn main:app --host 0.0.0.0 --port 7860
cuur.html ADDED
@@ -0,0 +1,531 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <link rel="shortcut icon"
8
+ href="data:image/png;base64,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" />
9
+ <title>SDCPP Server</title>
10
+ <style>
11
+ body {
12
+ font-family: Arial, sans-serif;
13
+ display: flex;
14
+ flex-direction: column;
15
+ align-items: center;
16
+ height: 100vh;
17
+ margin: 0;
18
+ background-color: #f0f0f0;
19
+ color: #333;
20
+ }
21
+
22
+ .container {
23
+ display: flex;
24
+ flex-direction: column;
25
+ justify-content: space-between;
26
+ align-items: center;
27
+ width: 90%;
28
+ height: auto;
29
+ min-height: auto;
30
+ background: white;
31
+ padding-inline: 20px;
32
+ border-radius: 10px;
33
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
34
+ gap: 1rem;
35
+ }
36
+
37
+ .header {
38
+ text-align: center;
39
+ }
40
+
41
+ .section {
42
+ width: 100%;
43
+ }
44
+
45
+ .section h2 {
46
+ margin-bottom: 10px;
47
+ }
48
+
49
+ .input-group {
50
+ display: flex;
51
+ flex-direction: column;
52
+ margin-bottom: 10px;
53
+ }
54
+
55
+ .input-group label {
56
+ margin-bottom: 5px;
57
+ font-weight: bold;
58
+ }
59
+
60
+
61
+ .prompt-input {
62
+ width: 100%;
63
+ padding: 10px;
64
+ border: 1px solid #ccc;
65
+ border-radius: 5px;
66
+ margin-bottom: 10px;
67
+ box-sizing: border-box;
68
+ resize: none;
69
+ }
70
+
71
+ .param-input {
72
+ width: 100%;
73
+ padding: 10px;
74
+ border: 1px solid #ccc;
75
+ border-radius: 5px;
76
+ margin-bottom: 10px;
77
+ box-sizing: border-box;
78
+ }
79
+
80
+ .line {
81
+ display: flex;
82
+ justify-content: space-between;
83
+ width: 100%;
84
+ }
85
+
86
+ .line .input-group {
87
+ width: 48%;
88
+ }
89
+
90
+ canvas {
91
+ width: 100%;
92
+ height: 100%;
93
+ }
94
+
95
+
96
+
97
+
98
+
99
+
100
+ .collapsible {
101
+ background-color: #eee;
102
+ color: #444;
103
+ cursor: pointer;
104
+ padding: 10px;
105
+ width: 100%;
106
+ border: none;
107
+ text-align: left;
108
+ outline: none;
109
+ font-size: 15px;
110
+ border-radius: 5px;
111
+ margin-bottom: 10px;
112
+ }
113
+
114
+ .content {
115
+ padding: 0 18px;
116
+ max-height: 0;
117
+ overflow: hidden;
118
+ transition: max-height 0.2s ease-out;
119
+ }
120
+
121
+ #model-id {
122
+ display: inline-block;
123
+ background: lightgray;
124
+ margin-bottom: 1rem;
125
+ padding: 5px 10px;
126
+ border-radius: 5px;
127
+ }
128
+
129
+ button {
130
+ background-color: #4CAF50;
131
+ color: white;
132
+ padding: 10px 20px;
133
+ border: none;
134
+ border-radius: 5px;
135
+ cursor: pointer;
136
+ font-size: 16px;
137
+ height: 3rem;
138
+ }
139
+
140
+ progress {
141
+ width: 100%;
142
+ }
143
+
144
+ button:hover {
145
+ background-color: #45a049;
146
+ }
147
+
148
+ .status {
149
+ margin-top: 5px;
150
+ font-size: 18px;
151
+ }
152
+
153
+
154
+ .left-section {
155
+ width: 100%;
156
+ height: auto;
157
+ padding: 15px;
158
+ box-sizing: border-box;
159
+ }
160
+
161
+ .right-section {
162
+ height: 100%;
163
+ width: 100%;
164
+ padding: 15px;
165
+ box-sizing: border-box;
166
+ }
167
+
168
+ @media (min-width: 768px) {
169
+ .container {
170
+ max-height: 95%;
171
+ min-height: 512px;
172
+ height: 95%;
173
+ flex-direction: row;
174
+ justify-content: space-between;
175
+ }
176
+
177
+ .left-section {
178
+ overflow-y: auto;
179
+ max-width: 100%;
180
+ max-height: 100%;
181
+ }
182
+
183
+
184
+ }
185
+
186
+ .image-container {
187
+ width: 100%;
188
+ height: 100%;
189
+ overflow-y: auto;
190
+ border: 1px solid #ccc;
191
+ display: flex;
192
+ flex-wrap: wrap;
193
+ gap: 10px;
194
+ padding: 10px;
195
+ background-color: #f5f5f5;
196
+ box-sizing: border-box;
197
+ }
198
+
199
+ .image-container img {
200
+ flex: 1 1 calc(33.333% - 10px);
201
+ min-width: 10px;
202
+ height: 150px;
203
+ object-fit: contain;
204
+ cursor: pointer;
205
+ display: inline-block;
206
+ vertical-align: top;
207
+ }
208
+
209
+
210
+ .fullscreen-overlay {
211
+ display: none;
212
+ position: fixed;
213
+ top: 0;
214
+ left: 0;
215
+ width: 100%;
216
+ height: 100%;
217
+ background-color: rgba(0, 0, 0, 0.9);
218
+ z-index: 1000;
219
+ justify-content: center;
220
+ align-items: center;
221
+ }
222
+
223
+ .fullscreen-content {
224
+ position: relative;
225
+ width: 90%;
226
+ height: 90%;
227
+ }
228
+
229
+ #fullscreenImg {
230
+ position: absolute;
231
+ top: 50%;
232
+ left: 50%;
233
+ transform: translate(-50%, -50%);
234
+ max-width: 90%;
235
+ max-height: 90%;
236
+ display: block;
237
+ margin: auto;
238
+ }
239
+
240
+ .nav-btn {
241
+ position: absolute;
242
+ top: 50%;
243
+ transform: translateY(-50%);
244
+ font-size: 40px;
245
+ color: white;
246
+ background: none;
247
+ border: none;
248
+ cursor: pointer;
249
+ padding: 10px;
250
+ }
251
+
252
+ .prev-btn {
253
+ left: 20px;
254
+ width: 30%;
255
+ height: 100%;
256
+ }
257
+
258
+ .next-btn {
259
+ right: 20px;
260
+ width: 30%;
261
+ height: 100%;
262
+ }
263
+
264
+
265
+ .close-btn {
266
+ position: absolute;
267
+ top: 20px;
268
+ right: 30px;
269
+ font-size: 50px;
270
+ color: white;
271
+ cursor: pointer;
272
+ }
273
+ </style>
274
+ </head>
275
+
276
+
277
+ <body>
278
+ <div class="header">
279
+ <p>Model:<span id="model-id">Z-Image-Turbo</span></p>
280
+ </div>
281
+ <div class="container">
282
+ <div class="left-section">
283
+ <div class="section">
284
+ <div class="input-group">
285
+ <label for="prompt">Prompt:</label>
286
+ <textarea id="prompt" rows="4" class="prompt-input"></textarea>
287
+ </div>
288
+ <div class="input-group">
289
+ <label for="neg_prompt">Negative Prompt:</label>
290
+ <textarea id="neg_prompt" rows="4"
291
+ class="prompt-input">blurry, ugly, bad vagina, deformed, unrealistic, multiple penises, extra arms, extra limbs, overexposed, dribbling, flat colours, labia, vagina</textarea>
292
+ </div>
293
+ <div class="line">
294
+ <button onclick="generateImage()">Generate</button>
295
+ <button onclick="update_queue()">status</button>
296
+ <button onclick="renderImages()">Gallery</button>
297
+ </div>
298
+ </div>
299
+ <div class="section">
300
+ <h2>Settings</h2>
301
+ <button class="collapsible">Loras</button>
302
+ <div id="lora_model" class="content">
303
+ </div>
304
+ <div class="line">
305
+ <div class="input-group">
306
+ <label for="gennum">Generate num:</label>
307
+ <input type="number" id="gennum" class="param-input" value=5>
308
+ </div>
309
+ <!-- <button onclick="addLora()">Add LoRA</button> -->
310
+ </div>
311
+ <div class="line">
312
+ <div class="input-group">
313
+ <label for="width">Width:</label>
314
+ <input type="number" id="width" class="param-input" value=960>
315
+ </div>
316
+ <div class="input-group">
317
+ <label for="height">Height:</label>
318
+ <input type="number" id="height" class="param-input" value=1280>
319
+ </div>
320
+ </div>
321
+ <div class="line">
322
+ <div class="input-group">
323
+ <label for="seed">Seed:</label>
324
+ <input type="number" id="seed" class="param-input" value=-1>
325
+ </div>
326
+ <div class="input-group">
327
+ <label for="batch_count">Batch Count:</label>
328
+ <input type="number" id="batch_count" class="param-input" value=2>
329
+ </div>
330
+ </div>
331
+ <div class="line">
332
+ <div class="input-group">
333
+ <label for="cfg_scale">CFG Scale:</label>
334
+ <input type="number" id="cfg_scale" class="param-input" value=1.0>
335
+ </div>
336
+ <div class="input-group">
337
+ <label for="steps">Steps:</label>
338
+ <input type="number" id="steps" class="param-input" value=4>
339
+ </div>
340
+ </div>
341
+ <div class="line">
342
+ <div class="input-group">
343
+ <label for="sample_method">Sample Method:</label>
344
+ <select id="sample_method" class="param-input">
345
+ <option value="euler">euler</option>
346
+ <option value="euler_a">euler_a</option>
347
+ <option value="heun">heun</option>
348
+ <option value="dpm++2s_a">dpm++2s_a</option>
349
+ <option value="dpm++2mv2">dpm++2mv2</option>
350
+ <option value="dpm++2m">dpm++2m</option>
351
+ <option value="dpm2">dpm2</option>
352
+ </select>
353
+ </div>
354
+ <div class="input-group">
355
+ <label for="scheduler">scheduler:</label>
356
+ <select id="scheduler" class="param-input">
357
+ <option value="discrete">discrete</option>
358
+ <option value="karras">karras</option>
359
+ <option value="simple">simple</option>
360
+ </select>
361
+ </div>
362
+ </div>
363
+ </div>
364
+ </div>
365
+ <div class="right-section">
366
+ <div class="image-container" id="imageContainer">
367
+ </div>
368
+ </div>
369
+ </div>
370
+ <div class="fullscreen-overlay" id="fullscreenOverlay">
371
+ <span class="close-btn" id="closeBtn">&times;</span>
372
+ <div class="fullscreen-content" id="fullscreenContent">
373
+ <img id="fullscreenImg" src="" alt="fullscreenImg">
374
+ <button class="nav-btn prev-btn" id="prevBtn">‹</button>
375
+ <button class="nav-btn next-btn" id="nextBtn">›</button>
376
+ </div>
377
+ </div>
378
+ <div class="status">
379
+ <p>Current task status: <span id="status"> -- </span> | Queue: <span id="queued_tasks">0</span></p>
380
+ </div>
381
+
382
+ <script>
383
+ async function addLora() {
384
+ const response = await fetch('/addLora', {
385
+ method: 'GET',
386
+ });
387
+ const data = await response.json();
388
+ //console.log("next", data.loras);
389
+ const lora_str = document.getElementById('lora_model');
390
+ lora_str.innerHTML = '';
391
+
392
+ data.loras.forEach((itemText, index) => {
393
+ const html = ` <label><input type="checkbox" name="loraitem" value=${index}>${itemText["title"]}</label><br>`;
394
+ lora_str.insertAdjacentHTML('beforeend', html);
395
+ });
396
+
397
+ }
398
+ async function update_queue() {
399
+ const response = await fetch('/status', {
400
+ method: 'GET',
401
+ });
402
+ const data = await response.json();
403
+ const display = document.getElementById('queued_tasks');
404
+ display.innerHTML = data.num;
405
+ const status = data.status;
406
+ document.getElementById('status').innerHTML = status;
407
+ }
408
+ async function generateImage() {
409
+ const prompt = document.getElementById('prompt').value;
410
+ const neg_prompt = document.getElementById('neg_prompt').value;
411
+ const width = document.getElementById('width').value;
412
+ const height = document.getElementById('height').value;
413
+ const cfg_scale = document.getElementById('cfg_scale').value;
414
+ const steps = document.getElementById('steps').value;
415
+ const sample_method = document.getElementById('sample_method').value;
416
+ const seed = document.getElementById('seed').value;
417
+ const batch_count = document.getElementById('batch_count').value;
418
+ const gennum = document.getElementById('gennum').value;
419
+ const scheduler = document.getElementById('scheduler').value;
420
+ const requestBody = {
421
+ prompt: prompt,
422
+ negative_prompt: neg_prompt,
423
+ width: width,
424
+ height: height,
425
+ cfg_scale: cfg_scale,
426
+ steps: steps,
427
+ sample_method: sample_method,
428
+ seed: seed,
429
+ batch_count: batch_count,
430
+ schedule: scheduler,
431
+ gennum: parseInt(gennum),
432
+ loras: getSelectedloras(),
433
+ };
434
+ const response = await fetch('/gen', {
435
+ method: 'POST',
436
+ headers: {
437
+ 'Content-Type': 'application/json'
438
+ },
439
+ body: JSON.stringify(requestBody)
440
+ });
441
+ const data = await response.json();
442
+ const status = data.status;
443
+ document.getElementById('status').innerHTML = status;
444
+ const display = document.getElementById('queued_tasks');
445
+ display.innerHTML = data.num;
446
+ }
447
+ var coll = document.getElementsByClassName("collapsible");
448
+ for (let i = 0; i < coll.length; i++) {
449
+ coll[i].addEventListener("click", function () {
450
+ this.classList.toggle("active");
451
+ var content = this.nextElementSibling;
452
+ content.style.transition = "max-height 0.3s ease-out"; // Add a transition effect
453
+ if (content.style.maxHeight) {
454
+ content.style.maxHeight = null;
455
+ } else {
456
+ content.style.maxHeight = content.scrollHeight + "px";
457
+ // Scroll to the top of the content
458
+ content.scrollTop = 0;
459
+ }
460
+ });
461
+ }
462
+ function getSelectedloras() {
463
+ const checkboxes = document.querySelectorAll('input[name="loraitem"]:checked');
464
+ const selectedValues = [];
465
+ checkboxes.forEach(checkbox => {
466
+ selectedValues.push(parseInt(checkbox.value));
467
+ });
468
+ return selectedValues;
469
+ }
470
+ const imageContainer = document.getElementById('imageContainer');
471
+ const fullscreenOverlay = document.getElementById('fullscreenOverlay');
472
+ const fullscreenImg = document.getElementById('fullscreenImg');
473
+ const closeBtn = document.getElementById('closeBtn');
474
+ const prevBtn = document.getElementById('prevBtn');
475
+ const nextBtn = document.getElementById('nextBtn');
476
+ const fullscreenContent = document.getElementById('fullscreenContent');
477
+
478
+
479
+ async function renderImages() {
480
+ const response = await fetch('getimages', {
481
+ method: 'GET',
482
+ });
483
+ const base64Images = await response.json().images;
484
+ imageContainer.innerHTML = '';
485
+ base64Images.forEach((src) => {
486
+ const img = document.createElement('img');
487
+ img.src = src;
488
+ img.onclick = () => openFullscreen(img);
489
+ imageContainer.appendChild(img);
490
+ });
491
+ }
492
+
493
+ function openFullscreen(index) {
494
+ index.id = "nowfullscreenImg"
495
+ fullscreenImg.src = index.src;
496
+ fullscreenOverlay.style.display = 'flex';
497
+ }
498
+
499
+ function closeFullscreen() {
500
+ document.getElementById('nowfullscreenImg').removeAttribute('id');
501
+ fullscreenOverlay.style.display = 'none';
502
+ }
503
+
504
+ function changeImage(direction) {
505
+ let con = document.getElementById('nowfullscreenImg');
506
+ let nextElement;
507
+ if (direction === 'next') {
508
+ // console.log("next");
509
+ nextElement = con.nextElementSibling;
510
+ } else if (direction === 'prev') {
511
+ nextElement = con.previousElementSibling;
512
+ }
513
+ if (nextElement) {
514
+ con.removeAttribute('id');
515
+ nextElement.id = "nowfullscreenImg"
516
+ fullscreenImg.src = nextElement.src;
517
+ }
518
+
519
+ }
520
+
521
+
522
+ closeBtn.onclick = closeFullscreen;
523
+ prevBtn.onclick = () => changeImage('prev');
524
+ nextBtn.onclick = () => changeImage('next');
525
+
526
+ addLora();
527
+ //renderImages();
528
+ </script>
529
+ </body>
530
+
531
+ </html>
lorasdata.py ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ loras = [
2
+
3
+ {
4
+ "image": "https://huggingface.co/Quorlen/Z_Image_Turbo_Colour_Grading_Tests_LoRA/resolve/main/images/ComfyUI_00003_.png",
5
+ "title": "Colour_Grading",
6
+ "repo": "Quorlen/Z_Image_Turbo_Colour_Grading_Tests_LoRA", # 0
7
+ "weights": "z_image_turbo_RGB_colors-#FF0006-#06FF00-#0006FF.safetensors",
8
+ "trigger_word": "",
9
+ "adapters": 1.0,
10
+ },
11
+ {
12
+ "image": "https://huggingface.co/Ttio2/Z-Image-Turbo-Ghibli-Style/resolve/main/images/z-image_00148_.png",
13
+ "title": "Ghibli",
14
+ "repo": "Ttio2/Z-Image-Turbo-Ghibli-Style", # 1
15
+ "weights": "ghibli_zimage_finetune.safetensors",
16
+ "trigger_word": "Ghibli style",
17
+ "adapters": 1.0,
18
+ },
19
+ {
20
+ "image": "https://huggingface.co/tarn59/pixel_art_style_lora_z_image_turbo/resolve/main/images/ComfyUI_00273_.png",
21
+ "title": "Pixel",
22
+ "repo": "tarn59/pixel_art_style_lora_z_image_turbo", # 2
23
+ "weights": "pixel_art_style_z_image_turbo.safetensors",
24
+ "trigger_word": "Pixel art style.",
25
+ "adapters": 1.0,
26
+ },
27
+ {
28
+ "image": "https://huggingface.co/renderartist/Saturday-Morning-Z-Image-Turbo/resolve/main/images/Saturday_Morning_Z_15.png",
29
+ "title": "Saturday",
30
+ "repo": "renderartist/Saturday-Morning-Z-Image-Turbo", # 3
31
+ "weights": "Saturday_Morning_Z_Image_Turbo_v1_renderartist_1250.safetensors",
32
+ "trigger_word": "saturd4ym0rning",
33
+ "adapters": 1.0,
34
+ },
35
+ {
36
+ "image": "https://huggingface.co/renderartist/Coloring-Book-Z-Image-Turbo-LoRA/resolve/main/images/CBZ_00274_.png",
37
+ "title": "Coloring",
38
+ "repo": "renderartist/Coloring-Book-Z-Image-Turbo-LoRA", # 4
39
+ "weights": "Coloring_Book_Z_Image_Turbo_v1_renderartist_2000.safetensors",
40
+ "trigger_word": "c0l0ringb00k",
41
+ "adapters": 1.0,
42
+ },
43
+ {
44
+ "image": "https://huggingface.co/wcde/Z-Image-Turbo-DeJPEG-Lora/resolve/main/images/01.png",
45
+ "title": "DeJPEG",
46
+ "repo": "wcde/Z-Image-Turbo-DeJPEG-Lora", # 5
47
+ "weights": "dejpeg_v3.safetensors",
48
+ "trigger_word": "",
49
+ "adapters": 1.0,
50
+ },
51
+ {
52
+ "image": "https://huggingface.co/suayptalha/Z-Image-Turbo-Realism-LoRA/resolve/main/images/n4aSpqa-YFXYo4dtcIg4W.png",
53
+ "title": "Realism",
54
+ "repo": "suayptalha/Z-Image-Turbo-Realism-LoRA", # 6
55
+ "weights": "pytorch_lora_weights.safetensors",
56
+ "trigger_word": "Realism",
57
+ "adapters": 1.0,
58
+ },
59
+ {
60
+ "image": "https://huggingface.co/renderartist/Classic-Painting-Z-Image-Turbo-LoRA/resolve/main/images/Classic_Painting_Z_00247_.png",
61
+ "title": "Classic",
62
+ "repo": "renderartist/Classic-Painting-Z-Image-Turbo-LoRA", # 7
63
+ "weights": "Classic_Painting_Z_Image_Turbo_v1_renderartist_1750.safetensors",
64
+ "trigger_word": "class1cpa1nt",
65
+ "adapters": 1.0,
66
+ },
67
+ {
68
+ "image": "https://huggingface.co/AiAF/D-ART_Z-Image-Turbo_LoRA/resolve/main/images/example_l3otpwzaz.png",
69
+ "title": "D-ART",
70
+ "repo": "AiAF/D-ART_Z-Image-Turbo_LoRA", # 8
71
+ "weights": "D-ART_Z-Image-Turbo.safetensors",
72
+ "trigger_word": "D-ART",
73
+ "adapters": 1.0,
74
+ },
75
+ {
76
+ "image": "https://huggingface.co/SkyAsl/Pixel-artist-Z/resolve/main/pixel-art-result.png",
77
+ "title": "Pixel-Z",
78
+ "repo": "SkyAsl/Pixel-artist-Z", # 9
79
+ "weights": "adapter_model.safetensors",
80
+ "trigger_word": "a pixel art character",
81
+ "adapters": 1.0,
82
+ },
83
+ # {
84
+ # "image": "https://huggingface.co/SkyAsl/Pixel-artist-Z/resolve/main/pixel-art-result.png",
85
+ # "title": "BoerBara",
86
+ # "repo": "BoerBaraBase.safetensors", # 10
87
+ # "weights": "",
88
+ # "trigger_word": "boerbara,This is a highly detailed, realistic digital painting of a muscular anthropomorphic",
89
+ # "adapters": 1.0,
90
+ # },
91
+ {
92
+ "image": "/Flaccid_VTX.png",
93
+ "title": "FlaccidVTX7",
94
+ "repo": "", # 10
95
+ "weights": "Flaccid_VTX7.safetensors",
96
+ "trigger_word": "flaccid penis",
97
+ "adapters": 0.9,
98
+ },
99
+ {
100
+ "image": "/zimage_penis_enc2_000007500.png",
101
+ "title": "zimage_penis_enc2_000007500",
102
+ "repo": "", # 11
103
+ "weights": "zimage_penis_enc2_000007500.safetensors",
104
+ "trigger_word": "flaccid penis,flaccid penis with foreskin and glans,uncircumcised flaccid penis",
105
+ "adapters": 0.9,
106
+ },
107
+ {
108
+ "image": "/zimage_uncutgems_v1.png",
109
+ "title": "zimage_uncutgems_v1",
110
+ "repo": "", # 12
111
+ "weights": "zimage_uncutgems_v1.safetensors",
112
+ "trigger_word": "uncutgems",
113
+ "adapters": 0.9,
114
+ },
115
+ ]
main.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Request, BackgroundTasks, UploadFile
2
+ from fastapi.responses import FileResponse
3
+ import subprocess
4
+ import json
5
+ import pymongo
6
+ from pymongo import MongoClient
7
+ import base64
8
+ from datetime import datetime
9
+ import time
10
+ from huggingface_hub import snapshot_download, hf_hub_download
11
+ import os
12
+ from bson import ObjectId
13
+ import shutil
14
+ import random
15
+
16
+ HF_TOKEN = os.environ.get("HF_TOKEN")
17
+ uri = os.getenv('MODEL_uri_ID')
18
+ client = MongoClient(uri)
19
+ database = client["szimg"]
20
+ collection = database["szimg"]
21
+ isrun = True
22
+ galleryimgs = []
23
+
24
+
25
+ buri = "mongodb://localhost:27017/"
26
+ bclient = MongoClient(buri)
27
+ bdatabase = bclient["szimg"]
28
+ bcollection = bdatabase["szimg"]
29
+
30
+ UPLOAD_DIR = "uploads"
31
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
32
+ IMAGES_DIR = "/app/qqq"
33
+ os.makedirs(IMAGES_DIR, exist_ok=True)
34
+ os.makedirs("lora", exist_ok=True)
35
+ os.makedirs("/app/data", exist_ok=True)
36
+
37
+ app = FastAPI()
38
+
39
+
40
+ @app.get("/")
41
+ def read_root():
42
+ return FileResponse("cuur.html")
43
+
44
+
45
+ @app.get("/status")
46
+ def greet():
47
+ return {"status": " -- " if isrun else " runing ", "num": bcollection.count_documents({})}
48
+
49
+
50
+ @app.post("/upload")
51
+ async def create_upload_file(file: UploadFile):
52
+ shutil.copy2(file.filename, "/app/data")
53
+ return {"file_size": file.size}
54
+
55
+
56
+ def load_pipeline():
57
+ try:
58
+ import lorasdata
59
+ te = True
60
+ for item in lorasdata.loras:
61
+ if item["repo"] == "":
62
+ if te:
63
+ te = False
64
+ path = snapshot_download(
65
+ repo_id="Diodaa/ppp",
66
+ local_dir="lora",
67
+ token=HF_TOKEN,
68
+ )
69
+ else:
70
+ path = hf_hub_download(
71
+ repo_id=item["repo"],
72
+ filename=item["weights"],
73
+ local_dir="lora",
74
+ )
75
+
76
+ # print(f" {item} : {path}")
77
+ except Exception as e:
78
+ print(f"download loras error: {e}")
79
+
80
+
81
+ load_pipeline()
82
+
83
+
84
+ def generate_image():
85
+ global isrun
86
+ global galleryimgs
87
+ print(f"generate_image", flush=True)
88
+
89
+ while True:
90
+ isrun = False
91
+ lp = ""
92
+ data2 = bcollection.find_one_and_delete({})
93
+ if data2 == None:
94
+ break
95
+ # print("jsondatas:", data2, flush=True)
96
+ # data2 = json.loads(jsondatas)
97
+ loradata = data2.get("loras", [])
98
+ if len(loradata) > 0:
99
+ lp = applyloras(loradata)
100
+ seed = data2.get("seed", "-1")
101
+ if seed == "-1":
102
+ seed = random.randint(0, 2**31 - 1)
103
+ fn = f'zimg-{datetime.fromtimestamp(time.time()).strftime("%Y%m%d-%H%M%S")}--{seed}-{"+".join(map(str, loradata))}'
104
+ filrna = f'{IMAGES_DIR}/{fn}'
105
+ command = [
106
+ '/app/sd/sd-cli',
107
+ '--diffusion-model', '/app/models/diffusion_models/z_image_turbo-Q4_0.gguf',
108
+ '--vae', '/app/models/vae/ae.safetensors',
109
+ '--llm', '/app/models/text_encoders/Qwen3-4B-Instruct-2507-Q4_0.gguf',
110
+ '-p', lp + data2["prompt"],
111
+ '-n', data2.get("negative_prompt", "blurry, ugly, bad vagina, deformed, unrealistic, multiple penises, extra arms, extra limbs, overexposed, dribbling, flat colours, labia, vagina"),
112
+ '--steps', data2.get("steps", "4"),
113
+ '--cfg-scale', data2.get("cfg_scale", "1.0"),
114
+ '-H', data2.get("height", "1280"),
115
+ '-W', data2.get("width", "960"),
116
+ '-s', str(seed),
117
+ '-b', data2.get("batch_count", "2"),
118
+ "--sampling-method", data2.get("sample_method", "euler"),
119
+ '--scheduler', data2.get("schedule", "discrete"),
120
+ '--lora-model-dir', "/app/lora/",
121
+ "-o", filrna,
122
+ "--vae-tiling",
123
+ '--diffusion-fa'
124
+ ]
125
+ # print("command:", command, flush=True)
126
+
127
+ result = subprocess.run(
128
+ command,
129
+ )
130
+ # print("JSONdata:", result.stdout, "error", result.stderr, flush=True)
131
+ bat = int(data2.get("batch_count", "2"))
132
+ if bat > 1:
133
+ for i in range(bat):
134
+ filrna = f'{IMAGES_DIR}/{fn}_{i}.png'
135
+ with open(filrna, "rb") as image_file:
136
+ base64_data = base64.b64encode(
137
+ image_file.read()).decode('utf-8')
138
+
139
+ try:
140
+ # start example code here
141
+ na = f'{fn}_{i}'
142
+ collection.insert_one({na: base64_data})
143
+ except Exception as e:
144
+ raise Exception(
145
+ "The following error occurred: ", e)
146
+
147
+ if len(galleryimgs) >= 30:
148
+ # Remove oldest image if max size reached
149
+ file_to_delete = galleryimgs.pop(0)
150
+ if os.path.exists(file_to_delete):
151
+ os.remove(file_to_delete)
152
+ galleryimgs.append(filrna)
153
+ else:
154
+ filrna = f'{IMAGES_DIR}/{fn}.png'
155
+ with open(filrna, "rb") as image_file:
156
+ base64_data = base64.b64encode(
157
+ image_file.read()).decode('utf-8')
158
+
159
+ try:
160
+ # start example code here
161
+ na = f'{fn}'
162
+ collection.insert_one({na: base64_data})
163
+ except Exception as e:
164
+ raise Exception(
165
+ "The following error occurred: ", e)
166
+
167
+ if len(galleryimgs) >= 30:
168
+ # Remove oldest image if max size reached
169
+ file_to_delete = galleryimgs.pop(0)
170
+ if os.path.exists(file_to_delete):
171
+ os.remove(file_to_delete)
172
+ galleryimgs.append(filrna)
173
+ isrun = True
174
+
175
+
176
+ @app.post("/gen")
177
+ async def add_string(request: Request, background_tasks: BackgroundTasks):
178
+ global isrun
179
+ data2 = await request.json()
180
+ # print(f"add_string data2:", data2)
181
+ document_list = []
182
+ num = data2.get("gennum", 4)
183
+ for i in range(num):
184
+ data2["_id"] = ObjectId()
185
+ document_list.append(data2.copy())
186
+ result = bcollection.insert_many(document_list)
187
+ # result = bcollection.insert_one([data2])
188
+ # print(f"add_string {result}", document_list)
189
+ if isrun:
190
+ isrun = False
191
+ background_tasks.add_task(generate_image)
192
+
193
+ return {"status": " -- " if isrun else " runing ", "num": bcollection.count_documents({})}
194
+
195
+
196
+ def applyloras(loraData):
197
+ import lorasdata
198
+ loras = ""
199
+
200
+ for i in loraData:
201
+ lora = lorasdata.loras[i]
202
+ name, ext = os.path.splitext(lora["weights"])
203
+ adapters = lora["adapters"]
204
+ trigger_words = lora["trigger_word"]
205
+ loras += f'<lora:{name}:{adapters}>, {trigger_words}, '
206
+
207
+ # print("applyloras", loras)
208
+ return loras
209
+
210
+
211
+ @app.get("/addLora")
212
+ def addLora():
213
+ import lorasdata
214
+ # print("addLora", lorasdata.loras)
215
+ return {"loras": lorasdata.loras}
216
+
217
+
218
+ @app.get("/getimages")
219
+ def add_image():
220
+ # print("add_image", galleryimgs)
221
+ return {"images": galleryimgs}