LogicGoInfotechSpaces commited on
Commit
cd5a36a
·
1 Parent(s): ca6fc55

Fix Gemini blocked content handling and improve MongoDB status endpoint

Browse files

- Add explicit finish_reason checking for blocked content (17) and safety blocks (2)
- Add generation_config to request image/png response explicitly
- Better error messages for blocked content
- Improve /mongo-status endpoint to show recent 5 logs with full details
- This will help diagnose both Gemini API issues and verify MongoDB storage

Files changed (2) hide show
  1. api/main.py +22 -3
  2. src/core.py +36 -8
api/main.py CHANGED
@@ -491,9 +491,27 @@ def mongo_status(_: None = Depends(bearer_auth)) -> Dict[str, object]:
491
  try:
492
  count = mongo_logs.count_documents({})
493
  status["api_logs_count"] = count
494
- # Get latest document
495
- latest = mongo_logs.find_one(sort=[("timestamp", -1)])
496
- if latest:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
497
  status["latest_log"] = {
498
  "_id": str(latest.get("_id")),
499
  "output_id": latest.get("output_id"),
@@ -502,6 +520,7 @@ def mongo_status(_: None = Depends(bearer_auth)) -> Dict[str, object]:
502
  }
503
  except Exception as err:
504
  status["api_logs_error"] = str(err)
 
505
 
506
  return status
507
 
 
491
  try:
492
  count = mongo_logs.count_documents({})
493
  status["api_logs_count"] = count
494
+ # Get latest 5 documents
495
+ latest_docs = list(mongo_logs.find().sort("timestamp", -1).limit(5))
496
+ status["recent_logs"] = []
497
+ for doc in latest_docs:
498
+ doc_dict = {
499
+ "_id": str(doc.get("_id")),
500
+ "output_id": doc.get("output_id"),
501
+ "status": doc.get("status"),
502
+ "timestamp": doc.get("timestamp").isoformat() if isinstance(doc.get("timestamp"), datetime) else str(doc.get("timestamp")),
503
+ }
504
+ if "input_image_id" in doc:
505
+ doc_dict["input_image_id"] = doc.get("input_image_id")
506
+ if "input_mask_id" in doc:
507
+ doc_dict["input_mask_id"] = doc.get("input_mask_id")
508
+ if "error" in doc:
509
+ doc_dict["error"] = doc.get("error")
510
+ status["recent_logs"].append(doc_dict)
511
+
512
+ # Get latest document for backward compatibility
513
+ if latest_docs:
514
+ latest = latest_docs[0]
515
  status["latest_log"] = {
516
  "_id": str(latest.get("_id")),
517
  "output_id": latest.get("output_id"),
 
520
  }
521
  except Exception as err:
522
  status["api_logs_error"] = str(err)
523
+ log.error("Error querying MongoDB: %s", err, exc_info=True)
524
 
525
  return status
526
 
src/core.py CHANGED
@@ -163,21 +163,46 @@ def _call_gemini_edit(
163
  {"mime_type": "image/png", "data": mask_bytes},
164
  ]
165
 
