AkashKumarave commited on
Commit
ce15480
·
verified ·
1 Parent(s): 18678c2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +165 -244
app.py CHANGED
@@ -17,16 +17,10 @@ from typing import Optional
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,45 +34,27 @@ app.add_middleware(
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,18 +62,14 @@ def generate_jwt_token():
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,59 +80,31 @@ def validate_image(image_content: bytes):
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 and resize to 1024x1024 pixels with aspect ratio preservation"""
115
  try:
116
  contents = images + [prompt]
117
- response = genai.GenerativeModel(GEMINI_MODEL).generate_content(contents)
118
-
119
- text_response = ""
120
- image_path = None
121
-
122
- for part in response.candidates[0].content.parts:
123
- if part.text:
124
- text_response += part.text + "\n"
125
- elif hasattr(part, 'inline_data') and part.inline_data:
126
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
127
- temp_path = tmp.name
128
- generated_image = Image.open(BytesIO(part.inline_data.data))
129
-
130
- # Preserve aspect ratio by padding to 1024x1024
131
- original_width, original_height = generated_image.size
132
- target_size = 1024
133
- ratio = min(target_size / original_width, target_size / original_height)
134
- new_width = int(original_width * ratio)
135
- new_height = int(original_height * ratio)
136
-
137
- # Resize while preserving aspect ratio
138
- generated_image = generated_image.resize((new_width, new_height), Image.LANCZOS)
139
-
140
- # Create a new 1024x1024 canvas with black background
141
- new_image = Image.new('RGB', (target_size, target_size), (0, 0, 0))
142
- # Paste the resized image in the center
143
- offset = ((target_size - new_width) // 2, (target_size - new_height) // 2)
144
- new_image.paste(generated_image, offset)
145
-
146
- # Verify dimensions
147
- if new_image.size != (1024, 1024):
148
- logger.error(f"Output image dimensions {new_image.size} do not match expected 1024x1024")
149
- raise HTTPException(status_code=500, detail="Failed to create 1024x1024 image")
150
 
151
- new_image.save(temp_path, format="PNG")
152
- image_path = temp_path
153
- logger.info(f"Generated and padded image to 1024x1024 saved to: {temp_path} with prompt: {prompt}")
154
-
155
- if image_path:
156
- return image_path, ""
157
- else:
158
- return None, text_response.strip()
159
- except Exception as e:
160
- logger.error(f"Gemini API error: {str(e)}")
161
- raise HTTPException(status_code=500, detail=f"Gemini API error: {str(e)}")
162
-
163
- # ===== RAZORPAY FUNCTIONS =====
164
  def create_razorpay_order(amount: int):
165
  """Create a Razorpay order"""
166
  try:
@@ -178,9 +122,7 @@ def create_razorpay_order(amount: int):
178
  return order
179
  except Exception as e:
180
  logger.error(f"Failed to create Razorpay order: {str(e)}")
181
- raise HTTPException(status_code=500, detail=f"Failed to create order: {str(e)}")
182
-
183
- def verify_payment_signature(order_id: str, payment_id: str, signature: str):
184
  """Verify Razorpay payment signature"""
185
  try:
186
  if not razorpay_client:
@@ -198,50 +140,44 @@ def verify_payment_signature(order_id: str, payment_id: str, signature: str):
198
  return False
199
  except Exception as e:
200
  logger.error(f"Error verifying payment signature: {str(e)}")
201
- raise HTTPException(status_code=500, detail=f"Verification error: {str(e)}")
202
-
203
- # ===== MAIN PROCESSING =====
204
  async def generate_image(images: List[bytes], prompt: str, user_id: Optional[str] = None):
205
  """Handle complete image generation workflow"""
206
  # Validate images
207
  for img_content in images:
208
  if img_content:
209
- validate_image(img_content)
210
-
211
- # Convert bytes to PIL Images
212
- pil_images = []
213
- for img_content in images:
214
- try:
215
- img = Image.open(BytesIO(img_content))
216
- if img.mode == "RGBA":
217
- img = img.convert("RGBA")
218
- pil_images.append(img)
219
- except Exception as e:
220
- logger.error(f"Image conversion failed: {str(e)}")
221
- raise HTTPException(status_code=400, detail=f"Image conversion failed: {str(e)}")
222
 
223
- if len(pil_images) < 1:
224
- raise HTTPException(status_code=400, detail="At least one image required")
225
 
226
- # Check user premium status if Supabase is configured
227
- if user_id and supabase:
228
- try:
229
- user_data = supabase.table("users").select("is_premium").eq("user_id", user_id).execute()
230
- if not user_data.data or not user_data.data[0].get("is_premium"):
231
- raise HTTPException(status_code=403, detail="Premium subscription required")
232
- except Exception as e:
233
- logger.error(f"Supabase user check failed: {str(e)}")
234
- raise HTTPException(status_code=500, detail=f"User verification failed: {str(e)}")
235
-
236
- # Generate image using Gemini API
237
- image_path, text_response = generate_gemini_image(pil_images, prompt)
238
 
239
- if image_path:
240
- return image_path
241
- else:
242
- raise HTTPException(status_code=500, detail=f"Image generation failed: {text_response or 'Unknown error'}")
243
 
244
- # ===== API ENDPOINTS =====
 
 
 
245
  @app.post("/generate")
246
  async def generate_image_endpoint(
247
  prompt: str = Form(...),
@@ -253,68 +189,60 @@ async def generate_image_endpoint(
253
  if len(images) < 1:
254
  raise HTTPException(status_code=400, detail="At least one image required")
255
  if len(images) > 4:
256
- raise HTTPException(status_code=400, detail="Maximum 4 images allowed")
257
-
258
- image_contents = [await image.read() for image in images]
259
- output_path = await generate_image(image_contents, prompt, user_id)
260
-
261
- return FileResponse(
262
- path=output_path,
263
- media_type="image/png",
264
- filename=f"gemini_output_{Path(output_path).stem}.png"
265
- )
266
- except HTTPException as e:
267
- raise
268
- except Exception as e:
269
- logger.error(f"Error in /generate: {str(e)}")
270
- raise HTTPException(status_code=500, detail=str(e))
271
-
272
- @app.post("/create-razorpay-order")
273
  async def create_order_endpoint(
274
  request: Request,
275
  amount: Optional[int] = Form(None),
276
  body: Optional[CreateOrderRequest] = None
277
  ):
278
  """Create a Razorpay order (supports form-data and JSON)"""
279
- logger.info("Received create order request")
 
 
280
 
281
- try:
282
- if not razorpay_client:
283
- raise HTTPException(status_code=500, detail="Razorpay configuration missing")
284
-
285
- # Handle JSON body if provided
286
- if body and body.amount:
287
- amount = body.amount
288
- elif not amount:
289
- try:
290
- json_body = await request.json()
291
- amount = json_body.get('amount')
292
- except:
293
- pass
294
-
295
- if not amount or amount <= 0:
296
- raise HTTPException(status_code=422, detail="Missing or invalid 'amount' parameter")
297
-
298
- logger.info(f"Creating order with amount: {amount}")
299
- order = create_razorpay_order(amount)
300
-
301
- response_data = {
302
- "id": order["id"],
303
- "amount": order["amount"],
304
- "currency": "INR",
305
- "key_id": RAZORPAY_KEY_ID
306
- }
307
-
308
- logger.info(f"Order created successfully: {order['id']}")
309
- return JSONResponse(content=response_data)
310
-
311
- except HTTPException:
312
- raise
313
- except Exception as e:
314
- logger.error(f"Error creating order: {str(e)}")
315
- raise HTTPException(status_code=500, detail=f"Failed to create order: {str(e)}")
316
 
317
- @app.post("/verify-razorpay-payment")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
  async def verify_payment_endpoint(
319
  request: Request,
320
  razorpay_order_id: Optional[str] = Form(None),
@@ -324,62 +252,58 @@ async def verify_payment_endpoint(
324
  body: Optional[VerifyPaymentRequest] = None
325
  ):
326
  """Verify Razorpay payment signature (supports form-data and JSON)"""
327
- logger.info("Received payment verification request")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
 
329
- try:
330
- # Handle JSON body if provided
331
- if body:
332
- razorpay_order_id = razorpay_order_id or body.razorpay_order_id
333
- razorpay_payment_id = razorpay_payment_id or body.razorpay_payment_id
334
- razorpay_signature = razorpay_signature or body.razorpay_signature
335
- user_id = user_id or body.user_id
336
- else:
337
  try:
338
- json_body = await request.json()
339
- razorpay_order_id = razorpay_order_id or json_body.get('razorpay_order_id')
340
- razorpay_payment_id = razorpay_payment_id or json_body.get('razorpay_payment_id')
341
- razorpay_signature = razorpay_signature or json_body.get('razorpay_signature')
342
- user_id = user_id or json_body.get('user_id')
343
- except:
344
- pass
345
-
346
- # Validate required fields
347
- if not all([razorpay_order_id, razorpay_payment_id, razorpay_signature]):
348
- missing_fields = []
349
- if not razorpay_order_id: missing_fields.append("razorpay_order_id")
350
- if not razorpay_payment_id: missing_fields.append("razorpay_payment_id")
351
- if not razorpay_signature: missing_fields.append("razorpay_signature")
352
-
353
- logger.error(f"Missing required fields: {missing_fields}")
354
- raise HTTPException(
355
- status_code=422,
356
- detail=f"Missing required fields: {', '.join(missing_fields)}"
357
- )
358
-
359
- logger.info(f"Verifying payment for order_id: {razorpay_order_id}")
360
- is_valid = verify_payment_signature(razorpay_order_id, razorpay_payment_id, razorpay_signature)
361
 
362
- if is_valid:
363
- if user_id and supabase:
364
- logger.info(f"Updating Supabase for user_id: {user_id}")
365
- try:
366
- supabase.table("users").update({"is_premium": True}).eq("user_id", user_id).execute()
367
- logger.info(f"Successfully updated premium status for user: {user_id}")
368
- except Exception as e:
369
- logger.error(f"Failed to update Supabase: {str(e)}")
370
-
371
- return JSONResponse(content={"success": True, "message": "Payment verified successfully"})
372
- else:
373
- logger.warning(f"Payment verification failed for order: {razorpay_order_id}")
374
- return JSONResponse(content={"success": False, "message": "Payment verification failed"}, status_code=400)
375
-
376
- except HTTPException:
377
- raise
378
- except Exception as e:
379
- logger.error(f"Error verifying payment: {str(e)}")
380
- raise HTTPException(status_code=500, detail=f"Verification error: {str(e)}")
381
-
382
- @app.get("/")
383
  async def index():
384
  return {
385
  "status": "Gemini Image Editing API with Razorpay is running",
@@ -388,17 +312,14 @@ async def index():
388
  "create_order": "POST /create-razorpay-order",
389
  "verify_payment": "POST /verify-razorpay-payment"
390
  }
391
- }
392
-
393
- @app.get("/health")
394
  async def health_check():
395
  return {
396
  "status": "healthy",
397
  "razorpay_configured": bool(RAZORPAY_KEY_ID and RAZORPAY_KEY_SECRET),
398
  "supabase_configured": bool(SUPABASE_URL and SUPABASE_KEY),
399
  "gemini_configured": bool(GEMINI_API_KEY)
400
- }
401
-
402
- if __name__ == "__main__":
403
  import uvicorn
404
- 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# 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
  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
  "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
  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
  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
  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
  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
  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
  "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) here make a change the generated image needs to be in 1024 x 1024 pixels
325
+