rahul7star commited on
Commit
38052bd
·
verified ·
1 Parent(s): c49de18

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +186 -116
app.py CHANGED
@@ -1,172 +1,242 @@
1
  import os
2
  import math
3
  import time
 
4
  import tempfile
5
- from datetime import datetime, timedelta
6
-
7
  import gradio as gr
8
  from huggingface_hub import HfApi, hf_hub_download
9
- from PIL import Image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
  # ======================================================
12
  # CONFIG
13
  # ======================================================
14
- REPO_ID = "rahul7star/WAN22-Feb-2026"
15
- IMAGE_EXTS = (".png", ".jpg", ".jpeg", ".webp")
 
16
 
17
- PAGE_SIZE = 6
18
- TMP_DIR = tempfile.mkdtemp()
 
19
 
20
  api = HfApi()
21
 
 
22
  # ======================================================
23
- # GLOBAL INDEX (FAST, BUILT ONCE)
24
  # ======================================================
25
- FILE_INDEX: dict[str, list[str]] = {}
 
 
26
 
 
 
 
 
 
27
 
28
- def build_index():
29
- """
30
- Build an in-memory index:
31
- {
32
- "2026-02-03": [
33
- "2026-02-03/Upload-xxx/image.png",
34
- ...
35
- ]
36
- }
37
- """
38
- if FILE_INDEX:
39
- return
40
 
41
- print("📦 Indexing HuggingFace repo once…")
42
- files = api.list_repo_files(repo_id=REPO_ID)
43
-
44
- for f in files:
45
- if not f.lower().endswith(IMAGE_EXTS):
46
- continue
47
 
48
- parts = f.split("/")
49
- if len(parts) < 3:
50
- continue # must be date/Upload-xxx/image
 
 
 
51
 
52
- date_folder = parts[0]
53
- FILE_INDEX.setdefault(date_folder, []).append(f)
54
 
55
- # stable ordering
56
- for k in FILE_INDEX:
57
- FILE_INDEX[k].sort()
58
 
59
- print(f"✅ Indexed {sum(len(v) for v in FILE_INDEX.values())} images")
60
 
61
 
62
  # ======================================================
63
- # DATE HELPERS
64
  # ======================================================
65
- def last_20_days_available():
66
- today = datetime.utcnow().date()
67
- dates = []
68
 
69
- for i in range(20):
70
- d = (today - timedelta(days=i)).isoformat()
71
- if d in FILE_INDEX:
72
- dates.append(d)
73
 
74
- return dates
 
 
 
 
 
 
 
 
 
75
 
76
 
77
  # ======================================================
78
- # IMAGE LOADING (PAGINATED)
79
  # ======================================================
80
- def load_page(date: str, page: int):
81
- images = FILE_INDEX.get(date, [])
82
- total_pages = max(1, math.ceil(len(images) / PAGE_SIZE))
83
 
84
- page = max(0, min(page, total_pages - 1))
85
- start = page * PAGE_SIZE
86
- end = start + PAGE_SIZE
87
 
88
- gallery = []
89
- for path in images[start:end]:
90
- local = hf_hub_download(
91
- repo_id=REPO_ID,
92
- filename=path,
93
- local_dir=TMP_DIR,
94
- local_dir_use_symlinks=False,
95
- )
96
- gallery.append(Image.open(local))
97
 
98
- return (
99
- gallery,
100
- page,
101
- page > 0,
102
- end < len(images),
103
- f"Page {page + 1} / {total_pages}",
104
- )
105
 
106
 
107
- def on_date_change(date):
108
- return load_page(date, 0)
109
 
 
 
110
 
111
- def next_page(date, page):
112
- return load_page(date, page + 1)
113
 
114
 
