rairo commited on
Commit
25e63e1
·
verified ·
1 Parent(s): 57a8290

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +180 -2
main.py CHANGED
@@ -19,7 +19,7 @@ from elevenlabs import ElevenLabs
19
  # Import and configure Google GenAI, matching the Streamlit app
20
  from google import genai
21
  from google.genai import types
22
-
23
  # -----------------------------------------------------------------------------
24
  # 1. CONFIGURATION & INITIALIZATION
25
  # -----------------------------------------------------------------------------
@@ -74,7 +74,29 @@ GENERATION_MODEL = "gemini-2.0-flash-exp-image-generation"
74
  #GENERATION_MODEL = "gemini-2.5-flash-image-preview"
75
  #TTS_MODEL = "gemini-2.5-flash-preview-tts"
76
 
77
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  # -----------------------------------------------------------------------------
79
  # 2. HELPER FUNCTIONS (Adapted directly from Streamlit App & Template)
80
  # -----------------------------------------------------------------------------
@@ -233,6 +255,61 @@ import logging
233
  logging.basicConfig(level=logging.INFO)
234
  logger = logging.getLogger(__name__)
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  # =============================================================================
237
  # OPEN IMAGE PROXY ENDPOINT (NO AUTHENTICATION)
238
  # =============================================================================
@@ -1293,8 +1370,109 @@ def log_call_usage(project_id):
1293
  logger.error(f"[LOGGING] A database error occurred for user '{uid}': {e}")
1294
  return jsonify({'error': 'A server error occurred while updating credits.'}), 500
1295
 
 
 
 
 
 
 
 
 
 
 
 
 
1296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1297
 
 
 
1298
  # -----------------------------------------------------------------------------
1299
  # 7. MAIN EXECUTION
1300
  # -----------------------------------------------------------------------------
 
19
  # Import and configure Google GenAI, matching the Streamlit app
20
  from google import genai
21
  from google.genai import types
22
+ import stripe
23
  # -----------------------------------------------------------------------------
24
  # 1. CONFIGURATION & INITIALIZATION
25
  # -----------------------------------------------------------------------------
 
74
  #GENERATION_MODEL = "gemini-2.5-flash-image-preview"
75
  #TTS_MODEL = "gemini-2.5-flash-preview-tts"
76
 
77
+ # Stripe
78
+ # --- Stripe Initialization ---
79
+ STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY")
80
+ STRIPE_WEBHOOK_SECRET = os.environ.get("STRIPE_WEBHOOK_SECRET")
81
+
82
+ # Price IDs from Stripe dashboard (price_xxx...) – set these in your env
83
+ STRIPE_PRICE_FIXER = os.environ.get("STRIPE_PRICE_FIXER") # "The Fixer" (standard)
84
+ STRIPE_PRICE_PRO = os.environ.get("STRIPE_PRICE_PRO") # "The Pro" (premium)
85
+
86
+ # Frontend URLs for redirect after Checkout
87
+ STRIPE_SUCCESS_URL = os.environ.get(
88
+ "STRIPE_SUCCESS_URL",
89
+ "https://sozofix.tech/billing/success"
90
+ )
91
+ STRIPE_CANCEL_URL = os.environ.get(
92
+ "STRIPE_CANCEL_URL",
93
+ "https://sozofix.tech/billing/cancel"
94
+ )
95
+
96
+ if STRIPE_SECRET_KEY:
97
+ stripe.api_key = STRIPE_SECRET_KEY
98
+ else:
99
+ print("WARNING: STRIPE_SECRET_KEY is not set – Stripe endpoints will fail.")
100
  # -----------------------------------------------------------------------------
101
  # 2. HELPER FUNCTIONS (Adapted directly from Streamlit App & Template)
102
  # -----------------------------------------------------------------------------
 
255
  logging.basicConfig(level=logging.INFO)
256
  logger = logging.getLogger(__name__)
257
 
258
+ ## Stripe
259
+ PLAN_CONFIG = {
260
+ # The Fixer – standard
261
+ "standard": {"price_id": STRIPE_PRICE_FIXER, "credits": 200},
262
+ "fixer": {"price_id": STRIPE_PRICE_FIXER, "credits": 200},
263
+
264
+ # The Pro – premium
265
+ "premium": {"price_id": STRIPE_PRICE_PRO, "credits": 500},
266
+ "pro": {"price_id": STRIPE_PRICE_PRO, "credits": 500},
267
+ }
268
+
269
+ def get_or_create_stripe_customer(uid: str) -> str:
270
+ """
271
+ Ensure the Firebase user has a Stripe customer.
272
+ Stores the customer id on /users/{uid}/stripeCustomerId.
273
+ """
274
+ user_ref = db_ref.child(f'users/{uid}')
275
+ user_data = user_ref.get() or {}
276
+
277
+ existing_id = user_data.get("stripeCustomerId")
278
+ if existing_id:
279
+ return existing_id
280
+
281
+ email = user_data.get("email")
282
+ customer = stripe.Customer.create(
283
+ email=email,
284
+ metadata={"firebase_uid": uid}
285
+ )
286
+
287
+ user_ref.update({"stripeCustomerId": customer.id})
288
+ return customer.id
289
+
290
+
291
+ def apply_plan_credits(uid: str, plan_key: str):
292
+ """
293
+ Adds the correct number of credits for a plan
294
+ (200 for standard, 500 for premium).
295
+ """
296
+ plan_cfg = PLAN_CONFIG.get(plan_key)
297
+ if not plan_cfg:
298
+ logger.error(f"[STRIPE] Unknown plan '{plan_key}' for user {uid}")
299
+ return
300
+
301
+ credits_to_add = plan_cfg["credits"]
302
+ user_ref = db_ref.child(f'users/{uid}')
303
+ user_data = user_ref.get() or {}
304
+ current = user_data.get("credits", 0)
305
+
306
+ new_total = current + credits_to_add
307
+ user_ref.update({"credits": new_total})
308
+ logger.info(
309
+ f"[STRIPE] Applied {credits_to_add} credits to user {uid} "
310
+ f"for plan '{plan_key}'. New total: {new_total}"
311
+ )
312
+
313
  # =============================================================================
