Spaces:
Running
Running
noahlee1234 commited on
Commit ·
7c53aed
1
Parent(s): 9f9f399
NaturalCAD: call /v1/generate from HF
Browse files- apps/backend-api/app/main.py +14 -0
- apps/gradio-demo/app/main.py +32 -41
apps/backend-api/app/main.py
CHANGED
|
@@ -548,6 +548,20 @@ async def upload_job_artifact(
|
|
| 548 |
return ArtifactUploadResponse(artifact=_artifact_to_record(saved))
|
| 549 |
|
| 550 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 551 |
@app.get("/")
|
| 552 |
def root() -> dict[str, str]:
|
| 553 |
return {
|
|
|
|
| 548 |
return ArtifactUploadResponse(artifact=_artifact_to_record(saved))
|
| 549 |
|
| 550 |
|
| 551 |
+
@app.post("/v1/generate")
|
| 552 |
+
def generate_and_return(request: GenerateSpecRequest, x_api_key: str | None = Header(default=None)):
|
| 553 |
+
_check_auth(x_api_key)
|
| 554 |
+
|
| 555 |
+
# Generate spec using existing endpoint
|
| 556 |
+
spec = _generate_spec(request)
|
| 557 |
+
|
| 558 |
+
# Generate build123d code
|
| 559 |
+
code = render_code_from_spec(spec.model_dump())
|
| 560 |
+
|
| 561 |
+
# Return the code as text
|
| 562 |
+
return {"code": code, "status": "ready"}
|
| 563 |
+
|
| 564 |
+
|
| 565 |
@app.get("/")
|
| 566 |
def root() -> dict[str, str]:
|
| 567 |
return {
|
apps/gradio-demo/app/main.py
CHANGED
|
@@ -458,49 +458,40 @@ mesh.export(str(glb_file))
|
|
| 458 |
|
| 459 |
def generate_from_prompt(prompt: str, mode: str, output_type: str):
|
| 460 |
started_at = time.time()
|
| 461 |
-
backend_ok = True
|
| 462 |
-
client_notice = None
|
| 463 |
-
fallback_level = "normal"
|
| 464 |
-
suspicious_input = False
|
| 465 |
-
job_data, backend_log = create_job(prompt, mode, output_type)
|
| 466 |
-
if job_data is None:
|
| 467 |
-
backend_ok = False
|
| 468 |
-
backend_log = backend_log or "Backend request failed."
|
| 469 |
-
spec = {
|
| 470 |
-
"output_type": output_type,
|
| 471 |
-
"geometry_family": "bracket_plate",
|
| 472 |
-
"parameters": {},
|
| 473 |
-
}
|
| 474 |
-
client_notice = "Backend was unavailable or disabled, so NaturalCAD used a simple local fallback."
|
| 475 |
-
fallback_level = "backend_unavailable"
|
| 476 |
-
else:
|
| 477 |
-
spec = job_data.get("spec")
|
| 478 |
-
suspicious_input = bool(job_data.get("suspicious_input", False))
|
| 479 |
-
fallback_level = job_data.get("fallback_level", "normal")
|
| 480 |
-
if suspicious_input:
|
| 481 |
-
client_notice = "Your prompt looked partly like code or unsafe instructions, so NaturalCAD used a safer interpretation for this run."
|
| 482 |
-
elif fallback_level == "underspecified":
|
| 483 |
-
client_notice = "Your prompt was pretty open-ended, so NaturalCAD filled in conservative defaults for this run."
|
| 484 |
-
|
| 485 |
-
if not spec:
|
| 486 |
-
_append_run_log({
|
| 487 |
-
"timestamp": datetime.now(timezone.utc).isoformat(),
|
| 488 |
-
"prompt": prompt,
|
| 489 |
-
"mode": mode,
|
| 490 |
-
"output_type": output_type,
|
| 491 |
-
"backend_ok": backend_ok,
|
| 492 |
-
"success": False,
|
| 493 |
-
"error": "Backend created no CAD spec.",
|
| 494 |
-
})
|
| 495 |
-
return None, None, None, backend_log, "Backend created no CAD spec."
|
| 496 |
-
|
| 497 |
-
job_id = str((job_data or {}).get("id", ""))
|
| 498 |
|
| 499 |
-
#
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 504 |
return code, code, code, combined_logs, final_summary
|
| 505 |
|
| 506 |
|
|
|
|
| 458 |
|
| 459 |
def generate_from_prompt(prompt: str, mode: str, output_type: str):
|
| 460 |
started_at = time.time()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 461 |
|
| 462 |
+
# Call the new /v1/generate endpoint on Fly
|
| 463 |
+
if BACKEND_URL:
|
| 464 |
+
payload = json.dumps({"prompt": prompt, "mode": mode, "output_type": output_type}).encode()
|
| 465 |
+
headers = {"Content-Type": "application/json"}
|
| 466 |
+
if BACKEND_API_KEY:
|
| 467 |
+
headers["x-api-key"] = BACKEND_API_KEY
|
| 468 |
+
|
| 469 |
+
req = request.Request(
|
| 470 |
+
f"{BACKEND_URL.rstrip('/')}/v1/generate",
|
| 471 |
+
data=payload,
|
| 472 |
+
headers=headers,
|
| 473 |
+
method="POST",
|
| 474 |
+
)
|
| 475 |
+
try:
|
| 476 |
+
with request.urlopen(req, timeout=BACKEND_TIMEOUT_SECONDS) as response:
|
| 477 |
+
result = json.loads(response.read().decode())
|
| 478 |
+
code = result.get("code", "")
|
| 479 |
+
if code:
|
| 480 |
+
combined_logs = f"Generated build123d code:\n\n{code}"
|
| 481 |
+
final_summary = "Code ready. Copy and run locally with build123d."
|
| 482 |
+
return code, code, code, combined_logs, final_summary
|
| 483 |
+
except Exception as exc:
|
| 484 |
+
pass
|
| 485 |
|
| 486 |
+
# Fallback to local spec generation
|
| 487 |
+
spec = {
|
| 488 |
+
"output_type": output_type,
|
| 489 |
+
"geometry_family": "bracket_plate",
|
| 490 |
+
"parameters": {"width": 60, "height": 40, "thickness": 6},
|
| 491 |
+
}
|
| 492 |
+
code = render_code_from_spec(spec)
|
| 493 |
+
combined_logs = f"Local fallback:\n{code}"
|
| 494 |
+
final_summary = "Code generated."
|
| 495 |
return code, code, code, combined_logs, final_summary
|
| 496 |
|
| 497 |
|