mirabarukaso commited on
Commit
264c7c2
·
1 Parent(s): 8650fd3

Add semi-auto tag complete

Browse files
Files changed (4) hide show
  1. app.py +28 -2
  2. json/e621_sfw.csv +0 -0
  3. scripts/lib.py +17 -18
  4. scripts/tag_autocomplete.py +94 -0
app.py CHANGED
@@ -5,7 +5,26 @@ from lib import init, refresh_character_thumb_image
5
  from lib import JAVA_SCRIPT, CSS_SCRIPT, TITLE
6
 
7
  if __name__ == '__main__':
8
- character_list, character_list_cn, LANG = init()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  with gr.Blocks(js=JAVA_SCRIPT, css=CSS_SCRIPT, title=TITLE) as ui:
11
  with gr.Row():
@@ -33,10 +52,14 @@ if __name__ == '__main__':
33
  with gr.Row(elem_classes='main_row'):
34
  with gr.Column(elem_classes='column_prompts'):
35
  thumb_image = gr.Gallery(type="pil", columns=3, show_download_button=False, object_fit='contain', label="Thumb")
 
 
 
 
36
 
37
  with gr.Row():
38
  gr.Markdown("<h2><span style=\"color:orangered\">Thumb Image create by waiNSFWIllustrious_v120.safetensors with ComfyUI</span></h2>",)
39
- gr.Markdown(f"<a href='https://github.com/mirabarukaso/character_select_stand_alone_app'>Character Select SAA</a>")
40
 
41
  character1.change(fn=refresh_character_thumb_image,
42
  inputs=[character1,character2,character3],
@@ -48,4 +71,7 @@ if __name__ == '__main__':
48
  inputs=[character1,character2,character3],
49
  outputs=[thumb_image])
50
 
 
 
 
51
  ui.launch()
 
5
  from lib import JAVA_SCRIPT, CSS_SCRIPT, TITLE
6
 
7
  if __name__ == '__main__':
8
+ character_list, character_list_cn, LANG, TAG_AUTOCOMPLETE = init()
9
+
10
+ def update_suggestions(text):
11
+ matches = TAG_AUTOCOMPLETE.get_suggestions(text)
12
+ items = []
13
+ if matches:
14
+ for _, m in enumerate(matches):
15
+ key = f"{m['prompt']} ({m['heat']})"
16
+ items.append([key])
17
+ return gr.Dataset(samples=items)
18
+
19
+ def apply_suggestion(evt: gr.SelectData, text, custom_prompt):
20
+ suggestion = evt.value
21
+ #print(f"You selected {evt.value} at {evt.index} from {evt.target} for {custom_prompt}")
22
+ if not custom_prompt or not suggestion:
23
+ return custom_prompt
24
+
25
+ parts = custom_prompt.split(',')
26
+ parts[-1] = suggestion[0].split(' ')[0].replace('_', ' ').replace(':', ' ')
27
+ return ', '.join(parts) + ', '
28
 
29
  with gr.Blocks(js=JAVA_SCRIPT, css=CSS_SCRIPT, title=TITLE) as ui:
30
  with gr.Row():
 
52
  with gr.Row(elem_classes='main_row'):
53
  with gr.Column(elem_classes='column_prompts'):
54
  thumb_image = gr.Gallery(type="pil", columns=3, show_download_button=False, object_fit='contain', label="Thumb")
55
+
56
+ with gr.Row():
57
+ custom_prompt = gr.Textbox(value='', label='Semi-auto tag complete test. Try tag* *tag *tag* (e621_sfw.csv@DominikDoom)')
58
+ suggestions = gr.Dataset(components=[custom_prompt], samples_per_page=30, samples=[])
59
 
60
  with gr.Row():
61
  gr.Markdown("<h2><span style=\"color:orangered\">Thumb Image create by waiNSFWIllustrious_v120.safetensors with ComfyUI</span></h2>",)
62
+ gr.Markdown(f"<a href='https://github.com/mirabarukaso/character_select_stand_alone_app'>Character Select SAA</a>")
63
 
64
  character1.change(fn=refresh_character_thumb_image,
65
  inputs=[character1,character2,character3],
 
71
  inputs=[character1,character2,character3],
72
  outputs=[thumb_image])
73
 
74
+ custom_prompt.change(fn=update_suggestions, inputs=[custom_prompt], outputs=[suggestions])
75
+ suggestions.select(fn=apply_suggestion, inputs=[suggestions, custom_prompt], outputs=[custom_prompt])
76
+
77
  ui.launch()
