Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -188,7 +188,7 @@ def generate_narration_task(text, uid, epiphany_id, layer_name):
|
|
| 188 |
api_key = os.environ.get("DEEPGRAM_API_KEY")
|
| 189 |
if not api_key: return layer_name, None
|
| 190 |
|
| 191 |
-
DEEPGRAM_URL = "https://api.deepgram.com/v1/speak?model=aura-
|
| 192 |
headers = {"Authorization": f"Token {api_key}", "Content-Type": "text/plain"}
|
| 193 |
response = requests.post(DEEPGRAM_URL, headers=headers, data=text.encode('utf-8'))
|
| 194 |
response.raise_for_status()
|
|
@@ -477,17 +477,56 @@ def validate_odysseus_v6(t: dict) -> (bool, str):
|
|
| 477 |
# -----------------------------------------------------------------------------
|
| 478 |
|
| 479 |
# -----------------------------------------------------------------------------
|
| 480 |
-
# ODYSSEUS ENGINE V10:
|
| 481 |
# -----------------------------------------------------------------------------
|
| 482 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
@app.route('/api/trial/generate', methods=['POST'])
|
| 484 |
def generate_trial():
|
| 485 |
"""
|
| 486 |
-
Odysseus v10: The
|
| 487 |
-
|
| 488 |
Cost: 1 Spark.
|
| 489 |
"""
|
| 490 |
-
logger.info(">>> ODYSSEUS V10:
|
| 491 |
uid = verify_token(request.headers.get('Authorization'))
|
| 492 |
if not uid: return jsonify({"error": "Unauthorized"}), 401
|
| 493 |
|
|
@@ -507,39 +546,44 @@ def generate_trial():
|
|
| 507 |
if lock_ref.get(): return jsonify({"status": "locked"}), 409
|
| 508 |
lock_ref.set({"uid": uid, "at": datetime.utcnow().isoformat()})
|
| 509 |
|
| 510 |
-
# 3. Context
|
| 511 |
layer_obj = db_ref.child(f"epiphanies/{ep_id}/layers/{layer_key}").get() or {}
|
| 512 |
ctx_text = layer_obj.get("text", "General scientific principles.")
|
| 513 |
|
| 514 |
-
|
| 515 |
-
attempts, forged, last_raw = 0, None, ""
|
| 516 |
|
| 517 |
base_prompt = f"""
|
| 518 |
-
You are Athena's Master
|
| 519 |
-
|
| 520 |
|
| 521 |
TASK: Write a React component named 'Instrument'.
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
| 528 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
{{
|
| 530 |
-
"engine": "odysseus_v10",
|
| 531 |
"instrument_name": "Title",
|
| 532 |
-
"mission_brief": "Goal",
|
| 533 |
-
"
|
| 534 |
"component_code": "const Instrument = (props) => {{ ... }}; export default Instrument;",
|
| 535 |
-
"feynman_truth": "
|
| 536 |
}}
|
| 537 |
"""
|
| 538 |
|
| 539 |
try:
|
| 540 |
while attempts < 3 and not forged:
|
| 541 |
attempts += 1
|
| 542 |
-
current_prompt = base_prompt if attempts == 1 else f"REPAIR
|
| 543 |
|
| 544 |
res = client.models.generate_content(
|
| 545 |
model=ATHENA_FLASH,
|
|
@@ -550,41 +594,43 @@ def generate_trial():
|
|
| 550 |
last_raw = _strip_json_fences(res.text)
|
| 551 |
candidate = json.loads(last_raw)
|
| 552 |
|
| 553 |
-
# Validation
|
| 554 |
-
|
| 555 |
-
ok_c, last_errs = lint_component_code(
|
| 556 |
|
| 557 |
-
if
|
| 558 |
forged = candidate
|
| 559 |
break
|
|
|
|
|
|
|
| 560 |
|
| 561 |
if not forged:
|
| 562 |
lock_ref.delete()
|
| 563 |
-
return jsonify({"status": "failed", "
|
| 564 |
|
| 565 |
-
#
|
| 566 |
user_ref = db_ref.child(f'users/{uid}')
|
| 567 |
def credits_txn(cur):
|
| 568 |
-
|
| 569 |
-
return cur - 1
|
| 570 |
|
| 571 |
-
|
| 572 |
-
if
|
| 573 |
lock_ref.delete()
|
| 574 |
return jsonify({"error": "Insufficient Sparks"}), 402
|
| 575 |
|
| 576 |
-
#
|
| 577 |
forged["createdAt"] = datetime.utcnow().isoformat()
|
| 578 |
db_ref.child(trial_path).set(forged)
|
| 579 |
lock_ref.delete()
|
| 580 |
|
| 581 |
-
logger.info(f"Odysseus v10
|
| 582 |
return jsonify(forged), 201
|
| 583 |
|
| 584 |
except Exception as e:
|
| 585 |
lock_ref.delete()
|
| 586 |
-
logger.error(f"
|
| 587 |
-
return jsonify({"error": "The laws of
|
| 588 |
|
| 589 |
# -----------------------------------------------------------------------------
|
| 590 |
# 5. THE CHIRON MENTOR & SYSTEM UTILS
|
|
|
|
| 188 |
api_key = os.environ.get("DEEPGRAM_API_KEY")
|
| 189 |
if not api_key: return layer_name, None
|
| 190 |
|
| 191 |
+
DEEPGRAM_URL = "https://api.deepgram.com/v1/speak?model=aura-2-theia-en"
|
| 192 |
headers = {"Authorization": f"Token {api_key}", "Content-Type": "text/plain"}
|
| 193 |
response = requests.post(DEEPGRAM_URL, headers=headers, data=text.encode('utf-8'))
|
| 194 |
response.raise_for_status()
|
|
|
|
| 477 |
# -----------------------------------------------------------------------------
|
| 478 |
|
| 479 |
# -----------------------------------------------------------------------------
|
| 480 |
+
# ODYSSEUS ENGINE V10.1: HARDENED GAME CONSOLE (SYNTAX GUARD + VICTORY HOOKS)
|
| 481 |
# -----------------------------------------------------------------------------
|
| 482 |
|
| 483 |
+
# Enhanced Forbidden Patterns to prevent "Unexpected Token" errors in Babel
|
| 484 |
+
FORBIDDEN_CODE_PATTERNS = [
|
| 485 |
+
r"<!--[\s\S]*?-->", # No HTML comments (Babel killer)
|
| 486 |
+
r"\bonclick\b", # Must be onClick
|
| 487 |
+
r"\bonmousedown\b", # Must be onMouseDown
|
| 488 |
+
r"\bclass=", # Must be className
|
| 489 |
+
r"\bfetch\s*\(", # Security
|
| 490 |
+
r"\bXMLHttpRequest\b",
|
| 491 |
+
r"\bWebSocket\b",
|
| 492 |
+
r"\beval\s*\(",
|
| 493 |
+
r"\bnew\s+Function\s*\(",
|
| 494 |
+
]
|
| 495 |
+
|
| 496 |
+
REQUIRED_CODE_PATTERNS = [
|
| 497 |
+
r"\bexport\s+default\s+Instrument\b",
|
| 498 |
+
r"props\.onAction", # Must implement handshake
|
| 499 |
+
r"props\.onWin" # Must implement victory
|
| 500 |
+
]
|
| 501 |
+
|
| 502 |
+
def lint_component_code(code: str) -> (bool, list):
|
| 503 |
+
"""Surgical syntax check for codegen reliability."""
|
| 504 |
+
errors = []
|
| 505 |
+
if not isinstance(code, str) or len(code.strip()) < 50:
|
| 506 |
+
return False, ["component_code missing or too short"]
|
| 507 |
+
|
| 508 |
+
for pat in FORBIDDEN_CODE_PATTERNS:
|
| 509 |
+
if re.search(pat, code, re.IGNORECASE):
|
| 510 |
+
errors.append(f"Syntax Violation: Found illegal pattern '{pat}'")
|
| 511 |
+
|
| 512 |
+
for pat in REQUIRED_CODE_PATTERNS:
|
| 513 |
+
if not re.search(pat, code):
|
| 514 |
+
errors.append(f"Protocol Violation: Missing required pattern '{pat}'")
|
| 515 |
+
|
| 516 |
+
# Ensure no raw HTML-style comments are present
|
| 517 |
+
if "<!--" in code or "-->" in code:
|
| 518 |
+
errors.append("Syntax Error: Use {/* */} for comments in JSX, not <!-- -->")
|
| 519 |
+
|
| 520 |
+
return len(errors) == 0, errors
|
| 521 |
+
|
| 522 |
@app.route('/api/trial/generate', methods=['POST'])
|
| 523 |
def generate_trial():
|
| 524 |
"""
|
| 525 |
+
Odysseus v10.1: The Hardened Instrumentalist.
|
| 526 |
+
Architects bespoke, interactive React games with a 3-pass syntax repair loop.
|
| 527 |
Cost: 1 Spark.
|
| 528 |
"""
|
| 529 |
+
logger.info(">>> ODYSSEUS V10.1: FORGING HARDENED INSTRUMENT")
|
| 530 |
uid = verify_token(request.headers.get('Authorization'))
|
| 531 |
if not uid: return jsonify({"error": "Unauthorized"}), 401
|
| 532 |
|
|
|
|
| 546 |
if lock_ref.get(): return jsonify({"status": "locked"}), 409
|
| 547 |
lock_ref.set({"uid": uid, "at": datetime.utcnow().isoformat()})
|
| 548 |
|
| 549 |
+
# 3. Load Scientific Context
|
| 550 |
layer_obj = db_ref.child(f"epiphanies/{ep_id}/layers/{layer_key}").get() or {}
|
| 551 |
ctx_text = layer_obj.get("text", "General scientific principles.")
|
| 552 |
|
| 553 |
+
attempts, forged, last_raw, last_errs = 0, None, "", []
|
|
|
|
| 554 |
|
| 555 |
base_prompt = f"""
|
| 556 |
+
You are Athena's Master Game Architect. Forge an interactive scientific 'Instrument' for {subject}.
|
| 557 |
+
Context: {ctx_text}
|
| 558 |
|
| 559 |
TASK: Write a React component named 'Instrument'.
|
| 560 |
+
This is a GAME that requires user interaction to achieve a scientific victory.
|
| 561 |
+
|
| 562 |
+
TECHNICAL CONSTRAINTS (STRICT):
|
| 563 |
+
1. REACT ONLY: Use React hooks (useState, useEffect, useRef). No external libs. Use SVG/Canvas.
|
| 564 |
+
2. HANDSHAKE: Component receives `{{ onAction, onWin }}` as props.
|
| 565 |
+
- Call `props.onAction()` the moment the user interacts.
|
| 566 |
+
- Call `props.onWin()` when the specific scientific goal is reached.
|
| 567 |
+
3. WIN CONDITION: You MUST define a logic state (e.g., matching a frequency) that triggers `onWin()`.
|
| 568 |
+
4. NO COMMENTS: Do not use HTML comments <!-- -->. Use {{/* */}} if needed.
|
| 569 |
+
5. CAMELCASE: Use className, onClick, onMouseDown, etc.
|
| 570 |
+
6. ENTROPY: The system must fail/decay if the user stops interacting.
|
| 571 |
+
|
| 572 |
+
JSON OUTPUT SCHEMA:
|
| 573 |
{{
|
| 574 |
+
"engine": "odysseus_v10.1",
|
| 575 |
"instrument_name": "Title",
|
| 576 |
+
"mission_brief": "Goal description.",
|
| 577 |
+
"controls_guide": "Manual: 'Drag the X to the Y', 'Tap the Z to pulse', 'Hold the X until Y'.",
|
| 578 |
"component_code": "const Instrument = (props) => {{ ... }}; export default Instrument;",
|
| 579 |
+
"feynman_truth": "Scientific revelation."
|
| 580 |
}}
|
| 581 |
"""
|
| 582 |
|
| 583 |
try:
|
| 584 |
while attempts < 3 and not forged:
|
| 585 |
attempts += 1
|
| 586 |
+
current_prompt = base_prompt if attempts == 1 else f"REPAIR LOGIC ERROR: {last_errs}\nPREVIOUS CODE: {last_raw}"
|
| 587 |
|
| 588 |
res = client.models.generate_content(
|
| 589 |
model=ATHENA_FLASH,
|
|
|
|
| 594 |
last_raw = _strip_json_fences(res.text)
|
| 595 |
candidate = json.loads(last_raw)
|
| 596 |
|
| 597 |
+
# Validation Step
|
| 598 |
+
code = candidate.get("component_code", "")
|
| 599 |
+
ok_c, last_errs = lint_component_code(code)
|
| 600 |
|
| 601 |
+
if ok_c:
|
| 602 |
forged = candidate
|
| 603 |
break
|
| 604 |
+
else:
|
| 605 |
+
logger.warning(f"Attempt {attempts} failed syntax check: {last_errs}")
|
| 606 |
|
| 607 |
if not forged:
|
| 608 |
lock_ref.delete()
|
| 609 |
+
return jsonify({"status": "failed", "errors": last_errs}), 422
|
| 610 |
|
| 611 |
+
# 4. Atomic Credit Check & Deduction (1 Spark)
|
| 612 |
user_ref = db_ref.child(f'users/{uid}')
|
| 613 |
def credits_txn(cur):
|
| 614 |
+
if (cur or 0) < 1: return cur
|
| 615 |
+
return cur - 1
|
| 616 |
|
| 617 |
+
updated_credits = user_ref.child('credits').transaction(credits_txn)
|
| 618 |
+
if updated_credits is None: # Transaction aborted/failed sparks
|
| 619 |
lock_ref.delete()
|
| 620 |
return jsonify({"error": "Insufficient Sparks"}), 402
|
| 621 |
|
| 622 |
+
# 5. Persist & Return
|
| 623 |
forged["createdAt"] = datetime.utcnow().isoformat()
|
| 624 |
db_ref.child(trial_path).set(forged)
|
| 625 |
lock_ref.delete()
|
| 626 |
|
| 627 |
+
logger.info(f"Odysseus v10.1 success for {subject} in {attempts} attempt(s).")
|
| 628 |
return jsonify(forged), 201
|
| 629 |
|
| 630 |
except Exception as e:
|
| 631 |
lock_ref.delete()
|
| 632 |
+
logger.error(f"v10.1 Global Failure: {e}")
|
| 633 |
+
return jsonify({"error": "The laws of the universe failed to stabilize. Retry."}), 500
|
| 634 |
|
| 635 |
# -----------------------------------------------------------------------------
|
| 636 |
# 5. THE CHIRON MENTOR & SYSTEM UTILS
|