115
- def prev_page(date, page):
116
- return load_page(date, page - 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
 
119
  # ======================================================
120
- # UI
121
  # ======================================================
122
- def create_app(dates):
123
- with gr.Blocks() as demo:
124
- gr.Markdown("## 📅 OhamLab Daily Image Browser")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
- with gr.Row():
127
- date_dd = gr.Dropdown(
128
- choices=dates,
129
- value=dates[0] if dates else None,
130
- label="Select date (last 20 days)",
131
- )
132
 
133
- gallery = gr.Gallery(columns=3, height="auto")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  page_state = gr.State(0)
135
- page_info = gr.Markdown()
 
 
136
 
137
  with gr.Row():
138
- prev_btn = gr.Button("⬅ Previous", interactive=False)
139
- next_btn = gr.Button("Next ➡", interactive=False)
140
-
141
- # Events
142
- date_dd.change(
143
- on_date_change,
144
- date_dd,
145
- [gallery, page_state, prev_btn, next_btn, page_info],
146
- )
147
 
148
- next_btn.click(
149
- next_page,
150
- [date_dd, page_state],
151
- [gallery, page_state, prev_btn, next_btn, page_info],
152
- )
153
 
154
- prev_btn.click(
155
- prev_page,
156
- [date_dd, page_state],
157
- [gallery, page_state, prev_btn, next_btn, page_info],
158
- )
159
-
160
- return demo
161
 
 
162
 
163
- # ======================================================
164
- # ENTRY POINT (IMPORTANT FOR PYTHON 3.10)
165
- # ======================================================
166
- if __name__ == "__main__":
167
- build_index()
168
- available_dates = last_20_days_available()
169
 
170
- app = create_app(available_dates)
171
- app.launch()
172
-
 
1
  import os
2
  import math
3
  import time
4
+ import random
5
  import tempfile
 
 
6
  import gradio as gr
7
  from huggingface_hub import HfApi, hf_hub_download
8
+
9
+ # ======================================================
10
+ # QUOTA CONFIG
11
+ # ======================================================
12
+ LIMIT = int(os.getenv("APP_DAILY_LIMIT", "3"))
13
+ WINDOW = 86400
14
+ usage = {}
15
+
16
+ def quota_guard(fn):
17
+ def wrapper(*args, **kwargs):
18
+ request: gr.Request | None = kwargs.get("request")
19
+ session = request.session_hash if request else "global"
20
+ now = time.time()
21
+
22
+ count, start = usage.get(session, (0, now))
23
+ if now - start > WINDOW:
24
+ count, start = 0, now
25
+
26
+ if count >= LIMIT:
27
+ raise gr.Error(
28
+ f"🚫 Daily demo limit reached.\n\n"
29
+ f"Max {LIMIT} unlocks per day.\n"
30
+ f"Please try again after 24 hours."
31
+ )
32
+
33
+ usage[session] = (count + 1, start)
34
+ return fn(*args)
35
+ return wrapper
36
+
37
 
38
  # ======================================================
39
  # CONFIG
40
  # ======================================================
41
+ REPO_ID = "rahul7star/ohamlab"
42
+ FREE_REPO = "rahul7star/ohamlab"
43
+ FREE_IMAGE_DIR = "showcase/image"
44
 
45
+ APP_PASSWORD = os.getenv("APP_PASSWORD")
46
+ if not APP_PASSWORD:
47
+ raise RuntimeError("APP_PASSWORD env var not set")
48
 
49
  api = HfApi()
50
 
51
+
52
  # ======================================================
53
+ # FREE IMAGE PREVIEW
54
  # ======================================================
55
+ def load_free_images():
56
+ tmp = tempfile.mkdtemp()
57
+ files = api.list_repo_files(FREE_REPO)
58
 
59
+ images = [
60
+ f for f in files
61
+ if f.startswith(FREE_IMAGE_DIR + "/")
62
+ and f.lower().endswith((".png", ".jpg", ".jpeg", ".webp"))
63
+ ]
64
 
65
+ if not images:
66
+ return []
 
 
 
 
 
 
 
 
 
 
67
 
68
+ random.shuffle(images)
69
+ picked = (images * 5)[:5] if len(images) < 5 else images[:5]
 
 
 
 
70
 
71
+ local = []
72
+ for img in picked:
73
+ try:
74
+ local.append(hf_hub_download(FREE_REPO, img, local_dir=tmp))
75
+ except Exception:
76
+ pass
77
 
78
+ return local
 
79
 
 
 
 
80
 
81
+ FREE_IMAGES = load_free_images()
82
 
83
 
84
  # ======================================================
85
+ # PRO HELPERS
86
  # ======================================================
87
+ def list_date_folders():
88
+ files = api.list_repo_files(REPO_ID)
89
+ return sorted({f.split("/")[0] for f in files if "/" in f})
90
 
 
 
 
 
91
 
92
+ def load_images_for_date(date_folder):
93
+ files = api.list_repo_files(REPO_ID)
94
+ items = []
95
+
96
+ for f in files:
97
+ if f.startswith(date_folder + "/") and f.lower().endswith((".png", ".jpg", ".jpeg", ".webp")):
98
+ url = f"https://huggingface.co/{REPO_ID}/resolve/main/{f}"
99
+ items.append(url)
100
+
101
+ return items
102
 
103
 
104
  # ======================================================
105
+ # PAGINATION
106
  # ======================================================
107
+ def render_grid(date_folder, page, page_size):
108
+ data = load_images_for_date(date_folder)
109
+ total_pages = max(1, math.ceil(len(data) / page_size))
110
 
111
+ page = max(0, min(int(page), total_pages - 1))
112
+ start, end = page * page_size, (page + 1) * page_size
 
113
 
114
+ cards = [
115
+ f"<div class='card'><img src='{img}'></div>"
116
+ for img in data[start:end]
117
+ ]
 
 
 
 
 
118
 
119
+ return f"""
120
+ <div class="grid">{''.join(cards)}</div>
121
+ <div class="page-info">Page {page+1} / {total_pages}</div>
122
+ """, page
 
 
 
123
 
124
 
125
+ def next_page(date, page, size):
126
+ return render_grid(date, page + 1, size)
127
 
128
+ def prev_page(date, page, size):
129
+ return render_grid(date, page - 1, size)
130
 
131
+ def reset_page(date, size):
132
+ return render_grid(date, 0, size)
133
 
134
 
135
+ # ======================================================
136
+ # AUTH
137
+ # ======================================================
138
+ @quota_guard
139
+ def check_password(pwd):
140
+ if pwd != APP_PASSWORD:
141
+ return (
142
+ gr.update(visible=True),
143
+ gr.update(visible=False),
144
+ gr.update(visible=True),
145
+ "",
146
+ 0,
147
+ "❌ Wrong password",
148
+ latest
149
+ )
150
+
151
+ dates = list_date_folders()
152
+ latest = dates[-1]
153
+ html, page = render_grid(latest, 0, 6)
154
+
155
+ return (
156
+ gr.update(visible=False),
157
+ gr.update(visible=True),
158
+ gr.update(visible=False),
159
+ html,
160
+ page,
161
+ "✅ Access granted",
162
+ latest
163
+ )
164
 
165
 
166
  # ======================================================
167
+ # CSS
168
  # ======================================================
169
+ css = """
170
+ .grid {
171
+ display:grid;
172
+ grid-template-columns:repeat(auto-fill,minmax(220px,1fr));
173
+ gap:16px;
174
+ }
175
+ .card {
176
+ background:#0b1220;
177
+ padding:10px;
178
+ border-radius:14px;
179
+ }
180
+ .card img {
181
+ width:100%;
182
+ border-radius:10px;
183
+ }
184
+
185
+ footer, .gradio-footer { display:none!important; }
186
+
187
+ #ohamlab-footer {
188
+ position:fixed;
189
+ bottom:0;
190
+ width:100%;
191
+ background:#f8f9fb;
192
+ font-size:12px;
193
+ padding:8px;
194
+ border-top:1px solid #e5e7eb;
195
+ text-align:center;
196
+ }
197
+ """
198
 
 
 
 
 
 
 
199
 
200
+ # ======================================================
201
+ # UI
202
+ # ======================================================
203
+ with gr.Blocks(theme=gr.themes.Soft(), css=css) as demo:
204
+ gr.Markdown("# 🔐 OhamLab Image Showcase- For PRO Users 18+ only unlock")
205
+
206
+ # ---------- LOGIN ----------
207
+ with gr.Column(visible=True) as login_box:
208
+ pwd = gr.Textbox(type="password", label="Password")
209
+ login_btn = gr.Button("Unlock")
210
+ status = gr.Markdown()
211
+
212
+ with gr.Column(visible=True) as free_preview:
213
+ gr.Markdown("### 🎁 Free Image Preview")
214
+ with gr.Row():
215
+ for img in FREE_IMAGES:
216
+ gr.Image(img, show_label=False)
217
+
218
+ # ---------- PRO ----------
219
+ with gr.Column(visible=False) as app:
220
+ current_date = gr.State("")
221
  page_state = gr.State(0)
222
+ page_size = gr.State(6)
223
+
224
+ gallery = gr.HTML()
225
 
226
  with gr.Row():
227
+ prev_btn = gr.Button("⬅ Previous")
228
+ next_btn = gr.Button("Next ➡")
 
 
 
 
 
 
 
229
 
230
+ prev_btn.click(prev_page, [current_date, page_state, page_size], [gallery, page_state])
231
+ next_btn.click(next_page, [current_date, page_state, page_size], [gallery, page_state])
 
 
 
232
 
233
+ login_btn.click(
234
+ check_password,
235
+ inputs=pwd,
236
+ outputs=[login_box, app, free_preview, gallery, page_state, status, current_date]
237
+ )
 
 
238
 
239
+ gr.HTML("<div id='ohamlab-footer'>© OhamLab Copyright</div>")
240
 
 
 
 
 
 
 
241
 
242
+ demo.launch()