166
- response = model.generate_content(content, stream=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
167
 
168
  output_img: Image.Image | None = None
169
 
170
- # Debug: log response structure
171
- log.debug("Gemini response type: %s", type(response))
172
- log.debug("Gemini response has candidates: %s", hasattr(response, "candidates"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
  # Extract first image from response parts
175
  try:
176
- candidates = getattr(response, "candidates", [])
177
  log.debug("Number of candidates: %d", len(candidates))
178
 
179
  for idx, candidate in enumerate(candidates):
180
- log.debug("Candidate %d type: %s", idx, type(candidate))
181
  parts = getattr(candidate, "content", None)
182
  if not parts:
183
  log.debug("Candidate %d has no content", idx)
@@ -189,7 +214,6 @@ def _call_gemini_edit(
189
  log.debug("Candidate %d has %d parts", idx, len(response_parts))
190
 
191
  for part_idx, part in enumerate(response_parts):
192
- log.debug("Part %d type: %s", part_idx, type(part))
193
  inline = getattr(part, "inline_data", None)
194
  if inline:
195
  log.debug("Part %d has inline_data, mime_type: %s", part_idx, getattr(inline, "mime_type", None))
@@ -214,11 +238,15 @@ def _call_gemini_edit(
214
  # Log full response for debugging
215
  try:
216
  response_text = str(response)
217
- log.error("Gemini generate_content returned no image. Full response (first 500 chars): %s", response_text[:500])
218
  # Try to extract any error messages
219
  if hasattr(response, "prompt_feedback"):
220
  feedback = response.prompt_feedback
221
  log.error("Prompt feedback: %s", feedback)
 
 
 
 
222
  except Exception:
223
  pass
224
  raise RuntimeError("Gemini generate_content returned no image. Check logs for details.")
 
163
  {"mime_type": "image/png", "data": mask_bytes},
164
  ]
165
 
166
+ # Request image response explicitly
167
+ generation_config = {
168
+ "response_mime_type": "image/png",
169
+ }
170
+
171
+ try:
172
+ response = model.generate_content(
173
+ content,
174
+ generation_config=generation_config,
175
+ stream=False
176
+ )
177
+ except Exception as gen_err:
178
+ log.error("Gemini generate_content raised exception: %s", gen_err, exc_info=True)
179
+ raise RuntimeError(f"Gemini API error: {gen_err}")
180
 
181
  output_img: Image.Image | None = None
182
 
183
+ # Check for blocked content or errors
184
+ candidates = getattr(response, "candidates", [])
185
+ if not candidates:
186
+ log.error("Gemini returned no candidates")
187
+ raise RuntimeError("Gemini API returned no candidates. The request may have been blocked.")
188
+
189
+ # Check finish_reason for blocked content
190
+ for idx, candidate in enumerate(candidates):
191
+ finish_reason = getattr(candidate, "finish_reason", None)
192
+ if finish_reason:
193
+ # finish_reason values: 0=STOP, 1=MAX_TOKENS, 2=SAFETY, 3=RECITATION, 4=OTHER, 17=BLOCKED
194
+ if finish_reason == 17 or finish_reason == 2:
195
+ safety_ratings = getattr(candidate, "safety_ratings", [])
196
+ log.error("Gemini blocked the request. Finish reason: %s, Safety ratings: %s", finish_reason, safety_ratings)
197
+ raise RuntimeError(f"Gemini API blocked the content (finish_reason={finish_reason}). The image may violate safety policies.")
198
+ elif finish_reason != 0: # 0 = STOP (normal completion)
199
+ log.warning("Gemini finished with non-zero reason: %s", finish_reason)
200
 
201
  # Extract first image from response parts
202
  try:
 
203
  log.debug("Number of candidates: %d", len(candidates))
204
 
205
  for idx, candidate in enumerate(candidates):
 
206
  parts = getattr(candidate, "content", None)
207
  if not parts:
208
  log.debug("Candidate %d has no content", idx)
 
214
  log.debug("Candidate %d has %d parts", idx, len(response_parts))
215
 
216
  for part_idx, part in enumerate(response_parts):
 
217
  inline = getattr(part, "inline_data", None)
218
  if inline:
219
  log.debug("Part %d has inline_data, mime_type: %s", part_idx, getattr(inline, "mime_type", None))
 
238
  # Log full response for debugging
239
  try:
240
  response_text = str(response)
241
+ log.error("Gemini generate_content returned no image. Full response (first 1000 chars): %s", response_text[:1000])
242
  # Try to extract any error messages
243
  if hasattr(response, "prompt_feedback"):
244
  feedback = response.prompt_feedback
245
  log.error("Prompt feedback: %s", feedback)
246
+ # Check candidates for finish reasons
247
+ for idx, candidate in enumerate(candidates):
248
+ finish_reason = getattr(candidate, "finish_reason", None)
249
+ log.error("Candidate %d finish_reason: %s", idx, finish_reason)
250
  except Exception:
251
  pass
252
  raise RuntimeError("Gemini generate_content returned no image. Check logs for details.")