rairo commited on
Commit
1fa4bd8
·
verified ·
1 Parent(s): a41baa0

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +53 -38
main.py CHANGED
@@ -240,38 +240,43 @@ def generate_master_blueprint_task(subject, flattened_data, uid, epiphany_id):
240
  return None
241
 
242
  #Prepare hi fidelity images to proper scale
243
- def prepare_vision_bytes(image_bytes, max_size_mb=9.5):
244
  """
245
- Surgically compresses/resizes image bytes to stay under the 10MB API limit.
246
- Target: 9.5MB to allow a safe margin for the rest of the request payload.
247
  """
248
- size_mb = len(image_bytes) / (1024 * 1024)
249
- if size_mb <= max_size_mb:
250
- return image_bytes
251
-
252
- logger.info(f"Vision Scaler: Image is {size_mb:.2f}MB. Optimizing for API...")
253
  try:
254
  img = Image.open(io.BytesIO(image_bytes))
255
 
256
- # Target resolution: 2048px on the long side is optimal for Gemini detection
257
- max_dim = 2048
 
 
 
 
 
258
  w, h = img.size
259
- if max(w, h) > max_dim:
260
- scale = max_dim / max(w, h)
261
- img = img.resize((int(w * scale), int(h * scale)), Image.Resampling.LANCZOS)
262
-
263
- output = io.BytesIO()
264
- # Convert to RGB (removes Alpha channel if present to save space)
265
- # Save as optimized JPEG at 85% quality
266
- img.convert('RGB').save(output, format="JPEG", quality=85, optimize=True)
267
- new_bytes = output.getvalue()
 
 
 
 
 
 
 
268
 
269
- new_size_mb = len(new_bytes)/(1024*1024)
270
- logger.info(f"Vision Scaler: Optimization complete. New size: {new_size_mb:.2f}MB")
271
- return new_bytes
272
  except Exception as e:
273
- logger.error(f"Vision Scaler Failure: {e}")
274
- return image_bytes # Fallback to original and hope for the best
 
275
  # -----------------------------------------------------------------------------
276
  # 4. PRIMARY ENDPOINTS: GENERATE & THEIA SWEEP
277
  # -----------------------------------------------------------------------------
@@ -305,8 +310,11 @@ def generate_epiphany():
305
  return jsonify({'error': 'Visual image is required.'}), 400
306
 
307
  image_file = request.files['image']
308
- image_bytes = image_file.read()
 
 
309
  pil_image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
 
310
 
311
  try:
312
  # Step 1: Accurate Identification
@@ -410,7 +418,7 @@ def generate_epiphany():
410
 
411
  @app.route('/api/epiphany/theia', methods=['POST'])
412
  def theia_sweep():
413
- """Standalone Theia Mode: Bounding Box Annotations with Vision Scaling."""
414
  logger.info(">>> THEIA SWEEP INITIATED")
415
  uid = verify_token(request.headers.get('Authorization'))
416
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
@@ -418,27 +426,32 @@ def theia_sweep():
418
  epiphany_id = request.form.get('epiphanyId')
419
  if not epiphany_id: return jsonify({'error': 'epiphanyId is required.'}), 400
420
 
421
- # 1. Check if annotations already exist to prevent double-charging
422
  epiphany_ref = db_ref.child(f'epiphanies/{epiphany_id}')
423
  existing_data = epiphany_ref.get() or {}
424
  if 'annotations' in existing_data:
425
- return jsonify({"annotations": existing_data['annotations'], "status": "already_stored"}), 200
 
426
 
427
- # 2. Check Sparks
428
  user_ref = db_ref.child(f'users/{uid}')
429
  user_data = user_ref.get() or {}
430
  if user_data.get('credits', 0) < 4:
431
  return jsonify({'error': 'Need 4 Sparks for a Theia Sweep.'}), 402
432
 
433
- # --- IMAGE PRE-PROCESSING ---
434
  if 'image' not in request.files:
435
  return jsonify({'error': 'image file is required.'}), 400
436
 
437
  image_file = request.files['image']
438
  raw_bytes = image_file.read()
439
 
440
- # Surgical Fix: Stay under 10MB limit
441
- image_bytes = prepare_vision_bytes(raw_bytes)
 
 
 
 
442
 
443
  subject = existing_data.get('subject', 'Complex System')
444
 
@@ -453,7 +466,7 @@ def theia_sweep():
453
  """
454
 
455
  try:
456
- pil_image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
457
  res = client.models.generate_content(
458
  model=ATHENA_FLASH,
459
  contents=[sweep_prompt, pil_image],
@@ -464,19 +477,21 @@ def theia_sweep():
464
  )
465
 
466
  raw_json = res.text.strip()
467
- # Use helper to strip fences if present
468
- if "```" in raw_json:
469
- raw_json = _strip_json_fences(raw_json)
 
470
 
471
  annotations = json.loads(raw_json)
472
 
473
- # 3. STORE IN DB & CHARGE
474
  epiphany_ref.update({"annotations": annotations})
475
  user_ref.update({'credits': user_data.get('credits', 0) - 4})
476
 
 
477
  return jsonify({"annotations": annotations}), 200
478
  except Exception as e:
479
- logger.error(f"Theia Sweep Error: {e}")
480
  return jsonify({'error': str(e)}), 500
481
 
482
  @app.route('/api/epiphany/deep-dive', methods=['POST'])
 
240
  return None
241
 
242
  #Prepare hi fidelity images to proper scale
243
+ def prepare_vision_image(image_bytes):
244
  """
