Skip to content

Commit

Permalink
optimized display of nested entries
Browse files Browse the repository at this point in the history
  • Loading branch information
Haoming02 committed Dec 15, 2023
1 parent 2dd9b9f commit 3a91f00
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 32 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ This is an Extension for the [Automatic1111 Webui](https://github.com/AUTOMATIC1

## How to Use
This Extension creates buttons in a new `Extra Networks` tab, **EZ Tags**.
When clicked, it will add the specified prompts into either the Positive or Negative field.
When clicked, it will add the specified string into either the Positive or Negative prompt field.

## Use Cases
You can use this Extension to simply make shortcuts for very long prompts:
Expand Down Expand Up @@ -42,11 +42,14 @@ Category:
- The `Show dirs` toggle displays the Categories for filtering
- You can have multiple `.yml` *(or `.yaml`)* files in the `tags` folder for better organizations
- You can also have the same Category in multiple files
- You can live reload the entries by pressing `Refresh` without restarting the UI
- Due to how the Webui is coded, the buttons are sorted like **Date Created** on launch
- You can live reload the entries by pressing **Refresh** without restarting the UI
> To avoid race condition, **Refresh** can only be triggered once per second
- **New:** Nested categories are now supported

## Sorting
- **Default Sort:** First by `Category`, then by `Display Name`
- **Date Created:** By `Index` *(the order they are written in the YAML)*
- **Date Modified:** First by `Category`, then by `Index`
- **Name:** By `Display Name`

> Due to how the Webui is coded, the buttons are sorted like **Date Created** on launch
9 changes: 6 additions & 3 deletions samples/example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Subject:
Cat: cat

Style:
Animal: wildlife photography, photograph, wildlife, soft focus, 4k, national geographic
Digital: ultra realistic, concept art, intricate details, highly detailed, photorealistic, sharp focus, volumetric lighting, unreal engine
Sketch: sketch, drawing, detailed, pencil, black and white
2D:
Sketch: sketch, drawing, detailed, pencil, black and white
Anime: absurdres, official_art, key_visual, anime
3D:
Animal: wildlife photography, photograph, wildlife, soft focus, 4k, national geographic
Digital: ultra realistic, concept art, intricate details, highly detailed, photorealistic, sharp focus, volumetric lighting, unreal engine
6 changes: 4 additions & 2 deletions scripts/eztags.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ def __init__(self):
super().__init__('EZ Tags')

def refresh(self):
yaml_utils.reload_yaml()
logs = yaml_utils.reload_yaml()
if len(logs) > 0:
print('\n[Easy Tag Insert]:')
print('\n'.join(logs) + "\n")

def create_item(self, category, index, name, i):
return {
Expand Down Expand Up @@ -110,7 +113,6 @@ def create_html(self, tabname):

# ========== REGISTER CALLBACK ==========
def registerTab():
yaml_utils.reload_yaml()
ui_extra_networks.register_page(EasyTags())

script_callbacks.on_before_ui(registerTab)
Expand Down
89 changes: 65 additions & 24 deletions scripts/yaml_utils.py
Original file line number Diff line number Diff line change
@@ -1,78 +1,119 @@
import modules.scripts as scripts
import yaml
import shutil
import yaml
import time
import os
import re


SAMPLE_FOLDER = os.path.join(scripts.basedir(), 'samples')
TAGS_FOLDER = os.path.join(scripts.basedir(), 'tags')

TAGS = {}
ERRORS = []


def sanitize(item:str) -> str:
return re.sub('[^a-zA-Z0-9 \.]', '', item).replace(' ', '_')

def sanitize_int(index:int) -> str:
return f'{index:03}'


def check_dupe(A, parent:str):
B = TAGS[parent]

if isinstance(A, str):
if A in B:
ERRORS.append(f'Key Collision: "{parent}/{A}" Detected!')

elif isinstance(A, dict):
for k in A.keys():
if k in B:
ERRORS.append(f'Key Collision: "{parent}/{k}" Detected!')

else:
raise ValueError

def is_single_layer(item:dict) -> bool:
for v in item.values():
if not isinstance(v, str):
return False

return True

def parse_nested(category:str, parent:str, tags:dict):
global TAGS

def parse_nested(parent:str, tags:dict):
for k, v in tags.items():
key = f'{parent}/{k}' if parent else k

if isinstance(v, dict):
parse_nested(category, key, v)
if not is_single_layer(v):
parse_nested(key, v)

else:
if key in TAGS[category]:
print(f'\n[Easy Tag Insert]: Duplicated Key [{category}/{key}] Detected!\n')
else:
if key in TAGS:
check_dupe(v, key)
TAGS[key].update(v)
else:
TAGS[key] = v

TAGS[category].update({key: v})
else:
if parent in TAGS:
check_dupe(k, parent)
TAGS[parent].update({k: v})
else:
TAGS[parent] = {k: v}

def load_dictionary(tags:dict):
global TAGS
for key, value in tags.items():

if isinstance(value, str):
print(f'\n[Easy Tag Insert]: Top-Level Entry {{"{key}": "{value}"}} is not Supported...\n')
ERRORS.append(f'Top-Level Entry {{"{key}": "{value}"}} is not Supported...')
continue

if not is_single_layer(value):
if key not in TAGS:
TAGS[key] = {}

parse_nested(key, '', value)
parse_nested(key, value)

else:
if key not in TAGS:
TAGS[key] = value
if key in TAGS:
check_dupe(value, key)
TAGS[key].update(value)
else:
for k in value.keys():
if k in TAGS[key]:
print(f'\n[Easy Tag Insert]: Duplicated Key [{key}/{k}] Detected!\n')
TAGS[key] = value


# 1 sec
threshold = 1.0
last_executed = 0

def timegate() -> bool:
global last_executed
current_time = time.time()

if (current_time - last_executed) >= threshold:
last_executed = current_time
return True

return False

TAGS[key].update(value)

def reload_yaml():
if not timegate():
return []

if not os.path.exists(TAGS_FOLDER):
print('\n[Easy Tag Insert]: Folder "tags" not found. Initializing...\n')
shutil.copytree(SAMPLE_FOLDER, TAGS_FOLDER)

global TAGS
TAGS = {}
TAGS.clear()
ERRORS.clear()

for FILE in os.listdir(TAGS_FOLDER):
if '.yml' not in FILE and '.yaml' not in FILE:
print(f'Non-YAML File: "{FILE}" found in Tags folder...')
print(f'Detected Non-YAML File: "{os.path.join(TAGS_FOLDER, FILE)}"...')
continue

with open(os.path.join(TAGS_FOLDER, FILE)) as stream:
load_dictionary(yaml.safe_load(stream))

return ERRORS

0 comments on commit 3a91f00

Please sign in to comment.