Bl4ckSpaces commited on
Commit
66f9d4b
·
verified ·
1 Parent(s): 3757e16

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +151 -127
app.py CHANGED
@@ -6,124 +6,192 @@ import random
6
  import time
7
  import threading
8
  import os
 
 
9
  from datetime import datetime, date
 
 
10
 
11
  # --- 1. CONFIGURATION ---
12
 
13
- # DATABASE (JSONBIN)
14
- JSONBIN_ID = "6962ebfe43b1c97be927b07d"
15
- JSONBIN_KEY = "$2a$10$khoKkhYEAUCG.O0xHDHiY.Ei88KlSV1l3olI2pxc86mUSsTaNpJx6"
16
- JSONBIN_URL = f"https://api.jsonbin.io/v3/b/{JSONBIN_ID}"
17
 
18
- # TARGET GPU (ALEXNASA TURBO - STABIL)
 
19
  GPU_SPACE_URL = "https://alexnasa-ltx-2-turbo.hf.space"
20
 
21
- # TOKEN GENERATOR (27 TOKENS)
22
  GENERATION_TOKENS = [
23
- # BATCH 1
24
  "hf_" + "PiRCDDtPcPFMLWkTkVaZmzoleHOunXnLIA", "hf_" + "BHvZXGICstaktSwycmwNmzHGrTNmKxnlRZ",
25
  "hf_" + "ZdgawyTPzXIpwhnRYIteUKSMsWnEDtGKtM", "hf_" + "nMiFYAFsINxAJWPwiCQlaunmdgmrcxKoaT",
26
  "hf_" + "PccpUIbTckCiafwErDLkRlsvqhgtfZaBHL", "hf_" + "faGyXBPfBkaHXDMUSJtxEggonhhZbomFIz",
27
  "hf_" + "SndsPaRWsevDXCgZcSjTUlBYUJqOkSfFmn", "hf_" + "CqobFdUpeVCeuhUaiuXwvdczBUmoUHXRGa",
28
  "hf_" + "JKCQYUhhHPPkpucegqkNSyureLdXpmeXRF", "hf_" + "tBYfslUwHNiNMufzwAYIlrDVovEWmOQulC",
29
  "hf_" + "LKLdrdUxyUyKODSUthmqHXqDMfHrQueera", "hf_" + "ivSBboJYQVcifWkCNcOTOnxUQrZOtOglnU",
30
- # BATCH 2
31
  "hf_" + "jiSbBMUmAniRpJOmVIlczuqpRjwSeuizLk", "hf_" + "VcXaKQLEawBWZbNrBOSLTjrVtTuSvobhLL",
32
  "hf_" + "ZrlTPvhDmYqZGGFuIqDDCrQRcWRhYcuyOI", "hf_" + "FCambosUqUQJrThbIveHglnvjoNpOGWBsW",
33
  "hf_" + "kUyoiWTbZlNfSrdTNaVINuwlNTQseFCfZB", "hf_" + "WGarKlgPBzpJeKxpqirFgnKKAtOFBFomSe",
34
  "hf_" + "IZwzmRBCALYfvYtmtvTWsIQYvHuRGUiGyr",
35
- # BATCH 3
36
  "hf_" + "NtijfwwAPQRknELkhIWjMQQUUqzgwhIjeu", "hf_" + "obVKYRMqECBoLsBWOKyfVWtHlugAhhuaIH",
37
  "hf_" + "EsDAvVqRZCbigQrpDFNinlVeijagnAjETW", "hf_" + "yuMifxRJoXWKPRGgYFrXHXTGdoKBuCZCUU",
38
  "hf_" + "YthKrdEtrmyDbBteZcGzNeoDqGAxzeEinv", "hf_" + "JgNjfcunLsOBcZIaOYcFqgcZIZWjbnocJn",
39
  "hf_" + "cINBgwvihyKiTpxwDTXjnHTnlQivLCluGJ", "hf_" + "jnciPeeWUwQbHNITBRtOgPjnqWkgAqZDhq"
40
  ]
