Werli commited on
Commit
ff48ad9
·
verified ·
1 Parent(s): afb6ec0

Upload 11 files

Browse files
.gitattributes CHANGED
@@ -1,35 +1,30 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bin.* filter=lfs diff=lfs merge=lfs -text
5
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.model filter=lfs diff=lfs merge=lfs -text
12
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
13
+ *.onnx filter=lfs diff=lfs merge=lfs -text
14
+ *.ot filter=lfs diff=lfs merge=lfs -text
15
+ *.parquet filter=lfs diff=lfs merge=lfs -text
16
+ *.pb filter=lfs diff=lfs merge=lfs -text
17
+ *.pt filter=lfs diff=lfs merge=lfs -text
18
+ *.pth filter=lfs diff=lfs merge=lfs -text
19
+ *.rar filter=lfs diff=lfs merge=lfs -text
20
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
21
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
22
+ *.tflite filter=lfs diff=lfs merge=lfs -text
23
+ *.tgz filter=lfs diff=lfs merge=lfs -text
24
+ *.xz filter=lfs diff=lfs merge=lfs -text
25
+ *.zip filter=lfs diff=lfs merge=lfs -text
26
+ *.zstandard filter=lfs diff=lfs merge=lfs -text
27
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
28
+ 1girl.png filter=lfs diff=lfs merge=lfs -text
29
+ images/image1.png filter=lfs diff=lfs merge=lfs -text
30
+ images/image2.png filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ images
2
+ .vs
3
+ venv
4
+ tmp
5
+ *.pyc
README.md CHANGED
@@ -1,14 +1,40 @@
1
- ---
2
- title: Multi Tagger
3
- emoji: 🐠
4
- colorFrom: red
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 5.23.3
8
- app_file: app.py
9
- pinned: false
10
- license: apache-2.0
11
- short_description: Image captioning
12
- ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Multi-Tagger
3
+ emoji: 💬
4
+ colorFrom: purple
5
+ colorTo: indigo
6
+ sdk: gradio
7
+ sdk_version: 5.23.3
8
+ app_file: app.py
9
+ pinned: true
10
+ short_description: Image captioning
11
+ license: apache-2.0
12
+ ---
13
+
14
+ # Configuration
15
+
16
+ `title`: _string_
17
+ Display title for the Space
18
+
19
+ `emoji`: _string_
20
+ Space emoji (emoji-only character allowed)
21
+
22
+ `colorFrom`: _string_
23
+ Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
24
+
25
+ `colorTo`: _string_
26
+ Color for Thumbnail gradient (red, yellow, green, blue, indigo, purple, pink, gray)
27
+
28
+ `sdk`: _string_
29
+ Can be either `gradio`, `streamlit`, or `static`
30
+
31
+ `sdk_version` : _string_
32
+ Only applicable for `streamlit` SDK.
33
+ See [doc](https://hf.co/docs/hub/spaces) for more info on supported versions.
34
+
35
+ `app_file`: _string_
36
+ Path to your main application file (which contains either `gradio` or `streamlit` Python code, or `static` html code).
37
+ Path is relative to the root of the repository.
38
+
39
+ `pinned`: _boolean_
40
+ Whether the Space stays on top of your list.
app.py ADDED
@@ -0,0 +1,1103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
3
+ import io
4
+ import copy
5
+ import requests
6
+ import numpy as np
7
+ import spaces
8
+ import gradio as gr
9
+ from transformers import AutoProcessor, AutoModelForCausalLM
10
+ from transformers import AutoModelForCausalLM, AutoProcessor
11
+ from transformers.dynamic_module_utils import get_imports
12
+ from PIL import Image, ImageDraw, ImageFont
13
+ import matplotlib.pyplot as plt
14
+ import matplotlib.patches as patches
15
+ from unittest.mock import patch
16
+
17
+ import argparse
18
+ import huggingface_hub
19
+ import onnxruntime as rt
20
+ import pandas as pd
21
+ import traceback
22
+ import tempfile
23
+ import zipfile
24
+ import re
25
+ import ast
26
+ import time
27
+ from datetime import datetime, timezone
28
+ from collections import defaultdict
29
+ from classifyTags import classify_tags
30
+ # Add scheduler code here
31
+ from apscheduler.schedulers.background import BackgroundScheduler
32
+
33
+ os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
34
+ def fixed_get_imports(filename: str | os.PathLike) -> list[str]:
35
+ """Work around for https://huggingface.co/microsoft/phi-1_5/discussions/72."""
36
+ if not str(filename).endswith("/modeling_florence2.py"):
37
+ return get_imports(filename)
38
+ imports = get_imports(filename)
39
+ if "flash_attn" in imports:
40
+ imports.remove("flash_attn")
41
+ return imports
42
+
43
+ @spaces.GPU
44
+ def get_device_type():
45
+ import torch
46
+ if torch.cuda.is_available():
47
+ return "cuda"
48
+ else:
49
+ if (torch.backends.mps.is_available() and torch.backends.mps.is_built()):
50
+ return "mps"
51
+ else:
52
+ return "cpu"
53
+
54
+ model_id = 'MiaoshouAI/Florence-2-base-PromptGen-v2.0'
55
+
56
+ import subprocess
57
+ device = get_device_type()
58
+ if (device == "cuda"):
59
+ subprocess.run('pip install flash-attn --no-build-isolation', env={'FLASH_ATTENTION_SKIP_CUDA_BUILD': "TRUE"}, shell=True)
60
+ model = AutoModelForCausalLM.from_pretrained("MiaoshouAI/Florence-2-base-PromptGen-v2.0", trust_remote_code=True)
61
+ processor = AutoProcessor.from_pretrained("MiaoshouAI/Florence-2-base-PromptGen-v2.0", trust_remote_code=True)
62
+ model.to(device)
63
+ else:
64
+ #https://huggingface.co/microsoft/Florence-2-base-ft/discussions/4
65
+ with patch("transformers.dynamic_module_utils.get_imports", fixed_get_imports):
66
+ model = AutoModelForCausalLM.from_pretrained("MiaoshouAI/Florence-2-base-PromptGen-v2.0", trust_remote_code=True)
67
+ processor = AutoProcessor.from_pretrained("MiaoshouAI/Florence-2-base-PromptGen-v2.0", trust_remote_code=True)
68
+ model.to(device)
69
+
70
+ TITLE = "Multi-Tagger"
71
+ DESCRIPTION = """
72
+ Multi-Tagger is a powerful and versatile application that integrates two cutting-edge models: Waifu Diffusion and Florence 2. This app is designed to provide comprehensive image analysis and captioning capabilities, making it a valuable tool for AI artists, researchers, and enthusiasts.
73
+
74
+ Features:
75
+ - Supports batch processing of multiple images.
76
+ - Tags images with multiple categories: general tags, character tags, and ratings.
77
+ - Tags are categorized into groups (e.g., general, characters, ratings).
78
+ - Displays categorized tags in a structured format.
79
+ - Integrates Llama3 models to reorganize the tags into a readable English article.
80
+ - Includes a separate tab for image captioning using Florence 2.
81
+ - Florence 2 supports CUDA, MPS or CPU if one of them is available.
82
+ - Supports various captioning tasks (e.g., Caption, Detailed Caption, Object Detection).
83
+ - Displays output text and images for tasks that generate visual outputs.
84
+ - The space will restart every 2 days to ensure stability and performance. It uses a background scheduler to handle the restart process.
85
+
86
+ Example image by [me.](https://huggingface.co/Werli)
87
+ """
88
+ colormap = ['blue','orange','green','purple','brown','pink','gray','olive','cyan','red',
89
+ 'lime','indigo','violet','aqua','magenta','coral','gold','tan','skyblue']
90
+
91
+ # Dataset v3 series of models:
92
+ SWINV2_MODEL_DSV3_REPO = "SmilingWolf/wd-swinv2-tagger-v3"
93
+ CONV_MODEL_DSV3_REPO = "SmilingWolf/wd-convnext-tagger-v3"
94
+ VIT_MODEL_DSV3_REPO = "SmilingWolf/wd-vit-tagger-v3"
95
+ VIT_LARGE_MODEL_DSV3_REPO = "SmilingWolf/wd-vit-large-tagger-v3"
96
+ EVA02_LARGE_MODEL_DSV3_REPO = "SmilingWolf/wd-eva02-large-tagger-v3"
97
+
98
+ # Dataset v2 series of models:
99
+ MOAT_MODEL_DSV2_REPO = "SmilingWolf/wd-v1-4-moat-tagger-v2"
100
+ SWIN_MODEL_DSV2_REPO = "SmilingWolf/wd-v1-4-swinv2-tagger-v2"
101
+ CONV_MODEL_DSV2_REPO = "SmilingWolf/wd-v1-4-convnext-tagger-v2"
102
+ CONV2_MODEL_DSV2_REPO = "SmilingWolf/wd-v1-4-convnextv2-tagger-v2"
103
+ VIT_MODEL_DSV2_REPO = "SmilingWolf/wd-v1-4-vit-tagger-v2"
104
+
105
+ # IdolSankaku series of models:
106
+ EVA02_LARGE_MODEL_IS_DSV1_REPO = "deepghs/idolsankaku-eva02-large-tagger-v1"
107
+ SWINV2_MODEL_IS_DSV1_REPO = "deepghs/idolsankaku-swinv2-tagger-v1"
108
+
109
+ # Files to download from the repos
110
+ MODEL_FILENAME = "model.onnx"
111
+ LABEL_FILENAME = "selected_tags.csv"
112
+
113
+ # LLAMA model
114
+ META_LLAMA_3_3B_REPO = "jncraton/Llama-3.2-3B-Instruct-ct2-int8"
115
+ META_LLAMA_3_8B_REPO = "avans06/Meta-Llama-3.2-8B-Instruct-ct2-int8_float16"
116
+
117
+ # https://github.com/toriato/stable-diffusion-webui-wd14-tagger/blob/a9eacb1eff904552d3012babfa28b57e1d3e295c/tagger/ui.py#L368
118
+ kaomojis = [
119
+ "0_0",
120
+ "(o)_(o)",
121
+ "+_+",
122
+ "+_-",
123
+ "._.",
124
+ "<o>_<o>",
125
+ "<|>_<|>",
126
+ "=_=",
127
+ ">_<",
128
+ "3_3",
129
+ "6_9",
130
+ ">_o",
131
+ "@_@",
132
+ "^_^",
133
+ "o_o",
134
+ "u_u",
135
+ "x_x",
136
+ "|_|",
137
+ "||_||",
138
+ ]
139
+ def parse_args() -> argparse.Namespace:
140
+ parser = argparse.ArgumentParser()
141
+ parser.add_argument("--score-slider-step", type=float, default=0.05)
142
+ parser.add_argument("--score-general-threshold", type=float, default=0.35)
143
+ parser.add_argument("--score-character-threshold", type=float, default=0.85)
144
+ parser.add_argument("--share", action="store_true")
145
+ return parser.parse_args()
146
+ def load_labels(dataframe) -> list[str]:
147
+ name_series = dataframe["name"]
148
+ name_series = name_series.map(
149
+ lambda x: x.replace("_", " ") if x not in kaomojis else x
150
+ )
151
+ tag_names = name_series.tolist()
152
+
153
+ rating_indexes = list(np.where(dataframe["category"] == 9)[0])
154
+ general_indexes = list(np.where(dataframe["category"] == 0)[0])
155
+ character_indexes = list(np.where(dataframe["category"] == 4)[0])
156
+ return tag_names, rating_indexes, general_indexes, character_indexes
157
+ def mcut_threshold(probs):
158
+ """
159
+ Maximum Cut Thresholding (MCut)
160
+ Largeron, C., Moulin, C., & Gery, M. (2012). MCut: A Thresholding Strategy
161
+ for Multi-label Classification. In 11th International Symposium, IDA 2012
162
+ (pp. 172-183).
163
+ """
164
+ sorted_probs = probs[probs.argsort()[::-1]]
165
+ difs = sorted_probs[:-1] - sorted_probs[1:]
166
+ t = difs.argmax()
167
+ thresh = (sorted_probs[t] + sorted_probs[t + 1]) / 2
168
+ return thresh
169
+ class Timer:
170
+ def __init__(self):
171
+ self.start_time = time.perf_counter() # Record the start time
172
+ self.checkpoints = [("Start", self.start_time)] # Store checkpoints
173
+
174
+ def checkpoint(self, label="Checkpoint"):
175
+ """Record a checkpoint with a given label."""
176
+ now = time.perf_counter()
177
+ self.checkpoints.append((label, now))
178
+
179
+ def report(self, is_clear_checkpoints = True):
180
+ # Determine the max label width for alignment
181
+ max_label_length = max(len(label) for label, _ in self.checkpoints)
182
+
183
+ prev_time = self.checkpoints[0][1]
184
+ for label, curr_time in self.checkpoints[1:]:
185
+ elapsed = curr_time - prev_time
186
+ print(f"{label.ljust(max_label_length)}: {elapsed:.3f} seconds")
187
+ prev_time = curr_time
188
+
189
+ if is_clear_checkpoints:
190
+ self.checkpoints.clear()
191
+ self.checkpoint() # Store checkpoints
192
+
193
+ def report_all(self):
194
+ """Print all recorded checkpoints and total execution time with aligned formatting."""
195
+ print("\n> Execution Time Report:")
196
+
197
+ # Determine the max label width for alignment
198
+ max_label_length = max(len(label) for label, _ in self.checkpoints) if len(self.checkpoints) > 0 else 0
199
+
200
+ prev_time = self.start_time
201
+ for label, curr_time in self.checkpoints[1:]:
202
+ elapsed = curr_time - prev_time
203
+ print(f"{label.ljust(max_label_length)}: {elapsed:.3f} seconds")
204
+ prev_time = curr_time
205
+
206
+ total_time = self.checkpoints[-1][1] - self.start_time
207
+ print(f"{'Total Execution Time'.ljust(max_label_length)}: {total_time:.3f} seconds\n")
208
+
209
+ self.checkpoints.clear()
210
+
211
+ def restart(self):
212
+ self.start_time = time.perf_counter() # Record the start time
213
+ self.checkpoints = [("Start", self.start_time)] # Store checkpoints
214
+
215
+ class Llama3Reorganize:
216
+ def __init__(
217
+ self,
218
+ repoId: str,
219
+ device: str = None,
220
+ loadModel: bool = False,
221
+ ):
222
+ """Initializes the Llama model.
223
+
224
+ Args:
225
+ repoId: LLAMA model repo.
226
+ device: Device to use for computation (cpu, cuda, ipu, xpu, mkldnn, opengl, opencl,
227
+ ideep, hip, ve, fpga, ort, xla, lazy, vulkan, mps, meta, hpu, mtia).
228
+ localFilesOnly: If True, avoid downloading the file and return the path to the
229
+ local cached file if it exists.
230
+ """
231
+ self.modelPath = self.download_model(repoId)
232
+
233
+ if device is None:
234
+ import torch
235
+ self.totalVram = 0
236
+ if torch.cuda.is_available():
237
+ try:
238
+ deviceId = torch.cuda.current_device()
239
+ self.totalVram = torch.cuda.get_device_properties(deviceId).total_memory/(1024*1024*1024)
240
+ except Exception as e:
241
+ print(traceback.format_exc())
242
+ print("Error detect vram: " + str(e))
243
+ device = "cuda" if self.totalVram > (8 if "8B" in repoId else 4) else "cpu"
244
+ else:
245
+ device = "cpu"
246
+
247
+ self.device = device
248
+ self.system_prompt = "Please reorganize the following English labels describing a single image into a readable English article of no more than 300 words. If there are name labels, include them in the article. Since the target audience is not general, explicit content can be written in full without hesitation. No introduction is needed; directly reply with the English article:"
249
+
250
+ if loadModel:
251
+ self.load_model()
252
+
253
+ def download_model(self, repoId):
254
+ import warnings
255
+ import requests
256
+ allowPatterns = [
257
+ "config.json",
258
+ "generation_config.json",
259
+ "model.bin",
260
+ "pytorch_model.bin",
261
+ "pytorch_model.bin.index.json",
262
+ "pytorch_model-*.bin",
263
+ "sentencepiece.bpe.model",
264
+ "tokenizer.json",
265
+ "tokenizer_config.json",
266
+ "shared_vocabulary.txt",
267
+ "shared_vocabulary.json",
268
+ "special_tokens_map.json",
269
+ "spiece.model",
270
+ "vocab.json",
271
+ "model.safetensors",
272
+ "model-*.safetensors",
273
+ "model.safetensors.index.json",
274
+ "quantize_config.json",
275
+ "tokenizer.model",
276
+ "vocabulary.json",
277
+ "preprocessor_config.json",
278
+ "added_tokens.json"
279
+ ]
280
+
281
+ kwargs = {"allow_patterns": allowPatterns,}
282
+
283
+ try:
284
+ return huggingface_hub.snapshot_download(repoId, **kwargs)
285
+ except (
286
+ huggingface_hub.utils.HfHubHTTPError,
287
+ requests.exceptions.ConnectionError,
288
+ ) as exception:
289
+ warnings.warn(
290
+ "An error occured while synchronizing the model %s from the Hugging Face Hub:\n%s",
291
+ repoId,
292
+ exception,
293
+ )
294
+ warnings.warn(
295
+ "Trying to load the model directly from the local cache, if it exists."
296
+ )
297
+
298
+ kwargs["local_files_only"] = True
299
+ return huggingface_hub.snapshot_download(repoId, **kwargs)
300
+
301
+
302
+ def load_model(self):
303
+ import ctranslate2
304
+ import transformers
305
+ try:
306
+ print('\n\nLoading model: %s\n\n' % self.modelPath)
307
+ kwargsTokenizer = {"pretrained_model_name_or_path": self.modelPath}
308
+ kwargsModel = {"device": self.device, "model_path": self.modelPath, "compute_type": "auto"}
309
+ self.roleSystem = {"role": "system", "content": self.system_prompt}
310
+ self.Model = ctranslate2.Generator(**kwargsModel)
311
+
312
+ self.Tokenizer = transformers.AutoTokenizer.from_pretrained(**kwargsTokenizer)
313
+ self.terminators = [self.Tokenizer.eos_token_id, self.Tokenizer.convert_tokens_to_ids("<|eot_id|>")]
314
+
315
+ except Exception as e:
316
+ self.release_vram()
317
+ raise e
318
+
319
+
320
+ def release_vram(self):
321
+ try:
322
+ import torch
323
+ if torch.cuda.is_available():
324
+ if getattr(self, "Model", None) is not None and getattr(self.Model, "unload_model", None) is not None:
325
+ self.Model.unload_model()
326
+
327
+ if getattr(self, "Tokenizer", None) is not None:
328
+ del self.Tokenizer
329
+ if getattr(self, "Model", None) is not None:
330
+ del self.Model
331
+ import gc
332
+ gc.collect()
333
+ try:
334
+ torch.cuda.empty_cache()
335
+ except Exception as e:
336
+ print(traceback.format_exc())
337
+ print("\tcuda empty cache, error: " + str(e))
338
+ print("release vram end.")
339
+ except Exception as e:
340
+ print(traceback.format_exc())
341
+ print("Error release vram: " + str(e))
342
+
343
+ def reorganize(self, text: str, max_length: int = 400):
344
+ output = None
345
+ result = None
346
+ try:
347
+ input_ids = self.Tokenizer.apply_chat_template([self.roleSystem, {"role": "user", "content": text + "\n\nHere's the reorganized English article:"}], tokenize=False, add_generation_prompt=True)
348
+ source = self.Tokenizer.convert_ids_to_tokens(self.Tokenizer.encode(input_ids))
349
+ output = self.Model.generate_batch([source], max_length=max_length, max_batch_size=2, no_repeat_ngram_size=3, beam_size=2, sampling_temperature=0.7, sampling_topp=0.9, include_prompt_in_result=False, end_token=self.terminators)
350
+ target = output[0]
351
+ result = self.Tokenizer.decode(target.sequences_ids[0])
352
+
353
+ if len(result) > 2:
354
+ if result[0] == "\"" and result[len(result) - 1] == "\"":
355
+ result = result[1:-1]
356
+ elif result[0] == "'" and result[len(result) - 1] == "'":
357
+ result = result[1:-1]
358
+ elif result[0] == "「" and result[len(result) - 1] == "」":
359
+ result = result[1:-1]
360
+ elif result[0] == "『" and result[len(result) - 1] == "』":
361
+ result = result[1:-1]
362
+ except Exception as e:
363
+ print(traceback.format_exc())
364
+ print("Error reorganize text: " + str(e))
365
+
366
+ return result
367
+
368
+
369
+ class Predictor:
370
+ def __init__(self):
371
+ self.model_target_size = None
372
+ self.last_loaded_repo = None
373
+ def download_model(self, model_repo):
374
+ csv_path = huggingface_hub.hf_hub_download(
375
+ model_repo,
376
+ LABEL_FILENAME,
377
+ )
378
+ model_path = huggingface_hub.hf_hub_download(
379
+ model_repo,
380
+ MODEL_FILENAME,
381
+ )
382
+ return csv_path, model_path
383
+ def load_model(self, model_repo):
384
+ if model_repo == self.last_loaded_repo:
385
+ return
386
+
387
+ csv_path, model_path = self.download_model(model_repo)
388
+
389
+ tags_df = pd.read_csv(csv_path)
390
+ sep_tags = load_labels(tags_df)
391
+
392
+ self.tag_names = sep_tags[0]
393
+ self.rating_indexes = sep_tags[1]
394
+ self.general_indexes = sep_tags[2]
395
+ self.character_indexes = sep_tags[3]
396
+
397
+ model = rt.InferenceSession(model_path)
398
+ _, height, width, _ = model.get_inputs()[0].shape
399
+ self.model_target_size = height
400
+
401
+ self.last_loaded_repo = model_repo
402
+ self.model = model
403
+ def prepare_image(self, path):
404
+ image = Image.open(path)
405
+ image = image.convert("RGBA")
406
+ target_size = self.model_target_size
407
+
408
+ canvas = Image.new("RGBA", image.size, (255, 255, 255))
409
+ canvas.alpha_composite(image)
410
+ image = canvas.convert("RGB")
411
+
412
+ # Pad image to square
413
+ image_shape = image.size
414
+ max_dim = max(image_shape)
415
+ pad_left = (max_dim - image_shape[0]) // 2
416
+ pad_top = (max_dim - image_shape[1]) // 2
417
+
418
+ padded_image = Image.new("RGB", (max_dim, max_dim), (255, 255, 255))
419
+ padded_image.paste(image, (pad_left, pad_top))
420
+
421
+ # Resize
422
+ if max_dim != target_size:
423
+ padded_image = padded_image.resize(
424
+ (target_size, target_size),
425
+ Image.BICUBIC,
426
+ )
427
+ # Convert to numpy array
428
+ image_array = np.asarray(padded_image, dtype=np.float32)
429
+
430
+ # Convert PIL-native RGB to BGR
431
+ image_array = image_array[:, :, ::-1]
432
+
433
+ return np.expand_dims(image_array, axis=0)
434
+
435
+ def create_file(self, text: str, directory: str, fileName: str) -> str:
436
+ # Write the text to a file
437
+ with open(os.path.join(directory, fileName), 'w+', encoding="utf-8") as file:
438
+ file.write(text)
439
+
440
+ return file.name
441
+
442
+ def predict(
443
+ self,
444
+ gallery,
445
+ model_repo,
446
+ general_thresh,
447
+ general_mcut_enabled,
448
+ character_thresh,
449
+ character_mcut_enabled,
450
+ characters_merge_enabled,
451
+ llama3_reorganize_model_repo,
452
+ additional_tags_prepend,
453
+ additional_tags_append,
454
+ tag_results,
455
+ progress=gr.Progress()
456
+ ):
457
+ gallery_len = len(gallery)
458
+ print(f"Predict load model: {model_repo}, gallery length: {gallery_len}")
459
+
460
+ timer = Timer() # Create a timer
461
+ progressRatio = 0.5 if llama3_reorganize_model_repo else 1
462
+ progressTotal = gallery_len + 1
463
+ current_progress = 0
464
+
465
+ self.load_model(model_repo)
466
+ current_progress += progressRatio/progressTotal;
467
+ progress(current_progress, desc="Initialize wd model finished")
468
+ timer.checkpoint(f"Initialize wd model")
469
+
470
+ # Result
471
+ txt_infos = []
472
+ output_dir = tempfile.mkdtemp()
473
+ if not os.path.exists(output_dir):
474
+ os.makedirs(output_dir)
475
+
476
+ sorted_general_strings = ""
477
+ rating = None
478
+ character_res = None
479
+ general_res = None
480
+
481
+ if llama3_reorganize_model_repo:
482
+ print(f"Llama3 reorganize load model {llama3_reorganize_model_repo}")
483
+ llama3_reorganize = Llama3Reorganize(llama3_reorganize_model_repo, loadModel=True)
484
+ current_progress += progressRatio/progressTotal;
485
+ progress(current_progress, desc="Initialize llama3 model finished")
486
+ timer.checkpoint(f"Initialize llama3 model")
487
+
488
+ timer.report()
489
+
490
+ prepend_list = [tag.strip() for tag in additional_tags_prepend.split(",") if tag.strip()]
491
+ append_list = [tag.strip() for tag in additional_tags_append.split(",") if tag.strip()]
492
+ if prepend_list and append_list:
493
+ append_list = [item for item in append_list if item not in prepend_list]
494
+
495
+ # Dictionary to track counters for each filename
496
+ name_counters = defaultdict(int)
497
+ # New code to create categorized output string
498
+ categorized_output_strings = []
499
+ for idx, value in enumerate(gallery):
500
+ try:
501
+ image_path = value[0]
502
+ image_name = os.path.splitext(os.path.basename(image_path))[0]
503
+
504
+ # Increment the counter for the current name
505
+ name_counters[image_name] += 1
506
+
507
+ if name_counters[image_name] > 1:
508
+ image_name = f"{image_name}_{name_counters[image_name]:02d}"
509
+
510
+ image = self.prepare_image(image_path)
511
+
512
+ input_name = self.model.get_inputs()[0].name
513
+ label_name = self.model.get_outputs()[0].name
514
+ print(f"Gallery {idx:02d}: Starting run wd model...")
515
+ preds = self.model.run([label_name], {input_name: image})[0]
516
+
517
+ labels = list(zip(self.tag_names, preds[0].astype(float)))
518
+
519
+ # First 4 labels are actually ratings: pick one with argmax
520
+ ratings_names = [labels[i] for i in self.rating_indexes]
521
+ rating = dict(ratings_names)
522
+
523
+ # Then we have general tags: pick any where prediction confidence > threshold
524
+ general_names = [labels[i] for i in self.general_indexes]
525
+
526
+ if general_mcut_enabled:
527
+ general_probs = np.array([x[1] for x in general_names])
528
+ general_thresh = mcut_threshold(general_probs)
529
+
530
+ general_res = [x for x in general_names if x[1] > general_thresh]
531
+ general_res = dict(general_res)
532
+
533
+ # Everything else is characters: pick any where prediction confidence > threshold
534
+ character_names = [labels[i] for i in self.character_indexes]
535
+
536
+ if character_mcut_enabled:
537
+ character_probs = np.array([x[1] for x in character_names])
538
+ character_thresh = mcut_threshold(character_probs)
539
+ character_thresh = max(0.15, character_thresh)
540
+
541
+ character_res = [x for x in character_names if x[1] > character_thresh]
542
+ character_res = dict(character_res)
543
+ character_list = list(character_res.keys())
544
+
545
+ sorted_general_list = sorted(
546
+ general_res.items(),
547
+ key=lambda x: x[1],
548
+ reverse=True,
549
+ )
550
+ sorted_general_list = [x[0] for x in sorted_general_list]
551
+ #Remove values from character_list that already exist in sorted_general_list
552
+ character_list = [item for item in character_list if item not in sorted_general_list]
553
+ #Remove values from sorted_general_list that already exist in prepend_list or append_list
554
+ if prepend_list:
555
+ sorted_general_list = [item for item in sorted_general_list if item not in prepend_list]
556
+ if append_list:
557
+ sorted_general_list = [item for item in sorted_general_list if item not in append_list]
558
+
559
+ sorted_general_list = prepend_list + sorted_general_list + append_list
560
+
561
+ sorted_general_strings = ", ".join((character_list if characters_merge_enabled else []) + sorted_general_list).replace("(", "\(").replace(")", "\)")
562
+
563
+ classified_tags, unclassified_tags = classify_tags(sorted_general_list)
564
+
565
+ # Create a single string of all categorized tags
566
+ categorized_output_string = ', '.join([', '.join(tags) for tags in classified_tags.values()])
567
+ categorized_output_strings.append(categorized_output_string)
568
+
569
+ current_progress += progressRatio/progressTotal;
570
+ progress(current_progress, desc=f"image{idx:02d}, predict finished")
571
+ timer.checkpoint(f"image{idx:02d}, predict finished")
572
+
573
+ if llama3_reorganize_model_repo:
574
+ print(f"Starting reorganize with llama3...")
575
+ reorganize_strings = llama3_reorganize.reorganize(sorted_general_strings)
576
+ reorganize_strings = re.sub(r" *Title: *", "", reorganize_strings)
577
+ reorganize_strings = re.sub(r"\n+", ",", reorganize_strings)
578
+ reorganize_strings = re.sub(r",,+", ",", reorganize_strings)
579
+ sorted_general_strings += "," + reorganize_strings
580
+
581
+ current_progress += progressRatio/progressTotal;
582
+ progress(current_progress, desc=f"image{idx:02d}, llama3 reorganize finished")
583
+ timer.checkpoint(f"image{idx:02d}, llama3 reorganize finished")
584
+
585
+ txt_file = self.create_file(sorted_general_strings, output_dir, image_name + ".txt")
586
+ txt_infos.append({"path":txt_file, "name": image_name + ".txt"})
587
+
588
+ tag_results[image_path] = { "strings": sorted_general_strings, "classified_tags": classified_tags, "rating": rating, "character_res": character_res, "general_res": general_res, "unclassified_tags": unclassified_tags }
589
+ timer.report()
590
+ except Exception as e:
591
+ print(traceback.format_exc())
592
+ print("Error predict: " + str(e))
593
+ # Result
594
+ download = []
595
+ if txt_infos is not None and len(txt_infos) > 0:
596
+ downloadZipPath = os.path.join(output_dir, "images-tagger-" + datetime.now().strftime("%Y%m%d-%H%M%S") + ".zip")
597
+ with zipfile.ZipFile(downloadZipPath, 'w', zipfile.ZIP_DEFLATED) as taggers_zip:
598
+ for info in txt_infos:
599
+ # Get file name from lookup
600
+ taggers_zip.write(info["path"], arcname=info["name"])
601
+ download.append(downloadZipPath)
602
+
603
+ if llama3_reorganize_model_repo:
604
+ llama3_reorganize.release_vram()
605
+ del llama3_reorganize
606
+
607
+ progress(1, desc=f"Predict completed")
608
+ timer.report_all() # Print all recorded times
609
+ print("Predict is complete.")
610
+
611
+ # Collect all categorized output strings into a single string
612
+ final_categorized_output = ', '.join(categorized_output_strings)
613
+
614
+ return download, sorted_general_strings, classified_tags, rating, character_res, general_res, unclassified_tags, tag_results, final_categorized_output
615
+ # END
616
+
617
+ def get_selection_from_gallery(gallery: list, tag_results: dict, selected_state: gr.SelectData):
618
+ if not selected_state:
619
+ return selected_state
620
+
621
+ tag_result = { "strings": "", "classified_tags": "{}", "rating": "", "character_res": "", "general_res": "", "unclassified_tags": "{}" }
622
+ if selected_state.value["image"]["path"] in tag_results:
623
+ tag_result = tag_results[selected_state.value["image"]["path"]]
624
+
625
+ return (selected_state.value["image"]["path"], selected_state.value["caption"]), tag_result["strings"], tag_result["classified_tags"], tag_result["rating"], tag_result["character_res"], tag_result["general_res"], tag_result["unclassified_tags"]
626
+
627
+ def append_gallery(gallery: list, image: str):
628
+ if gallery is None:
629
+ gallery = []
630
+ if not image:
631
+ return gallery, None
632
+
633
+ gallery.append(image)
634
+
635
+ return gallery, None
636
+
637
+
638
+ def extend_gallery(gallery: list, images):
639
+ if gallery is None:
640
+ gallery = []
641
+ if not images:
642
+ return gallery
643
+
644
+ # Combine the new images with the existing gallery images
645
+ gallery.extend(images)
646
+
647
+ return gallery
648
+
649
+ def remove_image_from_gallery(gallery: list, selected_image: str):
650
+ if not gallery or not selected_image:
651
+ return gallery
652
+
653
+ selected_image = ast.literal_eval(selected_image) #Use ast.literal_eval to parse text into a tuple.
654
+ # Remove the selected image from the gallery
655
+ if selected_image in gallery:
656
+ gallery.remove(selected_image)
657
+ return gallery
658
+
659
+ # END
660
+
661
+ def fig_to_pil(fig):
662
+ buf = io.BytesIO()
663
+ fig.savefig(buf, format='png')
664
+ buf.seek(0)
665
+ return Image.open(buf)
666
+
667
+ @spaces.GPU
668
+ def run_example(task_prompt, image, text_input=None):
669
+ if text_input is None:
670
+ prompt = task_prompt
671
+ else:
672
+ prompt = task_prompt + text_input
673
+ inputs = processor(text=prompt, images=image, return_tensors="pt").to(device)
674
+ generated_ids = model.generate(
675
+ input_ids=inputs["input_ids"],
676
+ pixel_values=inputs["pixel_values"],
677
+ max_new_tokens=1024,
678
+ early_stopping=False,
679
+ do_sample=False,
680
+ num_beams=3,
681
+ )
682
+ generated_text = processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
683
+ parsed_answer = processor.post_process_generation(
684
+ generated_text,
685
+ task=task_prompt,
686
+ image_size=(image.width, image.height)
687
+ )
688
+ return parsed_answer
689
+
690
+ def plot_bbox(image, data):
691
+ fig, ax = plt.subplots()
692
+ ax.imshow(image)
693
+ for bbox, label in zip(data['bboxes'], data['labels']):
694
+ x1, y1, x2, y2 = bbox
695
+ rect = patches.Rectangle((x1, y1), x2-x1, y2-y1, linewidth=1, edgecolor='r', facecolor='none')
696
+ ax.add_patch(rect)
697
+ plt.text(x1, y1, label, color='white', fontsize=8, bbox=dict(facecolor='red', alpha=0.5))
698
+ ax.axis('off')
699
+ return fig
700
+
701
+ def draw_polygons(image, prediction, fill_mask=False):
702
+ draw = ImageDraw.Draw(image)
703
+ scale = 1
704
+ for polygons, label in zip(prediction['polygons'], prediction['labels']):
705
+ color = random.choice(colormap)
706
+ fill_color = random.choice(colormap) if fill_mask else None
707
+ for _polygon in polygons:
708
+ _polygon = np.array(_polygon).reshape(-1, 2)
709
+ if len(_polygon) < 3:
710
+ print('Invalid polygon:', _polygon)
711
+ continue
712
+ _polygon = (_polygon * scale).reshape(-1).tolist()
713
+ if fill_mask:
714
+ draw.polygon(_polygon, outline=color, fill=fill_color)
715
+ else:
716
+ draw.polygon(_polygon, outline=color)
717
+ draw.text((_polygon[0] + 8, _polygon[1] + 2), label, fill=color)
718
+ return image
719
+
720
+ def convert_to_od_format(data):
721
+ bboxes = data.get('bboxes', [])
722
+ labels = data.get('bboxes_labels', [])
723
+ od_results = {
724
+ 'bboxes': bboxes,
725
+ 'labels': labels
726
+ }
727
+ return od_results
728
+
729
+ def draw_ocr_bboxes(image, prediction):
730
+ scale = 1
731
+ draw = ImageDraw.Draw(image)
732
+ bboxes, labels = prediction['quad_boxes'], prediction['labels']
733
+ for box, label in zip(bboxes, labels):
734
+ color = random.choice(colormap)
735
+ new_box = (np.array(box) * scale).tolist()
736
+ draw.polygon(new_box, width=3, outline=color)
737
+ draw.text((new_box[0]+8, new_box[1]+2),
738
+ "{}".format(label),
739
+ align="right",
740
+ fill=color)
741
+ return image
742
+
743
+ def convert_to_od_format(data):
744
+ bboxes = data.get('bboxes', [])
745
+ labels = data.get('bboxes_labels', [])
746
+ od_results = {
747
+ 'bboxes': bboxes,
748
+ 'labels': labels
749
+ }
750
+ return od_results
751
+
752
+ def draw_ocr_bboxes(image, prediction):
753
+ scale = 1
754
+ draw = ImageDraw.Draw(image)
755
+ bboxes, labels = prediction['quad_boxes'], prediction['labels']
756
+ for box, label in zip(bboxes, labels):
757
+ color = random.choice(colormap)
758
+ new_box = (np.array(box) * scale).tolist()
759
+ draw.polygon(new_box, width=3, outline=color)
760
+ draw.text((new_box[0]+8, new_box[1]+2),
761
+ "{}".format(label),
762
+ align="right",
763
+ fill=color)
764
+ return image
765
+ def process_image(image, task_prompt, text_input=None):
766
+ # Test
767
+ if isinstance(image, str): # If image is a file path
768
+ image = Image.open(image) # Load image from file path
769
+ else: # If image is a NumPy array
770
+ image = Image.fromarray(image) # Convert NumPy array to PIL Image
771
+ if task_prompt == 'Caption':
772
+ task_prompt = '<CAPTION>'
773
+ results = run_example(task_prompt, image)
774
+ return results[task_prompt], None
775
+ elif task_prompt == 'Detailed Caption':
776
+ task_prompt = '<DETAILED_CAPTION>'
777
+ results = run_example(task_prompt, image)
778
+ return results[task_prompt], None
779
+ elif task_prompt == 'More Detailed Caption':
780
+ task_prompt = '<MORE_DETAILED_CAPTION>'
781
+ results = run_example(task_prompt, image)
782
+ return results[task_prompt], plot_bbox(image, results['<CAPTION_TO_PHRASE_GROUNDING>'])
783
+ elif task_prompt == 'Caption + Grounding':
784
+ task_prompt = '<CAPTION>'
785
+ results = run_example(task_prompt, image)
786
+ text_input = results[task_prompt]
787
+ task_prompt = '<CAPTION_TO_PHRASE_GROUNDING>'
788
+ results = run_example(task_prompt, image, text_input)
789
+ results['<CAPTION>'] = text_input
790
+ fig = plot_bbox(image, results['<CAPTION_TO_PHRASE_GROUNDING>'])
791
+ return results, fig_to_pil(fig)
792
+ elif task_prompt == 'Detailed Caption + Grounding':
793
+ task_prompt = '<DETAILED_CAPTION>'
794
+ results = run_example(task_prompt, image)
795
+ text_input = results[task_prompt]
796
+ task_prompt = '<CAPTION_TO_PHRASE_GROUNDING>'
797
+ results = run_example(task_prompt, image, text_input)
798
+ results['<DETAILED_CAPTION>'] = text_input
799
+ fig = plot_bbox(image, results['<CAPTION_TO_PHRASE_GROUNDING>'])
800
+ return results, fig_to_pil(fig)
801
+ elif task_prompt == 'More Detailed Caption + Grounding':
802
+ task_prompt = '<MORE_DETAILED_CAPTION>'
803
+ results = run_example(task_prompt, image)
804
+ text_input = results[task_prompt]
805
+ task_prompt = '<CAPTION_TO_PHRASE_GROUNDING>'
806
+ results = run_example(task_prompt, image, text_input)
807
+ results['<MORE_DETAILED_CAPTION>'] = text_input
808
+ fig = plot_bbox(image, results['<CAPTION_TO_PHRASE_GROUNDING>'])
809
+ return results, fig_to_pil(fig)
810
+ elif task_prompt == 'Object Detection':
811
+ task_prompt = '<OD>'
812
+ results = run_example(task_prompt, image)
813
+ fig = plot_bbox(image, results['<OD>'])
814
+ return results, fig_to_pil(fig)
815
+ elif task_prompt == 'Dense Region Caption':
816
+ task_prompt = '<DENSE_REGION_CAPTION>'
817
+ results = run_example(task_prompt, image)
818
+ fig = plot_bbox(image, results['<DENSE_REGION_CAPTION>'])
819
+ return results, fig_to_pil(fig)
820
+ elif task_prompt == 'Region Proposal':
821
+ task_prompt = '<REGION_PROPOSAL>'
822
+ results = run_example(task_prompt, image)
823
+ fig = plot_bbox(image, results['<REGION_PROPOSAL>'])
824
+ return results, fig_to_pil(fig)
825
+ elif task_prompt == 'Caption to Phrase Grounding':
826
+ task_prompt = '<CAPTION_TO_PHRASE_GROUNDING>'
827
+ results = run_example(task_prompt, image, text_input)
828
+ fig = plot_bbox(image, results['<CAPTION_TO_PHRASE_GROUNDING>'])
829
+ return results, fig_to_pil(fig)
830
+ elif task_prompt == 'Referring Expression Segmentation':
831
+ task_prompt = '<REFERRING_EXPRESSION_SEGMENTATION>'
832
+ results = run_example(task_prompt, image, text_input)
833
+ output_image = copy.deepcopy(image)
834
+ output_image = draw_polygons(output_image, results['<REFERRING_EXPRESSION_SEGMENTATION>'], fill_mask=True)
835
+ return results, output_image
836
+ elif task_prompt == 'Region to Segmentation':
837
+ task_prompt = '<REGION_TO_SEGMENTATION>'
838
+ results = run_example(task_prompt, image, text_input)
839
+ output_image = copy.deepcopy(image)
840
+ output_image = draw_polygons(output_image, results['<REGION_TO_SEGMENTATION>'], fill_mask=True)
841
+ return results, output_image
842
+ elif task_prompt == 'Open Vocabulary Detection':
843
+ task_prompt = '<OPEN_VOCABULARY_DETECTION>'
844
+ results = run_example(task_prompt, image, text_input)
845
+ bbox_results = convert_to_od_format(results['<OPEN_VOCABULARY_DETECTION>'])
846
+ fig = plot_bbox(image, bbox_results)
847
+ return results, fig_to_pil(fig)
848
+ elif task_prompt == 'Region to Category':
849
+ task_prompt = '<REGION_TO_CATEGORY>'
850
+ results = run_example(task_prompt, image, text_input)
851
+ return results, None
852
+ elif task_prompt == 'Region to Description':
853
+ task_prompt = '<REGION_TO_DESCRIPTION>'
854
+ results = run_example(task_prompt, image, text_input)
855
+ return results, None
856
+ elif task_prompt == 'OCR':
857
+ task_prompt = '<OCR>'
858
+ results = run_example(task_prompt, image)
859
+ return results, None
860
+ elif task_prompt == 'OCR with Region':
861
+ task_prompt = '<OCR_WITH_REGION>'
862
+ results = run_example(task_prompt, image)
863
+ output_image = copy.deepcopy(image)
864
+ output_image = draw_ocr_bboxes(output_image, results['<OCR_WITH_REGION>'])
865
+ return results, output_image
866
+ else:
867
+ return "", None # Return empty string and None for unknown task prompts
868
+ ##############
869
+ # Custom CSS to set the height of the gr.Dropdown menu
870
+ css = """
871
+ div.progress-level div.progress-level-inner {
872
+ text-align: left !important;
873
+ width: 55.5% !important;
874
+ #output {
875
+ height: 500px;
876
+ overflow: auto;
877
+ border: 1px solid #ccc;
878
+ }
879
+ """
880
+ single_task_list =[
881
+ 'Caption', 'Detailed Caption', 'More Detailed Caption', 'Object Detection',
882
+ 'Dense Region Caption', 'Region Proposal', 'Caption to Phrase Grounding',
883
+ 'Referring Expression Segmentation', 'Region to Segmentation',
884
+ 'Open Vocabulary Detection', 'Region to Category', 'Region to Description',
885
+ 'OCR', 'OCR with Region'
886
+ ]
887
+ cascaded_task_list =[
888
+ 'Caption + Grounding', 'Detailed Caption + Grounding', 'More Detailed Caption + Grounding'
889
+ ]
890
+ def update_task_dropdown(choice):
891
+ if choice == 'Cascaded task':
892
+ return gr.Dropdown(choices=cascaded_task_list, value='Caption + Grounding')
893
+ else:
894
+ return gr.Dropdown(choices=single_task_list, value='Caption')
895
+
896
+ args = parse_args()
897
+
898
+ predictor = Predictor()
899
+
900
+ dropdown_list = [
901
+ EVA02_LARGE_MODEL_DSV3_REPO,
902
+ SWINV2_MODEL_DSV3_REPO,
903
+ CONV_MODEL_DSV3_REPO,
904
+ VIT_MODEL_DSV3_REPO,
905
+ VIT_LARGE_MODEL_DSV3_REPO,
906
+ # ---
907
+ MOAT_MODEL_DSV2_REPO,
908
+ SWIN_MODEL_DSV2_REPO,
909
+ CONV_MODEL_DSV2_REPO,
910
+ CONV2_MODEL_DSV2_REPO,
911
+ VIT_MODEL_DSV2_REPO,
912
+ # ---
913
+ SWINV2_MODEL_IS_DSV1_REPO,
914
+ EVA02_LARGE_MODEL_IS_DSV1_REPO,
915
+ ]
916
+ llama_list = [
917
+ META_LLAMA_3_3B_REPO,
918
+ META_LLAMA_3_8B_REPO,
919
+ ]
920
+
921
+ # This is workaround will make the space restart every 2 days. (for test).
922
+ def _restart_space():
923
+ HF_TOKEN = os.getenv("HF_TOKEN")
924
+ if not HF_TOKEN:
925
+ raise ValueError("HF_TOKEN environment variable is not set.")
926
+ huggingface_hub.HfApi().restart_space(repo_id="Werli/Multi-Tagger", token=HF_TOKEN, factory_reboot=False)
927
+ scheduler = BackgroundScheduler()
928
+ # Add a job to restart the space every 2 days (172800 seconds)
929
+ restart_space_job = scheduler.add_job(_restart_space, "interval", seconds=172800)
930
+ # Start the scheduler
931
+ scheduler.start()
932
+ next_run_time_utc = restart_space_job.next_run_time.astimezone(timezone.utc)
933
+ NEXT_RESTART = f"Next Restart: {next_run_time_utc.strftime('%Y-%m-%d %H:%M:%S')} (UTC)"
934
+
935
+ # Using "reilnuud/polite" theme
936
+ with gr.Blocks(title=TITLE, css=css, theme="Werli/wd-tagger-images", fill_width=True) as demo:
937
+ gr.Markdown(value=f"<h1 style='text-align: center; margin-bottom: 1rem'>{TITLE}</h1>")
938
+ gr.Markdown(value=DESCRIPTION)
939
+ gr.Markdown(NEXT_RESTART)
940
+ with gr.Tab(label="Waifu Diffusion"):
941
+ with gr.Row():
942
+ with gr.Column():
943
+ submit = gr.Button(value="Submit", variant="primary", size="lg")
944
+ with gr.Column(variant="panel"):
945
+ # Create an Image component for uploading images
946
+ image_input = gr.Image(label="Upload an Image or clicking paste from clipboard button", type="filepath", sources=["upload", "clipboard"], height=150)
947
+ with gr.Row():
948
+ upload_button = gr.UploadButton("Upload multiple images", file_types=["image"], file_count="multiple", size="sm")
949
+ remove_button = gr.Button("Remove Selected Image", size="sm")
950
+ gallery = gr.Gallery(columns=5, rows=5, show_share_button=False, interactive=True, height="500px", label="Gallery that displaying a grid of images")
951
+
952
+ model_repo = gr.Dropdown(
953
+ dropdown_list,
954
+ value=EVA02_LARGE_MODEL_DSV3_REPO,
955
+ label="Model",
956
+ )
957
+ with gr.Row():
958
+ general_thresh = gr.Slider(
959
+ 0,
960
+ 1,
961
+ step=args.score_slider_step,
962
+ value=args.score_general_threshold,
963
+ label="General Tags Threshold",
964
+ scale=3,
965
+ )
966
+ general_mcut_enabled = gr.Checkbox(
967
+ value=False,
968
+ label="Use MCut threshold",
969
+ scale=1,
970
+ )
971
+ with gr.Row():
972
+ character_thresh = gr.Slider(
973
+ 0,
974
+ 1,
975
+ step=args.score_slider_step,
976
+ value=args.score_character_threshold,
977
+ label="Character Tags Threshold",
978
+ scale=3,
979
+ )
980
+ character_mcut_enabled = gr.Checkbox(
981
+ value=False,
982
+ label="Use MCut threshold",
983
+ scale=1,
984
+ )
985
+ with gr.Row():
986
+ characters_merge_enabled = gr.Checkbox(
987
+ value=True,
988
+ label="Merge characters into the string output",
989
+ scale=1,
990
+ )
991
+ with gr.Row():
992
+ llama3_reorganize_model_repo = gr.Dropdown(
993
+ [None] + llama_list,
994
+ value=None,
995
+ label="Llama3 Model",
996
+ info="Use the Llama3 model to reorganize the article (Note: very slow)",
997
+ )
998
+ with gr.Row():
999
+ additional_tags_prepend = gr.Text(label="Prepend Additional tags (comma split)")
1000
+ additional_tags_append = gr.Text(label="Append Additional tags (comma split)")
1001
+ with gr.Row():
1002
+ clear = gr.ClearButton(
1003
+ components=[
1004
+ gallery,
1005
+ model_repo,
1006
+ general_thresh,
1007
+ general_mcut_enabled,
1008
+ character_thresh,
1009
+ character_mcut_enabled,
1010
+ characters_merge_enabled,
1011
+ llama3_reorganize_model_repo,
1012
+ additional_tags_prepend,
1013
+ additional_tags_append,
1014
+ ],
1015
+ variant="secondary",
1016
+ size="lg",
1017
+ )
1018
+ with gr.Column(variant="panel"):
1019
+ download_file = gr.File(label="Output (Download)")
1020
+ sorted_general_strings = gr.Textbox(label="Output (string)", show_label=True, show_copy_button=True)
1021
+ categorized_output = gr.Textbox(label="Categorized Output (string)", show_label=True, show_copy_button=True)
1022
+ categorized = gr.JSON(label="Categorized (tags)")
1023
+ rating = gr.Label(label="Rating")
1024
+ character_res = gr.Label(label="Output (characters)")
1025
+ general_res = gr.Label(label="Output (tags)")
1026
+ unclassified = gr.JSON(label="Unclassified (tags)")
1027
+ clear.add(
1028
+ [
1029
+ download_file,
1030
+ sorted_general_strings,
1031
+ categorized,
1032
+ rating,
1033
+ character_res,
1034
+ general_res,
1035
+ unclassified,
1036
+ ]
1037
+ )
1038
+ tag_results = gr.State({})
1039
+ # Define the event listener to add the uploaded image to the gallery
1040
+ image_input.change(append_gallery, inputs=[gallery, image_input], outputs=[gallery, image_input])
1041
+ # When the upload button is clicked, add the new images to the gallery
1042
+ upload_button.upload(extend_gallery, inputs=[gallery, upload_button], outputs=gallery)
1043
+ # Event to update the selected image when an image is clicked in the gallery
1044
+ selected_image = gr.Textbox(label="Selected Image", visible=False)
1045
+ gallery.select(get_selection_from_gallery, inputs=[gallery, tag_results], outputs=[selected_image, sorted_general_strings, categorized, rating, character_res, general_res, unclassified])
1046
+ # Event to remove a selected image from the gallery
1047
+ remove_button.click(remove_image_from_gallery, inputs=[gallery, selected_image], outputs=gallery)
1048
+ submit.click(
1049
+ predictor.predict,
1050
+ inputs=[
1051
+ gallery,
1052
+ model_repo,
1053
+ general_thresh,
1054
+ general_mcut_enabled,
1055
+ character_thresh,
1056
+ character_mcut_enabled,
1057
+ characters_merge_enabled,
1058
+ llama3_reorganize_model_repo,
1059
+ additional_tags_prepend,
1060
+ additional_tags_append,
1061
+ tag_results,
1062
+ ],
1063
+ outputs=[download_file, sorted_general_strings, categorized, rating, character_res, general_res, unclassified, tag_results, categorized_output,],
1064
+ )
1065
+ gr.Examples(
1066
+ [["images/1girl.png", VIT_LARGE_MODEL_DSV3_REPO, 0.35, False, 0.85, False]],
1067
+ inputs=[
1068
+ image_input,
1069
+ model_repo,
1070
+ general_thresh,
1071
+ general_mcut_enabled,
1072
+ character_thresh,
1073
+ character_mcut_enabled,
1074
+ ],
1075
+ )
1076
+ with gr.Tab(label="Florence 2 Image Captioning"):
1077
+ with gr.Row():
1078
+ with gr.Column(variant="panel"):
1079
+ input_img = gr.Image(label="Input Picture")
1080
+ task_type = gr.Radio(choices=['Single task', 'Cascaded task'], label='Task type selector', value='Single task')
1081
+ task_prompt = gr.Dropdown(choices=single_task_list, label="Task Prompt", value="Caption")
1082
+ task_type.change(fn=update_task_dropdown, inputs=task_type, outputs=task_prompt)
1083
+ text_input = gr.Textbox(label="Text Input (optional)")
1084
+ submit_btn = gr.Button(value="Submit")
1085
+ with gr.Column(variant="panel"):
1086
+ #OUTPUT
1087
+ output_text = gr.Textbox(label="Output Text", show_label=True, show_copy_button=True, lines=8) # Here is the problem!
1088
+ output_img = gr.Image(label="Output Image")
1089
+ gr.Examples(
1090
+ examples=[
1091
+ ["images/image1.png", 'Object Detection'],
1092
+ ["images/image2.png", 'OCR with Region']
1093
+ ],
1094
+ inputs=[input_img, task_prompt],
1095
+ outputs=[output_text, output_img],
1096
+ fn=process_image,
1097
+ cache_examples=False,
1098
+ label='Try examples'
1099
+ )
1100
+ submit_btn.click(process_image, [input_img, task_prompt, text_input], [output_text, output_img])
1101
+
1102
+ demo.queue(max_size=2)
1103
+ demo.launch(debug=True) # test
classifyTags.py ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import defaultdict
2
+
3
+
4
+ def classify_tags (tags: list[str], local_test: bool = False):
5
+ # Dictionary for automatic classification
6
+ classified_tags: defaultdict[str, str] = defaultdict(list)
7
+ fuzzy_match_tags: defaultdict[str, str] = defaultdict(list)
8
+ fuzzy_match_keylen = 0
9
+ fuzzy_match_category = ""
10
+ unclassified_tags: list[str] = []
11
+
12
+
13
+ # Logic for automatic grouping
14
+ for tag in tags:
15
+ classified = False
16
+ tag_new = tag.replace(" ", "_").replace("-", "_").replace("\\(", "(").replace("\\)", ")") # Replace spaces in source tags with underscores \"
17
+
18
+ keyword = ""
19
+ category = ""
20
+ if tag_new in reversed_categories:
21
+ category = reversed_categories[tag_new]
22
+ classified = True
23
+ else:
24
+ tag_parts = tag_new.split("_") # Split tags by "_" to ensure keyword matching is based on whole words
25
+ for keyword, category in reversed_categories.items():
26
+ keyword = keyword.replace("-", "_").strip("_")
27
+ verify = tag_new.replace(keyword, "")
28
+ # Check if the tag contains the keyword
29
+ if (tag_new == keyword or tag_new.lstrip("0123456789") == keyword or (keyword in tag_new and (verify.startswith("_") or verify.endswith("_")))):
30
+ classified = True
31
+ elif any(tag_part == keyword for tag_part in tag_parts):
32
+ classified = True
33
+ elif local_test and keyword in tag_new and len(keyword) > fuzzy_match_keylen:
34
+ fuzzy_match_keylen = len(keyword)
35
+ fuzzy_match_category = category
36
+ if classified:
37
+ break
38
+
39
+ if classified and tag not in classified_tags[category]: # Avoid duplicates
40
+ classified_tags[category].append(tag)
41
+
42
+ if not classified and fuzzy_match_keylen > 0 and tag not in fuzzy_match_tags[fuzzy_match_category]:
43
+ classified = True
44
+ fuzzy_match_tags[fuzzy_match_category].append(tag)
45
+ fuzzy_match_keylen = 0
46
+ fuzzy_match_category = ""
47
+
48
+ if not classified and tag not in unclassified_tags:
49
+ unclassified_tags.append(tag) # Unclassified tags
50
+
51
+ if local_test:
52
+ # Output the grouping result
53
+ for category, tags in classified_tags.items():
54
+ print(f"{category}:")
55
+ print(", ".join(tags))
56
+ print()
57
+
58
+ print()
59
+ print("Fuzzy match:")
60
+ for category, tags in fuzzy_match_tags.items():
61
+ print(f"{category}:")
62
+ print(", ".join(tags))
63
+ print()
64
+ print()
65
+
66
+ if len(unclassified_tags) > 0:
67
+ print(f"\nUnclassified tags: {len(unclassified_tags)}")
68
+ print(f"{unclassified_tags[:200]}") # Display some unclassified tags
69
+
70
+ return classified_tags, unclassified_tags
71
+
72
+ # Define grouping rules (categories and keywords)
73
+ categories = {
74
+ "explicit" : ["sex", "69", "paizuri", "cum", "precum", "areola_slip", "hetero", "erection", "oral", "fellatio", "yaoi", "ejaculation", "ejaculating", "masturbation", "handjob", "bulge", "rape", "doggystyle", "threesome", "missionary", "object_insertion", "nipple", "nipples", "pussy", "anus", "penis", "groin", "testicles", "testicle", "anal", "cameltoe", "areolae", "dildo", "clitoris", "top-down_bottom-up", "gag", "groping", "gagged", "gangbang", "orgasm", "femdom", "incest", "bukkake", "breast_out", "vaginal", "vagina", "public_indecency", "breast_sucking", "folded", "cunnilingus", "foreskin", "bestiality", "footjob", "uterus", "flaccid", "defloration", "butt_plug", "cowgirl_position", "reverse_cowgirl_position", "squatting_cowgirl_position", "reverse_upright_straddle", "irrumatio", "deepthroat", "pokephilia", "gaping", "orgy", "cleft_of_venus", "futanari", "futasub", "futa", "cumdrip", "fingering", "vibrator", "partially_visible_vulva", "penetration", "penetrated", "cumshot", "exhibitionism", "breast_milk", "grinding", "clitoral", "urethra", "phimosis", "cervix", "impregnation", "tribadism", "molestation", "pubic_hair", "clothed_female_nude_male", "clothed_male_nude_female", "clothed_female_nude_female", "clothed_male_nude_male", "sex_machine", "milking_machine", "ovum", "chikan", "pussy_juice_drip_through_clothes", "ejaculating_while_penetrated", "suspended_congress", "reverse_suspended_congress", "spread_pussy_under_clothes", "anilingus", "reach-around", "humping", "consensual_tentacles", "tentacle_pit", ],
75
+ #外観状態/外觀狀態
76
+ "Appearance Status" : ["backless", "bandaged_neck", "bleeding", "blood", "blush", "body_writing", "bodypaint", "bottomless", "breath", "bruise", "butt_crack", "cold", "covered_mouth", "crack", "cross-section", "crotchless", "crying", "curvy", "cuts", "dirty", "dripping", "drunk", "from_mouth", "glowing", "hairy", "halterneck", "hot", "injury", "latex", "leather", "levitation", "lipstick_mark", "_markings", "makeup", "mole", "moles", "no_bra", "nosebleed", "nude", "outfit", "pantylines", "peeing", "piercing", "piercings", "pregnant", "public_nudity", "reverse", "_skin", "_submerged", "saliva", "scar", "scratches", "see-through", "shadow", "shibari", "sideless", "skindentation", "sleeping","tan", "soap_bubbles", "steam", "steaming_body", "stitches", "sweat", "sweatdrop", "sweaty", "tanlines", "tattoo", "tattoo", "tears", "topless", "transparent", "trefoil", "trembling", "veins", "visible_air", "wardrobe_malfunction", "wet", "x-ray", "unconscious", "handprint", ],
77
+ #動作姿勢/動作姿勢
78
+ "Action Pose" : ["afloat", "afterimage", "against_fourth_wall", "against_wall", "aiming", "all_fours", "another's_mouth", "arm_", "arm_support", "arms_", "arms_behind_back", "asphyxiation", "attack", "back", "ballet", "bara", "bathing", "battle", "bdsm", "beckoning", "bent_over", "bite_mark", "biting", "bondage", "breast_suppress", "breathing", "burning", "bust_cup", "carry", "carrying", "caught", "chained", "cheek_squash", "chewing", "cigarette", "clapping", "closed_eye", "come_hither", "cooking", "covering", "cuddling", "dancing", "_docking", "destruction", "dorsiflexion", "dreaming", "dressing", "drinking", "driving", "dropping", "eating", "exercise", "expansion", "exposure", "facing", "failure", "fallen_down", "falling", "feeding", "fetal_position", "fighting", "finger_on_trigger", "finger_to_cheek", "finger_to_mouth", "firing", "fishing", "flashing", "fleeing", "flexible", "flexing", "floating", "flying", "fourth_wall", "freediving", "frogtie", "_grab", "girl_on_top", "giving", "grabbing", "grabbing_", "gymnastics", "_hold", "hadanugi_dousa", "hairdressing", "hand_", "hand_on", "hand_on_wall", "hands_", "headpat", "hiding", "holding", "hug", "hugging", "imagining", "in_container", "in_mouth", "in_palm", "jealous", "jumping", "kabedon", "kicking", "kiss", "kissing", "kneeling", "_lift", "lactation", "laundry", "licking", "lifted_by_self", "looking", "lowleg", "lying", "melting", "midair", "moaning", "_open", "on_back", "on_bed", "on_ground", "on_lap", "on_one_knee", "one_eye_closed", "open_", "over_mouth", "own_mouth", "_peek", "_pose", "_press", "_pull", "padding", "paint", "painting_(action)", "palms_together", "pee", "peeking", "pervert", "petting", "pigeon-toed", "piggyback", "pinching", "pinky_out", "pinned", "plantar_flexion", "planted", "playing", "pocky", "pointing", "poke", "poking", "pouring", "pov", "praying", "presenting", "profanity", "pulled_by_self", "pulling", "pump_action", "punching", "_rest", "raised", "reaching", "reading", "reclining", "reverse_grip", "riding", "running", "_slip", "salute", "screaming", "seiza", "selfie", "sewing", "shaking", "shoe_dangle", "shopping", "shouting", "showering", "shushing", "singing", "sitting", "slapping", "smell", "smelling", "smoking", "smother", "solo", "spanked", "spill", "spilling", "spinning", "splashing", "split", "squatting", "squeezed", "standing", "staring", "straddling", "strangling", "stretching", "surfing", "suspension", "swimming", "talking", "teardrop", "tearing_clothes", "throwing", "tied_up", "tiptoes", "toe_scrunch", "toothbrush", "trigger_discipline", "tripping", "tsundere", "turning_head", "twitching", "two-handed", "tying", "_up", "unbuttoned", "undressed", "undressing", "unsheathed", "unsheathing", "unzipped", "unzipping", "upright_straddle", "v", "V", "vore", "_wielding","wading", "walk-in", "walking", "wariza", "waving", "wedgie", "wrestling", "writing", "yawning", "yokozuwari", "_conscious", "massage", "struggling", "shrugging", "drugged", "tentacles_under_clothes", "archery", "cleaning", "tempura", "facepalm", "sadism", ],
79
+ #頭部装飾/頭部服飾
80
+ "Headwear" : ["antennae", "antlers", "aura", "bandaged_head", "bandana", "bandeau", "beanie", "beanie", "beret", "bespectacled", "blindfold", "bonnet", "_cap", "circlet", "crown", "_drill", "_drills", "diadem", "_eyewear", "ear_covers", "ear_ornament", "ear_tag", "earbuds", "earclip", "earmuffs", "earphones", "earpiece", "earring", "earrings", "eyeliner", "eyepatch", "eyewear_on_head", "facial", "fedora", "glasses", "goggles", "_headwear", "hachimaki", "hair_bobbles", "hair_ornament", "hair_rings", "hair_tie", "hairband", "hairclip", "hairpin", "hairpods", "halo", "hat", "head-mounted_display", "head_wreath", "headband", "headdress", "headgear", "headphones", "headpiece", "headset", "helm", "helmet", "hood", "kabuto_(helmet)", "kanzashi", "_mask", "maid_headdress", "mask", "mask", "mechanical_ears", "mechanical_eye", "mechanical_horns", "mob_cap", "monocle", "neck_ruff", "nightcap", "on_head", "pince-nez", "qingdai_guanmao", "scarf_over_mouth", "scrunchie", "sunglasses", "tam_o'_shanter", "tate_eboshi", "tiara", "topknot", "turban", "veil", "visor", "wig", "mitre", "tricorne", "bicorne", ],
81
+ #手部装飾/手部服飾
82
+ "Handwear" : ["arm_warmers", "armband", "armlet", "bandaged_arm", "bandaged_fingers", "bandaged_hand", "bandaged_wrist", "bangle", "bracelet", "bracelets", "bracer", "cuffs", "elbow_pads", "_gauntlets", "_glove", "_gloves", "gauntlets", "gloves", "kote", "kurokote", "mechanical_arm", "mechanical_arms", "mechanical_hands", "mittens", "mitts", "nail_polish", "prosthetic_arm", "wrist_cuffs", "wrist_guards", "wristband", "yugake", ],
83
+ #ワンピース衣装/一件式服裝
84
+ "One-Piece Outfit" : ["bodystocking", "bodysuit", "dress", "furisode", "gown", "hanfu", "jumpsuit", "kimono", "leotard", "microdress", "one-piece", "overalls", "robe", "spacesuit", "sundress", "yukata", ],
85
+ #上半身衣装/上半身服裝
86
+ "Upper Body Clothing" : ["aiguillette", "apron", "armor", "ascot", "babydoll", "bikini", "blazer", "blouse", "bowtie", "bra", "breast_curtain", "breast_curtains", "breast_pocket", "breastplate", "bustier", "_collar", "camisole", "cape", "capelet", "cardigan", "center_opening", "chemise", "chest_jewel", "choker", "cloak", "coat", "coattails", "collar", "corset", "criss-cross_halter", "crop_top", "dougi", "feather_boa", "gakuran", "hagoromo", "hanten_(clothes)", "haori", "harem_pants", "harness", "hoodie", "jacket", "japanese_clothes", "kappougi", "kariginu", "lapels", "lingerie", "maid", "mechanical_wings", "mizu_happi", "muneate", "neckerchief", "necktie", "negligee", "nightgown", "pajamas", "pauldron", "pauldrons", "plunging_neckline", "raincoat", "rei_no_himo", "sailor_collar", "sarashi", "scarf", "serafuku", "shawl", "shirt", "shoulder_", "sleepwear", "sleeve", "sleeveless", "sleeves", "sode", "spaghetti_strap", "sportswear", "strapless", "suit", "sundress", "suspenders", "sweater", "swimsuit", "_top", "_torso", "t-shirt", "tabard", "tailcoat", "tank_top", "tasuki", "tie_clip", "tunic", "turtleneck", "tuxedo", "_uniform", "undershirt", "uniform", "v-neck", "vambraces", "vest", "waistcoat", ],
87
+ #下半身衣装/下半身服裝
88
+ "Lower Body Clothing" : ["bare_hips", "bloomers", "briefs", "buruma", "crotch_seam", "cutoffs", "denim", "faulds", "fundoshi", "g-string", "garter_straps", "hakama", "hip_vent", "jeans", "knee_pads", "loincloth", "mechanical_tail", "microskirt", "miniskirt", "overskirt", "panties", "pants", "pantsu", "panty_straps", "pelvic_curtain", "petticoat", "sarong", "shorts", "side_slit", "skirt", "sweatpants", "swim_trunks", "thong", "underwear", "waist_cape", ],
89
+ #足元・レッグウェア/腳與腿部服飾
90
+ "Foot & Legwear" : ["anklet", "bandaged_leg", "boot", "boots", "_footwear", "flats", "flip-flops", "geta", "greaves", "_heels", "kneehigh", "kneehighs", "_legwear", "leg_warmers", "leggings", "loafers", "mary_janes", "mechanical_legs", "okobo", "over-kneehighs", "pantyhose", "prosthetic_leg", "pumps", "_shoe", "_sock", "sandals", "shoes", "skates", "slippers", "sneakers", "socks", "spikes", "tabi", "tengu-geta", "thigh_strap", "thighhighs", "uwabaki", "zouri", "legband", "ankleband", ],
91
+ #その他の装飾/其他服飾
92
+ "Other Accessories" : ["alternate_", "anklet", "badge", "beads", "belt", "belts", "bow", "brooch", "buckle", "button", "buttons", "_clothes", "_costume", "_cutout", "casual", "charm", "clothes_writing", "clothing_aside", "costume", "cow_print", "cross", "d-pad", "double-breasted", "drawstring", "epaulettes", "fabric", "fishnets", "floral_print", "formal", "frills", "_garter", "gem", "holster", "jewelry", "_knot", "lace", "lanyard", "leash", "magatama", "mechanical_parts", "medal", "medallion", "naked_bandage", "necklace", "_ornament", "(ornament)", "o-ring", "obi", "obiage", "obijime", "_pin", "_print", "padlock", "patterned_clothing", "pendant", "piercing", "plaid", "pocket", "polka_dot", "pom_pom_(clothes)", "pom_pom_(clothes)", "pouch", "ribbon", "_stripe", "_stripes", "sash", "shackles", "shimenawa", "shrug_(clothing)", "skin_tight", "spandex", "strap", "sweatband", "_trim", "tassel", "zettai_ryouiki", "zipper", ],
93
+ #表情/表情
94
+ "Facial Expression" : ["ahegao", "anger_vein", "angry", "annoyed", "confused", "drooling", "embarrassed", "expressionless", "eye_contact", "_face", "frown", "fucked_silly", "furrowed_brow", "glaring", "gloom_(expression)", "grimace", "grin", "happy", "jitome", "laughing", "_mouth", "nervous", "notice_lines", "o_o", "parted_lips", "pout", "puff_of_air", "restrained", "sad", "sanpaku", "scared", "scowl", "serious", "shaded_face", "shy", "sigh", "sleepy", "smile", "smirk", "smug", "snot", "spoken_ellipsis", "spoken_exclamation_mark", "spoken_interrobang", "spoken_question_mark", "squiggle", "surprised", "tareme", "tearing_up", "thinking", "tongue", "tongue_out", "torogao", "tsurime", "turn_pale", "wide-eyed", "wince", "worried", "heartbeat", ],
95
+ #絵文字/表情符號
96
+ "Facial Emoji" : ["!!", "!", "!?", "+++", "+_+", "...", "...?", "._.", "03:00", "0_0", ":/", ":3", ":<", ":>", ":>=", ":d", ":i", ":o", ":p", ":q", ":t", ":x", ":|", ";(", ";)", ";3", ";d", ";o", ";p", ";q", "=_=", ">:(", ">:)", ">_<", ">_o", ">o<", "?", "??", "@_@", "\m/", "\n/", "\o/", "\||/", "^^^", "^_^", "c:", "d:", "o_o", "o3o", "u_u", "w", "x", "x_x", "xd", "zzz", "|_|", ],
97
+ #頭部/頭部
98
+ "Head" : ["afro", "ahoge", "animal_ear_fluff", "_bangs", "_bun", "bald", "beard", "blunt_bangs", "blunt_ends", "bob_cut", "bowl_cut", "braid", "braids", "buzz_cut", "circle_cut", "colored_tips", "cowlick", "dot_nose", "dreadlocks", "_ear", "_ears", "_eye", "_eyes", "enpera", "eyeball", "eyebrow", "eyebrow_cut", "eyebrows", "eyelashes", "eyeshadow", "faceless", "facepaint", "facial_mark", "fang", "forehead", "freckles", "goatee", "_hair", "_horn", "_horns", "hair_", "hair_bun", "hair_flaps", "hair_intakes", "hair_tubes", "half_updo", "head_tilt", "heterochromia", "hime_cut", "hime_cut", "horns", "in_eye", "inverted_bob", "kemonomimi_mode", "lips", "mascara", "mohawk", "mouth_", "mustache", "nose", "one-eyed", "one_eye", "one_side_up", "_pupils", "parted_bangs", "pompadour", "ponytail", "ringlets", "_sclera", "sideburns", "sidecut", "sidelock", "sidelocks", "skull", "snout", "stubble", "swept_bangs", "tails", "teeth", "third_eye", "twintails", "two_side_up", "undercut", "updo", "v-shaped_eyebrows", "whiskers", "tentacle_hair", ],
99
+ #手部/手部
100
+ "Hands" : ["_arm", "_arms", "claws", "_finger", "_fingers", "fingernails", "_hand", "_nail", "_nails", "palms", "rings", "thumbs_up", ],
101
+ #上半身/上半身
102
+ "Upper Body" : ["abs", "armpit", "armpits", "backboob", "belly", "biceps", "breast_rest", "breasts", "button_gap", "cleavage", "collarbone", "dimples_of_venus", "downblouse", "flat_chest", "linea_alba", "median_furrow", "midriff", "nape", "navel", "pectorals", "ribs", "_shoulder", "_shoulders", "shoulder_blades", "sideboob", "sidetail", "spine", "stomach", "strap_gap", "toned", "underboob", "underbust", ],
103
+ #下半身/下半身
104
+ "Lower Body" : ["ankles", "ass", "barefoot", "crotch", "feet", "highleg", "hip_bones", "hooves", "kneepits", "knees", "legs", "soles", "tail", "thigh_gap", "thighlet", "thighs", "toenail", "toenails", "toes", "wide_hips", ],
105
+ #生物/生物
106
+ "Creature" : ["(animal)", "anglerfish", "animal", "bear", "bee", "bird", "bug", "butterfly", "cat", "chick", "chicken", "chinese_zodiac", "clownfish", "coral", "crab", "creature", "crow", "dog", "dove", "dragon", "duck", "eagle", "fish", "fish", "fox", "fox", "frog", "frog", "goldfish", "hamster", "horse", "jellyfish", "ladybug", "lion", "mouse", "octopus", "owl", "panda", "penguin", "pig", "pigeon", "rabbit", "rooster", "seagull", "shark", "sheep", "shrimp", "snail", "snake", "squid", "starfish", "tanuki", "tentacles", "tiger", "turtle", "weasel", "whale", "wolf", "parrot", "sparrow", "unicorn", ],
107
+ #植物/植物
108
+ "Plant" : ["bamboo", "bouquet", "branch", "bush", "cherry_blossoms", "clover", "daisy", "(flower)", "flower", "flower", "gourd", "hibiscus", "holly", "hydrangea", "leaf", "lily_pad", "lotus", "moss", "palm_leaf", "palm_tree", "petals", "plant", "plum_blossoms", "rose", "spider_lily", "sunflower", "thorns", "tree", "tulip", "vines", "wisteria", "acorn", ],
109
+ #食べ物/食物
110
+ "Food" : ["apple", "baguette", "banana", "baozi", "beans", "bento", "berry", "blueberry", "bread", "broccoli", "burger", "cabbage", "cake", "candy", "carrot", "cheese", "cherry", "chili_pepper", "chocolate", "coconut", "cookie", "corn", "cream", "crepe", "cucumber", "cucumber", "cupcake", "curry", "dango", "dessert", "doughnut", "egg", "eggplant", "_(food)", "_(fruit)", "food", "french_fries", "fruit", "grapes", "ice_cream", "icing", "lemon", "lettuce", "lollipop", "macaron", "mandarin_orange", "meat", "melon", "mochi", "mushroom", "noodles", "omelet", "omurice", "onigiri", "onion", "pancake", "parfait", "pasties", "pastry", "peach", "pineapple", "pizza", "popsicle", "potato", "pudding", "pumpkin", "radish", "ramen", "raspberry", "rice", "roasted_sweet_potato", "sandwich", "sausage", "seaweed", "skewer", "spitroast", "spring_onion", "strawberry", "sushi", "sweet_potato", "sweets", "taiyaki", "takoyaki", "tamagoyaki", "tempurakanbea", "toast", "tomato", "vegetable", "wagashi", "wagashi", "watermelon", "jam", "popcorn", ],
111
+ #飲み物/飲品
112
+ "Beverage" : ["alcohol", "beer", "coffee", "cola", "drink", "juice", "juice_box", "milk", "sake", "soda", "tea", "whiskey", "wine", "cocktail", ],
113
+ #音楽/音樂
114
+ "Music" : ["band", "baton_(conducting)", "beamed", "cello", "concert", "drum", "drumsticks", "eighth_note", "flute", "guitar", "harp", "horn", "(instrument)", "idol", "instrument", "k-pop", "lyre", "(music)", "megaphone", "microphone", "music", "musical_note", "phonograph", "piano", "plectrum", "quarter_note", "recorder", "sixteenth_note", "sound_effects", "trumpet", "utaite", "violin", "whistle", ],
115
+ #武器・装備/武器・裝備
116
+ "Weapons & Equipment" : ["ammunition", "arrow_(projectile)", "axe", "bandolier", "baseball_bat", "beretta_92", "bolt_action", "bomb", "bullet", "bullpup", "cannon", "chainsaw", "crossbow", "dagger", "energy_sword", "explosive", "fighter_jet", "gohei", "grenade", "gun", "hammer", "handgun", "holstered", "jet", "katana", "knife", "kunai", "lance", "mallet", "nata_(tool)", "polearm", "quiver", "rapier", "revolver", "rifle", "rocket_launcher", "scabbard", "scope", "scythe", "sheath", "sheathed", "shield", "shotgun", "shuriken", "spear", "staff", "suppressor", "sword", "tank", "tantou", "torpedo", "trident", "(weapon)", "wand", "weapon", "whip", "yumi_(bow)", "h&k_hk416", "rocket_launcher", "heckler_&_koch", ],
117
+ #乗り物/交通器具
118
+ "Vehicles" : ["aircraft", "airplane", "bicycle", "boat", "car", "caterpillar_tracks", "flight_deck", "helicopter", "motor_vehicle", "motorcycle", "ship", "spacecraft", "spoiler_(automobile)", "train", "truck", "watercraft", "wheel", "wheelbarrow", "wheelchair", "inflatable_raft", ],
119
+ #建物/建物
120
+ "Buildings" : ["apartment", "aquarium", "architecture", "balcony", "building", "cafe", "castle", "church", "gym", "hallway", "hospital", "house", "library", "(place)", "porch", "restaurant", "restroom", "rooftop", "shop", "skyscraper", "stadium", "stage", "temple", "toilet", "tower", "train_station", "veranda", ],
121
+ #室内/室內
122
+ "Indoor" : ["bath", "bathroom", "bathtub", "bed", "bed_sheet", "bedroom", "blanket", "bookshelf", "carpet", "ceiling", "chair", "chalkboard", "classroom", "counter", "cupboard", "curtains", "cushion", "dakimakura", "desk", "door", "doorway", "drawer", "_floor", "floor", "futon", "indoors", "interior", "kitchen", "kotatsu", "locker", "mirror", "pillow", "room", "rug", "school_desk", "shelf", "shouji", "sink", "sliding_doors", "stairs", "stool", "storeroom", "table", "tatami", "throne", "window", "windowsill", "bathhouse", "chest_of_drawers", ],
123
+ #屋外/室外
124
+ "Outdoor" : ["alley", "arch", "beach", "bridge", "bus_stop", "bush", "cave", "(city)", "city", "cliff", "crescent", "crosswalk", "day", "desert", "fence", "ferris_wheel", "field", "forest", "grass", "graveyard", "hill", "lake", "lamppost", "moon", "mountain", "night", "ocean", "onsen", "outdoors", "path", "pool", "poolside", "railing", "railroad", "river", "road", "rock", "sand", "shore", "sky", "smokestack", "snow", "snowball", "snowman", "street", "sun", "sunlight", "sunset", "tent", "torii", "town", "tree", "turret", "utility_pole", "valley", "village", "waterfall", ],
125
+ #物品/物品
126
+ "Objects" : ["anchor", "android", "armchair", "(bottle)", "backpack", "bag", "ball", "balloon", "bandages", "bandaid", "bandaids", "banknote", "banner", "barcode", "barrel", "baseball", "basket", "basketball", "beachball", "bell", "bench", "binoculars", "board_game", "bone", "book", "bottle", "bowl", "box", "box_art", "briefcase", "broom", "bucket", "(chess)", "(computer)", "(computing)", "(container)", "cage", "calligraphy_brush", "camera", "can", "candle", "candlestand", "cane", "card", "cartridge", "cellphone", "chain", "chandelier", "chess", "chess_piece", "choko_(cup)", "chopsticks", "cigar", "clipboard", "clock", "clothesline", "coin", "comb", "computer", "condom", "controller", "cosmetics", "couch", "cowbell", "crazy_straw", "cup", "cutting_board", "dice", "digital_media_player", "doll", "drawing_tablet", "drinking_straw", "easel", "electric_fan", "emblem", "envelope", "eraser", "feathers", "figure", "fire", "fishing_rod", "flag", "flask", "folding_fan", "fork", "frying_pan", "(gemstone)", "game_console", "gears", "gemstone", "gift", "glass", "glowstick", "gold", "handbag", "handcuffs", "handheld_game_console", "hose", "id_card", "innertube", "iphone", "jack-o'-lantern", "jar", "joystick", "key", "keychain", "kiseru", "ladder", "ladle", "lamp", "lantern", "laptop", "letter", "letterboxed", "lifebuoy", "lipstick", "liquid", "lock", "lotion", "_machine", "map", "marker", "model_kit", "money", "monitor", "mop", "mug", "needle", "newspaper", "nintendo", "nintendo_switch", "notebook", "(object)", "ofuda", "orb", "origami", "(playing_card)", "pack", "paddle", "paintbrush", "pan", "paper", "parasol", "patch", "pc", "pen", "pencil", "pencil", "pendant_watch", "phone", "pill", "pinwheel", "plate", "playstation", "pocket_watch", "pointer", "poke_ball", "pole", "quill", "racket", "randoseru", "remote_control", "ring", "rope", "sack", "saddle", "sakazuki", "satchel", "saucer", "scissors", "scroll", "seashell", "seatbelt", "shell", "shide", "shopping_cart", "shovel", "shower_head", "silk", "sketchbook", "smartphone", "soap", "sparkler", "spatula", "speaker", "spoon", "statue", "stethoscope", "stick", "sticker", "stopwatch", "string", "stuffed_", "stylus", "suction_cups", "suitcase", "surfboard", "syringe", "talisman", "tanzaku", "tape", "teacup", "teapot", "teddy_bear", "television", "test_tube", "tiles", "tokkuri", "tombstone", "torch", "towel", "toy", "traffic_cone", "tray", "treasure_chest", "uchiwa", "umbrella", "vase", "vial", "video_game", "viewfinder", "volleyball", "wallet", "watch", "watch", "whisk", "whiteboard", "wreath", "wrench", "wristwatch", "yunomi", "ace_of_hearts", "inkwell", "compass", "ipod", "sunscreen", "rocket", "cobblestone", ],
127
+ #キャラクター設定/角色設定
128
+ "Character Design" : ["+boys", "+girls", "1other", "39", "_boys", "_challenge", "_connection", "_female", "_fur", "_girls", "_interface", "_male", "_man", "_person", "abyssal_ship", "age_difference", "aged_down", "aged_up", "albino", "alien", "alternate_muscle_size", "ambiguous_gender", "amputee", "androgynous", "angel", "animalization", "ass-to-ass", "assault_visor", "au_ra", "baby", "bartender", "beak", "bishounen", "borrowed_character", "boxers", "boy", "breast_envy", "breathing_fire", "bride", "broken", "brother_and_sister", "brothers", "camouflage", "cheating_(relationship)", "cheerleader", "chibi", "child", "clone", "command_spell", "comparison", "contemporary", "corpse", "corruption", "cosplay", "couple", "creature_and_personification", "crossdressing", "crossover", "cyberpunk", "cyborg", "cyclops", "damaged", "dancer", "danmaku", "darkness", "death", "defeat", "demon", "disembodied_", "draph", "drone", "duel", "dwarf", "egyptian", "electricity", "elezen", "elf", "enmaided", "erune", "everyone", "evolutionary_line", "expressions", "fairy", "family", "fangs", "fantasy", "fashion", "fat", "father_and_daughter", "father_and_son", "fewer_digits", "fins", "flashback", "fluffy", "fumo_(doll)", "furry", "fusion", "fuuin_no_tsue", "gameplay_mechanics", "genderswap", "ghost", "giant", "giantess", "gibson_les_paul", "girl", "goblin", "groom", "guro", "gyaru", "habit", "harem", "harpy", "harvin", "heads_together", "health_bar", "height_difference", "hitodama", "horror_(theme)", "humanization", "husband_and_wife", "hydrokinesis", "hypnosis", "hyur", "idol", "insignia", "instant_loss", "interracial", "interspecies", "japari_bun", "jeweled_branch_of_hourai", "jiangshi", "jirai_kei", "joints", "karakasa_obake", "keyhole", "kitsune", "knight", "kodona", "kogal", "kyuubi", "lamia", "left-handed", "loli", "lolita", "look-alike", "machinery", "magic", "male_focus", "manly", "matching_outfits", "mature_female", "mecha", "mermaid", "meta", "miko", "milestone_celebration", "military", "mind_control", "miniboy", "minigirl", "miqo'te", "monster", "monsterification", "mother_and_daughter", "mother_and_son", "multiple_others", "muscular", "nanodesu_(phrase)", "narrow_waist", "nekomata", "netorare", "ninja", "no_humans", "nontraditional", "nun", "nurse", "object_namesake", "obliques", "office_lady", "old", "on_body", "onee-shota", "oni", "orc", "others", "otoko_no_ko", "oversized_object", "paint_splatter", "pantyshot", "pawpads", "persona", "personality", "personification", "pet_play", "petite", "pirate", "playboy_bunny", "player_2", "plugsuit", "plump", "poi", "pokemon", "police", "policewoman", "pom_pom_(cheerleading)", "princess", "prosthesis", "pun", "puppet", "race_queen", "radio_antenna", "real_life_insert", "redesign", "reverse_trap", "rigging", "robot", "rod_of_remorse", "sailor", "salaryman", "samurai", "sangvis_ferri", "scales", "scene_reference", "school", "sheikah", "shota", "shrine", "siblings", "side-by-side", "sidesaddle", "sisters", "size_difference", "skeleton", "skinny", "slave", "slime_(substance)", "soldier", "spiked_shell", "spokencharacter", "steampunk", "streetwear", "striker_unit", "strongman", "submerged", "suggestive", "super_saiyan", "superhero", "surreal", "take_your_pick", "tall", "talons", "taur", "teacher", "team_rocket", "three-dimensional_maneuver_gear", "time_paradox", "tomboy", "traditional_youkai", "transformation", "trick_or_treat", "tusks", "twins", "ufo", "under_covers", "v-fin", "v-fin", "vampire", "virtual_youtuber", "waitress", "watching_television", "wedding", "what", "when_you_see_it", "wife_and_wife", "wing", "wings", "witch", "world_war_ii", "yandere", "year_of", "yes", "yin_yang", "yordle", "you're_doing_it_wrong", "you_gonna_get_raped", "yukkuri_shiteitte_ne", "yuri", "zombie", "(alice_in_wonderland)", "(arknights)", "(blue_archive)", "(cosplay)", "(creature)", "(emblem)", "(evangelion)", "(fate)", "(fate/stay_night)", "(ff11)", "(fire_emblem)", "(genshin_impact)", "(grimm)", "(houseki_no_kuni)", "(hyouka)", "(idolmaster)", "(jojo)", "(kancolle)", "(kantai_collection)", "(kill_la_kill)", "(league_of_legends)", "(legends)", "(lyomsnpmp)", "(machimazo)", "(madoka_magica)", "(mecha)", "(meme)", "(nier:automata)", "(organ)", "(overwatch)", "(pokemon)", "(project_moon)", "(project_sekai)", "(sao)", "(senran_kagura)", "(splatoon)", "(touhou)", "(tsukumo_sana)", "(youkai_watch)", "(yu-gi-oh!_gx)", "(zelda)", "sextuplets", "imperial_japanese_army", "extra_faces", ],
129
+ #構図/構圖
130
+ "Composition" : ["abstract", "anime_coloring", "animification", "back-to-back", "bad_anatomy", "blurry", "border", "bound", "cameo", "cheek-to-cheek", "chromatic_aberration", "close-up", "collage", "color_guide", "colorful", "comic", "contrapposto", "cover", "cowboy_shot", "crosshatching", "depth_of_field", "dominatrix", "dutch_angle", "_focus", "face-to-face", "fake_screenshot", "film_grain", "fisheye", "flat_color", "foreshortening", "from_above", "from_behind", "from_below", "from_side", "full_body", "glitch", "greyscale", "halftone", "head_only", "heads-up_display", "high_contrast", "horizon", "_inset", "inset", "jaggy_lines", "1koma", "2koma", "3koma", "4koma", "5koma", "leaning", "leaning_forward", "leaning_to_the_side", "left-to-right_manga", "lens_flare", "limited_palette", "lineart", "lineup", "lower_body", "(medium)", "marker_(medium)", "meme", "mixed_media", "monochrome", "multiple_views", "muted_color", "oekaki", "on_side", "out_of_frame", "outline", "painting", "parody", "partially_colored", "partially_underwater_shot", "perspective", "photorealistic", "picture_frame", "pillarboxed", "portrait", "poster_(object)", "product_placement", "profile", "realistic", "recording", "retro_artstyle", "(style)", "_style", "sandwiched", "science_fiction", "sepia", "shikishi", "side-by-side", "sideways", "sideways_glance", "silhouette", "sketch", "spot_color", "still_life", "straight-on", "symmetry", "(texture)", "tachi-e", "taking_picture", "tegaki", "too_many", "traditional_media", "turnaround", "underwater", "upper_body", "upside-down", "upskirt", "variations", "wide_shot", "_design", "symbolism", "rounded_corners", "surrounded", ],
131
+ #季節/季節
132
+ "Season" : ["akeome", "anniversary", "autumn", "birthday", "christmas", "_day", "festival", "halloween", "kotoyoro", "nengajou", "new_year", "spring_(season)", "summer", "tanabata", "valentine", "winter", ],
133
+ #背景/背景
134
+ "Background" : ["_background", "backlighting", "bloom", "bokeh", "brick_wall", "bubble", "cable", "caustics", "cityscape", "cloud", "confetti", "constellation", "contrail", "crowd", "crystal", "dark", "debris", "dusk", "dust", "egasumi", "embers", "emphasis_lines", "energy", "evening", "explosion", "fireworks", "fog", "footprints", "glint", "graffiti", "ice", "industrial_pipe", "landscape", "light", "light_particles", "light_rays", "lightning", "lights", "moonlight", "motion_blur", "motion_lines", "mountainous_horizon", "nature", "(planet)", "pagoda", "people", "pillar", "planet", "power_lines", "puddle", "rain", "rainbow", "reflection", "ripples", "rubble", "ruins", "scenery", "shade", "shooting_star", "sidelighting", "smoke", "snowflakes", "snowing", "space", "sparkle", "sparks", "speed_lines", "spider_web", "spotlight", "star_(sky)", "stone_wall", "sunbeam", "sunburst", "sunrise", "_theme", "tile_wall", "twilight", "wall_clock", "wall_of_text", "water", "waves", "wind", "wire", "wooden_wall", "lighthouse", ],
135
+ # パターン/圖案
136
+ "Patterns" : ["arrow", "bass_clef", "blank_censor", "circle", "cube", "heart", "hexagon", "hexagram", "light_censor", "(pattern)", "pattern", "pentagram", "roman_numeral", "(shape)", "(symbol)", "shape", "sign", "symbol", "tally", "treble_clef", "triangle", "tube", "yagasuri", ],
137
+ #検閲/審查
138
+ "Censorship" : ["blur_censor", "_censor", "_censoring", "censored", "character_censor", "convenient", "hair_censor", "heart_censor", "identity_censor", "maebari", "novelty_censor", "soap_censor", "steam_censor", "tail_censor", "uncensored", ],
139
+ #その他/其他
140
+ "Others" : ["2007", "2008", "2009", "2010", "2011", "2012", "2013", "2014", "2015", "2016", "2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024", "artist", "artist_name", "artistic_error", "asian", "(company)", "character_name", "content_rating", "copyright", "cover_page", "dated", "english_text", "japan", "layer", "logo", "name", "numbered", "page_number", "pixiv_id", "ranguage", "reference_sheet", "signature", "speech_bubble", "subtitled", "text", "thank_you", "typo", "username", "wallpaper", "watermark", "web_address", "screwdriver", ],
141
+ }
142
+
143
+ # Use dictionary comprehension to reverse key-value pairs
144
+ reversed_categories = {value: key for key, values in categories.items() for value in values}
145
+
146
+
147
+ tags = []
148
+
149
+ if __name__ == "__main__":
150
+ classify_tags (tags, True)
151
+
images/1girl.png ADDED

Git LFS Details

  • SHA256: 2a9c1586e694c46e35fe4a1c64b139b0174deb5ff6808b835db546091cfeecb0
  • Pointer size: 132 Bytes
  • Size of remote file: 8.92 MB
images/image1.png ADDED

Git LFS Details

  • SHA256: 4f25a4557835b7f64f3f00f46d5dc6d07d118cf8625160f19885f401feeecf26
  • Pointer size: 131 Bytes
  • Size of remote file: 348 kB
images/image2.png ADDED

Git LFS Details

  • SHA256: b47aeeb6d74bbb3bb86b9e812eab4675d6ef0e8b7ce5c8973abfaf5337ac73a6
  • Pointer size: 131 Bytes
  • Size of remote file: 280 kB
pre-requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ pip>=23.0.0
requirements.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ huggingface-hub
2
+ apscheduler
3
+
4
+ --extra-index-url https://download.pytorch.org/whl/cu124
5
+ torch==2.5.0+cu124; sys_platform != 'darwin'
6
+ torchvision==0.20.0+cu124; sys_platform != 'darwin'
7
+ torch==2.5.0; sys_platform == 'darwin'
8
+ torchvision==0.20.0; sys_platform == 'darwin'
9
+
10
+ gradio
11
+ transformers
12
+ spaces
13
+ pillow
14
+ requests
15
+ numpy
16
+ timm
17
+ einops
18
+ optimum
19
+ accelerate
20
+ opencv-python
21
+ onnxruntime>=1.12.0
22
+ pandas==2.1.2
23
+ ctranslate2>=4.4.0
24
+ matplotlib
themes/[email protected] ADDED
@@ -0,0 +1 @@
 
 
1
+ {"theme": {"_font": [{"__gradio_font__": true, "name": "Rubik", "class": "google"}, {"__gradio_font__": true, "name": "ui-sans-serif", "class": "font"}, {"__gradio_font__": true, "name": "system-ui", "class": "font"}, {"__gradio_font__": true, "name": "sans-serif", "class": "font"}], "_font_mono": [{"__gradio_font__": true, "name": "Inconsolata", "class": "google"}, {"__gradio_font__": true, "name": "ui-monospace", "class": "font"}, {"__gradio_font__": true, "name": "Consolas", "class": "font"}, {"__gradio_font__": true, "name": "monospace", "class": "font"}], "_stylesheets": ["https://fonts.googleapis.com/css2?family=Rubik:wght@400;500&display=swap", "https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;500&display=swap"], "background_fill_primary": "white", "background_fill_primary_dark": "*neutral_950", "background_fill_secondary": "*neutral_50", "background_fill_secondary_dark": "*neutral_900", "block_background_fill": "*background_fill_primary", "block_background_fill_dark": "*neutral_800", "block_border_color": "*border_color_primary", "block_border_color_dark": "*border_color_primary", "block_border_width": "1px", "block_border_width_dark": "1px", "block_info_text_color": "*body_text_color_subdued", "block_info_text_color_dark": "*body_text_color_subdued", "block_info_text_size": "*text_sm", "block_info_text_weight": "400", "block_label_background_fill": "*background_fill_primary", "block_label_background_fill_dark": "*background_fill_secondary", "block_label_border_color": "*border_color_primary", "block_label_border_color_dark": "*border_color_primary", "block_label_border_width": "1px", "block_label_border_width_dark": "1px", "block_label_margin": "0", "block_label_padding": "*spacing_sm *spacing_lg", "block_label_radius": "calc(*radius_lg - 1px) 0 calc(*radius_lg - 1px) 0", "block_label_right_radius": "0 calc(*radius_lg - 1px) 0 calc(*radius_lg - 1px)", "block_label_shadow": "*block_shadow", "block_label_text_color": "*neutral_500", "block_label_text_color_dark": "*neutral_200", "block_label_text_size": "*text_sm", "block_label_text_weight": "400", "block_padding": "*spacing_xl calc(*spacing_xl + 2px)", "block_radius": "*radius_lg", "block_shadow": "none", "block_shadow_dark": "none", "block_title_background_fill": "none", "block_title_background_fill_dark": "none", "block_title_border_color": "none", "block_title_border_color_dark": "none", "block_title_border_width": "0px", "block_title_border_width_dark": "0px", "block_title_padding": "0", "block_title_radius": "none", "block_title_text_color": "*neutral_500", "block_title_text_color_dark": "*neutral_200", "block_title_text_size": "*text_md", "block_title_text_weight": "400", "body_background_fill": "*background_fill_primary", "body_background_fill_dark": "*background_fill_primary", "body_text_color": "*neutral_700", "body_text_color_dark": "*neutral_200", "body_text_color_subdued": "*neutral_400", "body_text_color_subdued_dark": "*neutral_500", "body_text_size": "*text_md", "body_text_weight": "400", "border_color_accent": "*primary_300", "border_color_accent_dark": "*neutral_600", "border_color_primary": "*neutral_200", "border_color_primary_dark": "*neutral_700", "button_border_width": "*input_border_width", "button_border_width_dark": "*input_border_width", "button_cancel_background_fill": "*button_secondary_background_fill", "button_cancel_background_fill_dark": "*button_secondary_background_fill", "button_cancel_background_fill_hover": "*button_cancel_background_fill", "button_cancel_background_fill_hover_dark": "*button_cancel_background_fill", "button_cancel_border_color": "*button_secondary_border_color", "button_cancel_border_color_dark": "*button_secondary_border_color", "button_cancel_border_color_hover": "*button_cancel_border_color", "button_cancel_border_color_hover_dark": "*button_cancel_border_color", "button_cancel_text_color": "*button_secondary_text_color", "button_cancel_text_color_dark": "*button_secondary_text_color", "button_cancel_text_color_hover": "*button_cancel_text_color", "button_cancel_text_color_hover_dark": "*button_cancel_text_color", "button_large_padding": "*spacing_lg calc(2 * *spacing_lg)", "button_large_radius": "*radius_lg", "button_large_text_size": "*text_lg", "button_large_text_weight": "500", "button_primary_background_fill": "*primary_200", "button_primary_background_fill_dark": "*primary_700", "button_primary_background_fill_hover": "*button_primary_background_fill", "button_primary_background_fill_hover_dark": "*button_primary_background_fill", "button_primary_border_color": "*primary_200", "button_primary_border_color_dark": "*primary_600", "button_primary_border_color_hover": "*button_primary_border_color", "button_primary_border_color_hover_dark": "*button_primary_border_color", "button_primary_text_color": "*primary_600", "button_primary_text_color_dark": "white", "button_primary_text_color_hover": "*button_primary_text_color", "button_primary_text_color_hover_dark": "*button_primary_text_color", "button_secondary_background_fill": "*neutral_200", "button_secondary_background_fill_dark": "*neutral_600", "button_secondary_background_fill_hover": "*button_secondary_background_fill", "button_secondary_background_fill_hover_dark": "*button_secondary_background_fill", "button_secondary_border_color": "*neutral_200", "button_secondary_border_color_dark": "*neutral_600", "button_secondary_border_color_hover": "*button_secondary_border_color", "button_secondary_border_color_hover_dark": "*button_secondary_border_color", "button_secondary_text_color": "*neutral_700", "button_secondary_text_color_dark": "white", "button_secondary_text_color_hover": "*button_secondary_text_color", "button_secondary_text_color_hover_dark": "*button_secondary_text_color", "button_shadow": "none", "button_shadow_active": "none", "button_shadow_hover": "none", "button_small_padding": "*spacing_sm calc(2 * *spacing_sm)", "button_small_radius": "*radius_lg", "button_small_text_size": "*text_md", "button_small_text_weight": "400", "button_transition": "background-color 0.2s ease", "checkbox_background_color": "*background_fill_primary", "checkbox_background_color_dark": "*neutral_800", "checkbox_background_color_focus": "*checkbox_background_color", "checkbox_background_color_focus_dark": "*checkbox_background_color", "checkbox_background_color_hover": "*checkbox_background_color", "checkbox_background_color_hover_dark": "*checkbox_background_color", "checkbox_background_color_selected": "*secondary_600", "checkbox_background_color_selected_dark": "*secondary_600", "checkbox_border_color": "*neutral_300", "checkbox_border_color_dark": "*neutral_700", "checkbox_border_color_focus": "*secondary_500", "checkbox_border_color_focus_dark": "*secondary_500", "checkbox_border_color_hover": "*neutral_300", "checkbox_border_color_hover_dark": "*neutral_600", "checkbox_border_color_selected": "*secondary_600", "checkbox_border_color_selected_dark": "*secondary_600", "checkbox_border_radius": "*radius_sm", "checkbox_border_width": "*input_border_width", "checkbox_border_width_dark": "*input_border_width", "checkbox_check": "url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e\")", "checkbox_label_background_fill": "*button_secondary_background_fill", "checkbox_label_background_fill_dark": "*button_secondary_background_fill", "checkbox_label_background_fill_hover": "*button_secondary_background_fill_hover", "checkbox_label_background_fill_hover_dark": "*button_secondary_background_fill_hover", "checkbox_label_background_fill_selected": "*checkbox_label_background_fill", "checkbox_label_background_fill_selected_dark": "*checkbox_label_background_fill", "checkbox_label_border_color": "*border_color_primary", "checkbox_label_border_color_dark": "*border_color_primary", "checkbox_label_border_color_hover": "*checkbox_label_border_color", "checkbox_label_border_color_hover_dark": "*checkbox_label_border_color", "checkbox_label_border_width": "*input_border_width", "checkbox_label_border_width_dark": "*input_border_width", "checkbox_label_gap": "*spacing_lg", "checkbox_label_padding": "*spacing_md calc(2 * *spacing_md)", "checkbox_label_shadow": "none", "checkbox_label_text_color": "*body_text_color", "checkbox_label_text_color_dark": "*body_text_color", "checkbox_label_text_color_selected": "*checkbox_label_text_color", "checkbox_label_text_color_selected_dark": "*checkbox_label_text_color", "checkbox_label_text_size": "*text_md", "checkbox_label_text_weight": "400", "checkbox_shadow": "*input_shadow", "color_accent": "*primary_500", "color_accent_soft": "*primary_50", "color_accent_soft_dark": "*neutral_700", "container_radius": "*radius_lg", "embed_radius": "*radius_md", "error_background_fill": "#fee2e2", "error_background_fill_dark": "*background_fill_primary", "error_border_color": "#fecaca", "error_border_color_dark": "*border_color_primary", "error_border_width": "1px", "error_border_width_dark": "1px", "error_text_color": "#ef4444", "error_text_color_dark": "#ef4444", "font": "'Rubik', 'ui-sans-serif', 'system-ui', sans-serif", "font_mono": "'Inconsolata', 'ui-monospace', 'Consolas', monospace", "form_gap_width": "0px", "input_background_fill": "*neutral_100", "input_background_fill_dark": "*neutral_700", "input_background_fill_focus": "*secondary_500", "input_background_fill_focus_dark": "*secondary_600", "input_background_fill_hover": "*input_background_fill", "input_background_fill_hover_dark": "*input_background_fill", "input_border_color": "*border_color_primary", "input_border_color_dark": "*border_color_primary", "input_border_color_focus": "*secondary_300", "input_border_color_focus_dark": "*neutral_700", "input_border_color_hover": "*input_border_color", "input_border_color_hover_dark": "*input_border_color", "input_border_width": "0px", "input_border_width_dark": "0px", "input_padding": "*spacing_xl", "input_placeholder_color": "*neutral_400", "input_placeholder_color_dark": "*neutral_500", "input_radius": "*radius_lg", "input_shadow": "none", "input_shadow_dark": "none", "input_shadow_focus": "*input_shadow", "input_shadow_focus_dark": "*input_shadow", "input_text_size": "*text_md", "input_text_weight": "400", "layout_gap": "*spacing_xxl", "link_text_color": "*secondary_600", "link_text_color_active": "*secondary_600", "link_text_color_active_dark": "*secondary_500", "link_text_color_dark": "*secondary_500", "link_text_color_hover": "*secondary_700", "link_text_color_hover_dark": "*secondary_400", "link_text_color_visited": "*secondary_500", "link_text_color_visited_dark": "*secondary_600", "loader_color": "*color_accent", "loader_color_dark": "*color_accent", "name": "base", "neutral_100": "#f5f5f4", "neutral_200": "#e7e5e4", "neutral_300": "#d6d3d1", "neutral_400": "#a8a29e", "neutral_50": "#fafaf9", "neutral_500": "#78716c", "neutral_600": "#57534e", "neutral_700": "#44403c", "neutral_800": "#292524", "neutral_900": "#1c1917", "neutral_950": "#0f0e0d", "panel_background_fill": "*background_fill_secondary", "panel_background_fill_dark": "*background_fill_secondary", "panel_border_color": "*border_color_primary", "panel_border_color_dark": "*border_color_primary", "panel_border_width": "0", "panel_border_width_dark": "0", "primary_100": "#e0f2fe", "primary_200": "#bae6fd", "primary_300": "#7dd3fc", "primary_400": "#38bdf8", "primary_50": "#f0f9ff", "primary_500": "#0ea5e9", "primary_600": "#0284c7", "primary_700": "#0369a1", "primary_800": "#075985", "primary_900": "#0c4a6e", "primary_950": "#0b4165", "prose_header_text_weight": "500", "prose_text_size": "*text_md", "prose_text_weight": "400", "radio_circle": "url(\"data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e\")", "radius_lg": "3px", "radius_md": "3px", "radius_sm": "3px", "radius_xl": "3px", "radius_xs": "3px", "radius_xxl": "3px", "radius_xxs": "3px", "secondary_100": "#e0f2fe", "secondary_200": "#bae6fd", "secondary_300": "#7dd3fc", "secondary_400": "#38bdf8", "secondary_50": "#f0f9ff", "secondary_500": "#0ea5e9", "secondary_600": "#0284c7", "secondary_700": "#0369a1", "secondary_800": "#075985", "secondary_900": "#0c4a6e", "secondary_950": "#0b4165", "section_header_text_size": "*text_md", "section_header_text_weight": "400", "shadow_drop": "rgba(0,0,0,0.05) 0px 1px 2px 0px", "shadow_drop_lg": "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)", "shadow_inset": "rgba(0,0,0,0.05) 0px 2px 4px 0px inset", "shadow_spread": "3px", "shadow_spread_dark": "1px", "slider_color": "*primary_600", "slider_color_dark": "*primary_600", "spacing_lg": "8px", "spacing_md": "6px", "spacing_sm": "4px", "spacing_xl": "10px", "spacing_xs": "2px", "spacing_xxl": "16px", "spacing_xxs": "1px", "stat_background_fill": "*primary_300", "stat_background_fill_dark": "*primary_500", "table_border_color": "*neutral_300", "table_border_color_dark": "*neutral_700", "table_even_background_fill": "white", "table_even_background_fill_dark": "*neutral_950", "table_odd_background_fill": "*neutral_50", "table_odd_background_fill_dark": "*neutral_900", "table_radius": "*radius_lg", "table_row_focus": "*color_accent_soft", "table_row_focus_dark": "*color_accent_soft", "text_lg": "16px", "text_md": "14px", "text_sm": "12px", "text_xl": "22px", "text_xs": "10px", "text_xxl": "26px", "text_xxs": "9px"}, "version": "0.0.1"}