File size: 7,239 Bytes
a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 bd711e3 a4157a2 bd711e3 e9f4bee a4157a2 bd711e3 a4157a2 a5ce452 a4157a2 bd711e3 a4157a2 a5ce452 bd711e3 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 a5ce452 a4157a2 bd711e3 a4157a2 a5ce452 bd711e3 a5ce452 bd711e3 a5ce452 bd711e3 a5ce452 a4157a2 a5ce452 a4157a2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | import os
import re
import gradio as ui
from huggingface_hub import HfApi, hf_hub_url
REPO_ID = "Crocody/mymuse"
REPO_TYPE = "dataset"
HF_TOKEN = os.getenv("HF_TOKEN")
api = HfApi(token=HF_TOKEN)
def natural_sort_key(s):
return [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s)]
def get_lora_samples(sort_desc=False):
try:
files = api.list_repo_files(repo_id=REPO_ID, repo_type=REPO_TYPE)
samples = [f for f in files if f.startswith("LoRA_Samples/") and f.lower().endswith(('.png', '.jpg', '.jpeg'))]
samples.sort(key=lambda x: natural_sort_key(os.path.basename(x)), reverse=sort_desc)
return samples
except Exception as e:
print(f"ํ์ผ ๋ก๋ ์คํจ: {e}")
return []
def update_gallery_data(sort_desc=False):
paths = get_lora_samples(sort_desc=sort_desc)
gallery_val = [(hf_hub_url(repo_id=REPO_ID, repo_type=REPO_TYPE, filename=p), os.path.splitext(os.path.basename(p))[0]) for p in paths]
return gallery_val, paths
def generate_download_links(image_path):
if not image_path:
return "<div style='color: #94a3b8; text-align: center; margin-top: 140px; font-size: 15px;'>์ผ์ชฝ ๋ชฉ๋ก์์ ๋ก๋ผ ์นด๋๋ฅผ ํด๋ฆญํ๋ฉด<br>๋ฒ์ ๋ณ ์ํ ์ ๋ณด ๋ฐ ๋ค์ด๋ก๋ ์ฐฝ์ด ํ์ฑํ๋ฉ๋๋ค.</div>"
filename = os.path.splitext(os.path.basename(image_path))[0]
img_url = hf_hub_url(repo_id=REPO_ID, repo_type=REPO_TYPE, filename=image_path)
target_folders = ["Qwen2509", "Qwen2512", "Zit", "Krea2"]
# 1. ์๋จ ์ด๋ฏธ์ง ๋ฐฐ์น ๋ฐ 2. ํ๋จ ํ
์คํธ ๋ด์ฉ ์ ๊ธฐ์ ๊ฒฐํฉ (HTML ๋ ์ด์์)
html_output = f"""
<div style='display: flex; flex-direction: column; align-items: center; gap: 20px;'>
<div style='width: 100%; max-width: 280px; aspect-ratio: 3/4; overflow: hidden; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);'>
<img src='{img_url}' style='width: 100%; height: 100%; object-fit: cover;' alt='{filename} preview'/>
</div>
<div style='width: 100%;'>
<h3 style='margin: 10px 0 5px 0; font-size: 18px; color: #1e293b; display: flex; align-items: center; gap: 6px;'>๐ฆ {filename} LoRA ๋ค์ด๋ก๋ ๋งํฌ</h3>
<table class='download-table'>
<thead>
<tr><th>๋ฒ์ / ํด๋</th><th>๋ค์ด๋ก๋ ๋งํฌ</th></tr>
</thead>
<tbody>
"""
all_files = api.list_repo_files(repo_id=REPO_ID, repo_type=REPO_TYPE)
for folder in target_folders:
target_file = f"{folder}/{filename}.safetensors"
match = [f for f in all_files if f.lower() == target_file.lower()]
if match:
download_url = hf_hub_url(repo_id=REPO_ID, repo_type=REPO_TYPE, filename=match[0])
html_output += f"<tr><td><b>{folder}</b></td><td><a href='{download_url}' target='_blank' class='btn-download'>๋ค์ด๋ก๋ ({filename}.safetensors)</a></td></tr>"
else:
html_output += f"<tr><td><b>{folder}</b></td><td style='color: #ef4444;'>ํ์ผ ์์</td></tr>"
html_output += """
</tbody>
</table>
</div>
</div>
"""
return html_output
# --- ์คํ์ผ์ํธ ---
custom_css = """
body, .gradio-container { background-color: #f4f6f9 !important; font-family: sans-serif !important; }
#lora-gallery { background: transparent !important; border: none !important; box-shadow: none !important; }
#lora-gallery .gallery-item { background: #ffffff !important; border-radius: 12px !important; border: 1px solid #e2e8f0 !important; padding: 14px !important; }
#info-panel { background: #ffffff !important; border-radius: 16px !important; border: 1px solid #e2e8f0 !important; padding: 24px !important; min-height: 500px; }
.download-table { width: 100%; border-collapse: separate; border-spacing: 0; margin-top: 15px; border-radius: 8px; overflow: hidden; border: 1px solid #e2e8f0; }
.download-table th { background-color: #f8fafc; color: #64748b; padding: 12px 16px; font-size: 14px; border-bottom: 1px solid #e2e8f0; }
.download-table td { padding: 14px 16px; font-size: 14px; border-bottom: 1px solid #e2e8f0; color: #334155; }
.btn-download { color: #2563eb !important; font-weight: 600; text-decoration: none; }
.btn-download:hover { text-decoration: underline; }
.nav-btn { font-weight: 600 !important; background: #ffffff !important; border: 1px solid #e2e8f0 !important; border-radius: 8px !important; }
"""
with ui.Blocks(css=custom_css) as demo:
with ui.Row():
ui.Markdown("# โจ mymuse LoRA Management Center")
with ui.Row(elem_id="action-bar"):
btn_asc = ui.Button("โฌ๏ธ ์ค๋ฆ์ฐจ์", elem_classes="nav-btn", scale=1)
btn_desc = ui.Button("โฌ๏ธ ๋ด๋ฆผ์ฐจ์", elem_classes="nav-btn", scale=1)
btn_refresh = ui.Button("๐ ์๋ก๊ณ ์นจ", elem_classes="nav-btn", scale=1)
with ui.Row():
# ์ผ์ชฝ ๊ทธ๋ฆฌ๋ ์์ญ
with ui.Column(scale=2):
initial_paths = get_lora_samples(sort_desc=False)
initial_gallery = [(hf_hub_url(repo_id=REPO_ID, repo_type=REPO_TYPE, filename=p), os.path.splitext(os.path.basename(p))[0]) for p in initial_paths]
gallery = ui.Gallery(
value=initial_gallery,
columns=4,
object_fit="cover",
height=750,
allow_preview=False,
show_label=False,
elem_id="lora-gallery"
)
paths_holder = ui.State(value=initial_paths)
# ์ค๋ฅธ์ชฝ ์ ๋ณด ์ถ๋ ฅ ์์ญ (์๋จ ์ด๋ฏธ์ง + ํ๋จ ์ ๋ณด ๊ตฌ์กฐ ๋ฐ์)
with ui.Column(scale=1):
with ui.HTML(elem_id="info-panel") as output_area:
output_area.value = "<div style='color: #94a3b8; text-align: center; margin-top: 180px; font-size: 15px;'>์ผ์ชฝ ๋ชฉ๋ก์์ ๋ก๋ผ ์นด๋๋ฅผ ํด๋ฆญํ๋ฉด<br>๋ฒ์ ๋ณ ์ํ ์ ๋ณด ๋ฐ ๋ค์ด๋ก๋ ์ฐฝ์ด ํ์ฑํ๋ฉ๋๋ค.</div>"
# --- ์ด๋ฒคํธ ํธ๋ค๋ง ---
btn_asc.click(
fn=lambda: update_gallery_data(sort_desc=False),
inputs=[],
outputs=[gallery, paths_holder]
)
btn_desc.click(
fn=lambda: update_gallery_data(sort_desc=True),
inputs=[],
outputs=[gallery, paths_holder]
)
def refresh_all():
gallery_val, paths = update_gallery_data(sort_desc=False)
reset_html = "<div style='color: #94a3b8; text-align: center; margin-top: 180px; font-size: 15px;'>์ผ์ชฝ ๋ชฉ๋ก์์ ๋ก๋ผ ์นด๋๋ฅผ ํด๋ฆญํ๋ฉด<br>๋ฒ์ ๋ณ ์ํ ์ ๋ณด ๋ฐ ๋ค์ด๋ก๋ ์ฐฝ์ด ํ์ฑํ๋ฉ๋๋ค.</div>"
return gallery_val, paths, reset_html
btn_refresh.click(
fn=refresh_all,
inputs=[],
outputs=[gallery, paths_holder, output_area]
)
def on_select(evt: ui.SelectData, paths):
return generate_download_links(paths[evt.index])
gallery.select(fn=on_select, inputs=[paths_holder], outputs=[output_area])
demo.launch() |