json/e621_sfw.csv ADDED
The diff for this file is too large to render. See raw diff
 
scripts/lib.py CHANGED
@@ -1,20 +1,13 @@
1
- import datetime
2
  import gzip
3
  import hashlib
4
  import os
5
- import glob
6
- import textwrap
7
- import gradio as gr
8
- import numpy as np
9
  import requests
10
  import json
11
  import base64
12
- import webbrowser
13
  from io import BytesIO
14
  from PIL import Image
15
- from PIL import PngImagePlugin
16
- import random
17
- import argparse
18
 
19
  # Language
20
  LANG_EN = {
@@ -60,10 +53,12 @@ character_list = ''
60
  character_dict = {}
61
  wai_image_dict = {}
62
  character_list_cn = ''
 
63
 
64
  wai_illustrious_character_select_files = [
65
  {'name': 'wai_character', 'file_path': os.path.join(json_folder, 'wai_characters.csv'), 'url':'https://raw.githubusercontent.com/mirabarukaso/character_select_stand_alone_app/refs/heads/main/json/wai_characters.csv'},
66
  {'name': 'wai_image', 'file_path': os.path.join(json_folder, 'wai_character_thumbs.json'), 'url': 'https://huggingface.co/datasets/flagrantia/character_select_stand_alone_app/resolve/main/wai_character_thumbs.json'},
 
67
  ]
68
  def get_md5_hash(input_str):
69
  md5_hash = hashlib.md5()
@@ -88,6 +83,7 @@ def load_jsons():
88
  global character_dict
89
  global wai_image_dict
90
  global character_list_cn
 
91
 
92
  # download file
93
  for item in wai_illustrious_character_select_files:
@@ -98,14 +94,17 @@ def load_jsons():
98
  if not os.path.exists(file_path):
99
  download_file(url, file_path)
100
 
101
- with open(file_path, 'r', encoding='utf-8') as file:
102
- if 'wai_character' == name:
103
- lines = file.readlines()
104
- for line in lines:
105
- key, value = line.split(',')
106
- character_dict[key.strip()]=value.strip()
107
- elif 'wai_image' == name:
108
- wai_image_dict = json.load(file)
 
 
 
109
 
110
  # Create list
111
  character_list = list(character_dict.values())
@@ -167,4 +166,4 @@ def init():
167
  load_jsons()
168
  print(f'[{CAT}]:Starting...')
169
 
170
- return character_list, character_list_cn, LANG
 
 
1
  import gzip
2
  import hashlib
3
  import os
 
 
 
 
4
  import requests
5
  import json
6
  import base64
7
+
8
  from io import BytesIO
9
  from PIL import Image
10
+ from tag_autocomplete import PromptSuggester
 
 
11
 
12
  # Language
13
  LANG_EN = {
 
53
  character_dict = {}
54
  wai_image_dict = {}
55
  character_list_cn = ''
56
+ TAG_AUTOCOMPLETE = None
57
 
58
  wai_illustrious_character_select_files = [
59
  {'name': 'wai_character', 'file_path': os.path.join(json_folder, 'wai_characters.csv'), 'url':'https://raw.githubusercontent.com/mirabarukaso/character_select_stand_alone_app/refs/heads/main/json/wai_characters.csv'},
60
  {'name': 'wai_image', 'file_path': os.path.join(json_folder, 'wai_character_thumbs.json'), 'url': 'https://huggingface.co/datasets/flagrantia/character_select_stand_alone_app/resolve/main/wai_character_thumbs.json'},
61
+ {'name': 'e621_sfw', 'file_path': os.path.join(json_folder, 'e621_sfw.csv'), 'url': 'https://raw.githubusercontent.com/DominikDoom/a1111-sd-webui-tagcomplete/refs/heads/main/tags/e621_sfw.csv'},
62
  ]
63
  def get_md5_hash(input_str):
64
  md5_hash = hashlib.md5()
 
83
  global character_dict
84
  global wai_image_dict
85
  global character_list_cn
86
+ global TAG_AUTOCOMPLETE
87
 
88
  # download file
89
  for item in wai_illustrious_character_select_files:
 
94
  if not os.path.exists(file_path):
95
  download_file(url, file_path)
96
 
97
+ if 'e621_sfw' == name:
98
+ TAG_AUTOCOMPLETE = PromptSuggester(file_path)
99
+ else:
100
+ with open(file_path, 'r', encoding='utf-8') as file:
101
+ if 'wai_character' == name:
102
+ lines = file.readlines()
103
+ for line in lines:
104
+ key, value = line.split(',')
105
+ character_dict[key.strip()]=value.strip()
106
+ elif 'wai_image' == name:
107
+ wai_image_dict = json.load(file)
108
 
109
  # Create list
110
  character_list = list(character_dict.values())
 
166
  load_jsons()
167
  print(f'[{CAT}]:Starting...')
168
 
169
+ return character_list, character_list_cn, LANG, TAG_AUTOCOMPLETE
scripts/tag_autocomplete.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import List, Dict
3
+
4
+ CAT = "Auto Tag Complete"
5
+
6
+ class PromptSuggester:
7
+ def __init__(self, prompt_file_path):
8
+ self.prompts = []
9
+ self.load_prompts(prompt_file_path)
10
+
11
+ def load_prompts(self, file_path: str):
12
+ if not os.path.exists(file_path):
13
+ print(f"File {file_path} not found.")
14
+ return
15
+
16
+ with open(file_path, 'r', encoding='utf-8') as f:
17
+ for line in f:
18
+ line = line.strip()
19
+ if not line:
20
+ continue
21
+
22
+ parts = line.split(',', 3)
23
+ if len(parts) >= 2:
24
+ prompt = parts[0].strip()
25
+ group = int(parts[1]) if parts[1].strip().isdigit() else 0
26
+ heat = int(parts[2]) if len(parts) > 2 and parts[2].strip().isdigit() else 0
27
+ aliases = parts[3].strip('"') if len(parts) > 3 else ""
28
+
29
+ if heat == 0:
30
+ heat = group
31
+ group = 0
32
+
33
+ self.prompts.append({
34
+ 'prompt': prompt,
35
+ 'group': group,
36
+ 'heat': heat,
37
+ 'aliases': aliases
38
+ })
39
+
40
+ self.prompts.sort(key=lambda x: x['heat'], reverse=True)
41
+ print(f"[{CAT}] Loaded {len(self.prompts)} prompts.")
42
+
43
+ def get_suggestions(self, text: str) -> List[Dict]:
44
+ if not text:
45
+ return []
46
+
47
+ parts = text.split(',')
48
+ last_word = parts[-1].strip().lower()
49
+
50
+ if not last_word:
51
+ return []
52
+
53
+ #print(f"Getting suggestions for: {last_word}")
54
+
55
+ matches = {}
56
+ for prompt_info in self.prompts:
57
+ prompt = prompt_info['prompt'].lower()
58
+ aliases = prompt_info['aliases'].lower().split(',') if prompt_info['aliases'] else []
59
+
60
+ if '*' in last_word:
61
+ # wildcards
62
+ if last_word.startswith('*') and last_word.endswith('*'):
63
+ # middle
64
+ pattern = last_word[1:-1]
65
+ if pattern in prompt or any(pattern in alias.strip() for alias in aliases):
66
+ if prompt not in matches or prompt_info['heat'] > matches[prompt]['heat']:
67
+ matches[prompt] = {'prompt': prompt_info['prompt'], 'heat': prompt_info['heat']}
68
+ elif last_word.startswith('*'):
69
+ # endswith
70
+ pattern = last_word[1:]
71
+ if prompt.endswith(pattern) or any(alias.strip().endswith(pattern) for alias in aliases):
72
+ if prompt not in matches or prompt_info['heat'] > matches[prompt]['heat']:
73
+ matches[prompt] = {'prompt': prompt_info['prompt'], 'heat': prompt_info['heat']}
74
+ elif last_word.endswith('*'):
75
+ # startswith
76
+ pattern = last_word[:-1]
77
+ if prompt.startswith(pattern) or any(alias.strip().startswith(pattern) for alias in aliases):
78
+ if prompt not in matches or prompt_info['heat'] > matches[prompt]['heat']:
79
+ matches[prompt] = {'prompt': prompt_info['prompt'], 'heat': prompt_info['heat']}
80
+ else:
81
+ # normal
82
+ if prompt.startswith(last_word) or any(alias.strip().startswith(last_word) for alias in aliases):
83
+ if prompt not in matches or prompt_info['heat'] > matches[prompt]['heat']:
84
+ matches[prompt] = {'prompt': prompt_info['prompt'], 'heat': prompt_info['heat']}
85
+
86
+ # we only need 30 items
87
+ if len(matches) == 30:
88
+ break
89
+
90
+ sorted_matches = sorted(matches.values(), key=lambda x: x['heat'], reverse=True)
91
+ #print(f"Found {len(sorted_matches)} unique matches")
92
+ return sorted_matches
93
+
94
+