rahul7star's picture
Update app.py
7a6085d verified
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
# ======================================================
@quota_guard
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()