314
  # OPEN IMAGE PROXY ENDPOINT (NO AUTHENTICATION)
315
  # =============================================================================
 
1370
  logger.error(f"[LOGGING] A database error occurred for user '{uid}': {e}")
1371
  return jsonify({'error': 'A server error occurred while updating credits.'}), 500
1372
 
1373
+ #Stripe Payments
1374
+ @app.route("/api/billing/create-checkout-session", methods=["POST"])
1375
+ def create_checkout_session():
1376
+ """
1377
+ Creates a Stripe Checkout Session for a recurring subscription.
1378
+ Plans:
1379
+ - 'standard' / 'fixer' → The Fixer (200 credits / month)
1380
+ - 'premium' / 'pro' → The Pro (500 credits / month)
1381
+ """
1382
+ uid = verify_token(request.headers.get("Authorization"))
1383
+ if not uid:
1384
+ return jsonify({"error": "Unauthorized"}), 401
1385
 
1386
+ if not STRIPE_SECRET_KEY or not STRIPE_PRICE_FIXER or not STRIPE_PRICE_PRO:
1387
+ logger.error("[STRIPE] Missing Stripe configuration.")
1388
+ return jsonify({"error": "Stripe is not configured on the server."}), 500
1389
+
1390
+ data = request.get_json() or {}
1391
+ plan = (data.get("plan") or "").lower().strip()
1392
+
1393
+ plan_cfg = PLAN_CONFIG.get(plan)
1394
+ if not plan_cfg or not plan_cfg["price_id"]:
1395
+ return jsonify({"error": "Invalid plan selected."}), 400
1396
+
1397
+ try:
1398
+ customer_id = get_or_create_stripe_customer(uid)
1399
+
1400
+ session = stripe.checkout.Session.create(
1401
+ mode="subscription",
1402
+ customer=customer_id,
1403
+ payment_method_types=["card"],
1404
+ line_items=[{
1405
+ "price": plan_cfg["price_id"],
1406
+ "quantity": 1,
1407
+ }],
1408
+ success_url=STRIPE_SUCCESS_URL + "?session_id={CHECKOUT_SESSION_ID}",
1409
+ cancel_url=STRIPE_CANCEL_URL,
1410
+ # So we can find the user/plan again from webhooks
1411
+ metadata={
1412
+ "firebase_uid": uid,
1413
+ "plan": plan,
1414
+ },
1415
+ subscription_data={
1416
+ "metadata": {
1417
+ "firebase_uid": uid,
1418
+ "plan": plan,
1419
+ }
1420
+ },
1421
+ )
1422
+
1423
+ logger.info(f"[STRIPE] Created checkout session {session.id} for user {uid}, plan {plan}")
1424
+ return jsonify({
1425
+ "id": session.id,
1426
+ "url": session.url,
1427
+ })
1428
+
1429
+ except Exception as e:
1430
+ logger.error(f"[STRIPE] Error creating checkout session: {e}")
1431
+ return jsonify({"error": "Failed to create checkout session."}), 500
1432
+
1433
+ @app.route("/api/billing/webhook", methods=["POST"])
1434
+ def stripe_webhook():
1435
+ if not STRIPE_WEBHOOK_SECRET:
1436
+ logger.error("[STRIPE] STRIPE_WEBHOOK_SECRET not set.")
1437
+ return jsonify({"error": "Webhook secret not configured."}), 500
1438
+
1439
+ payload = request.data
1440
+ sig_header = request.headers.get("Stripe-Signature")
1441
+
1442
+ try:
1443
+ event = stripe.Webhook.construct_event(
1444
+ payload, sig_header, STRIPE_WEBHOOK_SECRET
1445
+ )
1446
+ except stripe.error.SignatureVerificationError as e:
1447
+ logger.error(f"[STRIPE] Webhook signature verification failed: {e}")
1448
+ return "Invalid signature", 400
1449
+ except Exception as e:
1450
+ logger.error(f"[STRIPE] Webhook parsing error: {e}")
1451
+ return "Bad request", 400
1452
+
1453
+ event_type = event.get("type")
1454
+ obj = event.get("data", {}).get("object", {})
1455
+
1456
+ # We only care about successful subscription payments
1457
+ if event_type == "invoice.payment_succeeded":
1458
+ try:
1459
+ subscription_id = obj.get("subscription")
1460
+ if not subscription_id:
1461
+ return "", 200
1462
+
1463
+ sub = stripe.Subscription.retrieve(subscription_id)
1464
+ metadata = sub.get("metadata", {}) or {}
1465
+ uid = metadata.get("firebase_uid")
1466
+ plan = metadata.get("plan")
1467
+
1468
+ if uid and plan:
1469
+ logger.info(f"[STRIPE] invoice.payment_succeeded for user {uid}, plan {plan}")
1470
+ apply_plan_credits(uid, plan)
1471
+ except Exception as e:
1472
+ logger.error(f"[STRIPE] Error handling invoice.payment_succeeded: {e}")
1473
 
1474
+ # You can log other event types here if needed
1475
+ return "", 200
1476
  # -----------------------------------------------------------------------------
1477
  # 7. MAIN EXECUTION
1478
  # -----------------------------------------------------------------------------