41
 
42
- # RAM CACHE (Agar Database Cepat & Tidak Error)
43
  CACHED_DB = {"users": {}}
44
 
45
- # --- 2. HELPERS (CATBOX & DATABASE) ---
46
 
47
- def upload_to_catbox(file_path):
48
- """Upload ke Catbox.moe (Pihak Ketiga)"""
49
  try:
50
- url = "https://catbox.moe/user/api.php"
51
- data = {"reqtype": "fileupload"}
52
- with open(file_path, "rb") as f:
53
- files = {"fileToUpload": f}
54
- response = requests.post(url, data=data, files=files, timeout=30)
55
- if response.status_code == 200:
56
- print(f"✅ Uploaded to Catbox: {response.text}")
57
- return response.text
58
- return None
59
- except Exception as e:
60
- print(f"❌ Upload Error: {e}")
61
- return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
  def load_db():
64
- """Load DB dari JSONBin ke RAM saat startup"""
65
  global CACHED_DB
66
- headers = {"X-Master-Key": JSONBIN_KEY}
67
  try:
68
- print("🔄 Loading Database from JSONBin...")
69
- req = requests.get(JSONBIN_URL, headers=headers, timeout=10)
70
- data = req.json().get('record', {})
71
- if "users" not in data: data["users"] = {}
72
- CACHED_DB = data
73
- print("✅ Database Loaded to RAM!")
74
- except Exception as e:
75
- print(f"❌ DB Load Failed (Using Empty RAM): {e}")
76
- CACHED_DB = {"users": {}}
77
 
78
  def sync_db_background():
79
- """Simpan RAM ke JSONBin di Background (Anti-Lag)"""
80
  def task():
81
- headers = {"Content-Type": "application/json", "X-Master-Key": JSONBIN_KEY}
82
  try:
83
- requests.put(JSONBIN_URL, json=CACHED_DB, headers=headers, timeout=10)
84
- print("💾 Database Synced to Cloud")
85
- except Exception as e:
86
- print(f"⚠️ Cloud Sync Failed: {e}")
87
-
88
  threading.Thread(target=task).start()
89
 
90
  def save_db_ram(data):
91
- """Update RAM dan Trigger Sync"""
92
  global CACHED_DB
93
  CACHED_DB = data
94
  sync_db_background()
95
  return True
96
 
97
- # Load DB saat server nyala
98
  load_db()
99
 
100
- # --- 3. SERVER LOGIC ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  def auth_user(action, username, password, email):
103
  try:
104
- db = CACHED_DB # Baca dari RAM
105
  today_str = str(date.today())
106
 
107
  if not username or not password: return {"status": "error", "msg": "Input required."}
108
  is_admin = (username == "C0LA21")
109
 
110
  if action == "signup":
111
- if not email or "@" not in email: return {"status": "error", "msg": "Invalid Email."}
112
- if username in db["users"]: return {"status": "error", "msg": "Username taken."}
113
 
114
- # Cek Email Unik
 
 
 
 
 
 
115
  for user, data in db["users"].items():
116
- if data.get("email") == email:
117
- return {"status": "error", "msg": "Email registered."}
118
 
119
  start_credits = 999999 if is_admin else 5
120
-
121
  db["users"][username] = {
122
- "password": password,
123
- "email": email,
124
- "credits": start_credits,
125
- "last_restock": today_str,
126
- "gallery": []
127
  }
128
  save_db_ram(db)
129
  return {"status": "success", "msg": "Account Created!", "credits": start_credits}
@@ -133,43 +201,31 @@ def auth_user(action, username, password, email):
133
  user_data = db["users"][username]
134
  if str(user_data.get("password")) != str(password): return {"status": "error", "msg": "Wrong password."}
135
 
136
- # Restock Logic
137
  if user_data.get("last_restock") != today_str:
138
  user_data["credits"] = 999999 if is_admin else 5
139
  user_data["last_restock"] = today_str
140
  save_db_ram(db)
141
 
142
  if is_admin: user_data["credits"] = 999999
