MonkeyJuice commited on
Commit
7d3b3b8
·
1 Parent(s): c410097

change lib

Browse files
Files changed (12) hide show
  1. .pre-commit-config.yaml +0 -36
  2. .vscode/settings.json +23 -11
  3. README.md +4 -4
  4. app.py +33 -35
  5. createTagDom.py +20 -0
  6. cropImage.py +32 -0
  7. genTag.py +114 -41
  8. ignoreTag.txt +22 -15
  9. ignoreTag2.txt +2 -1
  10. requirements.txt +4 -4
  11. script.js +45 -21
  12. 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
- "python.linting.enabled": true,
3
- "python.linting.flake8Enabled": true,
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": true
14
  }
15
  },
16
- "editor.formatOnSave": true,
17
- "files.insertFinalNewline": true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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: DeepDanbooru
3
- emoji: 🏃
4
  colorFrom: gray
5
  colorTo: purple
6
  sdk: gradio
7
- sdk_version: 4.19.2
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, score_threshold: float):
12
- result_threshold = genTag(image, score_threshold)
13
  result_html = ''
14
  for label, prob in result_threshold.items():
15
- if is_ignore(label, 1):
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
- return result_html, result_text
 
24
 
25
- def predict_batch(zip_file, score_threshold: float, progress=gr.Progress()):
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("RGB")
34
- result_threshold = genTag(image, score_threshold)
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
- sources=["upload", "clipboard"],
47
- height='20em')
48
- score_threshold = gr.Slider(label='Score threshold',
49
- minimum=0,
50
- maximum=1,
51
- step=0.05,
52
- value=0.5)
53
  run_button = gr.Button('Run')
54
- result_text = gr.HTML(value="<div></div>")
 
 
 
 
 
 
55
  with gr.Column(scale=2):
56
- result_html = gr.HTML(value="<div></div>")
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=5,
 
71
  label='Result',
72
- show_copy_button=True)
 
73
 
74
  run_button.click(
75
  fn=predict,
76
- inputs=[image, score_threshold],
77
- outputs=[result_html, result_text],
78
  api_name='predict',
79
  )
80
  run_button2.click(
81
  fn=predict_batch,
82
- inputs=[batch_file, score_threshold2],
83
  outputs=[result_text2],
84
  api_name='predict_batch',
85
  )
86
 
87
- demo.queue().launch()
 
 
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 deepdanbooru as dd
6
  import huggingface_hub
7
  import numpy as np
8
- import PIL.Image
9
- import tensorflow as tf
 
10
 
11
- def load_model() -> tf.keras.Model:
12
- path = huggingface_hub.hf_hub_download('public-data/DeepDanbooru',
13
- 'model-resnet_custom_v3.h5')
14
- model = tf.keras.models.load_model(path)
15
- return model
16
 
 
 
 
17
 
18
- def load_labels() -> list[str]:
19
- path = huggingface_hub.hf_hub_download('public-data/DeepDanbooru',
20
- 'tags.txt')
21
- with open(path) as f:
22
- labels = [line.strip() for line in f.readlines()]
23
- return labels
24
 
25
 
26
- model = load_model()
27
- labels = load_labels()
 
 
28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  def genTag(image: PIL.Image.Image, score_threshold: float):
31
- _, height, width, _ = model.input_shape
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
- bangs,
 
 
22
  monochrome,
23
  letterboxed,
24
- bad_feet,
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
- toe_scrunch,
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
- git+https://github.com/KichangKim/DeepDanbooru@v3-20200915-sgd-e30#egg=deepdanbooru
2
- pillow==10.0.0
3
- pydantic==1.10.11
4
- tensorflow==2.13.0
 
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
- let tagItem = event.target.closest('.m5dd_list')
4
- let resultArea = event.target.closest('#m5dd_result')
5
- if (tagItem) {
6
- if (tagItem.classList.contains('use')) {
7
- tagItem.classList.remove('use')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  } else {
9
- tagItem.classList.add('use')
10
  }
11
- document.getElementById('m5dd_result').innerText =
12
- Array.from(document.querySelectorAll('.m5dd_list.use>span:nth-child(1)'))
13
- .map(v => v.innerText)
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: 0.2em 0.5em;
 
6
  }
7
 
8
- .m5dd_list>span:nth-child(1) {
9
  flex: 1;
 
10
  }
11
 
12
- .m5dd_list>span:nth-child(2) {
13
  color: #aaa;
 
14
  }
15
 
16
- .m5dd_list:nth-child(even) {
17
- background: #ecedf0;
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
+ }