rairo commited on
Commit
84f8480
·
verified ·
1 Parent(s): 9f73dec

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +227 -129
main.py CHANGED
@@ -47,6 +47,9 @@ try:
47
  firebase_db_url = os.environ.get("Firebase_DB")
48
  firebase_storage_bucket = os.environ.get("Firebase_Storage")
49
 
 
 
 
50
  cred = credentials.Certificate(credentials_json)
51
  firebase_admin.initialize_app(cred, {
52
  'databaseURL': firebase_db_url,
@@ -60,9 +63,9 @@ except Exception as e:
60
  bucket = storage.bucket()
61
  db_ref = db.reference()
62
 
63
- # --- Google GenAI Client Initialization (Gemini 3.0) ---
64
  try:
65
- logger.info("Initializing Google GenAI Client (Gemini 3.0 Ecosystem)...")
66
  api_key = os.environ.get("Gemini")
67
  if not api_key:
68
  raise ValueError("The 'Gemini' API key is not set.")
@@ -77,16 +80,18 @@ except Exception as e:
77
  ATHENA_FLASH = "gemini-3-flash-preview"
78
  ATHENA_PRO = "gemini-3-pro-image-preview"
79
 
80
- # Grounding / External API
81
  WOLFRAM_APP_ID = os.environ.get("WOLFRAM_APP_ID")
82
  OPENALEX_MAILTO = os.environ.get("OPENALEX_MAILTO", "rairo@sozofix.tech")
83
 
84
  # -----------------------------------------------------------------------------
85
- # 2. HELPER FUNCTIONS & GROUNDING
86
  # -----------------------------------------------------------------------------
87
 
88
  def verify_token(auth_header):
 
89
  if not auth_header or not auth_header.startswith('Bearer '):
 
90
  return None
91
  token = auth_header.split('Bearer ')[1]
92
  try:
@@ -97,39 +102,51 @@ def verify_token(auth_header):
97
  return None
98
 
99
  def verify_admin(auth_header):
 
100
  uid = verify_token(auth_header)
101
- if not uid: raise PermissionError('Invalid token')
 
102
  user_data = db_ref.child(f'users/{uid}').get()
103
  if not user_data or not user_data.get('is_admin', False):
 
104
  raise PermissionError('Admin access required')
105
  return uid
106
 
107
  def upload_to_storage(data_bytes, destination_blob_name, content_type):
 
108
  try:
109
  blob = bucket.blob(destination_blob_name)
110
  blob.upload_from_string(data_bytes, content_type=content_type)
111
  blob.make_public()
112
  return blob.public_url
113
  except Exception as e:
114
- logger.error(f"Failed to upload to Firebase Storage: {e}")
115
  return None
116
 
117
  def query_wolfram_alpha(query):
118
- if not WOLFRAM_APP_ID: return "Grounded in physical first principles."
 
 
119
  try:
120
  url = f"http://api.wolframalpha.com/v1/result?appid={WOLFRAM_APP_ID}&i={query}"
121
  response = requests.get(url, timeout=5)
122
- return response.text if response.status_code == 200 else "Constants verifying..."
123
- except: return "Grounding context pending."
 
 
 
 
124
 
125
  # -----------------------------------------------------------------------------
126
  # 3. TITANESS MEDIA ENGINE (CONSOLIDATED MASTER BLUEPRINT + ASYNC AUDIO)
127
  # -----------------------------------------------------------------------------
128
 
129
  def generate_narration_task(text, uid, epiphany_id, layer_name):
130
- """Deepgram Aura-Luna task for Athena's voice."""
131
- if not text: return layer_name, None
 
132
  try:
 
133
  api_key = os.environ.get("DEEPGRAM_API_KEY")
134
  if not api_key: return layer_name, None
135
 
@@ -138,26 +155,33 @@ def generate_narration_task(text, uid, epiphany_id, layer_name):
138
  response = requests.post(DEEPGRAM_URL, headers=headers, data=text.encode('utf-8'))
139
  response.raise_for_status()
140
 
141
- path = f"users/{uid}/epiphanies/{epiphany_id}/narrations/{layer_name}.mp3"
142
- return layer_name, upload_to_storage(response.content, path, 'audio/mpeg')
 
143
  except Exception as e:
144
- logger.error(f"TTS Task Error [{layer_name}]: {e}")
145
  return layer_name, None
146
 
147
  def generate_master_blueprint_task(subject, flattened_data, uid, epiphany_id):
148
- """Nano Banana Pro: Generates ONE consolidated 4K Technical Blueprint schematic."""
149
  try:
150
- logger.info(f"Generating Master Blueprint for: {subject}")
151
- # Build context for the visual
152
- context_str = f"Genesis: {flattened_data.get('genesis', '')[:100]}... Core: {flattened_data.get('scientific_core', '')[:100]}..."
 
 
 
 
 
153
 
154
  prompt = (
155
- f"Generate a single high-fidelity 4K Master Technical Blueprint for '{subject}'. "
156
- f"Layout: A four-quadrant schematic. Zone 1: Genesis (Origins). Zone 2: Scientific Core (The Physics). "
157
- f"Zone 3: Engineering Edge (Design Limits). Zone 4: Cross-Pollination (Future Tech-Tree). "
158
- f"Aesthetic: White-line architectural blueprint on midnight navy background. "
159
- f"Style: Leonardo Da Vinci meets modern 4K engineering software. High scientific accuracy. "
160
- f"Context details: {context_str}"
 
161
  )
162
 
163
  response = client.models.generate_content(
@@ -174,73 +198,77 @@ def generate_master_blueprint_task(subject, flattened_data, uid, epiphany_id):
174
  return upload_to_storage(image_bytes, path, 'image/png')
175
  return None
176
  except Exception as e:
177
- logger.error(f"Master Blueprint Engine Error: {e}")
178
  return None
179
 
180
  # -----------------------------------------------------------------------------
181
- # 4. CORE ENDPOINTS (EPIPHANY GENERATION & THEIA)
182
  # -----------------------------------------------------------------------------
183
 
184
  @app.route('/api/image-proxy', methods=['GET'])
185
  def image_proxy():
 
186
  image_url = request.args.get('url')
187
- if not image_url: return jsonify({'error': 'No URL'}), 400
188
  try:
189
  resp = requests.get(image_url, timeout=10)
190
- return Response(resp.content, content_type=resp.headers['Content-Type'])
191
- except Exception as e: return jsonify({'error': str(e)}), 500
 
192
 
193
  @app.route('/api/epiphany/generate', methods=['POST'])
194
  def generate_epiphany():
195
- logger.info(">>> TITANESS GENERATION INITIATED")
 
196
  uid = verify_token(request.headers.get('Authorization'))
197
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
198
 
199
  user_ref = db_ref.child(f'users/{uid}')
200
- user_data = user_ref.get()
201
 
202
- # 8 Sparks for Synthesis + Feynman Scholar + Consolidated Master Blueprint
203
- if not user_data or user_data.get('credits', 0) < 8:
204
- return jsonify({'error': 'Need 8 Sparks for Full Master Synthesis.'}), 402
205
 
206
  if 'image' not in request.files:
207
- return jsonify({'error': 'Visual input required.'}), 400
208
 
209
  image_file = request.files['image']
210
  image_bytes = image_file.read()
211
  pil_image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
212
 
213
  try:
214
- # Step 1: Precise Identification
215
- id_prompt = "Identify this object or system. Reply with ONLY the name (max 5 words)."
216
- subject = client.models.generate_content(model=ATHENA_FLASH, contents=[id_prompt, pil_image]).text.strip()
217
- logger.info(f"Synthesis Subject: {subject}")
218
-
219
- # Step 2: Synthesis + Universal Scholar Search
220
- physics_fact = query_wolfram_alpha(f"physics laws of {subject}")
 
221
  synthesis_prompt = f"""
222
- Act as Athena. Reveal the first principles of '{subject}' grounded in: {physics_fact}.
223
- Style: Richard Feynman. Simple analogies, profound engineering.
224
 
225
  Tasks:
226
- 1. Search the web (ArXiv, Patents, Journals) for 3 diverse sources about {subject} via Google Search.
227
  2. Create 4 Discovery Layers (genesis, scientific_core, engineering_edge, cross_pollination).
228
- 3. For each research source, provide URL, Title, and a 2-sentence Feynman Summary.
229
 
230
  MANDATORY JSON SCHEMA (FLAT):
231
  {{
232
- "title": "string",
233
- "genesis": "string",
234
- "scientific_core": "string",
235
- "engineering_edge": "string",
236
- "cross_pollination": "string",
237
  "scholar": [
238
- {{"title": "string", "url": "string", "feynman_summary": "string"}}
239
  ]
240
  }}
241
  """
242
 
243
- res = client.models.generate_content(
244
  model=ATHENA_FLASH,
245
  contents=[synthesis_prompt, pil_image],
246
  config=types.GenerateContentConfig(
@@ -249,31 +277,33 @@ def generate_epiphany():
249
  )
250
  )
251
 
252
- # --- DATA FLATTENING SENTINEL ---
253
- raw_json = res.text.strip()
254
- if "```json" in raw_json: raw_json = re.search(r'```json\n(.*?)\n```', raw_json, re.DOTALL).group(1)
 
 
255
  data = json.loads(raw_json)
256
  if isinstance(data, list): data = data[0]
257
-
258
- # Handle nesting variations to prevent KeyErrors
259
  if "epiphany" in data: data = data["epiphany"]
260
  elif "discovery_layers" in data: data = data["discovery_layers"]
261
 
262
- # Ensure all required keys exist (Prevent 500 errors in threads)
263
- required_keys = ['genesis', 'scientific_core', 'engineering_edge', 'cross_pollination']
264
- for k in required_keys:
265
- if k not in data: data[k] = f"First principles of the {k.replace('_', ' ')} are unfolding."
266
 
267
  epiphany_id = str(uuid.uuid4())
268
 
269
- # Step 3: Parallel Media (Titaness Execution)
 
270
  audios = {}
271
  master_blueprint_url = None
272
 
273
  with ThreadPoolExecutor(max_workers=5) as executor:
274
- # 4 Audio Threads
275
- aud_futures = [executor.submit(generate_narration_task, data[l], uid, epiphany_id, l) for l in required_keys]
276
- # 1 Master Blueprint Thread
277
  blu_future = executor.submit(generate_master_blueprint_task, subject, data, uid, epiphany_id)
278
 
279
  for f in aud_futures:
@@ -281,17 +311,17 @@ def generate_epiphany():
281
  audios[k] = v
282
  master_blueprint_url = blu_future.result()
283
 
284
- # Step 4: Storage & Record Persistence
285
- image_url = upload_to_storage(image_bytes, f"users/{uid}/epiphanies/{epiphany_id}/original.jpg", 'image/jpeg')
286
  epiphany_record = {
287
  "epiphanyId": epiphany_id,
288
  "uid": uid,
289
- "title": data.get('title', 'Universal Revelation'),
290
  "subject": subject,
291
  "imageURL": image_url,
292
  "masterBlueprint": master_blueprint_url,
293
  "layers": {
294
- l: {"text": data[l], "audio": audios.get(l)} for l in required_keys
295
  },
296
  "scholar": data.get('scholar', []),
297
  "createdAt": datetime.utcnow().isoformat()
@@ -304,34 +334,53 @@ def generate_epiphany():
304
  return jsonify(epiphany_record), 201
305
 
306
  except Exception as e:
307
- logger.error(f"Global Epiphany Error: {e}\n{traceback.format_exc()}")
308
  return jsonify({'error': str(e)}), 500
309
 
310
  @app.route('/api/epiphany/theia', methods=['POST'])
311
  def theia_sweep():
312
- """Independent Theia Mode: Bounding Boxes + Micro-Epiphanies via Code Execution."""
 
313
  uid = verify_token(request.headers.get('Authorization'))
314
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
 
 
 
 
 
 
 
 
 
 
315
 
 
316
  user_ref = db_ref.child(f'users/{uid}')
317
- if user_ref.get().get('credits', 0) < 4:
318
- return jsonify({'error': 'Need 4 Sparks for Theia Sweep.'}), 402
 
 
 
 
 
319
 
320
- epiphany_id = request.form.get('epiphanyId')
321
  image_file = request.files['image']
 
322
 
323
- context = db_ref.child(f'epiphanies/{epiphany_id}').get() or {}
324
- subject = context.get('subject', 'Complex System')
325
-
326
  sweep_prompt = f"""
327
- Theia Mode Activation: {subject}.
328
- Use Python to spatially deconstruct this image.
329
- Identify every functional component. Return JSON list:
330
- [ {{ "label": "string", "coordinates": [ymin, xmin, ymax, xmax], "micro_epiphany": "20-word Feynman summary" }} ]
 
 
 
 
 
331
  """
332
 
333
  try:
334
- pil_image = Image.open(io.BytesIO(image_file.read())).convert('RGB')
335
  res = client.models.generate_content(
336
  model=ATHENA_FLASH,
337
  contents=[sweep_prompt, pil_image],
@@ -340,62 +389,97 @@ def theia_sweep():
340
  response_mime_type='application/json'
341
  )
342
  )
 
343
  raw_json = res.text.strip()
344
- if "```json" in raw_json: raw_json = re.search(r'```json\n(.*?)\n```', raw_json, re.DOTALL).group(1)
 
 
345
  annotations = json.loads(raw_json)
 
 
346
 
347
- user_ref.update({'credits': user_ref.get().get('credits', 0) - 4})
348
  return jsonify({"annotations": annotations}), 200
349
  except Exception as e:
350
- logger.error(f"Theia Error: {e}")
351
  return jsonify({'error': str(e)}), 500
352
 
353
  @app.route('/api/epiphany/deep-dive', methods=['POST'])
354
  def deep_dive():
 
355
  uid = verify_token(request.headers.get('Authorization'))
356
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
357
- image_file = request.files['image']
 
 
358
  try:
359
- pil_image = Image.open(io.BytesIO(image_file.read())).convert('RGB')
360
  res = client.models.generate_content(
361
  model=ATHENA_FLASH,
362
- contents=["Feynman style: Explain this zoomed-in detail in 50 words.", pil_image]
363
  )
364
- db_ref.child(f'users/{uid}/credits').set(max(0, (db_ref.child(f'users/{uid}/credits').get() or 0) - 1))
 
 
 
 
365
  return jsonify({"analysis": res.text.strip()}), 200
366
- except Exception as e: return jsonify({'error': str(e)}), 500
 
367
 
368
  # -----------------------------------------------------------------------------
369
- # 5. CHIRON & SYSTEM TOOLS
370
  # -----------------------------------------------------------------------------
371
 
372
  @app.route('/api/user/call-briefing', methods=['GET'])
373
  def get_chiron_briefing():
 
374
  uid = verify_token(request.headers.get('Authorization'))
375
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
 
376
  try:
377
- last = db_ref.child('epiphanies').order_by_child('uid').equal_to(uid).limit_to_last(1).get() or {}
378
- ctx = "Exploring new frontiers."
379
- if last:
380
- e = list(last.values())[0]
381
- ctx = f"Subject: {e['subject']}. Recent papers: {e.get('scholar', [])[:1]}"
382
- prompt = f"Prep Chiron (Mentor). Context: {ctx}. 4-sentence brief for Socratic tutoring."
383
- res = client.models.generate_content(model=ATHENA_FLASH, contents=[prompt])
 
 
 
 
384
  return jsonify({"memory_summary": res.text.strip()}), 200
385
- except Exception as e: return jsonify({'error': str(e)}), 500
 
386
 
387
  @app.route('/api/log-call-usage', methods=['POST'])
388
- def log_usage():
 
389
  uid = verify_token(request.headers.get('Authorization'))
390
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
391
- data = request.json
392
- cost = math.ceil(data.get("durationSeconds", 0) / 60) * 3
393
- user_ref = db_ref.child(f'users/{uid}')
394
- new_bal = max(0, (user_ref.get().get('credits', 0) or 0) - cost)
395
- user_ref.update({'credits': new_bal})
396
- if data.get("transcript"):
397
- db_ref.child(f'transcripts/{uid}').push({"text": data["transcript"], "at": datetime.utcnow().isoformat()})
398
- return jsonify({"success": True, "remainingCredits": new_bal})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
  @app.route('/api/admin/dashboard', methods=['GET'])
401
  def admin_dashboard():
@@ -403,30 +487,36 @@ def admin_dashboard():
403
  verify_admin(request.headers.get('Authorization'))
404
  users = db_ref.child('users').get() or {}
405
  epiphanies = db_ref.child('epiphanies').get() or {}
406
- requests = db_ref.child('credit_requests').get() or {}
407
  return jsonify({
408
- "users": len(users),
409
- "epiphanies": len(epiphanies),
410
- "pending_spark_requests": len([r for r in requests.values() if r.get('status') == 'pending'])
411
- })
412
- except Exception as e: return jsonify({'error': str(e)}), 403
 
413
 
414
  @app.route('/api/feedback', methods=['POST'])
415
- def feedback():
416
  uid = verify_token(request.headers.get('Authorization'))
417
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
418
- db_ref.child('feedback').push({"uid": uid, "msg": request.json.get('message'), "at": datetime.utcnow().isoformat()})
419
- return jsonify({"success": True})
 
 
 
420
 
421
  @app.route('/api/user/request-credits', methods=['POST'])
422
  def request_sparks():
423
  uid = verify_token(request.headers.get('Authorization'))
424
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
425
- db_ref.child('credit_requests').push({"uid": uid, "at": datetime.utcnow().isoformat(), "status": "pending"})
426
- return jsonify({"success": True})
 
 
427
 
428
  # -----------------------------------------------------------------------------
429
- # 6. AUTH & PROFILE
430
  # -----------------------------------------------------------------------------
431
 
432
  @app.route('/api/auth/signup', methods=['POST'])
@@ -436,7 +526,10 @@ def signup():
436
  user_ref = db_ref.child(f'users/{uid}')
437
  if not user_ref.get():
438
  data = request.json
439
- user_ref.set({'email': data.get('email'), 'displayName': data.get('displayName', 'Seeker'), 'credits': 30, 'is_admin': False, 'createdAt': datetime.utcnow().isoformat()})
 
 
 
440
  return jsonify({'uid': uid, **user_ref.get()}), 201
441
 
442
  @app.route('/api/auth/social-signin', methods=['POST'])
@@ -444,13 +537,18 @@ def social_signin():
444
  uid = verify_token(request.headers.get('Authorization'))
445
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
446
  user_ref = db_ref.child(f'users/{uid}')
447
- if not user_ref.get():
 
448
  fu = auth.get_user(uid)
449
- user_ref.set({'email': fu.email, 'displayName': fu.display_name or 'Seeker', 'credits': 30, 'is_admin': False, 'createdAt': datetime.utcnow().isoformat()})
450
- return jsonify({'uid': uid, **user_ref.get()}), 200
 
 
 
 
451
 
452
  @app.route('/api/user/profile', methods=['GET'])
453
- def profile():
454
  uid = verify_token(request.headers.get('Authorization'))
455
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
456
  return jsonify(db_ref.child(f'users/{uid}').get())
@@ -463,9 +561,9 @@ def list_epiphanies():
463
  return jsonify(list(res.values()))
464
 
465
  # -----------------------------------------------------------------------------
466
- # 7. MAIN EXECUTION
467
  # -----------------------------------------------------------------------------
468
 
469
  if __name__ == '__main__':
470
- logger.info("Titaness Paradigm Paradigm Backbone Active on 7860...")
471
- app.run(debug=False, host="0.0.0.0", port=7860)
 
47
  firebase_db_url = os.environ.get("Firebase_DB")
48
  firebase_storage_bucket = os.environ.get("Firebase_Storage")
49
 
50
+ if not firebase_db_url or not firebase_storage_bucket:
51
+ raise ValueError("Firebase_DB and Firebase_Storage environment variables must be set.")
52
+
53
  cred = credentials.Certificate(credentials_json)
54
  firebase_admin.initialize_app(cred, {
55
  'databaseURL': firebase_db_url,
 
63
  bucket = storage.bucket()
64
  db_ref = db.reference()
65
 
66
+ # --- Google GenAI Client Initialization (Gemini 3.0 Ecosystem) ---
67
  try:
68
+ logger.info("Initializing Google GenAI Client (Titaness Paradigm)...")
69
  api_key = os.environ.get("Gemini")
70
  if not api_key:
71
  raise ValueError("The 'Gemini' API key is not set.")
 
80
  ATHENA_FLASH = "gemini-3-flash-preview"
81
  ATHENA_PRO = "gemini-3-pro-image-preview"
82
 
83
+ # Grounding / External API Keys
84
  WOLFRAM_APP_ID = os.environ.get("WOLFRAM_APP_ID")
85
  OPENALEX_MAILTO = os.environ.get("OPENALEX_MAILTO", "rairo@sozofix.tech")
86
 
87
  # -----------------------------------------------------------------------------
88
+ # 2. HELPER FUNCTIONS & AUTHENTICATION
89
  # -----------------------------------------------------------------------------
90
 
91
  def verify_token(auth_header):
92
+ """Verifies Firebase ID token from the Authorization header."""
93
  if not auth_header or not auth_header.startswith('Bearer '):
94
+ logger.warning("Auth Header missing or malformed.")
95
  return None
96
  token = auth_header.split('Bearer ')[1]
97
  try:
 
102
  return None
103
 
104
  def verify_admin(auth_header):
105
+ """Ensures the user has admin privileges in the Realtime Database."""
106
  uid = verify_token(auth_header)
107
+ if not uid:
108
+ raise PermissionError('Invalid token')
109
  user_data = db_ref.child(f'users/{uid}').get()
110
  if not user_data or not user_data.get('is_admin', False):
111
+ logger.warning(f"Unauthorized Admin access attempt by UID: {uid}")
112
  raise PermissionError('Admin access required')
113
  return uid
114
 
115
  def upload_to_storage(data_bytes, destination_blob_name, content_type):
116
+ """Uploads bytes to Firebase Storage and returns the public URL."""
117
  try:
118
  blob = bucket.blob(destination_blob_name)
119
  blob.upload_from_string(data_bytes, content_type=content_type)
120
  blob.make_public()
121
  return blob.public_url
122
  except Exception as e:
123
+ logger.error(f"Firebase Storage Upload Error: {e}")
124
  return None
125
 
126
  def query_wolfram_alpha(query):
127
+ """Fetches computational facts from Wolfram Alpha for grounding."""
128
+ if not WOLFRAM_APP_ID:
129
+ return "Grounded in first principles."
130
  try:
131
  url = f"http://api.wolframalpha.com/v1/result?appid={WOLFRAM_APP_ID}&i={query}"
132
  response = requests.get(url, timeout=5)
133
+ if response.status_code == 200:
134
+ return response.text
135
+ return "Constants verifying..."
136
+ except Exception as e:
137
+ logger.error(f"Wolfram Alpha Query Failed: {e}")
138
+ return "Grounding in progress."
139
 
140
  # -----------------------------------------------------------------------------
141
  # 3. TITANESS MEDIA ENGINE (CONSOLIDATED MASTER BLUEPRINT + ASYNC AUDIO)
142
  # -----------------------------------------------------------------------------
143
 
144
  def generate_narration_task(text, uid, epiphany_id, layer_name):
145
+ """Worker task for generating Deepgram audio in a thread."""
146
+ if not text or len(text) < 5:
147
+ return layer_name, None
148
  try:
149
+ logger.info(f"[THREAD] Starting Narration: {layer_name}")
150
  api_key = os.environ.get("DEEPGRAM_API_KEY")
151
  if not api_key: return layer_name, None
152
 
 
155
  response = requests.post(DEEPGRAM_URL, headers=headers, data=text.encode('utf-8'))
156
  response.raise_for_status()
157
 
158
+ path = f"users/{uid}/epiphanies/{epiphany_id}/audio/{layer_name}.mp3"
159
+ url = upload_to_storage(response.content, path, 'audio/mpeg')
160
+ return layer_name, url
161
  except Exception as e:
162
+ logger.error(f"Narration Task Error [{layer_name}]: {e}")
163
  return layer_name, None
164
 
165
  def generate_master_blueprint_task(subject, flattened_data, uid, epiphany_id):
166
+ """Worker task for generating the 16:9 Consolidated Master Blueprint."""
167
  try:
168
+ logger.info(f"[THREAD] Starting Nano Banana Master Blueprint for: {subject}")
169
+ # Build prompt context from synthesis
170
+ summary = (
171
+ f"Genesis: {flattened_data.get('genesis', '')[:100]}... "
172
+ f"Core: {flattened_data.get('scientific_core', '')[:100]}... "
173
+ f"Edge: {flattened_data.get('engineering_edge', '')[:100]}... "
174
+ f"Future: {flattened_data.get('cross_pollination', '')[:100]}..."
175
+ )
176
 
177
  prompt = (
178
+ f"Generate a single 4K Master Technical Blueprint for '{subject}'. "
179
+ f"Layout: A detailed four-quadrant schematic diagram. "
180
+ f"Quadrant 1: Genesis (Origins). Quadrant 2: Scientific Core (The Physics). "
181
+ f"Quadrant 3: Engineering Edge (Design Limits). Quadrant 4: Cross-Pollination (Future Tech). "
182
+ f"Aesthetic: White-line schematic style on a dark midnight navy background. "
183
+ f"Style: Leonardo Da Vinci meets modern 4K engineering schematics. High accuracy. "
184
+ f"Details to include: {summary}"
185
  )
186
 
187
  response = client.models.generate_content(
 
198
  return upload_to_storage(image_bytes, path, 'image/png')
199
  return None
200
  except Exception as e:
201
+ logger.error(f"Master Blueprint Thread Error: {e}")
202
  return None
203
 
204
  # -----------------------------------------------------------------------------
205
+ # 4. PRIMARY ENDPOINTS: GENERATE & THEIA SWEEP
206
  # -----------------------------------------------------------------------------
207
 
208
  @app.route('/api/image-proxy', methods=['GET'])
209
  def image_proxy():
210
+ """Proxies images to bypass CORS/AI Studio Preview blocks."""
211
  image_url = request.args.get('url')
212
+ if not image_url: return jsonify({'error': 'URL missing'}), 400
213
  try:
214
  resp = requests.get(image_url, timeout=10)
215
+ return Response(resp.content, content_type=resp.headers.get('Content-Type', 'image/jpeg'))
216
+ except Exception as e:
217
+ return jsonify({'error': str(e)}), 500
218
 
219
  @app.route('/api/epiphany/generate', methods=['POST'])
220
  def generate_epiphany():
221
+ """The Titaness Core: Synthesis + Feynman Scholar + Consolidated Blueprint."""
222
+ logger.info(">>> TITANESS GENERATION START")
223
  uid = verify_token(request.headers.get('Authorization'))
224
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
225
 
226
  user_ref = db_ref.child(f'users/{uid}')
227
+ user_data = user_ref.get() or {}
228
 
229
+ # Cost: 8 Sparks (Consolidated Synthesis + 4K Blueprint)
230
+ if user_data.get('credits', 0) < 8:
231
+ return jsonify({'error': 'Insufficient Sparks. (Full Synthesis requires 8 sparks)'}), 402
232
 
233
  if 'image' not in request.files:
234
+ return jsonify({'error': 'Visual image is required.'}), 400
235
 
236
  image_file = request.files['image']
237
  image_bytes = image_file.read()
238
  pil_image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
239
 
240
  try:
241
+ # Step 1: Accurate Identification
242
+ id_prompt = "Identify this precisely. Include specific model or species if visible. Reply with ONLY the name (max 5 words)."
243
+ id_res = client.models.generate_content(model=ATHENA_FLASH, contents=[id_prompt, pil_image])
244
+ subject = id_res.text.strip()
245
+ logger.info(f"Subject Identified: {subject}")
246
+
247
+ # Step 2: Grounded Feynman Synthesis + Research
248
+ physics_fact = query_wolfram_alpha(f"physics laws and constants of {subject}")
249
  synthesis_prompt = f"""
250
+ Act as Athena. Analyze '{subject}' grounded in: {physics_fact}.
251
+ Style: Richard Feynman. Simple analogies, profound engineering truths.
252
 
253
  Tasks:
254
+ 1. Search the web (ArXiv, Patents, Journals) for 3 diverse sources about {subject} using Google Search.
255
  2. Create 4 Discovery Layers (genesis, scientific_core, engineering_edge, cross_pollination).
256
+ 3. For each research source, provide Title, URL, and a 2-sentence Feynman Summary.
257
 
258
  MANDATORY JSON SCHEMA (FLAT):
259
  {{
260
+ "title": "Epic Title",
261
+ "genesis": "The origin/evolutionary logic.",
262
+ "scientific_core": "The first principles of physics.",
263
+ "engineering_edge": "Detailed stress/composition analysis.",
264
+ "cross_pollination": "Interdisciplinary application.",
265
  "scholar": [
266
+ {{"title": "Title", "url": "URL", "feynman_summary": "Summary"}}
267
  ]
268
  }}
269
  """
270
 
271
+ synth_res = client.models.generate_content(
272
  model=ATHENA_FLASH,
273
  contents=[synthesis_prompt, pil_image],
274
  config=types.GenerateContentConfig(
 
277
  )
278
  )
279
 
280
+ # --- SCHEMA SENTINEL: Handle JSON Code Blocks & Lists ---
281
+ raw_json = synth_res.text.strip()
282
+ if "```json" in raw_json:
283
+ raw_json = re.search(r'```json\n(.*?)\n```', raw_json, re.DOTALL).group(1)
284
+
285
  data = json.loads(raw_json)
286
  if isinstance(data, list): data = data[0]
287
+
288
+ # Flatten any AI nesting (e.g. data['epiphany']['genesis'])
289
  if "epiphany" in data: data = data["epiphany"]
290
  elif "discovery_layers" in data: data = data["discovery_layers"]
291
 
292
+ layers_list = ['genesis', 'scientific_core', 'engineering_edge', 'cross_pollination']
293
+ # Guard against missing keys
294
+ for k in layers_list:
295
+ if k not in data: data[k] = f"Analyzing first principles of {k.replace('_', ' ')}..."
296
 
297
  epiphany_id = str(uuid.uuid4())
298
 
299
+ # Step 3: PARALLEL TITANESS MEDIA ENGINE
300
+ logger.info(f"Step 3: Launching media threads for {epiphany_id}")
301
  audios = {}
302
  master_blueprint_url = None
303
 
304
  with ThreadPoolExecutor(max_workers=5) as executor:
305
+ # 4 Audio Threads + 1 Master Blueprint Thread
306
+ aud_futures = [executor.submit(generate_narration_task, data.get(l), uid, epiphany_id, l) for l in layers_list]
 
307
  blu_future = executor.submit(generate_master_blueprint_task, subject, data, uid, epiphany_id)
308
 
309
  for f in aud_futures:
 
311
  audios[k] = v
312
  master_blueprint_url = blu_future.result()
313
 
314
+ # Step 4: Record Persistence
315
+ image_url = upload_to_storage(image_bytes, f"users/{uid}/epiphanies/{epiphany_id}/vision.jpg", 'image/jpeg')
316
  epiphany_record = {
317
  "epiphanyId": epiphany_id,
318
  "uid": uid,
319
+ "title": data.get('title', f"Insight: {subject}"),
320
  "subject": subject,
321
  "imageURL": image_url,
322
  "masterBlueprint": master_blueprint_url,
323
  "layers": {
324
+ l: {"text": data.get(l, ""), "audio": audios.get(l)} for l in layers_list
325
  },
326
  "scholar": data.get('scholar', []),
327
  "createdAt": datetime.utcnow().isoformat()
 
334
  return jsonify(epiphany_record), 201
335
 
336
  except Exception as e:
337
+ logger.error(f"Global Epiphany Gen Error: {e}\n{traceback.format_exc()}")
338
  return jsonify({'error': str(e)}), 500
339
 
340
  @app.route('/api/epiphany/theia', methods=['POST'])
341
  def theia_sweep():
342
+ """Standalone Theia Mode: Bounding Box Annotations via Code Execution."""
343
+ logger.info(">>> THEIA SWEEP INITIATED")
344
  uid = verify_token(request.headers.get('Authorization'))
345
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
346
+
347
+ # 1. Defend against missing parameters (Fixed 400 logic)
348
+ epiphany_id = request.form.get('epiphanyId')
349
+ if not epiphany_id:
350
+ logger.error("Theia Sweep failed: epiphanyId missing from form.")
351
+ return jsonify({'error': 'epiphanyId is required.'}), 400
352
+
353
+ if 'image' not in request.files:
354
+ logger.error("Theia Sweep failed: Image file missing.")
355
+ return jsonify({'error': 'image file is required.'}), 400
356
 
357
+ # 2. Check Sparks
358
  user_ref = db_ref.child(f'users/{uid}')
359
+ user_data = user_ref.get() or {}
360
+ if user_data.get('credits', 0) < 4:
361
+ return jsonify({'error': 'Need 4 Sparks for a Theia Sweep.'}), 402
362
+
363
+ # 3. Fetch Context from the Epiphany
364
+ epiphany_context = db_ref.child(f'epiphanies/{epiphany_id}').get() or {}
365
+ subject = epiphany_context.get('subject', 'Complex System')
366
 
 
367
  image_file = request.files['image']
368
+ image_bytes = image_file.read()
369
 
 
 
 
370
  sweep_prompt = f"""
371
+ Activate Theia Mode for: {subject}.
372
+ Using Python Code Execution, perform a spatial deconstruction of this image.
373
+ Identify every functional, biological, or structural component.
374
+ For each component detected, return a JSON object:
375
+ 1. label: The name of the part.
376
+ 2. coordinates: [ymin, xmin, ymax, xmax] (normalized 0-1000).
377
+ 3. micro_epiphany: A 20-word Feynman-style secret about this part's role.
378
+
379
+ Return a JSON LIST ONLY.
380
  """
381
 
382
  try:
383
+ pil_image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
384
  res = client.models.generate_content(
385
  model=ATHENA_FLASH,
386
  contents=[sweep_prompt, pil_image],
 
389
  response_mime_type='application/json'
390
  )
391
  )
392
+
393
  raw_json = res.text.strip()
394
+ if "```json" in raw_json:
395
+ raw_json = re.search(r'```json\n(.*?)\n```', raw_json, re.DOTALL).group(1)
396
+
397
  annotations = json.loads(raw_json)
398
+ # Charge 4 sparks for Code Execution
399
+ user_ref.update({'credits': user_data.get('credits', 0) - 4})
400
 
401
+ logger.info(f"THEIA SUCCESS: {len(annotations)} components annotated.")
402
  return jsonify({"annotations": annotations}), 200
403
  except Exception as e:
404
+ logger.error(f"Theia Sweep Engine Error: {e}")
405
  return jsonify({'error': str(e)}), 500
406
 
407
  @app.route('/api/epiphany/deep-dive', methods=['POST'])
408
  def deep_dive():
409
+ """Manual Zoom analysis (1 Spark)."""
410
  uid = verify_token(request.headers.get('Authorization'))
411
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
412
+
413
+ if 'image' not in request.files: return jsonify({'error': 'No image'}), 400
414
+
415
  try:
416
+ pil_image = Image.open(io.BytesIO(request.files['image'].read())).convert('RGB')
417
  res = client.models.generate_content(
418
  model=ATHENA_FLASH,
419
+ contents=["In 50 words Feynman style, reveal the hidden significance of this zoomed detail.", pil_image]
420
  )
421
+ # Deduct 1 spark
422
+ user_ref = db_ref.child(f'users/{uid}')
423
+ new_val = max(0, (user_ref.get().get('credits', 0) or 0) - 1)
424
+ user_ref.update({'credits': new_val})
425
+
426
  return jsonify({"analysis": res.text.strip()}), 200
427
+ except Exception as e:
428
+ return jsonify({'error': str(e)}), 500
429
 
430
  # -----------------------------------------------------------------------------
431
+ # 5. THE CHIRON MENTOR & SYSTEM UTILS
432
  # -----------------------------------------------------------------------------
433
 
434
  @app.route('/api/user/call-briefing', methods=['GET'])
435
  def get_chiron_briefing():
436
+ """Preps ElevenLabs Chiron with scientific context from the last Epiphany."""
437
  uid = verify_token(request.headers.get('Authorization'))
438
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
439
+
440
  try:
441
+ # Fetch last epiphany for context
442
+ last_eps = db_ref.child('epiphanies').order_by_child('uid').equal_to(uid).limit_to_last(1).get() or {}
443
+ context_str = "Beginning an academic journey."
444
+ if last_eps:
445
+ eid = list(last_eps.keys())[0]
446
+ e = last_eps[eid]
447
+ scholar_sample = e.get('scholar', [])[:1]
448
+ context_str = f"Focus: {e['subject']}. Papers Analyzed: {scholar_sample[0]['title'] if scholar_sample else 'General'}"
449
+
450
+ brief_prompt = f"Prep Chiron (Socratic Mentor). Context: {context_str}. Write a 4-sentence briefing for a voice call."
451
+ res = client.models.generate_content(model=ATHENA_FLASH, contents=[brief_prompt])
452
  return jsonify({"memory_summary": res.text.strip()}), 200
453
+ except Exception as e:
454
+ return jsonify({'error': str(e)}), 500
455
 
456
  @app.route('/api/log-call-usage', methods=['POST'])
457
+ def log_call_usage():
458
+ """Handles Spark deduction (3 per min) for ElevenLabs sessions."""
459
  uid = verify_token(request.headers.get('Authorization'))
460
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
461
+
462
+ data = request.get_json()
463
+ duration = data.get("durationSeconds", 0)
464
+ cost = math.ceil(duration / 60) * 3
465
+
466
+ try:
467
+ user_ref = db_ref.child(f'users/{uid}')
468
+ current = user_ref.get().get('credits', 0)
469
+ new_bal = max(0, current - cost)
470
+ user_ref.update({'credits': new_bal})
471
+
472
+ if data.get("transcript"):
473
+ db_ref.child(f'transcripts/{uid}').push({
474
+ "text": data["transcript"], "createdAt": datetime.utcnow().isoformat()
475
+ })
476
+ return jsonify({"success": True, "remainingCredits": new_bal}), 200
477
+ except Exception as e:
478
+ return jsonify({'error': str(e)}), 500
479
+
480
+ # -----------------------------------------------------------------------------
481
+ # 6. ADMIN & FEEDBACK
482
+ # -----------------------------------------------------------------------------
483
 
484
  @app.route('/api/admin/dashboard', methods=['GET'])
485
  def admin_dashboard():
 
487
  verify_admin(request.headers.get('Authorization'))
488
  users = db_ref.child('users').get() or {}
489
  epiphanies = db_ref.child('epiphanies').get() or {}
490
+ credit_reqs = db_ref.child('credit_requests').get() or {}
491
  return jsonify({
492
+ "total_users": len(users),
493
+ "total_epiphanies": len(epiphanies),
494
+ "pending_requests": len([r for r in credit_reqs.values() if r.get('status') == 'pending'])
495
+ }), 200
496
+ except Exception as e:
497
+ return jsonify({'error': str(e)}), 403
498
 
499
  @app.route('/api/feedback', methods=['POST'])
500
+ def submit_feedback():
501
  uid = verify_token(request.headers.get('Authorization'))
502
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
503
+ data = request.json
504
+ db_ref.child('feedback').push({
505
+ "uid": uid, "message": data.get('message'), "at": datetime.utcnow().isoformat()
506
+ })
507
+ return jsonify({"success": True}), 201
508
 
509
  @app.route('/api/user/request-credits', methods=['POST'])
510
  def request_sparks():
511
  uid = verify_token(request.headers.get('Authorization'))
512
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
513
+ db_ref.child('credit_requests').push({
514
+ "uid": uid, "status": "pending", "at": datetime.utcnow().isoformat()
515
+ })
516
+ return jsonify({"success": True}), 201
517
 
518
  # -----------------------------------------------------------------------------
519
+ # 7. AUTHENTICATION & USER PROFILE
520
  # -----------------------------------------------------------------------------
521
 
522
  @app.route('/api/auth/signup', methods=['POST'])
 
526
  user_ref = db_ref.child(f'users/{uid}')
527
  if not user_ref.get():
528
  data = request.json
529
+ user_ref.set({
530
+ 'email': data.get('email'), 'displayName': data.get('displayName', 'Seeker'),
531
+ 'credits': 30, 'is_admin': False, 'createdAt': datetime.utcnow().isoformat()
532
+ })
533
  return jsonify({'uid': uid, **user_ref.get()}), 201
534
 
535
  @app.route('/api/auth/social-signin', methods=['POST'])
 
537
  uid = verify_token(request.headers.get('Authorization'))
538
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
539
  user_ref = db_ref.child(f'users/{uid}')
540
+ u = user_ref.get()
541
+ if not u:
542
  fu = auth.get_user(uid)
543
+ u = {
544
+ 'email': fu.email, 'displayName': fu.display_name or 'Seeker',
545
+ 'credits': 30, 'is_admin': False, 'createdAt': datetime.utcnow().isoformat()
546
+ }
547
+ user_ref.set(u)
548
+ return jsonify({'uid': uid, **u}), 200
549
 
550
  @app.route('/api/user/profile', methods=['GET'])
551
+ def get_profile():
552
  uid = verify_token(request.headers.get('Authorization'))
553
  if not uid: return jsonify({'error': 'Unauthorized'}), 401
554
  return jsonify(db_ref.child(f'users/{uid}').get())
 
561
  return jsonify(list(res.values()))
562
 
563
  # -----------------------------------------------------------------------------
564
+ # 8. MAIN EXECUTION
565
  # -----------------------------------------------------------------------------
566
 
567
  if __name__ == '__main__':
568
+ logger.info("Titaness Definitive Backbone Active on port 7860...")
569
+ app.run(debug=False, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))