Spaces:
Running
Running
| import os | |
| import math | |
| import time | |
| import random | |
| import tempfile | |
| import gradio as gr | |
| import pandas as pd | |
| from datasets import load_dataset | |
| from huggingface_hub import snapshot_download | |
| # ====================================================== | |
| # QUOTA CONFIG | |
| # ====================================================== | |
| LIMIT = 3 | |
| WINDOW = 86400 | |
| usage = {} | |
| def quota_guard(fn): | |
| def wrapper(*args, request: gr.Request = None, **kwargs): | |
| session = request.session_hash if request else "global" | |
| now = time.time() | |
| count, start = usage.get(session, (0, now)) | |
| if now - start > WINDOW: | |
| count = 0 | |
| start = now | |
| if count >= LIMIT: | |
| raise gr.Error( | |
| "🚫 Demo limit reached.\n\n" | |
| "You can unlock only 3 times per day.\n" | |
| "Please try again after 24 hours." | |
| ) | |
| usage[session] = (count + 1, start) | |
| return fn(*args, request=request, **kwargs) | |
| return wrapper | |
| # ====================================================== | |
| # CONFIG | |
| # ====================================================== | |
| APP_PASSWORD = os.getenv("APP_PASSWORD") | |
| if not APP_PASSWORD: | |
| raise RuntimeError("APP_PASSWORD environment variable not set") | |
| # PRO CONTENT | |
| PRO_DATASET = "rahul7star/Wan-video" | |
| # FREE PREVIEW (MODEL REPO) | |
| FREE_VIDEO_REPO = "rahul7star/ohamlab" | |
| FREE_VIDEO_FOLDER = "showcase/video" | |
| MAX_FREE_VIDEOS = 5 | |
| # ====================================================== | |
| # LOAD FREE VIDEOS (MODEL REPO) | |
| # ====================================================== | |
| def load_free_videos(): | |
| local_dir = snapshot_download( | |
| repo_id=FREE_VIDEO_REPO, | |
| repo_type="model", | |
| allow_patterns=["showcase/video/*"], | |
| local_dir=tempfile.mkdtemp(), | |
| local_dir_use_symlinks=False, | |
| ) | |
| video_dir = os.path.join(local_dir, FREE_VIDEO_FOLDER) | |
| if not os.path.isdir(video_dir): | |
| print(f"[WARN] Free video folder not found: {video_dir}") | |
| return [] | |
| videos = [ | |
| os.path.join(video_dir, f) | |
| for f in os.listdir(video_dir) | |
| if f.lower().endswith((".mp4", ".webm", ".mov")) | |
| ] | |
| print(f"[INFO] Loaded free videos: {videos}") | |
| return videos | |
| FREE_VIDEOS = load_free_videos() | |
| def pick_free_videos(max_count=MAX_FREE_VIDEOS): | |
| if not FREE_VIDEOS: | |
| return [] | |
| if len(FREE_VIDEOS) >= max_count: | |
| return random.sample(FREE_VIDEOS, max_count) | |
| # Repeat if fewer than max_count | |
| result = [] | |
| while len(result) < max_count: | |
| result.extend(FREE_VIDEOS) | |
| return result[:max_count] | |
| # ====================================================== | |
| # LOAD PRO DATASET | |
| # ====================================================== | |
| dataset = load_dataset(PRO_DATASET, split="test") | |
| df = dataset.to_pandas()[["video", "text", "date"]].dropna().reset_index(drop=True) | |
| # ====================================================== | |
| # PAGINATION | |
| # ====================================================== | |
| def render_grid(page, page_size): | |
| page = int(page) | |
| page_size = int(page_size) | |
| total_pages = max(1, math.ceil(len(df) / page_size)) | |
| page = max(0, min(page, total_pages - 1)) | |
| batch = df.iloc[page * page_size:(page + 1) * page_size] | |
| cards = [] | |
| for _, row in batch.iterrows(): | |
| cards.append(f""" | |
| <div class="card"> | |
| <video src="{row['video']}" controls preload="metadata"></video> | |
| <div class="meta"> | |
| <div class="date">{row['date']}</div> | |
| <div class="caption">{row['text']}</div> | |
| </div> | |
| </div> | |
| """) | |
| return f"<div class='grid'>{''.join(cards)}</div>", page | |
| def next_page(page, page_size): | |
| return render_grid(page + 1, page_size) | |
| def prev_page(page, page_size): | |
| return render_grid(page - 1, page_size) | |
| def reset_page(page_size): | |
| return render_grid(0, page_size) | |
| # ====================================================== | |
| # AUTH | |
| # ====================================================== | |
| def check_password(user_password, request: gr.Request): | |
| if user_password == APP_PASSWORD: | |
| html, page = render_grid(0, 5) | |
| return ( | |
| gr.update(visible=False), # login | |
| gr.update(visible=False), # free preview | |
| gr.update(visible=True), # pro content | |
| html, | |
| page, | |
| "✅ Access granted" | |
| ) | |
| return ( | |
| gr.update(visible=True), | |
| gr.update(visible=True), | |
| gr.update(visible=False), | |
| "", | |
| 0, | |
| "❌ Incorrect password" | |
| ) | |
| # ====================================================== | |
| # CSS | |
| # ====================================================== | |
| css = """ | |
| .grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 18px; | |
| } | |
| .card { | |
| background: #0b1220; | |
| border-radius: 14px; | |
| padding: 12px; | |
| } | |
| .card video { | |
| width: 100%; | |
| border-radius: 12px; | |
| } | |
| footer, .gradio-footer { | |
| display: none !important; | |
| } | |
| #ohamlab-footer { | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| width: 100%; | |
| text-align: center; | |
| padding: 8px; | |
| font-size: 12px; | |
| background: #f8f9fb; | |
| color: #555; | |
| border-top: 1px solid #e5e7eb; | |
| } | |
| """ | |
| # ====================================================== | |
| # UI | |
| # ====================================================== | |
| with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo: | |
| gr.Markdown("# 🔐 OhamLab Video Showcase- For PRO Users 18+ only unlock") | |
| # -------- LOGIN -------- | |
| with gr.Column(visible=True) as login_box: | |
| password_input = gr.Textbox(type="password", label="Password") | |
| login_btn = gr.Button("Unlock") | |
| login_status = gr.Markdown() | |
| # -------- FREE PREVIEW -------- | |
| with gr.Column(visible=True) as free_preview: | |
| gr.Markdown("### 🎬 Free Preview") | |
| free_videos = pick_free_videos() | |
| with gr.Row(): | |
| for v in free_videos: | |
| gr.Video(v) | |
| # -------- PRO CONTENT -------- | |
| with gr.Column(visible=False) as app_content: | |
| with gr.Row(): | |
| page_size = gr.Dropdown([1, 5, 10], value=5) | |
| page_state = gr.State(0) | |
| gallery = gr.HTML() | |
| with gr.Row(): | |
| prev_btn = gr.Button("⬅ Previous") | |
| next_btn = gr.Button("Next ➡") | |
| prev_btn.click(prev_page, [page_state, page_size], [gallery, page_state]) | |
| next_btn.click(next_page, [page_state, page_size], [gallery, page_state]) | |
| page_size.change(reset_page, [page_size], [gallery, page_state]) | |
| # -------- EVENTS -------- | |
| login_btn.click( | |
| check_password, | |
| inputs=password_input, | |
| outputs=[ | |
| login_box, | |
| free_preview, | |
| app_content, | |
| gallery, | |
| page_state, | |
| login_status, | |
| ], | |
| ) | |
| # -------- FOOTER -------- | |
| gr.HTML("<div id='ohamlab-footer'>© OhamLab Copyright</div>") | |
| demo.launch() | |