vorstcavry commited on
Commit
9b12a20
1 Parent(s): 9da7679

Upload 3 files

Browse files
extensions/Additional-Networks/fix/metadata_editor.py ADDED
@@ -0,0 +1,623 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import sys
4
+ import io
5
+ import base64
6
+ import platform
7
+ import subprocess as sp
8
+ from PIL import PngImagePlugin, Image
9
+
10
+ from modules import shared
11
+ import gradio as gr
12
+
13
+ import modules.ui
14
+ from modules.ui_components import ToolButton
15
+ import modules.extras
16
+ import modules.generation_parameters_copypaste as parameters_copypaste
17
+
18
+ from scripts import safetensors_hack, model_util
19
+ from scripts.model_util import MAX_MODEL_COUNT
20
+
21
+
22
+ folder_symbol = "\U0001f4c2" # 📂
23
+ keycap_symbols = [
24
+ "\u0031\ufe0f\u20e3", # 1️⃣
25
+ "\u0032\ufe0f\u20e3", # 2️⃣
26
+ "\u0033\ufe0f\u20e3", # 3️⃣
27
+ "\u0034\ufe0f\u20e3", # 4️⃣
28
+ "\u0035\ufe0f\u20e3", # 5️⃣
29
+ "\u0036\ufe0f\u20e3", # 6️⃣
30
+ "\u0037\ufe0f\u20e3", # 7️⃣
31
+ "\u0038\ufe0f\u20e3", # 8️
32
+ "\u0039\ufe0f\u20e3", # 9️
33
+ "\u1f51f", # 🔟
34
+ ]
35
+
36
+
37
+ def write_webui_model_preview_image(model_path, image):
38
+ basename, ext = os.path.splitext(model_path)
39
+ preview_path = f"{basename}.png"
40
+
41
+ # Copy any text-only metadata
42
+ use_metadata = False
43
+ metadata = PngImagePlugin.PngInfo()
44
+ for key, value in image.info.items():
45
+ if isinstance(key, str) and isinstance(value, str):
46
+ metadata.add_text(key, value)
47
+ use_metadata = True
48
+
49
+ image.save(preview_path, "PNG", pnginfo=(metadata if use_metadata else None))
50
+
51
+
52
+ def delete_webui_model_preview_image(model_path):
53
+ basename, ext = os.path.splitext(model_path)
54
+ preview_paths = [f"{basename}.preview.png", f"{basename}.png"]
55
+
56
+ for preview_path in preview_paths:
57
+ if os.path.isfile(preview_path):
58
+ os.unlink(preview_path)
59
+
60
+
61
+ def decode_base64_to_pil(encoding):
62
+ if encoding.startswith("data:image/"):
63
+ encoding = encoding.split(";")[1].split(",")[1]
64
+ return Image.open(io.BytesIO(base64.b64decode(encoding)))
65
+
66
+
67
+ def encode_pil_to_base64(image):
68
+ with io.BytesIO() as output_bytes:
69
+ # Copy any text-only metadata
70
+ use_metadata = False
71
+ metadata = PngImagePlugin.PngInfo()
72
+ for key, value in image.info.items():
73
+ if isinstance(key, str) and isinstance(value, str):
74
+ metadata.add_text(key, value)
75
+ use_metadata = True
76
+
77
+ image.save(output_bytes, "PNG", pnginfo=(metadata if use_metadata else None))
78
+ bytes_data = output_bytes.getvalue()
79
+ return base64.b64encode(bytes_data)
80
+
81
+
82
+ def open_folder(f):
83
+ if not os.path.exists(f):
84
+ print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.')
85
+ return
86
+ elif not os.path.isdir(f):
87
+ print(
88
+ f"""
89
+ WARNING
90
+ An open_folder request was made with an argument that is not a folder.
91
+ This could be an error or a malicious attempt to run code on your computer.
92
+ Requested path was: {f}
93
+ """,
94
+ file=sys.stderr,
95
+ )
96
+ return
97
+
98
+ if not shared.cmd_opts.hide_ui_dir_config:
99
+ path = os.path.normpath(f)
100
+ if platform.system() == "Windows":
101
+ os.startfile(path)
102
+ elif platform.system() == "Darwin":
103
+ sp.Popen(["open", path])
104
+ elif "microsoft-standard-WSL2" in platform.uname().release:
105
+ sp.Popen(["wsl-open", path])
106
+ else:
107
+ sp.Popen(["xdg-open", path])
108
+
109
+
110
+ def copy_metadata_to_all(module, model_path, copy_dir, same_session_only, missing_meta_only, cover_image):
111
+ """
112
+ Given a model with metadata, copies that metadata to all models in copy_dir.
113
+
114
+ :str module: Module name ("LoRA")
115
+ :str model: Model key in lora_models ("MyModel(123456abcdef)")
116
+ :str copy_dir: Directory to copy to
117
+ :bool same_session_only: Only copy to modules with the same ss_session_id
118
+ :bool missing_meta_only: Only copy to modules that are missing user metadata
119
+ :Optional[Image] cover_image: Cover image to embed in the file as base64
120
+ :returns: gr.HTML.update()
121
+ """
122
+ if model_path == "None":
123
+ return "No model selected."
124
+
125
+ if not os.path.isfile(model_path):
126
+ return f"Model path not found: {model_path}"
127
+
128
+ model_path = os.path.realpath(model_path)
129
+
130
+ if os.path.splitext(model_path)[1] != ".safetensors":
131
+ return "Model is not in .safetensors format."
132
+
133
+ if not os.path.isdir(copy_dir):
134
+ return "Please provide a directory containing models in .safetensors format."
135
+
136
+ print(f"[MetadataEditor] Copying metadata to models in {copy_dir}.")
137
+ metadata = model_util.read_model_metadata(model_path, module)
138
+ count = 0
139
+ for entry in os.scandir(copy_dir):
140
+ if entry.is_file():
141
+ path = os.path.realpath(os.path.join(copy_dir, entry.name))
142
+ if path != model_path and model_util.is_safetensors(path):
143
+ if same_session_only:
144
+ other_metadata = safetensors_hack.read_metadata(path)
145
+ if missing_meta_only and other_metadata.get("ssmd_display_name", "").strip():
146
+ print(f"[MetadataEditor] Skipping {path} as it already has metadata")
147
+ continue
148
+
149
+ session_id = metadata.get("ss_session_id", None)
150
+ other_session_id = other_metadata.get("ss_session_id", None)
151
+ if session_id is None or other_session_id is None or session_id != other_session_id:
152
+ continue
153
+
154
+ updates = {
155
+ "ssmd_cover_images": "[]",
156
+ "ssmd_display_name": "",
157
+ "ssmd_version": "",
158
+ "ssmd_keywords": "",
159
+ "ssmd_author": "",
160
+ "ssmd_source": "",
161
+ "ssmd_description": "",
162
+ "ssmd_rating": "0",
163
+ "ssmd_tags": "",
164
+ }
165
+
166
+ for k, v in metadata.items():
167
+ if k.startswith("ssmd_") and k != "ssmd_cover_images":
168
+ updates[k] = v
169
+
170
+ model_util.write_model_metadata(path, module, updates)
171
+ count += 1
172
+
173
+ print(f"[MetadataEditor] Updated {count} models in directory {copy_dir}.")
174
+ return f"Updated {count} models in directory {copy_dir}."
175
+
176
+
177
+ def load_cover_image(model_path, metadata):
178
+ """
179
+ Loads a cover image either from embedded metadata or an image file with
180
+ .preview.png/.png format
181
+ """
182
+ cover_images = json.loads(metadata.get("ssmd_cover_images", "[]"))
183
+ cover_image = None
184
+ if len(cover_images) > 0:
185
+ print("[MetadataEditor] Loading embedded cover image.")
186
+ cover_image = decode_base64_to_pil(cover_images[0])
187
+ else:
188
+ basename, ext = os.path.splitext(model_path)
189
+
190
+ preview_paths = [f"{basename}.preview.png", f"{basename}.png"]
191
+
192
+ for preview_path in preview_paths:
193
+ if os.path.isfile(preview_path):
194
+ print(f"[MetadataEditor] Loading webui preview image: {preview_path}")
195
+ cover_image = Image.open(preview_path)
196
+
197
+ return cover_image
198
+
199
+
200
+ # Dummy value since gr.Dataframe cannot handle an empty list
201
+ # https://github.com/gradio-app/gradio/issues/3182
202
+ unknown_folders = ["(Unknown)", 0, 0, 0]
203
+
204
+
205
+ def refresh_metadata(module, model_path):
206
+ """
207
+ Reads metadata from the model on disk and updates all Gradio components
208
+ """
209
+ if model_path == "None":
210
+ return {}, None, "", "", "", "", "", 0, "", "", "", "", "", {}, [unknown_folders]
211
+
212
+ if not os.path.isfile(model_path):
213
+ return (
214
+ {"info": f"Model path not found: {model_path}"},
215
+ None,
216
+ "",
217
+ "",
218
+ "",
219
+ "",
220
+ "",
221
+ 0,
222
+ "",
223
+ "",
224
+ "",
225
+ "",
226
+ "",
227
+ {},
228
+ [unknown_folders],
229
+ )
230
+
231
+ if os.path.splitext(model_path)[1] != ".safetensors":
232
+ return (
233
+ {"info": "Model is not in .safetensors format."},
234
+ None,
235
+ "",
236
+ "",
237
+ "",
238
+ "",
239
+ "",
240
+ 0,
241
+ "",
242
+ "",
243
+ "",
244
+ "",
245
+ "",
246
+ {},
247
+ [unknown_folders],
248
+ )
249
+
250
+ metadata = model_util.read_model_metadata(model_path, module)
251
+
252
+ if metadata is None:
253
+ training_params = {}
254
+ metadata = {}
255
+ else:
256
+ training_params = {k: v for k, v in metadata.items() if k.startswith("ss_")}
257
+
258
+ cover_image = load_cover_image(model_path, metadata)
259
+
260
+ display_name = metadata.get("ssmd_display_name", "")
261
+ author = metadata.get("ssmd_author", "")
262
+ # version = metadata.get("ssmd_version", "")
263
+ source = metadata.get("ssmd_source", "")
264
+ keywords = metadata.get("ssmd_keywords", "")
265
+ description = metadata.get("ssmd_description", "")
266
+ rating = int(metadata.get("ssmd_rating", "0"))
267
+ tags = metadata.get("ssmd_tags", "")
268
+ model_hash = metadata.get("sshs_model_hash", model_util.cache("hashes").get(model_path, {}).get("model", ""))
269
+ legacy_hash = metadata.get("sshs_legacy_hash", model_util.cache("hashes").get(model_path, {}).get("legacy", ""))
270
+
271
+ top_tags = {}
272
+ if "ss_tag_frequency" in training_params:
273
+ tag_frequency = json.loads(training_params.pop("ss_tag_frequency"))
274
+ count_max = 0
275
+ for dir, frequencies in tag_frequency.items():
276
+ for tag, count in frequencies.items():
277
+ tag = tag.strip()
278
+ existing = top_tags.get(tag, 0)
279
+ top_tags[tag] = count + existing
280
+ if len(top_tags) > 0:
281
+ top_tags = dict(sorted(top_tags.items(), key=lambda x: x[1], reverse=True))
282
+
283
+ count_max = max(top_tags.values())
284
+ top_tags = {k: float(v / count_max) for k, v in top_tags.items()}
285
+
286
+ dataset_folders = []
287
+ if "ss_dataset_dirs" in training_params:
288
+ dataset_dirs = json.loads(training_params.pop("ss_dataset_dirs"))
289
+ for dir, counts in dataset_dirs.items():
290
+ img_count = int(counts["img_count"])
291
+ n_repeats = int(counts["n_repeats"])
292
+ dataset_folders.append([dir, img_count, n_repeats, img_count * n_repeats])
293
+ if dataset_folders:
294
+ dataset_folders.append(
295
+ ["(Total)", sum(r[1] for r in dataset_folders), sum(r[2] for r in dataset_folders), sum(r[3] for r in dataset_folders)]
296
+ )
297
+ else:
298
+ dataset_folders.append(unknown_folders)
299
+
300
+ return (
301
+ training_params,
302
+ cover_image,
303
+ display_name,
304
+ author,
305
+ source,
306
+ keywords,
307
+ description,
308
+ rating,
309
+ tags,
310
+ model_hash,
311
+ legacy_hash,
312
+ model_path,
313
+ os.path.dirname(model_path),
314
+ top_tags,
315
+ dataset_folders,
316
+ )
317
+
318
+
319
+ def save_metadata(module, model_path, cover_image, display_name, author, source, keywords, description, rating, tags):
320
+ """
321
+ Writes metadata from the Gradio components to the model file
322
+ """
323
+ if model_path == "None":
324
+ return "No model selected.", "", ""
325
+
326
+ if not os.path.isfile(model_path):
327
+ return f"file not found: {model_path}", "", ""
328
+
329
+ if os.path.splitext(model_path)[1] != ".safetensors":
330
+ return "Model is not in .safetensors format", "", ""
331
+
332
+ metadata = safetensors_hack.read_metadata(model_path)
333
+ model_hash = safetensors_hack.hash_file(model_path)
334
+ legacy_hash = model_util.get_legacy_hash(metadata, model_path)
335
+
336
+ # TODO: Support multiple images
337
+ # Blocked on gradio not having a gallery upload option
338
+ # https://github.com/gradio-app/gradio/issues/1379
339
+ cover_images = []
340
+ if cover_image is not None:
341
+ cover_images.append(encode_pil_to_base64(cover_image).decode("ascii"))
342
+
343
+ # NOTE: User-specified metadata should NOT be prefixed with "ss_". This is
344
+ # to maintain backwards compatibility with the old hashing method. "ss_"
345
+ # should be used for training parameters that will never be manually
346
+ # updated on the model.
347
+ updates = {
348
+ "ssmd_cover_images": json.dumps(cover_images),
349
+ "ssmd_display_name": display_name,
350
+ "ssmd_author": author,
351
+ # "ssmd_version": version,
352
+ "ssmd_source": source,
353
+ "ssmd_keywords": keywords,
354
+ "ssmd_description": description,
355
+ "ssmd_rating": rating,
356
+ "ssmd_tags": tags,
357
+ "sshs_model_hash": model_hash,
358
+ "sshs_legacy_hash": legacy_hash,
359
+ }
360
+
361
+ model_util.write_model_metadata(model_path, module, updates)
362
+ if cover_image is None:
363
+ delete_webui_model_preview_image(model_path)
364
+ else:
365
+ write_webui_model_preview_image(model_path, cover_image)
366
+
367
+ model_name = os.path.basename(model_path)
368
+ return f"Model saved: {model_name}", model_hash, legacy_hash
369
+
370
+
371
+ model_name_filter = ""
372
+
373
+
374
+ def get_filtered_model_paths(s):
375
+ # newer Gradio seems to show None in the list?
376
+ # if not s:
377
+ # return ["None"] + list(model_util.lora_models.values())
378
+ # return ["None"] + [v for v in model_util.lora_models.values() if v and s in v.lower()]
379
+ if not s:
380
+ l = list(model_util.lora_models.values())
381
+ else:
382
+ l = [v for v in model_util.lora_models.values() if v and s in v.lower()]
383
+ l = [v for v in l if v] # remove None
384
+ l = ["None"] + l
385
+ return l
386
+
387
+ def get_filtered_model_paths_global():
388
+ global model_name_filter
389
+ return get_filtered_model_paths(model_name_filter)
390
+
391
+
392
+ def setup_ui(addnet_paste_params):
393
+ """
394
+ :dict addnet_paste_params: Dictionary of txt2img/img2img controls for each model weight slider,
395
+ for sending module and model to them from the metadata editor
396
+ """
397
+ can_edit = False
398
+
399
+ with gr.Row(equal_height=True):
400
+ # Lefthand column
401
+ with gr.Column(variant="panel"):
402
+ # Module and model selector
403
+ with gr.Row():
404
+ model_filter = gr.Textbox("", label="Model path filter", placeholder="Filter models by path name")
405
+
406
+ def update_model_filter(s):
407
+ global model_name_filter
408
+ model_name_filter = s.strip().lower()
409
+
410
+ model_filter.change(update_model_filter, inputs=[model_filter], outputs=[])
411
+ with gr.Row():
412
+ module = gr.Dropdown(
413
+ ["LoRA"],
414
+ label="Network module",
415
+ value="LoRA",
416
+ interactive=True,
417
+ elem_id="additional_networks_metadata_editor_module",
418
+ )
419
+ model = gr.Dropdown(
420
+ get_filtered_model_paths_global(),
421
+ label="Model",
422
+ value="None",
423
+ interactive=True,
424
+ elem_id="additional_networks_metadata_editor_model",
425
+ )
426
+ modules.ui.create_refresh_button(
427
+ model, model_util.update_models, lambda: {"choices": get_filtered_model_paths_global()}, "refresh_lora_models"
428
+ )
429
+
430
+ def submit_model_filter(s):
431
+ global model_name_filter
432
+ model_name_filter = s
433
+ paths = get_filtered_model_paths(s)
434
+ return gr.Dropdown.update(choices=paths, value="None")
435
+
436
+ model_filter.submit(submit_model_filter, inputs=[model_filter], outputs=[model])
437
+
438
+ # Model hashes and path
439
+ with gr.Row():
440
+ model_hash = gr.Textbox("", label="Model hash", interactive=False)
441
+ legacy_hash = gr.Textbox("", label="Legacy hash", interactive=False)
442
+ with gr.Row():
443
+ model_path = gr.Textbox("", label="Model path", interactive=False)
444
+ open_folder_button = ToolButton(
445
+ value=folder_symbol,
446
+ elem_id="hidden_element" if shared.cmd_opts.hide_ui_dir_config else "open_folder_metadata_editor",
447
+ )
448
+
449
+ # Send to txt2img/img2img buttons
450
+ for tabname in ["txt2img", "img2img"]:
451
+ with gr.Row():
452
+ with gr.Box():
453
+ with gr.Row():
454
+ gr.HTML(f"Send to {tabname}:")
455
+ for i in range(MAX_MODEL_COUNT):
456
+ send_to_button = ToolButton(
457
+ value=keycap_symbols[i], elem_id=f"additional_networks_send_to_{tabname}_{i}"
458
+ )
459
+ send_to_button.click(
460
+ fn=lambda modu, mod: (modu, model_util.find_closest_lora_model_name(mod) or "None"),
461
+ inputs=[module, model],
462
+ outputs=[addnet_paste_params[tabname][i]["module"], addnet_paste_params[tabname][i]["model"]],
463
+ )
464
+ send_to_button.click(fn=None, _js=f"addnet_switch_to_{tabname}", inputs=None, outputs=None)
465
+
466
+ # "Copy metadata to other models" panel
467
+ with gr.Row():
468
+ with gr.Column():
469
+ gr.HTML(value="Copy metadata to other models in directory")
470
+ copy_metadata_dir = gr.Textbox(
471
+ "",
472
+ label="Containing directory",
473
+ placeholder="All models in this directory will receive the selected model's metadata",
474
+ )
475
+ with gr.Row():
476
+ copy_same_session = gr.Checkbox(True, label="Only copy to models with same session ID")
477
+ copy_no_metadata = gr.Checkbox(True, label="Only copy to models with no metadata")
478
+ copy_metadata_button = gr.Button("Copy Metadata", variant="primary")
479
+
480
+ # Center column, metadata viewer/editor
481
+ with gr.Column():
482
+ with gr.Row():
483
+ display_name = gr.Textbox(value="", label="Name", placeholder="Display name for this model", interactive=can_edit)
484
+ author = gr.Textbox(value="", label="Author", placeholder="Author of this model", interactive=can_edit)
485
+ with gr.Row():
486
+ keywords = gr.Textbox(
487
+ value="", label="Keywords", placeholder="Activation keywords, comma-separated", interactive=can_edit
488
+ )
489
+ with gr.Row():
490
+ description = gr.Textbox(
491
+ value="",
492
+ label="Description",
493
+ placeholder="Model description/readme/notes/instructions",
494
+ lines=15,
495
+ interactive=can_edit,
496
+ )
497
+ with gr.Row():
498
+ source = gr.Textbox(
499
+ value="", label="Source", placeholder="Source URL where this model could be found", interactive=can_edit
500
+ )
501
+ with gr.Row():
502
+ rating = gr.Slider(minimum=0, maximum=10, step=1, label="Rating", value=0, interactive=can_edit)
503
+ tags = gr.Textbox(
504
+ value="",
505
+ label="Tags",
506
+ placeholder='Comma-separated list of tags ("artist, style, character, 2d, 3d...")',
507
+ lines=2,
508
+ interactive=can_edit,
509
+ )
510
+ with gr.Row():
511
+ editing_enabled = gr.Checkbox(label="Editing Enabled", value=can_edit)
512
+ with gr.Row():
513
+ save_metadata_button = gr.Button("Save Metadata", variant="primary", interactive=can_edit)
514
+ with gr.Row():
515
+ save_output = gr.HTML("")
516
+
517
+ # Righthand column, cover image and training parameters view
518
+ with gr.Column():
519
+ # Cover image
520
+ with gr.Row():
521
+ cover_image = gr.Image(
522
+ label="Cover image",
523
+ elem_id="additional_networks_cover_image",
524
+ source="upload",
525
+ interactive=can_edit,
526
+ type="pil",
527
+ image_mode="RGBA",
528
+ height=480
529
+ )
530
+
531
+ # Image parameters
532
+ with gr.Accordion("Image Parameters", open=False):
533
+ with gr.Row():
534
+ info2 = gr.HTML()
535
+ with gr.Row():
536
+ try:
537
+ send_to_buttons = parameters_copypaste.create_buttons(["txt2img", "img2img", "inpaint", "extras"])
538
+ except:
539
+ pass
540
+
541
+ # Training info, below cover image
542
+ with gr.Accordion("Training info", open=False):
543
+ # Top tags used
544
+ with gr.Row():
545
+ max_top_tags = int(shared.opts.data.get("additional_networks_max_top_tags", 20))
546
+ most_frequent_tags = gr.Label(value={}, label="Most frequent tags in captions", num_top_classes=max_top_tags)
547
+
548
+ # Dataset folders
549
+ with gr.Row():
550
+ max_dataset_folders = int(shared.opts.data.get("additional_networks_max_dataset_folders", 20))
551
+ dataset_folders = gr.Dataframe(
552
+ headers=["Name", "Image Count", "Repeats", "Total Images"],
553
+ datatype=["str", "number", "number", "number"],
554
+ label="Dataset folder structure",
555
+ max_rows=max_dataset_folders,
556
+ col_count=(4, "fixed"),
557
+ )
558
+
559
+ # Training Parameters
560
+ with gr.Row():
561
+ metadata_view = gr.JSON(value={}, label="Training parameters")
562
+
563
+ # Hidden/internal
564
+ with gr.Row(visible=False):
565
+ info1 = gr.HTML()
566
+ img_file_info = gr.Textbox(label="Generate Info", interactive=False, lines=6)
567
+
568
+ open_folder_button.click(fn=lambda p: open_folder(os.path.dirname(p)), inputs=[model_path], outputs=[])
569
+ copy_metadata_button.click(
570
+ fn=copy_metadata_to_all,
571
+ inputs=[module, model, copy_metadata_dir, copy_same_session, copy_no_metadata, cover_image],
572
+ outputs=[save_output],
573
+ )
574
+
575
+ def update_editing(enabled):
576
+ """
577
+ Enable/disable components based on "Editing Enabled" status
578
+ """
579
+ updates = [gr.Textbox.update(interactive=enabled)] * 6
580
+ updates.append(gr.Image.update(interactive=enabled))
581
+ updates.append(gr.Slider.update(interactive=enabled))
582
+ updates.append(gr.Button.update(interactive=enabled))
583
+ return updates
584
+
585
+ editing_enabled.change(
586
+ fn=update_editing,
587
+ inputs=[editing_enabled],
588
+ outputs=[display_name, author, source, keywords, description, tags, cover_image, rating, save_metadata_button],
589
+ )
590
+
591
+ cover_image.change(fn=modules.extras.run_pnginfo, inputs=[cover_image], outputs=[info1, img_file_info, info2])
592
+
593
+ try:
594
+ parameters_copypaste.bind_buttons(send_to_buttons, cover_image, img_file_info)
595
+ except:
596
+ pass
597
+
598
+ model.change(
599
+ refresh_metadata,
600
+ inputs=[module, model],
601
+ outputs=[
602
+ metadata_view,
603
+ cover_image,
604
+ display_name,
605
+ author,
606
+ source,
607
+ keywords,
608
+ description,
609
+ rating,
610
+ tags,
611
+ model_hash,
612
+ legacy_hash,
613
+ model_path,
614
+ copy_metadata_dir,
615
+ most_frequent_tags,
616
+ dataset_folders,
617
+ ],
618
+ )
619
+ save_metadata_button.click(
620
+ save_metadata,
621
+ inputs=[module, model, cover_image, display_name, author, source, keywords, description, rating, tags],
622
+ outputs=[save_output, model_hash, legacy_hash],
623
+ )
extensions/UmiWildacrd/discord/150_bra_gen.txt ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Adhesive backless{ __Colors__|} bra
2
+ Adhesive silicone{ __Colors__|} bra
3
+ Adjustable side-closure{ __Colors__|} bra
4
+ Adorned appliqué full-coverage{ __Colors__|} bra
5
+ Alluring sheer lace{ __Colors__|} bra
6
+ Animal print plunge{ __Colors__|} bra
7
+ Asymmetrical strap{ __Colors__|} bra
8
+ Backless halter{ __Colors__|} bra
9
+ Balconette{ __Colors__|} bra
10
+ Balcony{ __Colors__|} bra
11
+ Bandeau{ __Colors__|} bra
12
+ Bardot{ __Colors__|} bra
13
+ Beaded bohemian bandeau{ __Colors__|} bra
14
+ Beaded embellishment demi{ __Colors__|} bra
15
+ Bralette
16
+ Buckled harness cage{ __Colors__|} bra
17
+ Buckled studded leather balconette{ __Colors__|} bra
18
+ Bustier{ __Colors__|} bra
19
+ Butterfly{ __Colors__|} bra
20
+ Cage{ __Colors__|} bra
21
+ Cage halter bralette{ __Colors__|} bra
22
+ Camisole{ __Colors__|} bra
23
+ Chain-detailed racerback{ __Colors__|} bra
24
+ Chain-embellished open-back{ __Colors__|} bra
25
+ Charismatic charm underwire{ __Colors__|} bra
26
+ Chic cutout bralette{ __Colors__|} bra
27
+ Cinched waist longline{ __Colors__|} bra
28
+ Clear strap{ __Colors__|} bra
29
+ Colorful patchwork T-shirt{ __Colors__|} bra
30
+ Convertible{ __Colors__|} bra
31
+ Corded{ __Colors__|} bra
32
+ Corset-inspired satin bustier{ __Colors__|} bra
33
+ Crisscross{ __Colors__|} bra
34
+ Crisscross caged sports{ __Colors__|} bra
35
+ Crisscross cutout sports{ __Colors__|} bra
36
+ Crisscross front{ __Colors__|} bra
37
+ Crochet lace triangle{ __Colors__|} bra
38
+ Crotchless{ __Colors__|} bra
39
+ Cupless adhesive silicone{ __Colors__|} bra
40
+ Cutout{ __Colors__|} bra
41
+ Cutout deep V adhesive{ __Colors__|} bra
42
+ Dainty floral embroidered{ __Colors__|} bra
43
+ Daring open-back plunge{ __Colors__|} bra
44
+ Deco{ __Colors__|} bra
45
+ Deep V{ __Colors__|} bra
46
+ Delicate floral embroidered{ __Colors__|} bra
47
+ Delicate scalloped edge balconette{ __Colors__|} bra
48
+ Demi{ __Colors__|} bra
49
+ Diamante-studded push-up{ __Colors__|} bra
50
+ Diamond-shaped{ __Colors__|} bra
51
+ Double-layered{ __Colors__|} bra
52
+ Embroidered{ __Colors__|} bra
53
+ Empire waist{ __Colors__|} bra
54
+ Encapsulation{ __Colors__|} bra
55
+ Enchanted forest-themed{ __Colors__|} bra
56
+ Enhancer{ __Colors__|} bra
57
+ Ethnic-inspired beaded{ __Colors__|} bra
58
+ Feather-trimmed sheer{ __Colors__|} bra
59
+ Feathered burlesque{ __Colors__|} bra
60
+ Featherweight{ __Colors__|} bra
61
+ Festival-ready sequined{ __Colors__|} bra
62
+ Festive sequined holiday{ __Colors__|} bra
63
+ Fetish{ __Colors__|} bra
64
+ Fishnet mesh racerback{ __Colors__|} bra
65
+ Floral appliqué nursing{ __Colors__|} bra
66
+ Frilly heart-shaped retro{ __Colors__|} bra
67
+ Frilly mesh overlay{ __Colors__|} bra
68
+ Front-closure{ __Colors__|} bra
69
+ Front-hook{ __Colors__|} bra
70
+ Front-zip{ __Colors__|} bra
71
+ Full-coverage{ __Colors__|} bra
72
+ Futuristic metallic strappy{ __Colors__|} bra
73
+ Garter{ __Colors__|} bra
74
+ Glamorous crystal-embellished{ __Colors__|} bra
75
+ Glittery masquerade{ __Colors__|} bra
76
+ Halter{ __Colors__|} bra
77
+ Heart-shaped{ __Colors__|} bra
78
+ High-neck{ __Colors__|} bra
79
+ Illusion sheer lace plunge{ __Colors__|} bra
80
+ Illusion sheer plunge{ __Colors__|} bra
81
+ Intricate paisley-patterned{ __Colors__|} bra
82
+ Jeweled{ __Colors__|} bra
83
+ Jeweled chain-strap{ __Colors__|} bra
84
+ Jeweled chain-strap bralette{ __Colors__|} bra
85
+ Knotted strap triangle{ __Colors__|} bra
86
+ Lace{ __Colors__|} bra
87
+ Lace overlay{ __Colors__|} bra
88
+ Lace-trimmed plunge push-up{ __Colors__|} bra
89
+ Layered sheer mesh{ __Colors__|} bra
90
+ Lift{ __Colors__|} bra
91
+ Lingerie-inspired satin corset{ __Colors__|} bra
92
+ Longline{ __Colors__|} bra
93
+ Low-back{ __Colors__|} bra
94
+ Masquerade{ __Colors__|} bra
95
+ Maternity{ __Colors__|} bra
96
+ Mesh{ __Colors__|} bra
97
+ Metallic shimmery strapless{ __Colors__|} bra
98
+ Metallic shimmery strappy{ __Colors__|} bra
99
+ Minimizer{ __Colors__|} bra
100
+ Molded{ __Colors__|} bra
101
+ Multi-strap{ __Colors__|} bra
102
+ Neon strappy sports{ __Colors__|} bra
103
+ Neon strappy triangle{ __Colors__|} bra
104
+ Nursing{ __Colors__|} bra
105
+ One-shoulder{ __Colors__|} bra
106
+ Open-back{ __Colors__|} bra
107
+ Oriental-inspired silk bustier{ __Colors__|} bra
108
+ Oriental-inspired silk kimono{ __Colors__|} bra
109
+ Ornate beaded bohemian{ __Colors__|} bra
110
+ Oversized bow front-closure{ __Colors__|} bra
111
+ Padded{ __Colors__|} bra
112
+ Paisley-print triangle{ __Colors__|} bra
113
+ Pearls lace vintage{ __Colors__|} bra
114
+ Pleated satin backless{ __Colors__|} bra
115
+ Plunge{ __Colors__|} bra
116
+ Push-up{ __Colors__|} bra
117
+ Quilted satin push-up{ __Colors__|} bra
118
+ Racerback{ __Colors__|} bra
119
+ Retro{ __Colors__|} bra
120
+ Rhinestone-embellished T-shirt{ __Colors__|} bra
121
+ Ribbed{ __Colors__|} bra
122
+ Romantic ruffled balcony{ __Colors__|} bra
123
+ Scalloped edge minimizer{ __Colors__|} bra
124
+ Scoop{ __Colors__|} bra
125
+ Seamless{ __Colors__|} bra
126
+ Self-adhesive{ __Colors__|} bra
127
+ Sequined butterfly bralette{ __Colors__|} bra
128
+ Sheer{ __Colors__|} bra
129
+ Sheer mesh cutout{ __Colors__|} bra
130
+ Shelf{ __Colors__|} bra
131
+ Shiny metallic strapless{ __Colors__|} bra
132
+ Shirred{ __Colors__|} bra
133
+ Side-closure{ __Colors__|} bra
134
+ Silicone{ __Colors__|} bra
135
+ Silk velvet embroidered{ __Colors__|} bra
136
+ Sling{ __Colors__|} bra
137
+ Slip{ __Colors__|} bra
138
+ Sports{ __Colors__|} bra
139
+ Strapless{ __Colors__|} bra
140
+ Strappy cutout bandeau{ __Colors__|} bra
141
+ Stretchy{ __Colors__|} bra
142
+ Studded leather longline{ __Colors__|} bra
143
+ T-back{ __Colors__|} bra
144
+ T-shirt{ __Colors__|} bra
145
+ Tankini{ __Colors__|} bra
146
+ Triangle{ __Colors__|} bra
147
+ Tribal-print triangle{ __Colors__|} bra
148
+ U-plunge{ __Colors__|} bra
149
+ Underwire{ __Colors__|} bra
150
+ Unlined{ __Colors__|} bra
151
+ V-neck{ __Colors__|} bra
152
+ Velvet lace corset{ __Colors__|} bra
153
+ Vest{ __Colors__|} bra
154
+ Vintage{ __Colors__|} bra
155
+ Waist-cinching{ __Colors__|} bra
156
+ Water-resistant{ __Colors__|} bra
157
+ Waterfall{ __Colors__|} bra
158
+ Wireless{ __Colors__|} bra
extensions/UmiWildacrd/discord/200_pan_gen.txt ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Angel wing-shaped mesh{ __Colors__|} panties
2
+ Asymmetrical lace mesh boy shorts
3
+ Asymmetrical lace mesh hipster{ __Colors__|} panties
4
+ Beaded chain hipster{ __Colors__|} panties
5
+ Beaded sequined mesh boy shorts
6
+ Beaded sequined mesh hipster{ __Colors__|} panties
7
+ Beaded sequined mesh tanga{ __Colors__|} panties
8
+ Beaded sequined oriental-inspired silk lace{ __Colors__|} panties
9
+ Beaded sequined velvet lace tanga{ __Colors__|} panties
10
+ Buckled studded leather{ __Colors__|} panties
11
+ Cage frilly boy shorts
12
+ Cage velvet boy shorts
13
+ Cage velvet high-waisted{ __Colors__|} panties
14
+ Cage velvet lace hipster{ __Colors__|} panties
15
+ Cage velvet lace tanga{ __Colors__|} panties
16
+ Caged studded leather{ __Colors__|} panties
17
+ Chainmail lace crotchless{ __Colors__|} panties
18
+ Chainmail leather heart-shaped{ __Colors__|} panties
19
+ Chainmail leather high-waisted{ __Colors__|} panties
20
+ Chainmail leather low-rise{ __Colors__|} panties
21
+ Cotton frilly boy shorts
22
+ Cotton frilly thong{ __Colors__|} panties
23
+ Cotton low-rise frill{ __Colors__|} panties
24
+ Cotton low-rise heart-cutout{ __Colors__|} panties
25
+ Cotton mesh boy shorts
26
+ Crisscross heart-cutout{ __Colors__|} panties
27
+ Crotchless lace{ __Colors__|} panties
28
+ Crystal heart-shaped thong{ __Colors__|} panties
29
+ Crystal-embellished silk boy shorts
30
+ Crystal-embellished silk velvet boy shorts
31
+ Crystal-embellished silk velvet{ __Colors__|} panties
32
+ Distressed velvet lace-up{ __Colors__|} panties
33
+ Double-layered lace satin boy shorts
34
+ Double-layered lace satin tanga{ __Colors__|} panties
35
+ Double-layered lace satin thong{ __Colors__|} panties
36
+ Embroidered silk crotchless{ __Colors__|} panties
37
+ Embroidered silk hipster{ __Colors__|} panties
38
+ Embroidered silk tanga{ __Colors__|} panties
39
+ Embroidered silk velvet boy shorts
40
+ Embroidered silk velvet cage{ __Colors__|} panties
41
+ Embroidered silk velvet tanga{ __Colors__|} panties
42
+ Feather-trimmed velvet garter{ __Colors__|} panties
43
+ Feather-trimmed velvet lace boy shorts
44
+ Feather-trimmed velvet lace garter{ __Colors__|} panties
45
+ Fishnet diamante embellished{ __Colors__|} panties
46
+ Fishnet frilly boy shorts
47
+ Fishnet frilly garter{ __Colors__|} panties
48
+ Fishnet lace garter pearl{ __Colors__|} panties
49
+ Fishnet pearl hipster{ __Colors__|} panties
50
+ Floral embroidered lace boy shorts
51
+ Floral embroidered mesh boy shorts
52
+ Floral embroidered silk{ __Colors__|} panties
53
+ Floral embroidered velvet{ __Colors__|} panties
54
+ Floral printed cotton lace{ __Colors__|} panties
55
+ Floral printed cotton low-rise{ __Colors__|} panties
56
+ Floral printed cotton mesh{ __Colors__|} panties
57
+ Fur-trimmed low-rise hipster{ __Colors__|} panties
58
+ Glitter lace cage{ __Colors__|} panties
59
+ Glitter lace garter{ __Colors__|} panties
60
+ Glitter lace high-waisted{ __Colors__|} panties
61
+ Glittery mesh hipster{ __Colors__|} panties
62
+ Heart-shaped lace{ __Colors__|} panties
63
+ Heart-shaped satin hipster{ __Colors__|} panties
64
+ High-cut mesh{ __Colors__|} panties
65
+ High-waisted embroidered silk{ __Colors__|} panties
66
+ High-waisted frilly{ __Colors__|} panties
67
+ Holographic jeweled garter{ __Colors__|} panties
68
+ Holographic lace frilled{ __Colors__|} panties
69
+ Holographic lace sequin boy shorts
70
+ Holographic mesh lace boy shorts
71
+ Holographic mesh lace garter{ __Colors__|} panties
72
+ Holographic mesh ruffle-trimmed hipster{ __Colors__|} panties
73
+ Jeweled embroidered silk hipster{ __Colors__|} panties
74
+ Jeweled embroidered silk lace boy shorts
75
+ Jeweled embroidered silk thong{ __Colors__|} panties
76
+ Lace chiffon ruffle-trimmed garter{ __Colors__|} panties
77
+ Lace chiffon ruffle-trimmed hipster{ __Colors__|} panties
78
+ Lace chiffon ruffle-trimmed tanga{ __Colors__|} panties
79
+ Lace garter pearl{ __Colors__|} panties
80
+ Lace leather O-ring boy shorts
81
+ Lace leather O-ring{ __Colors__|} panties
82
+ Lace leather O-ring tanga{ __Colors__|} panties
83
+ Lace mesh boy shorts
84
+ Lace mesh garter{ __Colors__|} panties
85
+ Lace mesh high-waisted boy shorts
86
+ Lace mesh high-waisted{ __Colors__|} panties
87
+ Lace mesh hipster{ __Colors__|} panties
88
+ Lace satin bow{ __Colors__|} panties
89
+ Lace satin ruffle-trimmed{ __Colors__|} panties
90
+ Lace satin ruffle-trimmed tanga{ __Colors__|} panties
91
+ Lace velvet O-ring{ __Colors__|} panties
92
+ Lace velvet cage boy shorts
93
+ Lace velvet cage{ __Colors__|} panties
94
+ Lace velvet heart-cutout boy shorts
95
+ Lace velvet heart-cutout{ __Colors__|} panties
96
+ Lace velvet heart-cutout tanga{ __Colors__|} panties
97
+ Lace velvet jewel-trimmed boy shorts
98
+ Lace velvet jewel-trimmed{ __Colors__|} panties
99
+ Lace velvet pearl boy shorts
100
+ Lace velvet thong{ __Colors__|} panties
101
+ Leather lace-up crotchless{ __Colors__|} panties
102
+ Leather lace-up garter{ __Colors__|} panties
103
+ Leather lace-up pearl{ __Colors__|} panties
104
+ Leopard print velvet lace boy shorts
105
+ Leopard print velvet lace tanga{ __Colors__|} panties
106
+ Leopard print velvet lace-up{ __Colors__|} panties
107
+ Low-rise cotton frill{ __Colors__|} panties
108
+ Low-rise cotton{ __Colors__|} panties
109
+ Low-rise cotton star-cutout{ __Colors__|} panties
110
+ Mesh leather O-ring{ __Colors__|} panties
111
+ Mesh leather frilly{ __Colors__|} panties
112
+ Metallic thread embroidered mesh lace boy shorts
113
+ Metallic thread embroidered mesh lace{ __Colors__|} panties
114
+ Metallic thread embroidered mesh{ __Colors__|} panties
115
+ Open-back lace satin heart-cutout{ __Colors__|} panties
116
+ Open-back lace satin{ __Colors__|} panties
117
+ Open-back lace velvet{ __Colors__|} panties
118
+ Open-back mesh lace{ __Colors__|} panties
119
+ Open-back satin silk{ __Colors__|} panties
120
+ Open-back velvet silk{ __Colors__|} panties
121
+ Open-crotch{ __Colors__|} panties
122
+ Oriental-inspired silk lace boy shorts
123
+ Oriental-inspired silk lace cage{ __Colors__|} panties
124
+ Oriental-inspired silk lace garter{ __Colors__|} panties
125
+ Oriental-inspired silk pearl{ __Colors__|} panties
126
+ Oriental-inspired silk sequin cage{ __Colors__|} panties
127
+ Pearl crystal embellished velvet lace boy shorts
128
+ Pearl crystal embellished velvet lace{ __Colors__|} panties
129
+ Pearl crystal embellished velvet{ __Colors__|} panties
130
+ Pearl-studded fishnet boy shorts
131
+ Platform heart-shaped{ __Colors__|} panties
132
+ Platform heart-shaped silk lace boy shorts
133
+ Platform heart-shaped silk lace{ __Colors__|} panties
134
+ Platform heart-shaped velvet{ __Colors__|} panties
135
+ Rhinestone lace garter pearl boy shorts
136
+ Rhinestone lace garter pearl{ __Colors__|} panties
137
+ Rhinestone lace garter pearl tanga{ __Colors__|} panties
138
+ Rhinestone-studded holographic mesh lace boy shorts
139
+ Rhinestone-studded oriental-inspired silk{ __Colors__|} panties
140
+ Ruby-encrusted velvet lace cage{ __Colors__|} panties
141
+ Ruby-encrusted velvet lace high-waisted{ __Colors__|} panties
142
+ Ruffled silk crotchless{ __Colors__|} panties
143
+ Ruffled silk velvet boy shorts
144
+ Ruffled silk velvet hipster{ __Colors__|} panties
145
+ Ruffled silk velvet tanga{ __Colors__|} panties
146
+ Sapphire-studded holographic mesh lace{ __Colors__|} panties
147
+ Satin chiffon ruffle-trimmed boy shorts
148
+ Satin chiffon ruffle-trimmed cage{ __Colors__|} panties
149
+ Satin chiffon ruffle-trimmed garter{ __Colors__|} panties
150
+ Satin lace low-rise boy shorts
151
+ Satin lace low-rise{ __Colors__|} panties
152
+ Satin mesh cage boy shorts
153
+ Satin mesh cage{ __Colors__|} panties
154
+ Satin silk garter pearl{ __Colors__|} panties
155
+ Satin silk jeweled boy shorts
156
+ Satin silk jeweled garter{ __Colors__|} panties
157
+ Satin silk ruffle-trimmed hipster{ __Colors__|} panties
158
+ Satin-lace frilly boy shorts
159
+ Satin-lace garter{ __Colors__|} panties
160
+ Scalloped edge{ __Colors__|} panties
161
+ Scalloped edge silk lace boy shorts
162
+ Scalloped edge silk lace{ __Colors__|} panties
163
+ Scalloped edge silk lace tanga{ __Colors__|} panties
164
+ Scalloped lace heart-cutout{ __Colors__|} panties
165
+ Scalloped lace thong{ __Colors__|} panties
166
+ Sequin mesh high-waisted boy shorts
167
+ Sequin mesh high-waisted{ __Colors__|} panties
168
+ Sequin mesh high-waisted tanga{ __Colors__|} panties
169
+ Sheer mesh frilly hipster{ __Colors__|} panties
170
+ Sheer mesh lace boy shorts
171
+ Sheer mesh lace crotchless boy shorts
172
+ Sheer mesh lace crotchless{ __Colors__|} panties
173
+ Sheer mesh panel{ __Colors__|} panties
174
+ Sheer mesh pearl garter{ __Colors__|} panties
175
+ Sheer mesh satin boy shorts
176
+ Sheer mesh satin thong{ __Colors__|} panties
177
+ Silk mesh heart-cutout{ __Colors__|} panties
178
+ Silk mesh hipster{ __Colors__|} panties
179
+ Silk velvet jewel-trimmed briefs
180
+ Silver fishnet thong{ __Colors__|} panties
181
+ Strappy buckled bondage{ __Colors__|} panties
182
+ Strappy studded buckled{ __Colors__|} panties
183
+ Studded leather crotchless{ __Colors__|} panties
184
+ Studded leather heart-cutout{ __Colors__|} panties
185
+ Studded leather hipster{ __Colors__|} panties
186
+ Studded leather lace cage boy shorts
187
+ Studded leather lace cage{ __Colors__|} panties
188
+ Studded leather lace tanga{ __Colors__|} panties
189
+ Velvet fur-trimmed garter{ __Colors__|} panties
190
+ Velvet fur-trimmed hipster{ __Colors__|} panties
191
+ Velvet fur-trimmed thong{ __Colors__|} panties
192
+ Velvet lace frilly boy shorts
193
+ Velvet lace frilly{ __Colors__|} panties
194
+ Velvet lace frilly tanga{ __Colors__|} panties
195
+ Velvet lace hipster{ __Colors__|} panties
196
+ Velvet mesh low-rise boy shorts
197
+ Velvet mesh low-rise{ __Colors__|} panties
198
+ Velvet pearl crotchless{ __Colors__|} panties
199
+ Velvet pearl garter{ __Colors__|} panties
200
+ Velvet silk garter{ __Colors__|} panties
201
+ Velvet silk jeweled{ __Colors__|} panties