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 "
왼쪽 목록에서 로라 카드를 클릭하면
버전별 상태 정보 및 다운로드 창이 활성화됩니다.
"
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"]
# 1. 상단 이미지 배치 및 2. 하단 텍스트 내용 유기적 결합 (HTML 레이아웃)
html_output = f"""
📦 {filename} LoRA 다운로드 링크
| 버전 / 폴더 | 다운로드 링크 |
"""
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"| {folder} | 다운로드 ({filename}.safetensors) |
"
else:
html_output += f"| {folder} | 파일 없음 |
"
html_output += """
"""
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 = "왼쪽 목록에서 로라 카드를 클릭하면
버전별 상태 정보 및 다운로드 창이 활성화됩니다.
"
# --- 이벤트 핸들링 ---
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 = "왼쪽 목록에서 로라 카드를 클릭하면
버전별 상태 정보 및 다운로드 창이 활성화됩니다.
"
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()