Spaces:
Running
Running
File size: 7,032 Bytes
ce9d458 e4f3113 2c9f7a9 feaf0e8 be45aa3 6bd2d6f d08ffde 86a8e06 33779ec be45aa3 d08ffde 2c9f7a9 6eb9546 2c9f7a9 6eb9546 f4c5627 be45aa3 e34f78d 88bbc50 e34f78d 88bbc50 2c9f7a9 e34f78d 6eb9546 2c9f7a9 88bbc50 6eb9546 88bbc50 e4f3113 86a8e06 e4f3113 ce9d458 6bd2d6f be45aa3 6bd2d6f be45aa3 0300e23 6bd2d6f be45aa3 e34f78d feaf0e8 0300e23 feaf0e8 be45aa3 0300e23 be45aa3 6bd2d6f be45aa3 feaf0e8 be45aa3 6bd2d6f be45aa3 feaf0e8 f4c5627 be45aa3 feaf0e8 be45aa3 6bd2d6f be45aa3 0300e23 be45aa3 6bd2d6f be45aa3 feaf0e8 e4f3113 be45aa3 e4f3113 be45aa3 f4c5627 86a8e06 e34f78d e4f3113 f4c5627 e4f3113 86a8e06 f4c5627 86a8e06 f4c5627 86a8e06 0300e23 86a8e06 f4c5627 86a8e06 f4c5627 86a8e06 e34f78d ce9d458 f4c5627 ce9d458 88bbc50 e34f78d ce9d458 0300e23 ce9d458 be45aa3 ce9d458 e34f78d 0300e23 6957f64 0300e23 7a6085d ce9d458 0300e23 ce9d458 6eb9546 6957f64 876a2ff 0300e23 feaf0e8 be45aa3 6bd2d6f be45aa3 e6779ec 0300e23 f4c5627 0300e23 ce9d458 86a8e06 0300e23 ce9d458 feaf0e8 56ede89 d08ffde 0300e23 d08ffde |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
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()
|