AkashKumarave commited on
Commit
257250b
·
verified ·
1 Parent(s): 7052cef

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +219 -165
app.py CHANGED
@@ -17,10 +17,16 @@ from typing import Optional
17
  from PIL import Image
18
  from io import BytesIO
19
  import google.generativeai as genai
20
- import tempfile# Configure logging
 
 
21
  logging.basicConfig(level=logging.INFO)
22
- logger = logging.getLogger(__name__)# Initialize FastAPI app
23
- app = FastAPI(title="Gemini Image Editing API with Razorpay")# Enable CORS for frontend
 
 
 
 
24
  app.add_middleware(
25
  CORSMiddleware,
26
  allow_origins=[
@@ -34,27 +40,45 @@ app.add_middleware(
34
  allow_credentials=True,
35
  allow_methods=["*"],
36
  allow_headers=["*"],
37
- )# ===== API CONFIGURATION =====
 
 
38
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
39
- GEMINI_MODEL = "gemini-2.5-flash-image-preview"# Validate Gemini API key presence
 
 
40
  if not GEMINI_API_KEY:
41
  logger.error("GEMINI_API_KEY environment variable is not set")
42
- raise ValueError("GEMINI_API_KEY environment variable is required")# Configure Gemini API
43
- genai.configure(api_key=GEMINI_API_KEY)# ===== RAZORPAY CONFIGURATION =====
 
 
 
 
44
  RAZORPAY_KEY_ID = os.getenv("RAZORPAY_KEY_ID")
45
  RAZORPAY_KEY_SECRET = os.getenv("RAZORPAY_KEY_SECRET")
46
- razorpay_client = razorpay.Client(auth=(RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET)) if RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET else None# ===== SUPABASE CONFIGURATION =====
 
 
47
  SUPABASE_URL = os.getenv("SUPABASE_URL")
48
  SUPABASE_KEY = os.getenv("SUPABASE_KEY")
49
- supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) if SUPABASE_URL and SUPABASE_KEY else None# Pydantic models for JSON input validation
 
 
50
  class CreateOrderRequest(BaseModel):
51
- amount: intclass VerifyPaymentRequest(BaseModel):
 
 
52
  razorpay_order_id: str
53
  razorpay_payment_id: str
54
  razorpay_signature: str
55
- user_id: Optional[str] = Noneclass GenerateImageRequest(BaseModel):
 
 
56
  prompt: str
57
- user_id: Optional[str] = None# ===== AUTHENTICATION =====
 
 
58
  def generate_jwt_token():
59
  """Generate JWT token for API authentication"""
60
  payload = {
@@ -62,14 +86,18 @@ def generate_jwt_token():
62
  "exp": int(time.time()) + 1800, # 30 minutes expiration
63
  "nbf": int(time.time()) - 5 # Not before 5 seconds ago
64
  }
65
- return jwt.encode(payload, GEMINI_API_KEY, algorithm="HS256")# ===== IMAGE PROCESSING =====
 
 
66
  def prepare_image_base64(image_content: bytes):
67
  """Convert image bytes to base64 without prefix"""
68
  try:
69
  return base64.b64encode(image_content).decode('utf-8')
70
  except Exception as e:
71
  logger.error(f"Image processing failed: {str(e)}")
72
- raise HTTPException(status_code=500, detail=f"Image processing failed: {str(e)}")def validate_image(image_content: bytes):
 
 
73
  """Validate image meets API requirements"""
74
  try:
75
  size_mb = len(image_content) / (1024 * 1024)
@@ -80,31 +108,36 @@ def prepare_image_base64(image_content: bytes):
80
  raise HTTPException(status_code=400, detail="Unsupported image format. Use PNG, JPG, JPEG, or WEBP")
81
  return True, ""
82
  except Exception as e:
83
- raise HTTPException(status_code=400, detail=f"Image validation error: {str(e)}")def generate_gemini_image(images: List[Image.Image], prompt: str):
 
 
84
  """Generate or edit image using Gemini API"""
85
  try:
86
  contents = images + [prompt]
87
- response = genai.GenerativeModel(GEMINI_MODEL).generate_content(contents) text_response = ""
88
- image_path = None
89
-
90
- for part in response.candidates[0].content.parts:
91
- if part.text:
92
- text_response += part.text + "\n"
93
- elif hasattr(part, 'inline_data') and part.inline_data:
94
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
95
- temp_path = tmp.name
96
- generated_image = Image.open(BytesIO(part.inline_data.data))
97
- generated_image.save(temp_path)
98
- image_path = temp_path
99
- logger.info(f"Generated image saved to: {temp_path} with prompt: {prompt}")
100
 
101
- if image_path:
102
- return image_path, ""
103
- else:
104
- return None, text_response.strip()
105
- except Exception as e:
106
- logger.error(f"Gemini API error: {str(e)}")
107
- raise HTTPException(status_code=500, detail=f"Gemini API error: {str(e)}")# ===== RAZORPAY FUNCTIONS =====
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  def create_razorpay_order(amount: int):
109
  """Create a Razorpay order"""
110
  try:
@@ -122,7 +155,9 @@ def create_razorpay_order(amount: int):
122
  return order
123
  except Exception as e:
124
  logger.error(f"Failed to create Razorpay order: {str(e)}")
125
- raise HTTPException(status_code=500, detail=f"Failed to create order: {str(e)}")def verify_payment_signature(order_id: str, payment_id: str, signature: str):
 
 
126
  """Verify Razorpay payment signature"""
127
  try:
128
  if not razorpay_client:
@@ -140,44 +175,50 @@ def create_razorpay_order(amount: int):
140
  return False
141
  except Exception as e:
142
  logger.error(f"Error verifying payment signature: {str(e)}")
143
- raise HTTPException(status_code=500, detail=f"Verification error: {str(e)}")# ===== MAIN PROCESSING =====
 
 
144
  async def generate_image(images: List[bytes], prompt: str, user_id: Optional[str] = None):
145
  """Handle complete image generation workflow"""
146
  # Validate images
147
  for img_content in images:
148
  if img_content:
149
- validate_image(img_content)# Convert bytes to PIL Images
150
- pil_images = []
151
- for img_content in images:
152
- try:
153
- img = Image.open(BytesIO(img_content))
154
- if img.mode == "RGBA":
155
- img = img.convert("RGBA")
156
- pil_images.append(img)
157
- except Exception as e:
158
- logger.error(f"Image conversion failed: {str(e)}")
159
- raise HTTPException(status_code=400, detail=f"Image conversion failed: {str(e)}")
160
 
161
- if len(pil_images) < 1:
162
- raise HTTPException(status_code=400, detail="At least one image required")
 
 
 
 
 
 
 
 
 
163
 
164
- # Check user premium status if Supabase is configured
165
- if user_id and supabase:
166
- try:
167
- user_data = supabase.table("users").select("is_premium").eq("user_id", user_id).execute()
168
- if not user_data.data or not user_data.data[0].get("is_premium"):
169
- raise HTTPException(status_code=403, detail="Premium subscription required")
170
- except Exception as e:
171
- logger.error(f"Supabase user check failed: {str(e)}")
172
- raise HTTPException(status_code=500, detail=f"User verification failed: {str(e)}")
 
 
 
173
 
174
- # Generate image using Gemini API
175
- image_path, text_response = generate_gemini_image(pil_images, prompt)
176
 
177
- if image_path:
178
- return image_path
179
- else:
180
- raise HTTPException(status_code=500, detail=f"Image generation failed: {text_response or 'Unknown error'}")# ===== API ENDPOINTS =====
 
 
181
  @app.post("/generate")
182
  async def generate_image_endpoint(
183
  prompt: str = Form(...),
@@ -189,60 +230,66 @@ async def generate_image_endpoint(
189
  if len(images) < 1:
190
  raise HTTPException(status_code=400, detail="At least one image required")
191
  if len(images) > 4:
192
- raise HTTPException(status_code=400, detail="Maximum 4 images allowed") image_contents = [await image.read() for image in images]
193
- output_path = await generate_image(image_contents, prompt, user_id)
194
-
195
- return FileResponse(
196
- path=output_path,
197
- media_type="image/png",
198
- filename=f"gemini_output_{Path(output_path).stem}.png"
199
- )
200
- except HTTPException as e:
201
- raise
202
- except Exception as e:
203
- logger.error(f"Error in /generate: {str(e)}")
204
- raise HTTPException(status_code=500, detail=str(e))@app.post("/create-razorpay-order")
 
 
 
205
  async def create_order_endpoint(
206
  request: Request,
207
  amount: Optional[int] = Form(None),
208
  body: Optional[CreateOrderRequest] = None
209
  ):
210
  """Create a Razorpay order (supports form-data and JSON)"""
211
- logger.info("Received create order request")try:
212
- if not razorpay_client:
213
- raise HTTPException(status_code=500, detail="Razorpay configuration missing")
214
-
215
- # Handle JSON body if provided
216
- if body and body.amount:
217
- amount = body.amount
218
- elif not amount:
219
- try:
220
- json_body = await request.json()
221
- amount = json_body.get('amount')
222
- except:
223
- pass
224
-
225
- if not amount or amount <= 0:
226
- raise HTTPException(status_code=422, detail="Missing or invalid 'amount' parameter")
227
-
228
- logger.info(f"Creating order with amount: {amount}")
229
- order = create_razorpay_order(amount)
230
-
231
- response_data = {
232
- "id": order["id"],
233
- "amount": order["amount"],
234
- "currency": "INR",
235
- "key_id": RAZORPAY_KEY_ID
236
- }
237
-
238
- logger.info(f"Order created successfully: {order['id']}")
239
- return JSONResponse(content=response_data)
240
-
241
- except HTTPException:
242
- raise
243
- except Exception as e:
244
- logger.error(f"Error creating order: {str(e)}")
245
- raise HTTPException(status_code=500, detail=f"Failed to create order: {str(e)}")@app.post("/verify-razorpay-payment")
 
 
 
246
  async def verify_payment_endpoint(
247
  request: Request,
248
  razorpay_order_id: Optional[str] = Form(None),
@@ -252,58 +299,61 @@ async def verify_payment_endpoint(
252
  body: Optional[VerifyPaymentRequest] = None
253
  ):
254
  """Verify Razorpay payment signature (supports form-data and JSON)"""
255
- logger.info("Received payment verification request")try:
256
- # Handle JSON body if provided
257
- if body:
258
- razorpay_order_id = razorpay_order_id or body.razorpay_order_id
259
- razorpay_payment_id = razorpay_payment_id or body.razorpay_payment_id
260
- razorpay_signature = razorpay_signature or body.razorpay_signature
261
- user_id = user_id or body.user_id
262
- else:
263
- try:
264
- json_body = await request.json()
265
- razorpay_order_id = razorpay_order_id or json_body.get('razorpay_order_id')
266
- razorpay_payment_id = razorpay_payment_id or json_body.get('razorpay_payment_id')
267
- razorpay_signature = razorpay_signature or json_body.get('razorpay_signature')
268
- user_id = user_id or json_body.get('user_id')
269
- except:
270
- pass
271
-
272
- # Validate required fields
273
- if not all([razorpay_order_id, razorpay_payment_id, razorpay_signature]):
274
- missing_fields = []
275
- if not razorpay_order_id: missing_fields.append("razorpay_order_id")
276
- if not razorpay_payment_id: missing_fields.append("razorpay_payment_id")
277
- if not razorpay_signature: missing_fields.append("razorpay_signature")
278
-
279
- logger.error(f"Missing required fields: {missing_fields}")
280
- raise HTTPException(
281
- status_code=422,
282
- detail=f"Missing required fields: {', '.join(missing_fields)}"
283
- )
284
-
285
- logger.info(f"Verifying payment for order_id: {razorpay_order_id}")
286
- is_valid = verify_payment_signature(razorpay_order_id, razorpay_payment_id, razorpay_signature)
287
-
288
- if is_valid:
289
- if user_id and supabase:
290
- logger.info(f"Updating Supabase for user_id: {user_id}")
291
  try:
292
- supabase.table("users").update({"is_premium": True}).eq("user_id", user_id).execute()
293
- logger.info(f"Successfully updated premium status for user: {user_id}")
294
- except Exception as e:
295
- logger.error(f"Failed to update Supabase: {str(e)}")
296
-
297
- return JSONResponse(content={"success": True, "message": "Payment verified successfully"})
298
- else:
299
- logger.warning(f"Payment verification failed for order: {razorpay_order_id}")
300
- return JSONResponse(content={"success": False, "message": "Payment verification failed"}, status_code=400)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
- except HTTPException:
303
- raise
304
- except Exception as e:
305
- logger.error(f"Error verifying payment: {str(e)}")
306
- raise HTTPException(status_code=500, detail=f"Verification error: {str(e)}")@app.get("/")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  async def index():
308
  return {
309
  "status": "Gemini Image Editing API with Razorpay is running",
@@ -312,13 +362,17 @@ async def index():
312
  "create_order": "POST /create-razorpay-order",
313
  "verify_payment": "POST /verify-razorpay-payment"
314
  }
315
- }@app.get("/health")
 
 
316
  async def health_check():
317
  return {
318
  "status": "healthy",
319
  "razorpay_configured": bool(RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET),
320
  "supabase_configured": bool(SUPABASE_URL and SUPABASE_KEY),
321
  "gemini_configured": bool(GEMINI_API_KEY)
322
- }if __name__ == "__main__":
 
 
323
  import uvicorn
324
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
17
  from PIL import Image
18
  from io import BytesIO
19
  import google.generativeai as genai
20
+ import tempfile
21
+
22
+ # Configure logging
23
  logging.basicConfig(level=logging.INFO)
24
+ logger = logging.getLogger(__name__)
25
+
26
+ # Initialize FastAPI app
27
+ app = FastAPI(title="Gemini Image Editing API with Razorpay")
28
+
29
+ # Enable CORS for frontend
30
  app.add_middleware(
31
  CORSMiddleware,
32
  allow_origins=[
 
40
  allow_credentials=True,
41
  allow_methods=["*"],
42
  allow_headers=["*"],
43
+ )
44
+
45
+ # ===== API CONFIGURATION =====
46
  GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
47
+ GEMINI_MODEL = "gemini-2.5-flash-image-preview"
48
+
49
+ # Validate Gemini API key presence
50
  if not GEMINI_API_KEY:
51
  logger.error("GEMINI_API_KEY environment variable is not set")
52
+ raise ValueError("GEMINI_API_KEY environment variable is required")
53
+
54
+ # Configure Gemini API
55
+ genai.configure(api_key=GEMINI_API_KEY)
56
+
57
+ # ===== RAZORPAY CONFIGURATION =====
58
  RAZORPAY_KEY_ID = os.getenv("RAZORPAY_KEY_ID")
59
  RAZORPAY_KEY_SECRET = os.getenv("RAZORPAY_KEY_SECRET")
60
+ razorpay_client = razorpay.Client(auth=(RAZORPAY_KEY_ID, RAZORPAY_KEY_SECRET)) if RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET else None
61
+
62
+ # ===== SUPABASE CONFIGURATION =====
63
  SUPABASE_URL = os.getenv("SUPABASE_URL")
64
  SUPABASE_KEY = os.getenv("SUPABASE_KEY")
65
+ supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) if SUPABASE_URL and SUPABASE_KEY else None
66
+
67
+ # Pydantic models for JSON input validation
68
  class CreateOrderRequest(BaseModel):
69
+ amount: int
70
+
71
+ class VerifyPaymentRequest(BaseModel):
72
  razorpay_order_id: str
73
  razorpay_payment_id: str
74
  razorpay_signature: str
75
+ user_id: Optional[str] = None
76
+
77
+ class GenerateImageRequest(BaseModel):
78
  prompt: str
79
+ user_id: Optional[str] = None
80
+
81
+ # ===== AUTHENTICATION =====
82
  def generate_jwt_token():
83
  """Generate JWT token for API authentication"""
84
  payload = {
 
86
  "exp": int(time.time()) + 1800, # 30 minutes expiration
87
  "nbf": int(time.time()) - 5 # Not before 5 seconds ago
88
  }
89
+ return jwt.encode(payload, GEMINI_API_KEY, algorithm="HS256")
90
+
91
+ # ===== IMAGE PROCESSING =====
92
  def prepare_image_base64(image_content: bytes):
93
  """Convert image bytes to base64 without prefix"""
94
  try:
95
  return base64.b64encode(image_content).decode('utf-8')
96
  except Exception as e:
97
  logger.error(f"Image processing failed: {str(e)}")
98
+ raise HTTPException(status_code=500, detail=f"Image processing failed: {str(e)}")
99
+
100
+ def validate_image(image_content: bytes):
101
  """Validate image meets API requirements"""
102
  try:
103
  size_mb = len(image_content) / (1024 * 1024)
 
108
  raise HTTPException(status_code=400, detail="Unsupported image format. Use PNG, JPG, JPEG, or WEBP")
109
  return True, ""
110
  except Exception as e:
111
+ raise HTTPException(status_code=400, detail=f"Image validation error: {str(e)}")
112
+
113
+ def generate_gemini_image(images: List[Image.Image], prompt: str):
114
  """Generate or edit image using Gemini API"""
115
  try:
116
  contents = images + [prompt]
117
+ response = genai.GenerativeModel(GEMINI_MODEL).generate_content(contents)
118
+ text_response = ""
119
+ image_path = None
 
 
 
 
 
 
 
 
 
 
120
 
121
+ for part in response.candidates[0].content.parts:
122
+ if part.text:
123
+ text_response += part.text + "\n"
124
+ elif hasattr(part, 'inline_data') and part.inline_data:
125
+ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
126
+ temp_path = tmp.name
127
+ generated_image = Image.open(BytesIO(part.inline_data.data))
128
+ generated_image.save(temp_path)
129
+ image_path = temp_path
130
+ logger.info(f"Generated image saved to: {temp_path} with prompt: {prompt}")
131
+
132
+ if image_path:
133
+ return image_path, ""
134
+ else:
135
+ return None, text_response.strip()
136
+ except Exception as e:
137
+ logger.error(f"Gemini API error: {str(e)}")
138
+ raise HTTPException(status_code=500, detail=f"Gemini API error: {str(e)}")
139
+
140
+ # ===== RAZORPAY FUNCTIONS =====
141
  def create_razorpay_order(amount: int):
142
  """Create a Razorpay order"""
143
  try:
 
155
  return order
156
  except Exception as e:
157
  logger.error(f"Failed to create Razorpay order: {str(e)}")
158
+ raise HTTPException(status_code=500, detail=f"Failed to create order: {str(e)}")
159
+
160
+ def verify_payment_signature(order_id: str, payment_id: str, signature: str):
161
  """Verify Razorpay payment signature"""
162
  try:
163
  if not razorpay_client:
 
175
  return False
176
  except Exception as e:
177
  logger.error(f"Error verifying payment signature: {str(e)}")
178
+ raise HTTPException(status_code=500, detail=f"Verification error: {str(e)}")
179
+
180
+ # ===== MAIN PROCESSING =====
181
  async def generate_image(images: List[bytes], prompt: str, user_id: Optional[str] = None):
182
  """Handle complete image generation workflow"""
183
  # Validate images
184
  for img_content in images:
185
  if img_content:
186
+ validate_image(img_content)
 
 
 
 
 
 
 
 
 
 
187
 
188
+ # Convert bytes to PIL Images
189
+ pil_images = []
190
+ for img_content in images:
191
+ try:
192
+ img = Image.open(BytesIO(img_content))
193
+ if img.mode == "RGBA":
194
+ img = img.convert("RGBA")
195
+ pil_images.append(img)
196
+ except Exception as e:
197
+ logger.error(f"Image conversion failed: {str(e)}")
198
+ raise HTTPException(status_code=400, detail=f"Image conversion failed: {str(e)}")
199
 
200
+ if len(pil_images) < 1:
201
+ raise HTTPException(status_code=400, detail="At least one image required")
202
+
203
+ # Check user premium status if Supabase is configured
204
+ if user_id and supabase:
205
+ try:
206
+ user_data = supabase.table("users").select("is_premium").eq("user_id", user_id).execute()
207
+ if not user_data.data or not user_data.data[0].get("is_premium"):
208
+ raise HTTPException(status_code=403, detail="Premium subscription required")
209
+ except Exception as e:
210
+ logger.error(f"Supabase user check failed: {str(e)}")
211
+ raise HTTPException(status_code=500, detail=f"User verification failed: {str(e)}")
212
 
213
+ # Generate image using Gemini API
214
+ image_path, text_response = generate_gemini_image(pil_images, prompt)
215
 
216
+ if image_path:
217
+ return image_path
218
+ else:
219
+ raise HTTPException(status_code=500, detail=f"Image generation failed: {text_response or 'Unknown error'}")
220
+
221
+ # ===== API ENDPOINTS =====
222
  @app.post("/generate")
223
  async def generate_image_endpoint(
224
  prompt: str = Form(...),
 
230
  if len(images) < 1:
231
  raise HTTPException(status_code=400, detail="At least one image required")
232
  if len(images) > 4:
233
+ raise HTTPException(status_code=400, detail="Maximum 4 images allowed")
234
+ image_contents = [await image.read() for image in images]
235
+ output_path = await generate_image(image_contents, prompt, user_id)
236
+
237
+ return FileResponse(
238
+ path=output_path,
239
+ media_type="image/png",
240
+ filename=f"gemini_output_{Path(output_path).stem}.png"
241
+ )
242
+ except HTTPException as e:
243
+ raise
244
+ except Exception as e:
245
+ logger.error(f"Error in /generate: {str(e)}")
246
+ raise HTTPException(status_code=500, detail=str(e))
247
+
248
+ @app.post("/create-razorpay-order")
249
  async def create_order_endpoint(
250
  request: Request,
251
  amount: Optional[int] = Form(None),
252
  body: Optional[CreateOrderRequest] = None
253
  ):
254
  """Create a Razorpay order (supports form-data and JSON)"""
255
+ logger.info("Received create order request")
256
+ try:
257
+ if not razorpay_client:
258
+ raise HTTPException(status_code=500, detail="Razorpay configuration missing")
259
+
260
+ # Handle JSON body if provided
261
+ if body and body.amount:
262
+ amount = body.amount
263
+ elif not amount:
264
+ try:
265
+ json_body = await request.json()
266
+ amount = json_body.get('amount')
267
+ except:
268
+ pass
269
+
270
+ if not amount or amount <= 0:
271
+ raise HTTPException(status_code=422, detail="Missing or invalid 'amount' parameter")
272
+
273
+ logger.info(f"Creating order with amount: {amount}")
274
+ order = create_razorpay_order(amount)
275
+
276
+ response_data = {
277
+ "id": order["id"],
278
+ "amount": order["amount"],
279
+ "currency": "INR",
280
+ "key_id": RAZORPAY_KEY_ID
281
+ }
282
+
283
+ logger.info(f"Order created successfully: {order['id']}")
284
+ return JSONResponse(content=response_data)
285
+
286
+ except HTTPException:
287
+ raise
288
+ except Exception as e:
289
+ logger.error(f"Error creating order: {str(e)}")
290
+ raise HTTPException(status_code=500, detail=f"Failed to create order: {str(e)}")
291
+
292
+ @app.post("/verify-razorpay-payment")
293
  async def verify_payment_endpoint(
294
  request: Request,
295
  razorpay_order_id: Optional[str] = Form(None),
 
299
  body: Optional[VerifyPaymentRequest] = None
300
  ):
301
  """Verify Razorpay payment signature (supports form-data and JSON)"""
302
+ logger.info("Received payment verification request")
303
+ try:
304
+ # Handle JSON body if provided
305
+ if body:
306
+ razorpay_order_id = razorpay_order_id or body.razorpay_order_id
307
+ razorpay_payment_id = razorpay_payment_id or body.razorpay_payment_id
308
+ razorpay_signature = razorpay_signature or body.razorpay_signature
309
+ user_id = user_id or body.user_id
310
+ else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  try:
312
+ json_body = await request.json()
313
+ razorpay_order_id = razorpay_order_id or json_body.get('razorpay_order_id')
314
+ razorpay_payment_id = razorpay_payment_id or json_body.get('razorpay_payment_id')
315
+ razorpay_signature = razorpay_signature or json_body.get('razorpay_signature')
316
+ user_id = user_id or json_body.get('user_id')
317
+ except:
318
+ pass
319
+
320
+ # Validate required fields
321
+ if not all([razorpay_order_id, razorpay_payment_id, razorpay_signature]):
322
+ missing_fields = []
323
+ if not razorpay_order_id: missing_fields.append("razorpay_order_id")
324
+ if not razorpay_payment_id: missing_fields.append("razorpay_payment_id")
325
+ if not razorpay_signature: missing_fields.append("razorpay_signature")
326
+
327
+ logger.error(f"Missing required fields: {missing_fields}")
328
+ raise HTTPException(
329
+ status_code=422,
330
+ detail=f"Missing required fields: {', '.join(missing_fields)}"
331
+ )
332
+
333
+ logger.info(f"Verifying payment for order_id: {razorpay_order_id}")
334
+ is_valid = verify_payment_signature(razorpay_order_id, razorpay_payment_id, razorpay_signature)
335
 
336
+ if is_valid:
337
+ if user_id and supabase:
338
+ logger.info(f"Updating Supabase for user_id: {user_id}")
339
+ try:
340
+ supabase.table("users").update({"is_premium": True}).eq("user_id", user_id).execute()
341
+ logger.info(f"Successfully updated premium status for user: {user_id}")
342
+ except Exception as e:
343
+ logger.error(f"Failed to update Supabase: {str(e)}")
344
+
345
+ return JSONResponse(content={"success": True, "message": "Payment verified successfully"})
346
+ else:
347
+ logger.warning(f"Payment verification failed for order: {razorpay_order_id}")
348
+ return JSONResponse(content={"success": False, "message": "Payment verification failed"}, status_code=400)
349
+
350
+ except HTTPException:
351
+ raise
352
+ except Exception as e:
353
+ logger.error(f"Error verifying payment: {str(e)}")
354
+ raise HTTPException(status_code=500, detail=f"Verification error: {str(e)}")
355
+
356
+ @app.get("/")
357
  async def index():
358
  return {
359
  "status": "Gemini Image Editing API with Razorpay is running",
 
362
  "create_order": "POST /create-razorpay-order",
363
  "verify_payment": "POST /verify-razorpay-payment"
364
  }
365
+ }
366
+
367
+ @app.get("/health")
368
  async def health_check():
369
  return {
370
  "status": "healthy",
371
  "razorpay_configured": bool(RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET),
372
  "supabase_configured": bool(SUPABASE_URL and SUPABASE_KEY),
373
  "gemini_configured": bool(GEMINI_API_KEY)
374
+ }
375
+
376
+ if __name__ == "__main__":
377
  import uvicorn
378
  uvicorn.run(app, host="0.0.0.0", port=7860)