143
-
144
- # Return Gallery agar muncul di Frontend
145
- user_gallery = user_data.get("gallery", [])
146
- return {
147
- "status": "success",
148
- "msg": "Login OK.",
149
- "credits": user_data["credits"],
150
- "gallery": user_gallery
151
- }
152
 
153
  return {"status": "error", "msg": "Error."}
154
- except Exception as e:
155
- print(f"Auth Error: {e}")
156
- return {"status": "error", "msg": "Server Error."}
157
 
158
  def process_generation(username, password, prompt, neg_prompt, input_image, width, height, guidance, steps):
159
  print(f"🎬 Processing: {username}")
160
  try:
161
- db = CACHED_DB # Baca dari RAM
162
 
163
- # 1. AUTH CHECK
164
  if username not in db["users"]: return None, "Relogin required."
165
- user_data = db["users"][username]
166
- if str(user_data.get("password")) != str(password): return None, "Auth failed."
167
 
168
  is_admin = (username == "C0LA21")
169
- if not is_admin and user_data["credits"] <= 0:
170
- return None, "No credits left."
 
 
171
 
172
- # 2. GENERATE VIDEO (Alexnasa Logic)
173
  video_path = None
174
  last_error = ""
175
  session_tokens = GENERATION_TOKENS.copy()
