import gradio as gr, os, shutil, glob from huggingface_hub import upload_file # ---------- CONFIG ------------------------------------------------- DATASET_REPO = "ruilongli/capture-data" PENDING_DIR = "pending" APPROVED_DIR = "approved" ADMIN_KEY = os.getenv("ADMIN_KEY") # set in Space secrets HF_TOKEN = os.getenv("HF_TOKEN") for d in (PENDING_DIR, APPROVED_DIR): os.makedirs(d, exist_ok=True) # ------------------------------------------------------------------- # -------- HELPERS -------------------------------------------------- def list_pending(): # paths to files awaiting review return sorted(glob.glob(f"{PENDING_DIR}/*")) # -------- PUBLIC UPLOAD HANDLER ----------------------------------- def handle_upload(tmp_path): if not tmp_path: return "❌ No file received." fname = os.path.basename(tmp_path) shutil.copy(tmp_path, os.path.join(PENDING_DIR, fname)) return f"✅ `{fname}` uploaded for review!" # -------- ADMIN ACTIONS ------------------------------------------- def approve_files(_, selected_items): # no pw needed after login if not selected_items: return "⚠️ Nothing selected.", list_pending() log_lines = [] for item in selected_items: file_path = item[0] if isinstance(item, (tuple, list)) else item fname = os.path.basename(file_path) upload_file( # 1) push to dataset repo path_or_fileobj=file_path, path_in_repo=f"images/{fname}", repo_id=DATASET_REPO, repo_type="dataset", token=HF_TOKEN, ) shutil.move(file_path, os.path.join(APPROVED_DIR, fname)) # 2) move log_lines.append(f"✅ {fname}") return "\n".join(log_lines), list_pending() def refresh_files(_): # simply reload folder return "🔁 List refreshed.", list_pending() # -------- ADMIN LOGIN --------------------------------------------- def admin_login(pw): if pw != ADMIN_KEY: return "🔒 Wrong key!", gr.update(visible=False) return "✅ Logged in.", gr.update(visible=True) # show admin group # -------------------- UI ------------------------------------------ with gr.Blocks() as demo: # -------- public uploader ---------- gr.Markdown("## 🖼️ Anonymous Image Upload") with gr.Row(): up_comp = gr.File(type="filepath", file_types=["image"]) up_msg = gr.Textbox(label="Status") up_comp.upload(handle_upload, up_comp, up_msg) # -------- admin login widgets ------- with gr.Accordion("Admin login", open=False): login_pw = gr.Textbox(label="Admin key", type="password") login_btn = gr.Button("Log in") login_msg = gr.Textbox(label="Login status", interactive=False) # -------- admin panel (initially hidden) ----- admin_panel = gr.Column(visible=False) with admin_panel: gr.Markdown("## 🔍 Admin review panel") gallery = gr.Gallery( label="Pending images", value=list_pending(), columns=[4], height="auto", interactive=False, # selectable="multiple" ) with gr.Row(): approve_btn = gr.Button("Approve & publish", variant="primary") refresh_btn = gr.Button("🔄 Refresh list", variant="secondary") review_log = gr.Textbox(label="Log / Result", lines=6) # ---- wiring ---- login_btn.click(admin_login, login_pw, [login_msg, admin_panel]) approve_btn.click( fn=approve_files, inputs=[login_pw, gallery], # pw unused but keeps signature outputs=[review_log, gallery] ) refresh_btn.click( fn=refresh_files, inputs=[login_pw], outputs=[review_log, gallery] ) demo.queue().launch()