tinahmbuz commited on
Commit
f8a1b45
·
verified ·
1 Parent(s): 24d156e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +13 -243
app.py CHANGED
@@ -1,15 +1,8 @@
1
  import gradio as gr
2
  import os
3
  import librosa
4
- import numpy as np
5
  import zipfile
6
- from datetime import datetime, timedelta
7
- import hashlib
8
- import sqlite3
9
- import requests
10
- import jwt
11
- from cryptography.x509 import load_pem_x509_certificate
12
- from cryptography.hazmat.backends import default_backend
13
  from generalstems import (
14
  mp3_to_wav,
15
  demucs_separate,
@@ -17,214 +10,7 @@ from generalstems import (
17
  detect_key_advanced,
18
  detect_tempo_advanced
19
  )
20
- # -----------------------------
21
- # Clerk Authentication
22
- # -----------------------------
23
- CLERK_SECRET_KEY = os.environ.get("CLERK_SECRET_KEY")
24
- CLERK_PUBLISHABLE_KEY = "pk_test_ZWFzeS1wb2xlY2F0LTIyLmNsZXJrLmFjY291bnRzLmRldiQ"
25
- # Fetch Clerk's JWKS (public keys for verification)
26
- def get_clerk_public_key():
27
- """Get Clerk's public key for JWT verification"""
28
- try:
29
- response = requests.get("https://easy-polecat-22.clerk.accounts.dev/.well-known/jwks.json")
30
- jwks = response.json()
31
- # Use first key (typically RS256)
32
- return jwks['keys'][0]
33
- except Exception as e:
34
- print(f"[ERROR] Failed to fetch Clerk JWKS: {e}")
35
- return None
36
- def verify_clerk_token(token):
37
- """Verify JWT token from Clerk and return user_id"""
38
- if not token or not CLERK_SECRET_KEY:
39
- return None
40
 
41
- try:
42
- # Verify using Clerk API
43
- response = requests.get(
44
- f"https://api.clerk.com/v1/sessions/verify",
45
- headers={
46
- "Authorization": f"Bearer {CLERK_SECRET_KEY}",
47
- "Content-Type": "application/json"
48
- },
49
- json={"token": token}
50
- )
51
-
52
- if response.status_code == 200:
53
- data = response.json()
54
- user_id = data.get('user_id')
55
- print(f"[AUTH] Verified user: {user_id}")
56
- return user_id
57
- else:
58
- print(f"[AUTH] Verification failed: {response.status_code}")
59
- return None
60
-
61
- except Exception as e:
62
- print(f"[AUTH ERROR] {e}")
63
- return None
64
- # -----------------------------
65
- # Usage Limiting System - WITH AUTH
66
- # -----------------------------
67
- DB_PATH = "usage_limits.db"
68
- ANON_MAX_DAILY_USES = 1 # Anonymous users get 1 daily use
69
- AUTH_MAX_DAILY_USES = 3 # Authenticated users get 3 daily uses
70
- MAX_MONTHLY_USES = 15
71
- RESET_HOURS = 24
72
- def init_db():
73
- """Initialize SQLite database for persistent storage"""
74
- conn = sqlite3.connect(DB_PATH)
75
- # Add clerk_user_id column for authenticated users
76
- conn.execute("""
77
- CREATE TABLE IF NOT EXISTS usage (
78
- user_id TEXT PRIMARY KEY,
79
- clerk_user_id TEXT,
80
- daily_uses INTEGER DEFAULT 0,
81
- monthly_uses INTEGER DEFAULT 0,
82
- first_daily_use TIMESTAMP,
83
- first_monthly_use TIMESTAMP
84
- )
85
- """)
86
- conn.commit()
87
- conn.close()
88
- print("[INFO] Database initialized")
89
- init_db()
90
- def get_user_id(request: gr.Request, clerk_user_id=None):
91
- """Create identifier - prioritize Clerk ID, fallback to IP fingerprint"""
92
- if clerk_user_id:
93
- # Authenticated user - use Clerk ID
94
- return f"clerk_{clerk_user_id}"
95
-
96
- try:
97
- # Anonymous user - use IP fingerprint
98
- ip = request.headers.get("x-forwarded-for", "")
99
- if ip and "," in ip:
100
- ip = ip.split(",")[0].strip()
101
-
102
- if not ip:
103
- ip = request.headers.get("x-real-ip", "")
104
- if not ip:
105
- ip = request.headers.get("cf-connecting-ip", "")
106
- if not ip:
107
- ip = request.client.host if hasattr(request, 'client') else ""
108
-
109
- user_agent = request.headers.get("user-agent", "")
110
- accept_language = request.headers.get("accept-language", "")
111
-
112
- identifier_string = f"{ip}_{user_agent}_{accept_language}"
113
- identifier = hashlib.sha256(identifier_string.encode()).hexdigest()
114
- print(f"[DEBUG] Anonymous user ID: {identifier[:12]}... | IP: {ip}")
115
- return f"anon_{identifier}"
116
- except Exception as e:
117
- print(f"[ERROR] Failed to get user ID: {e}")
118
- return f"anon_{hashlib.sha256(str(datetime.now()).encode()).hexdigest()}"
119
- def check_usage_limit(request: gr.Request, clerk_user_id=None):
120
- """Check usage limits - authenticated users get 3 daily, anonymous get 1 daily"""
121
- user_id = get_user_id(request, clerk_user_id)
122
- now = datetime.now()
123
- is_authenticated = clerk_user_id is not None
124
-
125
- # Set max daily uses based on auth status
126
- max_daily_uses = AUTH_MAX_DAILY_USES if is_authenticated else ANON_MAX_DAILY_USES
127
-
128
- conn = sqlite3.connect(DB_PATH)
129
- cursor = conn.cursor()
130
-
131
- cursor.execute("""
132
- SELECT daily_uses, monthly_uses, first_daily_use, first_monthly_use, clerk_user_id
133
- FROM usage WHERE user_id = ?
134
- """, (user_id,))
135
-
136
- row = cursor.fetchone()
137
-
138
- if row:
139
- daily_uses, monthly_uses, first_daily_str, first_monthly_str, stored_clerk_id = row
140
- first_daily_use = datetime.fromisoformat(first_daily_str) if first_daily_str else now
141
- first_monthly_use = datetime.fromisoformat(first_monthly_str) if first_monthly_str else now
142
-
143
- print(f"[DEBUG] User: {'AUTH' if is_authenticated else 'ANON'} | Daily {daily_uses}/{max_daily_uses}, Monthly {monthly_uses}/{MAX_MONTHLY_USES}")
144
-
145
- # Reset daily counter after 24 hours
146
- if now - first_daily_use > timedelta(hours=RESET_HOURS):
147
- print(f"[DEBUG] Resetting daily usage")
148
- daily_uses = 0
149
- first_daily_use = now
150
- cursor.execute("""
151
- UPDATE usage SET daily_uses = 0, first_daily_use = ? WHERE user_id = ?
152
- """, (now.isoformat(), user_id))
153
- conn.commit()
154
-
155
- # Reset monthly counter after 30 days
156
- if now - first_monthly_use > timedelta(days=30):
157
- print(f"[DEBUG] Resetting monthly usage")
158
- monthly_uses = 0
159
- first_monthly_use = now
160
- cursor.execute("""
161
- UPDATE usage SET monthly_uses = 0, first_monthly_use = ? WHERE user_id = ?
162
- """, (now.isoformat(), user_id))
163
- conn.commit()
164
-
165
- # Check daily limit (1 for anonymous, 3 for authenticated)
166
- if daily_uses >= max_daily_uses:
167
- time_until_reset = (first_daily_use + timedelta(hours=RESET_HOURS)) - now
168
- hours = int(time_until_reset.total_seconds() // 3600)
169
- minutes = int((time_until_reset.total_seconds() % 3600) // 60)
170
- print(f"[DEBUG] DAILY LIMIT HIT")
171
- conn.close()
172
-
173
- # If anonymous user hit their limit, prompt to sign in
174
- if not is_authenticated:
175
- return False, 0, 0, "", "auth_required"
176
- else:
177
- return False, 0, 0, f"{hours}h {minutes}m", "daily"
178
-
179
- # Check monthly limit (authenticated users only)
180
- if is_authenticated and monthly_uses >= MAX_MONTHLY_USES:
181
- time_until_reset = (first_monthly_use + timedelta(days=30)) - now
182
- days = int(time_until_reset.total_seconds() // 86400)
183
- hours = int((time_until_reset.total_seconds() % 86400) // 3600)
184
- print(f"[DEBUG] MONTHLY LIMIT HIT")
185
- conn.close()
186
- return False, 0, 0, f"{days} days {hours}h", "monthly"
187
-
188
- daily_remaining = max_daily_uses - daily_uses
189
- monthly_remaining = MAX_MONTHLY_USES - monthly_uses
190
-
191
- else:
192
- # New user
193
- print(f"[DEBUG] New user - {'AUTH' if is_authenticated else 'ANON'}")
194
- cursor.execute("""
195
- INSERT INTO usage (user_id, clerk_user_id, daily_uses, monthly_uses, first_daily_use, first_monthly_use)
196
- VALUES (?, ?, 0, 0, ?, ?)
197
- """, (user_id, clerk_user_id, now.isoformat(), now.isoformat()))
198
- conn.commit()
199
- daily_remaining = max_daily_uses
200
- monthly_remaining = MAX_MONTHLY_USES
201
-
202
- conn.close()
203
- print(f"[DEBUG] User allowed - Daily: {daily_remaining}, Monthly: {monthly_remaining}")
204
- return True, daily_remaining, monthly_remaining, "", ""
205
- def increment_usage(request: gr.Request, clerk_user_id=None):
206
- """Increment usage counts"""
207
- user_id = get_user_id(request, clerk_user_id)
208
- is_authenticated = clerk_user_id is not None
209
- max_daily_uses = AUTH_MAX_DAILY_USES if is_authenticated else ANON_MAX_DAILY_USES
210
-
211
- conn = sqlite3.connect(DB_PATH)
212
- cursor = conn.cursor()
213
-
214
- cursor.execute("""
215
- UPDATE usage
216
- SET daily_uses = daily_uses + 1, monthly_uses = monthly_uses + 1
217
- WHERE user_id = ?
218
- """, (user_id,))
219
-
220
- conn.commit()
221
-
222
- cursor.execute("SELECT daily_uses, monthly_uses FROM usage WHERE user_id = ?", (user_id,))
223
- row = cursor.fetchone()
224
- if row:
225
- print(f"[DEBUG] Usage incremented - Daily: {row[0]}/{max_daily_uses}, Monthly: {row[1]}/{MAX_MONTHLY_USES}")
226
-
227
- conn.close()
228
  # -----------------------------
229
  # Download function
230
  # -----------------------------
@@ -264,7 +50,7 @@ def create_download_zip(selected_files):
264
  }
265
 
266
  filename = file_mapping.get(file_type)
267
- if (filename):
268
  file_path = os.path.join("stems", filename)
269
  if os.path.exists(file_path):
270
  zipf.write(file_path, filename)
@@ -273,27 +59,14 @@ def create_download_zip(selected_files):
273
  except Exception as e:
274
  print(f"Error creating zip: {e}")
275
  return None
 
276
  # -----------------------------
277
- # Main processing function - WITH AUTH
278
  # -----------------------------
279
- def process(song_file, options, auth_token, request: gr.Request):
280
- # Verify auth token
281
- clerk_user_id = verify_clerk_token(auth_token) if auth_token else None
282
-
283
- # Check usage limit
284
- allowed, daily_remaining, monthly_remaining, reset_time, limit_type = check_usage_limit(request, clerk_user_id)
285
-
286
- if not allowed:
287
- if limit_type == "auth_required":
288
- return [None] * 8 + ["AUTH_REQUIRED"]
289
- elif limit_type == "daily":
290
- return [None] * 8 + [f"LIMIT_ERROR:DAILY:{reset_time}"]
291
- elif limit_type == "monthly":
292
- return [None] * 8 + [f"LIMIT_ERROR:MONTHLY:{reset_time}"]
293
-
294
  try:
295
  if song_file is None:
296
- return [None] * 8 + [f"UPLOAD_REQUIRED:{daily_remaining}:{monthly_remaining}"]
297
 
298
  out_dir = "stems"
299
  os.makedirs(out_dir, exist_ok=True)
@@ -325,7 +98,7 @@ def process(song_file, options, auth_token, request: gr.Request):
325
  tempo = detect_tempo_advanced(y, sr)
326
  song_info = f"Key: {key} | Tempo: {tempo} BPM"
327
  except Exception as e:
328
- song_info = f"INFO_ERROR:{str(e)}"
329
  print(f"Info detection error: {e}")
330
 
331
  # WAV conversion
@@ -342,11 +115,7 @@ def process(song_file, options, auth_token, request: gr.Request):
342
  if "Refine Drums" in options and "drums" in stems:
343
  drum_refined = refine_drums(stems["drums"], out_dir)
344
 
345
- # Increment usage
346
- increment_usage(request, clerk_user_id)
347
-
348
- success_info = song_info if song_info else ""
349
- success_info += f"SUCCESS:{daily_remaining - 1}:{monthly_remaining - 1}"
350
 
351
  return (
352
  wav_path,
@@ -364,12 +133,13 @@ def process(song_file, options, auth_token, request: gr.Request):
364
  print(f"Processing error: {e}")
365
  import traceback
366
  traceback.print_exc()
367
- return [None] * 8 + ["PROCESSING_ERROR"]
 
368
  # -----------------------------
369
  # UI Layout
370
  # -----------------------------
371
  with gr.Blocks(title="Stem Splitter") as ui:
372
- gr.Markdown("## Stem Splitter API with Authentication")
373
 
374
  with gr.Row():
375
  with gr.Column():
@@ -379,7 +149,6 @@ with gr.Blocks(title="Stem Splitter") as ui:
379
  value=["All"],
380
  label="Options"
381
  )
382
- auth_token_input = gr.Textbox(label="Auth Token (optional)", visible=False)
383
  song_info = gr.Textbox(label="Status")
384
  process_btn = gr.Button("Process")
385
 
@@ -403,7 +172,7 @@ with gr.Blocks(title="Stem Splitter") as ui:
403
 
404
  process_btn.click(
405
  fn=process,
406
- inputs=[song_input, process_options, auth_token_input],
407
  outputs=[wav_out, vocals, bass, other, drums, kick, snare, hihat, song_info]
408
  )
409
 
@@ -412,5 +181,6 @@ with gr.Blocks(title="Stem Splitter") as ui:
412
  inputs=[download_options],
413
  outputs=[download_file]
414
  )
 
415
  if __name__ == "__main__":
416
  ui.launch(server_name="0.0.0.0", server_port=7860)
 
1
  import gradio as gr
2
  import os
3
  import librosa
 
4
  import zipfile
5
+ from datetime import datetime
 
 
 
 
 
 
6
  from generalstems import (
7
  mp3_to_wav,
8
  demucs_separate,
 
10
  detect_key_advanced,
11
  detect_tempo_advanced
12
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  # -----------------------------
15
  # Download function
16
  # -----------------------------
 
50
  }
51
 
52
  filename = file_mapping.get(file_type)
53
+ if filename:
54
  file_path = os.path.join("stems", filename)
55
  if os.path.exists(file_path):
56
  zipf.write(file_path, filename)
 
59
  except Exception as e:
60
  print(f"Error creating zip: {e}")
61
  return None
62
+
63
  # -----------------------------
64
+ # Main processing function
65
  # -----------------------------
66
+ def process(song_file, options):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  try:
68
  if song_file is None:
69
+ return [None] * 8 + ["Please upload a song file"]
70
 
71
  out_dir = "stems"
72
  os.makedirs(out_dir, exist_ok=True)
 
98
  tempo = detect_tempo_advanced(y, sr)
99
  song_info = f"Key: {key} | Tempo: {tempo} BPM"
100
  except Exception as e:
101
+ song_info = f"Info detection error: {str(e)}"
102
  print(f"Info detection error: {e}")
103
 
104
  # WAV conversion
 
115
  if "Refine Drums" in options and "drums" in stems:
116
  drum_refined = refine_drums(stems["drums"], out_dir)
117
 
118
+ success_info = song_info if song_info else "Processing complete!"
 
 
 
 
119
 
120
  return (
121
  wav_path,
 
133
  print(f"Processing error: {e}")
134
  import traceback
135
  traceback.print_exc()
136
+ return [None] * 8 + [f"Processing error: {str(e)}"]
137
+
138
  # -----------------------------
139
  # UI Layout
140
  # -----------------------------
141
  with gr.Blocks(title="Stem Splitter") as ui:
142
+ gr.Markdown("## Stem Splitter")
143
 
144
  with gr.Row():
145
  with gr.Column():
 
149
  value=["All"],
150
  label="Options"
151
  )
 
152
  song_info = gr.Textbox(label="Status")
153
  process_btn = gr.Button("Process")
154
 
 
172
 
173
  process_btn.click(
174
  fn=process,
175
+ inputs=[song_input, process_options],
176
  outputs=[wav_out, vocals, bass, other, drums, kick, snare, hihat, song_info]
177
  )
178
 
 
181
  inputs=[download_options],
182
  outputs=[download_file]
183
  )
184
+
185
  if __name__ == "__main__":
186
  ui.launch(server_name="0.0.0.0", server_port=7860)