Spaces:
Running
Running
MonkeyJuice
commited on
Commit
·
7d3b3b8
1
Parent(s):
c410097
change lib
Browse files- .pre-commit-config.yaml +0 -36
- .vscode/settings.json +23 -11
- README.md +4 -4
- app.py +33 -35
- createTagDom.py +20 -0
- cropImage.py +32 -0
- genTag.py +114 -41
- ignoreTag.txt +22 -15
- ignoreTag2.txt +2 -1
- requirements.txt +4 -4
- script.js +45 -21
- style.css +20 -7
.pre-commit-config.yaml
DELETED
@@ -1,36 +0,0 @@
|
|
1 |
-
repos:
|
2 |
-
- repo: https://github.com/pre-commit/pre-commit-hooks
|
3 |
-
rev: v4.2.0
|
4 |
-
hooks:
|
5 |
-
- id: check-executables-have-shebangs
|
6 |
-
- id: check-json
|
7 |
-
- id: check-merge-conflict
|
8 |
-
- id: check-shebang-scripts-are-executable
|
9 |
-
- id: check-toml
|
10 |
-
- id: check-yaml
|
11 |
-
- id: double-quote-string-fixer
|
12 |
-
- id: end-of-file-fixer
|
13 |
-
- id: mixed-line-ending
|
14 |
-
args: ['--fix=lf']
|
15 |
-
- id: requirements-txt-fixer
|
16 |
-
- id: trailing-whitespace
|
17 |
-
- repo: https://github.com/myint/docformatter
|
18 |
-
rev: v1.4
|
19 |
-
hooks:
|
20 |
-
- id: docformatter
|
21 |
-
args: ['--in-place']
|
22 |
-
- repo: https://github.com/pycqa/isort
|
23 |
-
rev: 5.12.0
|
24 |
-
hooks:
|
25 |
-
- id: isort
|
26 |
-
- repo: https://github.com/pre-commit/mirrors-mypy
|
27 |
-
rev: v0.991
|
28 |
-
hooks:
|
29 |
-
- id: mypy
|
30 |
-
args: ['--ignore-missing-imports']
|
31 |
-
additional_dependencies: ['types-python-slugify']
|
32 |
-
- repo: https://github.com/google/yapf
|
33 |
-
rev: v0.32.0
|
34 |
-
hooks:
|
35 |
-
- id: yapf
|
36 |
-
args: ['--parallel', '--in-place']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.vscode/settings.json
CHANGED
@@ -1,18 +1,30 @@
|
|
1 |
{
|
2 |
-
"
|
3 |
-
"
|
4 |
-
"python.linting.pylintEnabled": false,
|
5 |
-
"python.linting.lintOnSave": true,
|
6 |
-
"python.formatting.provider": "yapf",
|
7 |
-
"python.formatting.yapfArgs": [
|
8 |
-
"--style={based_on_style: pep8, indent_width: 4, blank_line_before_nested_class_or_def: false, spaces_before_comment: 2, split_before_logical_operator: true}"
|
9 |
-
],
|
10 |
"[python]": {
|
|
|
11 |
"editor.formatOnType": true,
|
12 |
"editor.codeActionsOnSave": {
|
13 |
-
"source.organizeImports":
|
14 |
}
|
15 |
},
|
16 |
-
"
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
}
|
|
|
1 |
{
|
2 |
+
"editor.formatOnSave": true,
|
3 |
+
"files.insertFinalNewline": false,
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
"[python]": {
|
5 |
+
"editor.defaultFormatter": "ms-python.black-formatter",
|
6 |
"editor.formatOnType": true,
|
7 |
"editor.codeActionsOnSave": {
|
8 |
+
"source.organizeImports": "explicit"
|
9 |
}
|
10 |
},
|
11 |
+
"[jupyter]": {
|
12 |
+
"files.insertFinalNewline": false
|
13 |
+
},
|
14 |
+
"black-formatter.args": [
|
15 |
+
"--line-length=119"
|
16 |
+
],
|
17 |
+
"isort.args": ["--profile", "black"],
|
18 |
+
"flake8.args": [
|
19 |
+
"--max-line-length=119"
|
20 |
+
],
|
21 |
+
"ruff.lint.args": [
|
22 |
+
"--line-length=119"
|
23 |
+
],
|
24 |
+
"notebook.output.scrolling": true,
|
25 |
+
"notebook.formatOnCellExecution": true,
|
26 |
+
"notebook.formatOnSave.enabled": true,
|
27 |
+
"notebook.codeActionsOnSave": {
|
28 |
+
"source.organizeImports": "explicit"
|
29 |
+
}
|
30 |
}
|
README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
-
emoji:
|
4 |
colorFrom: gray
|
5 |
colorTo: purple
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 4.
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
-
---
|
|
|
1 |
---
|
2 |
+
title: Tagger
|
3 |
+
emoji: 👀
|
4 |
colorFrom: gray
|
5 |
colorTo: purple
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 4.44.0
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
+
---
|
app.py
CHANGED
@@ -6,35 +6,34 @@ import gradio as gr
|
|
6 |
import PIL.Image
|
7 |
import zipfile
|
8 |
from genTag import genTag
|
|
|
9 |
from checkIgnore import is_ignore
|
|
|
10 |
|
11 |
-
def predict(image: PIL.Image.Image
|
12 |
-
result_threshold = genTag(image,
|
13 |
result_html = ''
|
14 |
for label, prob in result_threshold.items():
|
15 |
-
|
16 |
-
result_html += '<p class="m5dd_list">'
|
17 |
-
else:
|
18 |
-
result_html += '<p class="m5dd_list use">'
|
19 |
-
result_html = result_html + '<span>' + str(label) + '</span><span>' + str(round(prob, 3)) + '</span></p>'
|
20 |
result_html = '<div>' + result_html + '</div>'
|
21 |
result_filter = {key: value for key, value in result_threshold.items() if not is_ignore(key, 1)}
|
22 |
result_text = '<div id="m5dd_result">' + ', '.join(result_filter.keys()) + '</div>'
|
23 |
-
|
|
|
24 |
|
25 |
-
def predict_batch(zip_file,
|
26 |
result = ''
|
27 |
with zipfile.ZipFile(zip_file) as zf:
|
28 |
for file in progress.tqdm(zf.namelist()):
|
29 |
print(file)
|
30 |
-
if file.endswith(".png") or file.endswith(".jpg"):
|
31 |
image_file = zf.open(file)
|
32 |
image = PIL.Image.open(image_file)
|
33 |
-
image = image.convert("
|
34 |
-
result_threshold = genTag(image,
|
35 |
result_filter = {key: value for key, value in result_threshold.items() if not is_ignore(key, 2)}
|
36 |
tag = ', '.join(result_filter.keys())
|
37 |
-
result = result + str(file) + '\n' + str(tag) + '\n'
|
38 |
return result
|
39 |
|
40 |
with gr.Blocks(css="style.css", js="script.js") as demo:
|
@@ -43,45 +42,44 @@ with gr.Blocks(css="style.css", js="script.js") as demo:
|
|
43 |
with gr.Column(scale=1):
|
44 |
image = gr.Image(label='Upload a image',
|
45 |
type='pil',
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
minimum=0,
|
50 |
-
maximum=1,
|
51 |
-
step=0.05,
|
52 |
-
value=0.5)
|
53 |
run_button = gr.Button('Run')
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
with gr.Column(scale=2):
|
56 |
-
result_html = gr.HTML(value="
|
57 |
with gr.Tab(label='Batch'):
|
58 |
with gr.Row():
|
59 |
with gr.Column(scale=1):
|
60 |
batch_file = gr.File(label="Upload a ZIP file containing images",
|
61 |
-
file_types=['.zip']
|
62 |
-
height='20em')
|
63 |
-
score_threshold2 = gr.Slider(label='Score threshold',
|
64 |
-
minimum=0,
|
65 |
-
maximum=1,
|
66 |
-
step=0.05,
|
67 |
-
value=0.5)
|
68 |
run_button2 = gr.Button('Run')
|
69 |
with gr.Column(scale=2):
|
70 |
-
result_text2 = gr.Textbox(lines=
|
|
|
71 |
label='Result',
|
72 |
-
show_copy_button=True
|
|
|
73 |
|
74 |
run_button.click(
|
75 |
fn=predict,
|
76 |
-
inputs=[image
|
77 |
-
outputs=[result_html, result_text],
|
78 |
api_name='predict',
|
79 |
)
|
80 |
run_button2.click(
|
81 |
fn=predict_batch,
|
82 |
-
inputs=[batch_file
|
83 |
outputs=[result_text2],
|
84 |
api_name='predict_batch',
|
85 |
)
|
86 |
|
87 |
-
|
|
|
|
6 |
import PIL.Image
|
7 |
import zipfile
|
8 |
from genTag import genTag
|
9 |
+
from cropImage import cropImage
|
10 |
from checkIgnore import is_ignore
|
11 |
+
from createTagDom import create_tag_dom
|
12 |
|
13 |
+
def predict(image: PIL.Image.Image):
|
14 |
+
result_threshold = genTag(image, 0.5)
|
15 |
result_html = ''
|
16 |
for label, prob in result_threshold.items():
|
17 |
+
result_html += create_tag_dom(label, is_ignore(label, 1), prob)
|
|
|
|
|
|
|
|
|
18 |
result_html = '<div>' + result_html + '</div>'
|
19 |
result_filter = {key: value for key, value in result_threshold.items() if not is_ignore(key, 1)}
|
20 |
result_text = '<div id="m5dd_result">' + ', '.join(result_filter.keys()) + '</div>'
|
21 |
+
crop_image = cropImage(image)
|
22 |
+
return result_html, result_text, crop_image
|
23 |
|
24 |
+
def predict_batch(zip_file, progress=gr.Progress()):
|
25 |
result = ''
|
26 |
with zipfile.ZipFile(zip_file) as zf:
|
27 |
for file in progress.tqdm(zf.namelist()):
|
28 |
print(file)
|
29 |
+
if file.endswith(".png") or file.endswith(".jpg") or file.endswith(".jpeg"):
|
30 |
image_file = zf.open(file)
|
31 |
image = PIL.Image.open(image_file)
|
32 |
+
image = image.convert("RGBA")
|
33 |
+
result_threshold = genTag(image, 0.5)
|
34 |
result_filter = {key: value for key, value in result_threshold.items() if not is_ignore(key, 2)}
|
35 |
tag = ', '.join(result_filter.keys())
|
36 |
+
result = result + str(file) + '\n' + str(tag) + '\n\n'
|
37 |
return result
|
38 |
|
39 |
with gr.Blocks(css="style.css", js="script.js") as demo:
|
|
|
42 |
with gr.Column(scale=1):
|
43 |
image = gr.Image(label='Upload a image',
|
44 |
type='pil',
|
45 |
+
elem_classes='m5dd_image',
|
46 |
+
image_mode="RGBA",
|
47 |
+
sources=["upload", "clipboard"])
|
|
|
|
|
|
|
|
|
48 |
run_button = gr.Button('Run')
|
49 |
+
with gr.Accordion(label="Crop Image", open=False):
|
50 |
+
crop_image = gr.Image(elem_classes='m5dd_image2',
|
51 |
+
format='jpg',
|
52 |
+
show_label=False,
|
53 |
+
show_share_button=False,
|
54 |
+
container=False)
|
55 |
+
result_text = gr.HTML(value="")
|
56 |
with gr.Column(scale=2):
|
57 |
+
result_html = gr.HTML(value="")
|
58 |
with gr.Tab(label='Batch'):
|
59 |
with gr.Row():
|
60 |
with gr.Column(scale=1):
|
61 |
batch_file = gr.File(label="Upload a ZIP file containing images",
|
62 |
+
file_types=['.zip'])
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
run_button2 = gr.Button('Run')
|
64 |
with gr.Column(scale=2):
|
65 |
+
result_text2 = gr.Textbox(lines=20,
|
66 |
+
max_lines=20,
|
67 |
label='Result',
|
68 |
+
show_copy_button=True,
|
69 |
+
autoscroll=False)
|
70 |
|
71 |
run_button.click(
|
72 |
fn=predict,
|
73 |
+
inputs=[image],
|
74 |
+
outputs=[result_html, result_text, crop_image],
|
75 |
api_name='predict',
|
76 |
)
|
77 |
run_button2.click(
|
78 |
fn=predict_batch,
|
79 |
+
inputs=[batch_file],
|
80 |
outputs=[result_text2],
|
81 |
api_name='predict_batch',
|
82 |
)
|
83 |
|
84 |
+
if __name__ == "__main__":
|
85 |
+
demo.queue(max_size=20).launch()
|
createTagDom.py
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
|
3 |
+
from __future__ import annotations
|
4 |
+
|
5 |
+
def create_tag_dom(label, ignore, prob):
|
6 |
+
result_html = ''
|
7 |
+
if ignore:
|
8 |
+
result_html += '<div class="m5dd_list">'
|
9 |
+
else:
|
10 |
+
result_html += '<div class="m5dd_list use">'
|
11 |
+
result_html += '<span class="add action">➕</span>'
|
12 |
+
result_html += '<span class="dec action">➖</span>'
|
13 |
+
result_html += '<span class="label action">' + str(label) + '</span>'
|
14 |
+
result_html += '<span class="prob">' + str(round(prob, 3)) + '</span>'
|
15 |
+
result_html += '<span class="up action">🔼</span>'
|
16 |
+
result_html += '<span class="down action">🔽</span>'
|
17 |
+
result_html += '<a class="wiki action" href="https://danbooru.donmai.us/wiki_pages/' + label + '" target="_blank">📙</a>'
|
18 |
+
result_html += '</div>'
|
19 |
+
|
20 |
+
return result_html
|
cropImage.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
|
3 |
+
from __future__ import annotations
|
4 |
+
|
5 |
+
import PIL.Image
|
6 |
+
|
7 |
+
def cropImage(image: PIL.Image.Image):
|
8 |
+
original_width, original_height = image.size
|
9 |
+
scale = max(original_width, original_height) / min(original_width, original_height)
|
10 |
+
|
11 |
+
target_width = 512
|
12 |
+
target_height = 768
|
13 |
+
|
14 |
+
if scale < 1.1:
|
15 |
+
target_width = 640
|
16 |
+
target_height = 640
|
17 |
+
elif original_width > original_height:
|
18 |
+
target_width = 768
|
19 |
+
target_height = 512
|
20 |
+
|
21 |
+
if original_width / original_height > target_width / target_height:
|
22 |
+
new_width = int(original_height * (target_width / target_height))
|
23 |
+
crop_box = ((original_width - new_width) // 2, 0, (original_width + new_width) // 2, original_height)
|
24 |
+
else:
|
25 |
+
new_height = int(original_width * (target_height / target_width))
|
26 |
+
crop_box = (0, (original_height - new_height) // 2, original_width, (original_height + new_height) // 2)
|
27 |
+
|
28 |
+
cropped_image = image.convert("RGB")
|
29 |
+
cropped_image = cropped_image.crop(crop_box)
|
30 |
+
cropped_image = cropped_image.resize((target_width, target_height))
|
31 |
+
|
32 |
+
return cropped_image
|
genTag.py
CHANGED
@@ -2,54 +2,127 @@
|
|
2 |
|
3 |
from __future__ import annotations
|
4 |
|
5 |
-
import
|
6 |
import huggingface_hub
|
7 |
import numpy as np
|
8 |
-
import
|
9 |
-
import
|
|
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
model = tf.keras.models.load_model(path)
|
15 |
-
return model
|
16 |
|
|
|
|
|
|
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
labels = [line.strip() for line in f.readlines()]
|
23 |
-
return labels
|
24 |
|
25 |
|
26 |
-
|
27 |
-
|
|
|
|
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
def genTag(image: PIL.Image.Image, score_threshold: float):
|
31 |
-
|
32 |
-
image = np.asarray(image)
|
33 |
-
image = tf.image.resize(image,
|
34 |
-
size=(height, width),
|
35 |
-
method=tf.image.ResizeMethod.AREA,
|
36 |
-
preserve_aspect_ratio=True)
|
37 |
-
image = image.numpy()
|
38 |
-
image = dd.image.transform_and_pad_image(image, width, height)
|
39 |
-
image = image / 255.
|
40 |
-
probs = model.predict(image[None, ...])[0]
|
41 |
-
probs = probs.astype(float)
|
42 |
-
|
43 |
-
indices = np.argsort(probs)[::-1]
|
44 |
-
result_all = dict()
|
45 |
-
result_threshold = dict()
|
46 |
-
result_html = ''
|
47 |
-
for index in indices:
|
48 |
-
label = labels[index]
|
49 |
-
prob = probs[index]
|
50 |
-
result_all[label] = prob
|
51 |
-
if prob < score_threshold:
|
52 |
-
break
|
53 |
-
result_threshold[label] = prob
|
54 |
-
|
55 |
-
return result_threshold
|
|
|
2 |
|
3 |
from __future__ import annotations
|
4 |
|
5 |
+
import gradio as gr
|
6 |
import huggingface_hub
|
7 |
import numpy as np
|
8 |
+
import onnxruntime as rt
|
9 |
+
import pandas as pd
|
10 |
+
from PIL import Image
|
11 |
|
12 |
+
EVA02_LARGE_MODEL_DSV3_REPO = "SmilingWolf/wd-eva02-large-tagger-v3"
|
13 |
+
MODEL_FILENAME = "model.onnx"
|
14 |
+
LABEL_FILENAME = "selected_tags.csv"
|
|
|
|
|
15 |
|
16 |
+
def load_labels(dataframe) -> list[str]:
|
17 |
+
name_series = dataframe["name"]
|
18 |
+
tag_names = name_series.tolist()
|
19 |
|
20 |
+
rating_indexes = list(np.where(dataframe["category"] == 9)[0])
|
21 |
+
general_indexes = list(np.where(dataframe["category"] == 0)[0])
|
22 |
+
character_indexes = list(np.where(dataframe["category"] == 4)[0])
|
23 |
+
return tag_names, rating_indexes, general_indexes, character_indexes
|
|
|
|
|
24 |
|
25 |
|
26 |
+
class Predictor:
|
27 |
+
def __init__(self):
|
28 |
+
self.model_target_size = None
|
29 |
+
self.load_model(EVA02_LARGE_MODEL_DSV3_REPO)
|
30 |
|
31 |
+
def download_model(self, model_repo):
|
32 |
+
csv_path = huggingface_hub.hf_hub_download(
|
33 |
+
model_repo,
|
34 |
+
LABEL_FILENAME,
|
35 |
+
)
|
36 |
+
model_path = huggingface_hub.hf_hub_download(
|
37 |
+
model_repo,
|
38 |
+
MODEL_FILENAME,
|
39 |
+
)
|
40 |
+
return csv_path, model_path
|
41 |
+
|
42 |
+
def load_model(self, model_repo):
|
43 |
+
csv_path, model_path = self.download_model(model_repo)
|
44 |
+
|
45 |
+
tags_df = pd.read_csv(csv_path)
|
46 |
+
sep_tags = load_labels(tags_df)
|
47 |
+
|
48 |
+
self.tag_names = sep_tags[0]
|
49 |
+
self.rating_indexes = sep_tags[1]
|
50 |
+
self.general_indexes = sep_tags[2]
|
51 |
+
self.character_indexes = sep_tags[3]
|
52 |
+
|
53 |
+
model = rt.InferenceSession(model_path)
|
54 |
+
_, height, width, _ = model.get_inputs()[0].shape
|
55 |
+
self.model_target_size = height
|
56 |
+
|
57 |
+
self.model = model
|
58 |
+
|
59 |
+
def prepare_image(self, image):
|
60 |
+
target_size = self.model_target_size
|
61 |
+
|
62 |
+
canvas = Image.new("RGBA", image.size, (255, 255, 255))
|
63 |
+
canvas.alpha_composite(image)
|
64 |
+
image = canvas.convert("RGB")
|
65 |
+
|
66 |
+
# Pad image to square
|
67 |
+
image_shape = image.size
|
68 |
+
max_dim = max(image_shape)
|
69 |
+
pad_left = (max_dim - image_shape[0]) // 2
|
70 |
+
pad_top = (max_dim - image_shape[1]) // 2
|
71 |
+
|
72 |
+
padded_image = Image.new("RGB", (max_dim, max_dim), (255, 255, 255))
|
73 |
+
padded_image.paste(image, (pad_left, pad_top))
|
74 |
+
|
75 |
+
# Resize
|
76 |
+
if max_dim != target_size:
|
77 |
+
padded_image = padded_image.resize(
|
78 |
+
(target_size, target_size),
|
79 |
+
Image.BICUBIC,
|
80 |
+
)
|
81 |
+
|
82 |
+
# Convert to numpy array
|
83 |
+
image_array = np.asarray(padded_image, dtype=np.float32)
|
84 |
+
|
85 |
+
# Convert PIL-native RGB to BGR
|
86 |
+
image_array = image_array[:, :, ::-1]
|
87 |
+
|
88 |
+
return np.expand_dims(image_array, axis=0)
|
89 |
+
|
90 |
+
def predict(self, image, general_thresh):
|
91 |
+
image = self.prepare_image(image)
|
92 |
+
|
93 |
+
input_name = self.model.get_inputs()[0].name
|
94 |
+
label_name = self.model.get_outputs()[0].name
|
95 |
+
preds = self.model.run([label_name], {input_name: image})[0]
|
96 |
+
|
97 |
+
labels = list(zip(self.tag_names, preds[0].astype(float)))
|
98 |
+
|
99 |
+
# First 4 labels are actually ratings: pick one with argmax
|
100 |
+
ratings_names = [labels[i] for i in self.rating_indexes]
|
101 |
+
ratings_names = dict(ratings_names)
|
102 |
+
ratings_names = sorted(
|
103 |
+
ratings_names.items(),
|
104 |
+
key=lambda x: x[1],
|
105 |
+
reverse=True,
|
106 |
+
)
|
107 |
+
|
108 |
+
# Then we have general tags: pick any where prediction confidence > threshold
|
109 |
+
general_names = [labels[i] for i in self.general_indexes]
|
110 |
+
general_res = [x for x in general_names if x[1] > general_thresh]
|
111 |
+
general_res = dict(general_res)
|
112 |
+
|
113 |
+
ratings = "rating:" + ratings_names[0][0]
|
114 |
+
if ratings_names[0][0] == "general":
|
115 |
+
ratings = "rating:safe"
|
116 |
+
general_res[ratings] = ratings_names[0][1]
|
117 |
+
|
118 |
+
general_res = sorted(
|
119 |
+
general_res.items(),
|
120 |
+
key=lambda x: x[1],
|
121 |
+
reverse=True,
|
122 |
+
)
|
123 |
+
return dict(general_res)
|
124 |
+
|
125 |
+
predictor = Predictor()
|
126 |
|
127 |
def genTag(image: PIL.Image.Image, score_threshold: float):
|
128 |
+
return predictor.predict(image, score_threshold)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ignoreTag.txt
CHANGED
@@ -5,6 +5,8 @@ convenient_censoring,
|
|
5 |
bar_censor,
|
6 |
heart_censor,
|
7 |
censored,
|
|
|
|
|
8 |
twitter_username,
|
9 |
patreon_username,
|
10 |
signature,
|
@@ -13,20 +15,13 @@ artist_name,
|
|
13 |
character_name,
|
14 |
copyright_name,
|
15 |
artist_name,
|
16 |
-
virtual_youtuber,
|
17 |
-
eyebrows_visible_through_hair,
|
18 |
-
eyes_visible_through_hair,
|
19 |
-
hair_between_eyes,
|
20 |
web_address,
|
21 |
-
|
|
|
|
|
22 |
monochrome,
|
23 |
letterboxed,
|
24 |
-
|
25 |
-
oekaki,
|
26 |
-
holding_hands,
|
27 |
-
nail_polish,
|
28 |
-
sandwiched,
|
29 |
-
symbol-shaped_pupils,
|
30 |
greyscale,
|
31 |
sketch,
|
32 |
speech_bubble,
|
@@ -36,15 +31,12 @@ spoken_question_mark,
|
|
36 |
spoken_sweatdrop,
|
37 |
spoken_squiggle,
|
38 |
spoken_object,
|
39 |
-
letterboxed,
|
40 |
spoken_interrobang,
|
41 |
spoken_exclamation_mark,
|
42 |
spoken_anger_vein,
|
43 |
spoken_blush,
|
44 |
thought_bubble,
|
45 |
-
|
46 |
-
character_censor,
|
47 |
-
novelty_censor,
|
48 |
aqua_nails,
|
49 |
black_nails,
|
50 |
green_nails,
|
@@ -59,4 +51,19 @@ toenail_polish,
|
|
59 |
toenails,
|
60 |
yellow_nails,
|
61 |
blue_nails,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
interlocked_fingers,
|
|
|
|
|
|
|
|
5 |
bar_censor,
|
6 |
heart_censor,
|
7 |
censored,
|
8 |
+
character_censor,
|
9 |
+
novelty_censor,
|
10 |
twitter_username,
|
11 |
patreon_username,
|
12 |
signature,
|
|
|
15 |
character_name,
|
16 |
copyright_name,
|
17 |
artist_name,
|
|
|
|
|
|
|
|
|
18 |
web_address,
|
19 |
+
qr_code,
|
20 |
+
virtual_youtuber,
|
21 |
+
loli,
|
22 |
monochrome,
|
23 |
letterboxed,
|
24 |
+
realistic,
|
|
|
|
|
|
|
|
|
|
|
25 |
greyscale,
|
26 |
sketch,
|
27 |
speech_bubble,
|
|
|
31 |
spoken_sweatdrop,
|
32 |
spoken_squiggle,
|
33 |
spoken_object,
|
|
|
34 |
spoken_interrobang,
|
35 |
spoken_exclamation_mark,
|
36 |
spoken_anger_vein,
|
37 |
spoken_blush,
|
38 |
thought_bubble,
|
39 |
+
nail_polish,
|
|
|
|
|
40 |
aqua_nails,
|
41 |
black_nails,
|
42 |
green_nails,
|
|
|
51 |
toenails,
|
52 |
yellow_nails,
|
53 |
blue_nails,
|
54 |
+
eyebrows_visible_through_hair,
|
55 |
+
eyes_visible_through_hair,
|
56 |
+
hair_between_eyes,
|
57 |
+
bangs,
|
58 |
+
symbol-shaped_pupils,
|
59 |
+
toe_scrunch,
|
60 |
+
bad_feet,
|
61 |
+
oekaki,
|
62 |
+
holding_hands,
|
63 |
+
sandwiched,
|
64 |
+
mole,
|
65 |
+
navel,
|
66 |
interlocked_fingers,
|
67 |
+
striped_background,
|
68 |
+
striped,
|
69 |
+
vertical_stripes,
|
ignoreTag2.txt
CHANGED
@@ -1,3 +1,4 @@
|
|
1 |
rating:safe,
|
|
|
2 |
rating:questionable,
|
3 |
-
rating:explicit,
|
|
|
1 |
rating:safe,
|
2 |
+
rating:sensitive,
|
3 |
rating:questionable,
|
4 |
+
rating:explicit,
|
requirements.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
|
|
1 |
+
pillow==10.2.0
|
2 |
+
tensorflow==2.15.0.post1
|
3 |
+
onnxruntime>=1.12.0
|
4 |
+
huggingface-hub
|
script.js
CHANGED
@@ -1,24 +1,48 @@
|
|
|
|
1 |
|
2 |
-
document.addEventListener('click', function (event) {
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
} else {
|
9 |
-
|
10 |
}
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
.join(', ')
|
15 |
-
} else if (resultArea) {
|
16 |
-
const selection = window.getSelection()
|
17 |
-
selection.removeAllRanges()
|
18 |
-
const range = document.createRange()
|
19 |
-
range.selectNodeContents(resultArea)
|
20 |
-
selection.addRange(range)
|
21 |
-
} else {
|
22 |
-
return
|
23 |
-
}
|
24 |
-
})
|
|
|
1 |
+
async () => {
|
2 |
|
3 |
+
document.addEventListener('click', function (event) {
|
4 |
+
let tagItem = event.target.closest('.m5dd_list')
|
5 |
+
let resultArea = event.target.closest('#m5dd_result')
|
6 |
+
if (tagItem) {
|
7 |
+
let labelItem = event.target.closest('span.label')
|
8 |
+
let upItem = event.target.closest('span.up')
|
9 |
+
let downItem = event.target.closest('span.down')
|
10 |
+
let addItem = event.target.closest('span.add')
|
11 |
+
let decItem = event.target.closest('span.dec')
|
12 |
+
let actionItem = event.target.closest('span.action')
|
13 |
+
if (labelItem) {
|
14 |
+
if (tagItem.classList.contains('use')) {
|
15 |
+
tagItem.classList.remove('use')
|
16 |
+
} else {
|
17 |
+
tagItem.classList.add('use')
|
18 |
+
}
|
19 |
+
}
|
20 |
+
if (upItem) { }
|
21 |
+
if (downItem) { }
|
22 |
+
if (addItem) {
|
23 |
+
let label = tagItem.querySelector('span.label').innerText
|
24 |
+
tagItem.querySelector('span.label').innerText = `(${label})`
|
25 |
+
}
|
26 |
+
if (decItem) {
|
27 |
+
let label = tagItem.querySelector('span.label').innerText
|
28 |
+
label = label.replace(/^\s*\(\s*(.+?)\s*\)\s*$/, '$1')
|
29 |
+
tagItem.querySelector('span.label').innerText = label
|
30 |
+
}
|
31 |
+
if (actionItem) {
|
32 |
+
document.getElementById('m5dd_result').innerText =
|
33 |
+
Array.from(document.querySelectorAll('.m5dd_list.use>span.label'))
|
34 |
+
.map(v => v.innerText)
|
35 |
+
.join(', ')
|
36 |
+
}
|
37 |
+
} else if (resultArea) {
|
38 |
+
const selection = window.getSelection()
|
39 |
+
selection.removeAllRanges()
|
40 |
+
const range = document.createRange()
|
41 |
+
range.selectNodeContents(resultArea)
|
42 |
+
selection.addRange(range)
|
43 |
} else {
|
44 |
+
return
|
45 |
}
|
46 |
+
})
|
47 |
+
|
48 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
style.css
CHANGED
@@ -2,22 +2,35 @@
|
|
2 |
display: flex;
|
3 |
cursor: pointer;
|
4 |
font-size: 1.2em;
|
5 |
-
padding:
|
|
|
6 |
}
|
7 |
|
8 |
-
.m5dd_list>span
|
9 |
flex: 1;
|
|
|
10 |
}
|
11 |
|
12 |
-
.m5dd_list>span
|
13 |
color: #aaa;
|
|
|
14 |
}
|
15 |
|
16 |
-
.m5dd_list:nth-child(even) {
|
17 |
-
|
18 |
-
}
|
19 |
|
20 |
-
.m5dd_list:not(.use)>span {
|
21 |
text-decoration: line-through;
|
22 |
color: #ccc;
|
23 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
display: flex;
|
3 |
cursor: pointer;
|
4 |
font-size: 1.2em;
|
5 |
+
padding: .5em;
|
6 |
+
user-select: none;
|
7 |
}
|
8 |
|
9 |
+
.m5dd_list>span.label {
|
10 |
flex: 1;
|
11 |
+
padding: 0 .5em;
|
12 |
}
|
13 |
|
14 |
+
.m5dd_list>span.prob {
|
15 |
color: #aaa;
|
16 |
+
padding: 0 .5em;
|
17 |
}
|
18 |
|
19 |
+
.m5dd_list:nth-child(even) { background: #ECEDF0; }
|
20 |
+
.dark .m5dd_list:nth-child(even) { background: #1F2937; }
|
|
|
21 |
|
22 |
+
.m5dd_list:not(.use)>span.label {
|
23 |
text-decoration: line-through;
|
24 |
color: #ccc;
|
25 |
}
|
26 |
+
|
27 |
+
.m5dd_image .upload-container .image-frame {
|
28 |
+
height: 20em;
|
29 |
+
}
|
30 |
+
|
31 |
+
.m5dd_image .upload-container .image-frame {
|
32 |
+
height: 20em;
|
33 |
+
}
|
34 |
+
.m5dd_image2 .image-container {
|
35 |
+
height: 20em;
|
36 |
+
}
|