@@ -177,82 +233,50 @@ def process_generation(username, password, prompt, neg_prompt, input_image, widt
177
 
178
  for i, current_token in enumerate(session_tokens):
179
  try:
180
- print(f"🚀 Attempt {i+1} using token ...{current_token[-4:]}")
181
  client_gpu = Client(GPU_SPACE_URL, headers={"Authorization": f"Bearer {current_token}"})
182
-
183
- # PARAMETER FIX ALEXNASA (4.0s)
184
  result = client_gpu.predict(
185
- input_image=input_image,
186
- prompt=prompt,
187
- duration=4.0, # 4 Detik (Hemat Token)
188
- enhance_prompt=True,
189
- seed=random.randint(0, 999999),
190
- randomize_seed=True,
191
- height=int(height),
192
- width=int(width),
193
- camera_lora="No LoRA", # Wajib di Alexnasa
194
- api_name="/generate_video" # API Wajib Alexnasa
195
  )
196
-
197
  if isinstance(result, (list, tuple)): video_path = result[0]
198
  else: video_path = result
199
-
200
  if video_path: break
201
-
202
  except Exception as e:
203
- err_msg = str(e)
204
- if "quota" in err_msg.lower(): print(f"⚠️ Token {i+1} Limit")
205
- else: print(f"⚠️ Token {i+1} Error: {err_msg[:30]}")
206
- last_error = err_msg
207
  continue
208
 
209
  if not video_path:
210
- return None, f"All Servers Busy (Quota Limit). Try later. Err: {last_error[:20]}"
211
 
212
- # 3. UPLOAD KE CATBOX (Pihak Ketiga)
213
- print("☁️ Uploading to Catbox...")
214
  video_url = upload_to_catbox(video_path)
215
 
216
  if video_url:
217
- # 4. SIMPAN HISTORY KE RAM & SYNC JSONBIN
218
- gallery_item = {
219
- "url": video_url,
220
- "prompt": prompt[:60] + "...",
221
- "date": str(datetime.now().strftime("%Y-%m-%d")),
222
- "type": "video"
223
- }
224
-
225
- # Init list jika belum ada
226
- if "gallery" not in db["users"][username]:
227
- db["users"][username]["gallery"] = []
228
-
229
  db["users"][username]["gallery"].insert(0, gallery_item)
230
- # Limit 15 item agar JSONBin tidak penuh
231
- db["users"][username]["gallery"] = db["users"][username]["gallery"][:15]
232
-
233
- if not is_admin:
234
- db["users"][username]["credits"] -= 1
235
-
236
- save_db_ram(db) # Sync Background
237
 
 
 
238
  return video_path, f"Success! Credits: {db['users'][username]['credits']}"
239
  else:
240
- return video_path, "Generated but Catbox Upload Failed."
241
 
242
  except Exception as e:
243
- print(f"❌ System Error: {e}")
244
- return None, f"System Error: {e}"
245
 
246
  def ping_server(username=None):
247
- # Dummy online counter karena kita balik ke single server
248
- return {"status": "alive", "online": random.randint(3, 8), "msg": "Soda is fizzy!"}
249
 
250
- # --- 4. UI ---
251
  with gr.Blocks() as app:
252
  action = gr.Textbox(); user = gr.Textbox(); pw = gr.Textbox(); email = gr.Textbox()
253
  p = gr.Textbox(); np = gr.Textbox(); img_in = gr.Image(type="filepath")
254
  w = gr.Number(); h = gr.Number(); g = gr.Number(); s = gr.Number()
255
-
256
  out_json = gr.JSON()
257
  out_vid = gr.Video()
258
  out_txt = gr.Textbox()
 
6
  import time
7
  import threading
8
  import os
9
+ import re
10
+ import dns.resolver # Library DNS untuk cek domain asli
11
  from datetime import datetime, date
12
+ from huggingface_hub import HfApi, hf_hub_download
13
+ from PIL import Image
14
 
15
  # --- 1. CONFIGURATION ---
16
 
17
+ # DATASET DATABASE
18
+ DATASET_REPO_ID = "Bl4ckSpaces/soda-data"
19
+ DATABASE_FILENAME = "soda_users.json"
 
20
 
21
+ # TOKEN
22
+ STORAGE_TOKEN = "hf_" + "gcQpArWmJAlvIapWLNsJOWUvmbkkVCktgV"
23
  GPU_SPACE_URL = "https://alexnasa-ltx-2-turbo.hf.space"
24
 
25
+ # GENERATION TOKENS (27 TOKENS)
26
  GENERATION_TOKENS = [
 
27
  "hf_" + "PiRCDDtPcPFMLWkTkVaZmzoleHOunXnLIA", "hf_" + "BHvZXGICstaktSwycmwNmzHGrTNmKxnlRZ",
28
  "hf_" + "ZdgawyTPzXIpwhnRYIteUKSMsWnEDtGKtM", "hf_" + "nMiFYAFsINxAJWPwiCQlaunmdgmrcxKoaT",
29
  "hf_" + "PccpUIbTckCiafwErDLkRlsvqhgtfZaBHL", "hf_" + "faGyXBPfBkaHXDMUSJtxEggonhhZbomFIz",
30
  "hf_" + "SndsPaRWsevDXCgZcSjTUlBYUJqOkSfFmn", "hf_" + "CqobFdUpeVCeuhUaiuXwvdczBUmoUHXRGa",
31
  "hf_" + "JKCQYUhhHPPkpucegqkNSyureLdXpmeXRF", "hf_" + "tBYfslUwHNiNMufzwAYIlrDVovEWmOQulC",
32
  "hf_" + "LKLdrdUxyUyKODSUthmqHXqDMfHrQueera", "hf_" + "ivSBboJYQVcifWkCNcOTOnxUQrZOtOglnU",
 
33
  "hf_" + "jiSbBMUmAniRpJOmVIlczuqpRjwSeuizLk", "hf_" + "VcXaKQLEawBWZbNrBOSLTjrVtTuSvobhLL",
34
  "hf_" + "ZrlTPvhDmYqZGGFuIqDDCrQRcWRhYcuyOI", "hf_" + "FCambosUqUQJrThbIveHglnvjoNpOGWBsW",
35
  "hf_" + "kUyoiWTbZlNfSrdTNaVINuwlNTQseFCfZB", "hf_" + "WGarKlgPBzpJeKxpqirFgnKKAtOFBFomSe",
36
  "hf_" + "IZwzmRBCALYfvYtmtvTWsIQYvHuRGUiGyr",
 
37
  "hf_" + "NtijfwwAPQRknELkhIWjMQQUUqzgwhIjeu", "hf_" + "obVKYRMqECBoLsBWOKyfVWtHlugAhhuaIH",
38
  "hf_" + "EsDAvVqRZCbigQrpDFNinlVeijagnAjETW", "hf_" + "yuMifxRJoXWKPRGgYFrXHXTGdoKBuCZCUU",
39
  "hf_" + "YthKrdEtrmyDbBteZcGzNeoDqGAxzeEinv", "hf_" + "JgNjfcunLsOBcZIaOYcFqgcZIZWjbnocJn",
40
  "hf_" + "cINBgwvihyKiTpxwDTXjnHTnlQivLCluGJ", "hf_" + "jnciPeeWUwQbHNITBRtOgPjnqWkgAqZDhq"
41
  ]
42
 
 
43
  CACHED_DB = {"users": {}}
44
 
45
+ # --- 2. ADVANCED SECURITY (MULTI-LAYER EMAIL CHECK) ---
46
 
47
+ def check_dns_mx(domain):
48
+ """Cek apakah domain punya server email beneran (MX Record)"""
49
  try:
50
+ dns.resolver.resolve(domain, 'MX')
51
+ return True
52
+ except:
53
+ return False
54
+
55
+ def validate_email_multilayer(email):
56
+ """
57
+ Sistem Validasi Berlapis:
58
+ 1. Cek Format & Blacklist Domain
59
+ 2. Cek API 1 (MailCheck)
60
+ 3. Cek API 2 (Debounce)
61
+ 4. Cek API 3 (Eva)
62
+ 5. Fallback: Cek DNS MX Record Manual
63
+ """
64
+ print(f"🛡️ Security Scan: Checking {email}...")
65
+
66
+ # LAYER 1: Basic Regex & Common Blocklist
67
+ if not re.match(r"[^@]+@[^@]+\.[^@]+", email):
68
+ return False, "Invalid format."
69
+
70
+ domain = email.split('@')[1].lower()
71
+ blocked_domains = ["tempmail.com", "10minutemail.com", "yopmail.com", "throwawaymail.com"]
72
+ if domain in blocked_domains:
73
+ return False, "Disposable/Temp mail detected."
74
+
75
+ # LAYER 2: Multi-API Check (Round Robin)
76
+ # Kita coba satu per satu. Jika satu gagal/limit, lanjut ke berikutnya.
77
+
78
+ # API 1: MailCheck.ai (Cek Disposable)
79
+ try:
80
+ r = requests.get(f"https://api.mailcheck.ai/domain/{domain}", timeout=3)
81
+ if r.status_code == 200:
82
+ data = r.json()
83
+ if data.get('disposable'): return False, "Disposable domain detected (L1)."
84
+ except:
85
+ print("⚠️ API 1 (MailCheck) busy/failed, switching to backup...")
86
+
87
+ # API 2: Debounce.io (Cek Disposable)
88
+ try:
89
+ r = requests.get(f"https://disposable.debounce.io/?email={email}", timeout=3)
90
+ if r.status_code == 200:
91
+ data = r.json()
92
+ if data.get('disposable') == "true": return False, "Disposable domain detected (L2)."
93
+ except:
94
+ print("⚠️ API 2 (Debounce) busy/failed, switching to backup...")
95
+
96
+ # API 3: Eva PingUtil (Validasi Format & Domain)
97
+ try:
98
+ r = requests.get(f"https://api.eva.pingutil.com/email?email={email}", timeout=3)
99
+ if r.status_code == 200:
100
+ data = r.json()
101
+ if data.get('data', {}).get('disposable'): return False, "Disposable domain detected (L3)."
102
+ if not data.get('data', {}).get('deliverable'):
103
+ # Note: Deliverable false bisa berarti inbox penuh, tapi kita strict aja
104
+ # Kecuali Gmail/Yahoo kadang false positive, jadi kita skip block deliverable utk domain besar
105
+ if "gmail" not in domain and "yahoo" not in domain:
106
+ return False, "Email address looks undeliverable."
107
+ except:
108
+ print("⚠️ API 3 (Eva) busy/failed, switching to internal DNS...")
109
+
110
+ # LAYER 3: THE ULTIMATE FALLBACK (Internal DNS Check)
111
+ # Jika semua API di atas mati/limit, server kita cek sendiri ke internet.
112
+ if not check_dns_mx(domain):
113
+ return False, "Domain does not have a valid mail server."
114
+
115
+ print("✅ Security Scan Passed.")
116
+ return True, "Valid"
117
+
118
+ # --- 3. DATABASE SYSTEM ---
119
 
120
  def load_db():
 
121
  global CACHED_DB
122
+ print("🔄 Downloading DB...")
123
  try:
124
+ path = hf_hub_download(repo_id=DATASET_REPO_ID, filename=DATABASE_FILENAME, repo_type="dataset", token=STORAGE_TOKEN)
125
+ with open(path, 'r') as f: CACHED_DB = json.load(f)
126
+ print("✅ DB Loaded")
127
+ except: CACHED_DB = {"users": {}}
 
 
 
 
 
128
 
129
  def sync_db_background():
 
130
  def task():
 
131
  try:
132
+ with open(DATABASE_FILENAME, 'w') as f: json.dump(CACHED_DB, f, indent=2)
133
+ api = HfApi(token=STORAGE_TOKEN)
134
+ api.upload_file(path_or_fileobj=DATABASE_FILENAME, path_in_repo=DATABASE_FILENAME, repo_id=DATASET_REPO_ID, repo_type="dataset")
135
+ print("💾 Cloud Sync OK")
136
+ except: pass
137
  threading.Thread(target=task).start()
138
 
139
  def save_db_ram(data):
 
140
  global CACHED_DB
141
  CACHED_DB = data
142
  sync_db_background()
143
  return True
144
 
 
145
  load_db()
146
 
147
+ # --- 4. HELPER UPLOAD ---
148
+ def upload_to_catbox(file_path):
149
+ try:
150
+ url = "https://catbox.moe/user/api.php"
151
+ data = {"reqtype": "fileupload"}
152
+ with open(file_path, "rb") as f:
153
+ files = {"fileToUpload": f}
154
+ response = requests.post(url, data=data, files=files, timeout=45)
155
+ if response.status_code == 200: return response.text
156
+ return None
157
+ except: return None
158
+
159
+ def resize_image_for_video(image_path, width, height):
160
+ try:
161
+ print(f"🖼️ Resizing image to {width}x{height}...")
162
+ img = Image.open(image_path)
163
+ img = img.resize((int(width), int(height)), Image.LANCZOS)
164
+ img.save(image_path)
165
+ return image_path
166
+ except: return image_path
167
+
168
+ # --- 5. SERVER LOGIC ---
169
 
170
  def auth_user(action, username, password, email):
171
  try:
172
+ db = CACHED_DB
173
  today_str = str(date.today())
174
 
175
  if not username or not password: return {"status": "error", "msg": "Input required."}
176
  is_admin = (username == "C0LA21")
177
 
178
  if action == "signup":
179
+ if not email: return {"status": "error", "msg": "Email required."}
 
180
 
181
+ # --- SECURITY CHECK ---
182
+ is_valid, msg = validate_email_multilayer(email)
183
+ if not is_valid:
184
+ return {"status": "error", "msg": f"Security Block: {msg}"}
185
+ # ----------------------
186
+
187
+ if username in db["users"]: return {"status": "error", "msg": "Username taken."}
188
  for user, data in db["users"].items():
189
+ if data.get("email") == email: return {"status": "error", "msg": "Email registered."}
 
190
 
191
  start_credits = 999999 if is_admin else 5
 
192
  db["users"][username] = {
193
+ "password": password, "email": email,
194
+ "credits": start_credits, "last_restock": today_str, "gallery": []
 
 
 
195
  }
196
  save_db_ram(db)
197
  return {"status": "success", "msg": "Account Created!", "credits": start_credits}
 
201
  user_data = db["users"][username]
202
  if str(user_data.get("password")) != str(password): return {"status": "error", "msg": "Wrong password."}
203
 
 
204
  if user_data.get("last_restock") != today_str:
205
  user_data["credits"] = 999999 if is_admin else 5
206
  user_data["last_restock"] = today_str
207
  save_db_ram(db)
208
 
209
  if is_admin: user_data["credits"] = 999999
210
+ return {"status": "success", "msg": "Login OK.", "credits": user_data["credits"], "gallery": user_data.get("gallery", [])}
 
 
 
 
 
 
 
 
211
 
212
  return {"status": "error", "msg": "Error."}
213
+ except: return {"status": "error", "msg": "Server Error."}
 
 
214
 
215
  def process_generation(username, password, prompt, neg_prompt, input_image, width, height, guidance, steps):
216
  print(f"🎬 Processing: {username}")
217
  try:
218
+ db = CACHED_DB
219
 
 
220
  if username not in db["users"]: return None, "Relogin required."
221
+ if str(db["users"][username].get("password")) != str(password): return None, "Auth failed."
 
222
 
223
  is_admin = (username == "C0LA21")
224
+ if not is_admin and db["users"][username]["credits"] <= 0: return None, "No credits left."
225
+
226
+ if input_image:
227
+ input_image = resize_image_for_video(input_image, width, height)
228
 
 
229
  video_path = None
230
  last_error = ""
231
  session_tokens = GENERATION_TOKENS.copy()
 
233
 
234
  for i, current_token in enumerate(session_tokens):
235
  try:
236
+ print(f"🚀 Attempt {i+1}...")
237
  client_gpu = Client(GPU_SPACE_URL, headers={"Authorization": f"Bearer {current_token}"})
 
 
238
  result = client_gpu.predict(
239
+ input_image=input_image, prompt=prompt, duration=4.0, enhance_prompt=True,
240
+ seed=random.randint(0, 999999), randomize_seed=True,
241
+ height=int(height), width=int(width), camera_lora="No LoRA",
242
+ api_name="/generate_video"
 
 
 
 
 
 
243
  )
 
244
  if isinstance(result, (list, tuple)): video_path = result[0]
245
  else: video_path = result
 
246
  if video_path: break
 
247
  except Exception as e:
248
+ last_error = str(e)
 
 
 
249
  continue
250
 
251
  if not video_path:
252
+ return None, f"Servers Busy (Quota Limit). Try later. Err: {last_error[:20]}"
253
 
254
+ print("☁️ Uploading...")
 
255
  video_url = upload_to_catbox(video_path)
256
 
257
  if video_url:
258
+ gallery_item = {"url": video_url, "prompt": prompt[:60], "date": str(date.today()), "type": "video"}
259
+ if "gallery" not in db["users"][username]: db["users"][username]["gallery"] = []
 
 
 
 
 
 
 
 
 
 
260
  db["users"][username]["gallery"].insert(0, gallery_item)
261
+ db["users"][username]["gallery"] = db["users"][username]["gallery"][:20]
 
 
 
 
 
 
262
 
263
+ if not is_admin: db["users"][username]["credits"] -= 1
264
+ save_db_ram(db)
265
  return video_path, f"Success! Credits: {db['users'][username]['credits']}"
266
  else:
267
+ return video_path, "Generated but Upload Failed."
268
 
269
  except Exception as e:
270
+ print(f"❌ Critical: {e}")
271
+ return None, f"Failed: {e}"
272
 
273
  def ping_server(username=None):
274
+ return {"status": "alive", "msg": "Soda is fizzy!"}
 
275
 
 
276
  with gr.Blocks() as app:
277
  action = gr.Textbox(); user = gr.Textbox(); pw = gr.Textbox(); email = gr.Textbox()
278
  p = gr.Textbox(); np = gr.Textbox(); img_in = gr.Image(type="filepath")
279
  w = gr.Number(); h = gr.Number(); g = gr.Number(); s = gr.Number()
 
280
  out_json = gr.JSON()
281
  out_vid = gr.Video()
282
  out_txt = gr.Textbox()