ui_edit_user_metadata.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import datetime
  2. import html
  3. import random
  4. import gradio as gr
  5. import re
  6. from modules import ui_extra_networks_user_metadata
  7. def is_non_comma_tagset(tags):
  8. average_tag_length = sum(len(x) for x in tags.keys()) / len(tags)
  9. return average_tag_length >= 16
  10. re_word = re.compile(r"[-_\w']+")
  11. re_comma = re.compile(r" *, *")
  12. def build_tags(metadata):
  13. tags = {}
  14. ss_tag_frequency = metadata.get("ss_tag_frequency", {})
  15. if ss_tag_frequency is not None and hasattr(ss_tag_frequency, 'items'):
  16. for _, tags_dict in ss_tag_frequency.items():
  17. for tag, tag_count in tags_dict.items():
  18. tag = tag.strip()
  19. tags[tag] = tags.get(tag, 0) + int(tag_count)
  20. if tags and is_non_comma_tagset(tags):
  21. new_tags = {}
  22. for text, text_count in tags.items():
  23. for word in re.findall(re_word, text):
  24. if len(word) < 3:
  25. continue
  26. new_tags[word] = new_tags.get(word, 0) + text_count
  27. tags = new_tags
  28. ordered_tags = sorted(tags.keys(), key=tags.get, reverse=True)
  29. return [(tag, tags[tag]) for tag in ordered_tags]
  30. class LoraUserMetadataEditor(ui_extra_networks_user_metadata.UserMetadataEditor):
  31. def __init__(self, ui, tabname, page):
  32. super().__init__(ui, tabname, page)
  33. self.select_sd_version = None
  34. self.taginfo = None
  35. self.edit_activation_text = None
  36. self.slider_preferred_weight = None
  37. self.edit_notes = None
  38. def save_lora_user_metadata(self, name, desc, sd_version, activation_text, preferred_weight, negative_text, notes):
  39. user_metadata = self.get_user_metadata(name)
  40. user_metadata["description"] = desc
  41. user_metadata["sd version"] = sd_version
  42. user_metadata["activation text"] = activation_text
  43. user_metadata["preferred weight"] = preferred_weight
  44. user_metadata["negative text"] = negative_text
  45. user_metadata["notes"] = notes
  46. self.write_user_metadata(name, user_metadata)
  47. def get_metadata_table(self, name):
  48. table = super().get_metadata_table(name)
  49. item = self.page.items.get(name, {})
  50. metadata = item.get("metadata") or {}
  51. keys = {
  52. 'ss_output_name': "Output name:",
  53. 'ss_sd_model_name': "Model:",
  54. 'ss_clip_skip': "Clip skip:",
  55. 'ss_network_module': "Kohya module:",
  56. }
  57. for key, label in keys.items():
  58. value = metadata.get(key, None)
  59. if value is not None and str(value) != "None":
  60. table.append((label, html.escape(value)))
  61. ss_training_started_at = metadata.get('ss_training_started_at')
  62. if ss_training_started_at:
  63. table.append(("Date trained:", datetime.datetime.utcfromtimestamp(float(ss_training_started_at)).strftime('%Y-%m-%d %H:%M')))
  64. ss_bucket_info = metadata.get("ss_bucket_info")
  65. if ss_bucket_info and "buckets" in ss_bucket_info:
  66. resolutions = {}
  67. for _, bucket in ss_bucket_info["buckets"].items():
  68. resolution = bucket["resolution"]
  69. resolution = f'{resolution[1]}x{resolution[0]}'
  70. resolutions[resolution] = resolutions.get(resolution, 0) + int(bucket["count"])
  71. resolutions_list = sorted(resolutions.keys(), key=resolutions.get, reverse=True)
  72. resolutions_text = html.escape(", ".join(resolutions_list[0:4]))
  73. if len(resolutions) > 4:
  74. resolutions_text += ", ..."
  75. resolutions_text = f"<span title='{html.escape(', '.join(resolutions_list))}'>{resolutions_text}</span>"
  76. table.append(('Resolutions:' if len(resolutions_list) > 1 else 'Resolution:', resolutions_text))
  77. image_count = 0
  78. for _, params in metadata.get("ss_dataset_dirs", {}).items():
  79. image_count += int(params.get("img_count", 0))
  80. if image_count:
  81. table.append(("Dataset size:", image_count))
  82. return table
  83. def put_values_into_components(self, name):
  84. user_metadata = self.get_user_metadata(name)
  85. values = super().put_values_into_components(name)
  86. item = self.page.items.get(name, {})
  87. metadata = item.get("metadata") or {}
  88. tags = build_tags(metadata)
  89. gradio_tags = [(tag, str(count)) for tag, count in tags[0:24]]
  90. return [
  91. *values[0:5],
  92. item.get("sd_version", "Unknown"),
  93. gr.HighlightedText.update(value=gradio_tags, visible=True if tags else False),
  94. user_metadata.get('activation text', ''),
  95. float(user_metadata.get('preferred weight', 0.0)),
  96. user_metadata.get('negative text', ''),
  97. gr.update(visible=True if tags else False),
  98. gr.update(value=self.generate_random_prompt_from_tags(tags), visible=True if tags else False),
  99. ]
  100. def generate_random_prompt(self, name):
  101. item = self.page.items.get(name, {})
  102. metadata = item.get("metadata") or {}
  103. tags = build_tags(metadata)
  104. return self.generate_random_prompt_from_tags(tags)
  105. def generate_random_prompt_from_tags(self, tags):
  106. max_count = None
  107. res = []
  108. for tag, count in tags:
  109. if not max_count:
  110. max_count = count
  111. v = random.random() * max_count
  112. if count > v:
  113. for x in "({[]})":
  114. tag = tag.replace(x, '\\' + x)
  115. res.append(tag)
  116. return ", ".join(sorted(res))
  117. def create_extra_default_items_in_left_column(self):
  118. # this would be a lot better as gr.Radio but I can't make it work
  119. self.select_sd_version = gr.Dropdown(['SD1', 'SD2', 'SDXL', 'Unknown'], value='Unknown', label='Stable Diffusion version', interactive=True)
  120. def create_editor(self):
  121. self.create_default_editor_elems()
  122. self.taginfo = gr.HighlightedText(label="Training dataset tags")
  123. self.edit_activation_text = gr.Text(label='Activation text', info="Will be added to prompt along with Lora")
  124. self.slider_preferred_weight = gr.Slider(label='Preferred weight', info="Set to 0 to disable", minimum=0.0, maximum=2.0, step=0.01)
  125. self.edit_negative_text = gr.Text(label='Negative prompt', info="Will be added to negative prompts")
  126. with gr.Row() as row_random_prompt:
  127. with gr.Column(scale=8):
  128. random_prompt = gr.Textbox(label='Random prompt', lines=4, max_lines=4, interactive=False)
  129. with gr.Column(scale=1, min_width=120):
  130. generate_random_prompt = gr.Button('Generate', size="lg", scale=1)
  131. self.edit_notes = gr.TextArea(label='Notes', lines=4)
  132. generate_random_prompt.click(fn=self.generate_random_prompt, inputs=[self.edit_name_input], outputs=[random_prompt], show_progress=False)
  133. def select_tag(activation_text, evt: gr.SelectData):
  134. tag = evt.value[0]
  135. words = re.split(re_comma, activation_text)
  136. if tag in words:
  137. words = [x for x in words if x != tag and x.strip()]
  138. return ", ".join(words)
  139. return activation_text + ", " + tag if activation_text else tag
  140. self.taginfo.select(fn=select_tag, inputs=[self.edit_activation_text], outputs=[self.edit_activation_text], show_progress=False)
  141. self.create_default_buttons()
  142. viewed_components = [
  143. self.edit_name,
  144. self.edit_description,
  145. self.html_filedata,
  146. self.html_preview,
  147. self.edit_notes,
  148. self.select_sd_version,
  149. self.taginfo,
  150. self.edit_activation_text,
  151. self.slider_preferred_weight,
  152. self.edit_negative_text,
  153. row_random_prompt,
  154. random_prompt,
  155. ]
  156. self.button_edit\
  157. .click(fn=self.put_values_into_components, inputs=[self.edit_name_input], outputs=viewed_components)\
  158. .then(fn=lambda: gr.update(visible=True), inputs=[], outputs=[self.box])
  159. edited_components = [
  160. self.edit_description,
  161. self.select_sd_version,
  162. self.edit_activation_text,
  163. self.slider_preferred_weight,
  164. self.edit_negative_text,
  165. self.edit_notes,
  166. ]
  167. self.setup_save_handler(self.button_save, self.save_lora_user_metadata, edited_components)