# admin.py import os import json import hmac import zipfile import shutil from typing import List, Tuple ALLOWED_IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".tif", ".tiff"} _ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "") # Hugging Face Space Secret 권장 def _persistent_base_dir() -> str: return os.environ.get("HF_PERSISTENT_DIR", "/data") def _data_root() -> str: return _persistent_base_dir() def verify_password(input_pw: str) -> bool: return bool(_ADMIN_PASSWORD) and hmac.compare_digest(input_pw or "", _ADMIN_PASSWORD) def list_sessions() -> Tuple[List[str], str]: root = _data_root() os.makedirs(root, exist_ok=True) try: items = sorted( [d for d in os.listdir(root) if os.path.isdir(os.path.join(root, d))], reverse=True ) if not items: return [], "Info: No saved sessions found under /data." return items, f"Found {len(items)} session folder(s) under /data." except Exception as e: return [], f"Error: Failed to list sessions. {e}" def session_info(session: str) -> Tuple[str, List[str]]: root = _data_root() if not session: return "Error: No session selected.", [] path = os.path.join(root, session) if not os.path.isdir(path): return "Error: Session folder does not exist.", [] # meta.json meta_text = "" meta_path = os.path.join(path, "meta.json") if os.path.isfile(meta_path): try: with open(meta_path, "r", encoding="utf-8") as fp: meta = json.load(fp) meta_text = json.dumps(meta, ensure_ascii=False, indent=2) except Exception as e: meta_text = f"(Failed to read meta.json: {e})" originals = [] for name in os.listdir(path): p = os.path.join(path, name) if os.path.isfile(p) and os.path.splitext(name)[1].lower() in ALLOWED_IMAGE_EXTS: originals.append(p) total_imgs = len(originals) info_md = ( f"**Session:** `{session}` \n" f"**Path:** `{path}` \n" f"**Images (total):** {total_imgs} \n" ) if meta_text: info_md += "\n\n**meta.json**\n```json\n" + meta_text + "\n```" return info_md def zip_session(session: str) -> str: root = _data_root() if not session: raise ValueError("Error: No session selected.") src_dir = os.path.join(root, session) if not os.path.isdir(src_dir): raise ValueError("Error: Session folder does not exist.") zip_path = f"/tmp/{session}.zip" try: if os.path.exists(zip_path): os.remove(zip_path) with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zf: for rootdir, _, files in os.walk(src_dir): for f in files: full = os.path.join(rootdir, f) arc = os.path.relpath(full, src_dir) zf.write(full, arcname=arc) except Exception as e: raise RuntimeError(f"Error: Failed to create zip. {e}") return zip_path def delete_session(session: str) -> str: """ Delete the entire session folder (and its contents). Returns a status message. """ root = _data_root() if not session: return "Error: No session selected." path = os.path.join(root, session) if not os.path.isdir(path): return "Error: Session folder does not exist." try: shutil.rmtree(path) return f"Success: Deleted session '{session}'." except Exception as e: return f"Error: Failed to delete session '{session}'. {e}"