"""Pinned JujoHotaru catalog, optional slot selection and sample cards.""" import html import json from pathlib import Path from urllib.parse import quote NONE_LORA = "---" PONY_LABEL = "Pony用・ILL未検証" PONY_WARNING = ( "Pony系モデル向けのSDXL LoRAです。Illustriousで読み込めても、効き方・画質・再現性は未検証です。" "効果が弱い、意図しない描写になる場合があります。掲載画像もILLでの生成結果とは限りません。" ) CATALOG_ROOT = Path(__file__).resolve().parent / "assets" / "jujo" CATALOGS = { family: json.loads((CATALOG_ROOT / f"{family}.json").read_text(encoding="utf-8")) for family in ("anima", "illustrious") } JUJO_ENTRIES = { family: {entry["name"]: entry for entry in sorted(catalog["entries"], key=lambda entry: bool(entry.get("pony_only")))} for family, catalog in CATALOGS.items() } def lora_selected(enabled, name): """The no-selection value is inactive even when Enable is checked.""" return bool(enabled and name and name != NONE_LORA) def jujo_label(family, name): entry = JUJO_ENTRIES[family].get(name) prefix = f"[{PONY_LABEL}] " if entry and entry.get("pony_only") else "" return f"{prefix}JujoHotaru / {entry['title']} / {name}" if entry else name def pony_selection_notice(family, names): selected = [name for name in names if JUJO_ENTRIES.get(family, {}).get(name, {}).get("pony_only")] if not selected: return "" return f"> **注意:{PONY_LABEL}** \n> {PONY_WARNING} \n> 選択中:" + "、".join(f"`{name}`" for name in dict.fromkeys(selected)) def sample_card(family, name): entry = JUJO_ENTRIES[family].get(name) if not entry: return "

LoRAを選択すると作者のサンプルと配布元を表示します。

" catalog = CATALOGS[family] base = f"https://huggingface.co/{catalog['repo']}" doc_url = f"{base}/blob/{catalog['revision']}/{quote(entry['doc'])}" image_url = f"{base}/resolve/{catalog['revision']}/{quote(entry['image'])}" if entry["image"] else None note = "シリーズ共通の比較サンプル" if entry["group_sample"] else "選択したLoRAのサンプル" image = ( f'' f'' if image_url else "

サンプル画像は配布元で確認してください。

" ) hint = ( "眼の形シリーズは強度0.3~1.5が作者の目安です。複数併用時は合計1.0~1.5を目安にしてください。" if family == "anima" and entry["doc"] == "eyeshapes/README.md" else "このアイコレクションXLはILLでは強度1.5~2.0が作者の目安です。タイプに応じてtareme / tsurimeも参照してください。" if family == "illustrious" and entry["doc"] == "sdxl/eyecollexl/README.md" else "強度・補助プロンプトの推奨は下の作者説明を確認してください。" ) return ( f'

{html.escape(entry["title"])}

{html.escape(name)}

' + (f'

{PONY_LABEL}:{PONY_WARNING}

' if entry.get("pony_only") else "") + f'

{note} · JujoHotaru(十条蛍)作成。掲載画像は作者の生成例です。

' f'{image}

{hint}

' f'

作者の使い方・サンプル・配布元を開く

' ) def jujo_credits(family): catalog = CATALOGS[family] license_text = ( "CircleStone Labs Non-Commercial License(非商用)。" "[ライセンス](https://huggingface.co/JujoHotaru/anima_lora/blob/main/LICENSE.md) / " "[NOTICE](https://huggingface.co/JujoHotaru/anima_lora/blob/main/NOTICE.md)" if family == "anima" else "作者配布条件はMITまたはCreativeML Open RAIL-Mのデュアルライセンス。" "[ライセンス](https://huggingface.co/JujoHotaru/lora/blob/main/LICENSE)" ) return ( "\n\n### JujoHotaru LoRA・掲載サンプル\n\n" f"- 作者: **JujoHotaru(十条蛍 / Hotaru Jujo)**\n" f"- 配布元: [{catalog['repo']}]({catalog['source']})\n" f"- 登録: {len(catalog['entries'])}種類。掲載サンプル画像も作者のリポジトリを参照\n" + (f"- Pony用を含みます。`{PONY_LABEL}` 表示のものはILLでの互換性を保証しません\n" if family == "illustrious" else "") + f"- {license_text}\n" "- 個別ファイルの説明・推奨強度はLoRAサンプル欄の配布元リンクを確認してください。\n" )