245
+ Resizes and optimizes the image to ensure it is under the 10MB Gemini limit.
246
+ Returns a PIL Image object ready for the SDK.
247
  """
 
 
 
 
 
248
  try:
249
  img = Image.open(io.BytesIO(image_bytes))
250
 
251
+ # 1. Convert to RGB to strip Alpha channels (saves 25% space)
252
+ if img.mode != 'RGB':
253
+ img = img.convert('RGB')
254
+
255
+ # 2. If the file is huge, reduce the physical resolution.
256
+ # 2000px is more than enough for Athena to see components.
257
+ max_dimension = 2000
258
  w, h = img.size
259
+ if max(w, h) > max_dimension:
260
+ scale = max_dimension / max(w, h)
261
+ new_size = (int(w * scale), int(h * scale))
262
+ img = img.resize(new_size, Image.Resampling.LANCZOS)
263
+ logger.info(f"Theia Vision: Resized from {w}x{h} to {new_size[0]}x{new_size[1]}")
264
+
265
+ # 3. Final Quality Check: If the image is still dense,
266
+ # we do an in-memory compression cycle to strip metadata.
267
+ buffer = io.BytesIO()
268
+ img.save(buffer, format="JPEG", quality=85, optimize=True)
269
+ final_img = Image.open(buffer)
270
+
271
+ final_size = len(buffer.getvalue())
272
+ logger.info(f"Theia Vision: Optimized payload size: {final_size / 1024 / 1024:.2f}MB")
273
+
274
+ return final_img, final_size
275
 
 
 
 
276
  except Exception as e:
277
+ logger.error(f"Theia Vision Scaler Failure: {e}")
278
+ # Fallback to original
279
+ return Image.open(io.BytesIO(image_bytes))
280
  # -----------------------------------------------------------------------------
281
  # 4. PRIMARY ENDPOINTS: GENERATE & THEIA SWEEP
282
  # -----------------------------------------------------------------------------
 
310
  return jsonify({'error': 'Visual image is required.'}), 400
311
 
312
  image_file = request.files['image']
313
+ raw_bytes = image_file.read()
314
+ # THE FIX:
315
+ image_bytes = prepare_vision_bytes(raw_bytes)
316
  pil_image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
317
+
318
 
319
  try:
320
  # Step 1: Accurate Identification
 
418
 
419
  @app.route('/api/epiphany/theia', methods=['POST'])
420
  def theia_sweep():
421
+ """Standalone Theia Mode: Bounding Box Annotations with Automatic Image Scaling."""
422
  logger.info(">>> THEIA SWEEP INITIATED")
423
  uid = verify_token(request.headers.get('Authorization'))
424
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
 
426
  epiphany_id = request.form.get('epiphanyId')
427
  if not epiphany_id: return jsonify({'error': 'epiphanyId is required.'}), 400
428
 
429
+ # 1. Cache Check
430
  epiphany_ref = db_ref.child(f'epiphanies/{epiphany_id}')
431
  existing_data = epiphany_ref.get() or {}
432
  if 'annotations' in existing_data:
433
+ logger.info(f"Theia: Returning cached annotations for {epiphany_id}")
434
+ return jsonify({"annotations": existing_data['annotations'], "status": "cached"}), 200
435
 
436
+ # 2. Credit Check
437
  user_ref = db_ref.child(f'users/{uid}')
438
  user_data = user_ref.get() or {}
439
  if user_data.get('credits', 0) < 4:
440
  return jsonify({'error': 'Need 4 Sparks for a Theia Sweep.'}), 402
441
 
442
+ # 3. Image Handling with Scaler
443
  if 'image' not in request.files:
444
  return jsonify({'error': 'image file is required.'}), 400
445
 
446
  image_file = request.files['image']
447
  raw_bytes = image_file.read()
448
 
449
+ # --- THE CRITICAL FIX ---
450
+ # We process the raw bytes into a scaled/optimized PIL Image
451
+
452
+ pil_image, scaled_size = prepare_vision_image(raw_bytes)
453
+
454
+ logger.info(f"Theia Post-Scale Size: {scaled_size / (1024 * 1024):.2f} MB")
455
 
456
  subject = existing_data.get('subject', 'Complex System')
457
 
 
466
  """
467
 
468
  try:
469
+ # Pass the optimized PIL image to the SDK
470
  res = client.models.generate_content(
471
  model=ATHENA_FLASH,
472
  contents=[sweep_prompt, pil_image],
 
477
  )
478
 
479
  raw_json = res.text.strip()
480
+ if "```json" in raw_json:
481
+ raw_json = re.search(r'```json\n(.*?)\n```', raw_json, re.DOTALL).group(1)
482
+ elif "```" in raw_json:
483
+ raw_json = raw_json.replace("```", "").strip()
484
 
485
  annotations = json.loads(raw_json)
486
 
487
+ # 4. Persistence & Deduction
488
  epiphany_ref.update({"annotations": annotations})
489
  user_ref.update({'credits': user_data.get('credits', 0) - 4})
490
 
491
+ logger.info(f"THEIA SUCCESS: {len(annotations)} annotations found.")
492
  return jsonify({"annotations": annotations}), 200
493
  except Exception as e:
494
+ logger.error(f"Theia Sweep Execution Error: {e}")
495
  return jsonify({'error': str(e)}), 500
496
 
497
  @app.route('/api/epiphany/deep-dive', methods=['POST'])