import gradio as gr import spaces # ZERO GPU # ref: https://qiita.com/tregu148/items/fccccbbc47d966dd2fc2 def gradio_copy_text(_text: None): gr.Info("Copied!") COPY_ACTION_JS = """\ (inputs, _outputs) => { // inputs is the string value of the input_text if (inputs.trim() !== "") { navigator.clipboard.writeText(inputs); } }""" def _people_tag(noun: str, minimum: int = 1, maximum: int = 5): return ( [f"1{noun}"] + [f"{num}{noun}s" for num in range(minimum + 1, maximum + 1)] + [f"{maximum+1}+{noun}s"] ) PEOPLE_TAGS = ( _people_tag("girl") + _people_tag("boy") + _people_tag("other") + ["no humans"] ) RATING_MAP = { "safe": "rating_safe", "sensitive": "rating_safe", "nsfw": "rating_questionable", "explicit, nsfw": "rating_explicit", "explicit": "rating_explicit", "rating:safe": "rating_safe", "rating:general": "rating_safe", "rating:sensitive": "rating_safe", "rating:questionable, nsfw": "rating_explicit", "rating:explicit, nsfw": "rating_explicit", } DESCRIPTION_MD = """ # Convert general Danbooru tags to Pony e621 tags """.strip() DESCRIPTION_MD2 = """ The dictionary was generated using the following repository: [ponapon280/danbooru-e621-converter](https://github.com/ponapon280/danbooru-e621-converter) """.strip() def character_list_to_series_list(character_list): def get_series_dict(): import re with open('characterfull.txt', 'r') as f: lines = f.readlines() series_dict = {} for line in lines: parts = line.strip().split(', ') if len(parts) >= 3: name = parts[-2].replace("\\", "") if name.endswith(")"): names = name.split("(") character_name = "(".join(names[:-1]) if character_name.endswith(" "): name = character_name[:-1] series = re.sub(r'\\[()]', '', parts[-1]) series_dict[name] = series return series_dict output_series_tag = [] series_tag = "" series_dict = get_series_dict() for tag in character_list: series_tag = series_dict.get(tag, "") if tag.endswith(")"): tags = tag.split("(") character_tag = "(".join(tags[:-1]) if character_tag.endswith(" "): character_tag = character_tag[:-1] series_tag = tags[-1].replace(")", "") if series_tag: output_series_tag.append(series_tag) return output_series_tag def get_e621_dict(): with open('danbooru_e621.csv', 'r', encoding="utf-8") as f: lines = f.readlines() e621_dict = {} for line in lines: parts = line.strip().split(',') e621_dict[parts[0]] = parts[1] return e621_dict def danbooru_to_e621(dtag, e621_dict): def d_to_e(match, e621_dict): dtag = match.group(0) etag = e621_dict.get(dtag.strip().replace("_", " "), "") if etag: return etag else: return dtag import re tag = re.sub(r'[\w ]+', lambda wrapper: d_to_e(wrapper, e621_dict), dtag, 2) return tag def nai_to_webui(ntag): def n_to_w(match): import re ntag = match.group(0) power = 1.0 for i in range(ntag.count("{")): power *= 1.05 for i in range(ntag.count("[")): power *= 0.952 wtag_word = re.sub(r'(?:{+([\w ,_]+)}+)|(?:\[+([\w ,_]+)\]+)', r'\1\2', ntag, 2) wtag = f"({wtag_word}:{power:.2f})" if wtag: return wtag else: return ntag import re tag = re.sub(r'(?:{+[\w ,_]+}+)|(?:\[+[\w ,_]+\]+)', lambda wrapper: n_to_w(wrapper), ntag) return tag def animagine_prompt(character: list[str], general: list[str], tag_type): people_tags: list[str] = [] other_tags: list[str] = [] rating_tags: list[str] = [] e621_dict = get_e621_dict() for tag in general: tag = danbooru_to_e621(tag, e621_dict) if tag in PEOPLE_TAGS: people_tags.append(tag) elif tag in RATING_MAP.keys(): rating_tags.append(RATING_MAP.get(tag.replace(" ",""), "")) else: other_tags.append(tag) rating_tags = sorted(set(rating_tags), key=rating_tags.index) rating_tags = [rating_tags[0]] if rating_tags else [] output_series_tag = character_list_to_series_list(character) all_tag = ", ".join(people_tags + character + output_series_tag + other_tags + rating_tags) if tag_type == "NovelAI": all_tag = nai_to_webui(all_tag) return all_tag def convert_tags( input_copyright = "", input_character = "", input_general = "", tag_type = "WebUI", ): character = [] general = [] character.append(input_character) if input_character else [] general = input_general.split(",") if input_general else [] prompt = animagine_prompt( character, general, tag_type ) return prompt, gr.update(interactive=True,) def demo(): with gr.Blocks() as ui: gr.Markdown(DESCRIPTION_MD) with gr.Row(): with gr.Column(): with gr.Group(): input_copyright = gr.Textbox( label="Copyright tags", placeholder="vocaloid", ) input_character = gr.Textbox( label="Character tags", placeholder="hatsune miku", ) input_general = gr.TextArea( label="General tags", lines=6, placeholder="1girl, solo, ...", ) tag_type = gr.Radio( label="Style of tags", choices=["WebUI", "NovelAI"], value="WebUI", ) start_btn = gr.Button(value="Convert", variant="primary") with gr.Column(): with gr.Group(): prompt_text = gr.TextArea(label="Prompt", lines=6, interactive=False) copy_btn = gr.Button(value="Copy to clipboard", interactive=False) gr.Markdown(DESCRIPTION_MD2) start_btn.click( convert_tags, inputs=[input_copyright, input_character, input_general, tag_type], outputs=[ prompt_text, copy_btn, ], ) copy_btn.click(gradio_copy_text, inputs=[prompt_text], js=COPY_ACTION_JS) return ui if __name__ == "__main__": demo().queue().launch()