financing-starts-now / model_runtime.py
GitHub Actions
Deploy financing-starts-now from e5d6456
d979993
Raw
History Blame Contribute Delete
2.92 kB
"""Financing Starts Now β€” runtime client.
Talks to the Modal backend (modal.App("financing-starts-now")) over HTTP, OR
serves canned data when FINANCING_MOCK is set β€” same signatures either way, so
the UI never branches on mode. The HF Space deploy injects
FINANCING_STARTS_NOW_API_URL.
"""
from __future__ import annotations
import os
import httpx
API_URL = os.environ.get(
"FINANCING_STARTS_NOW_API_URL",
"https://rafalbogusdxc--financing-starts-now-api.modal.run",
).rstrip("/")
MOCK = os.environ.get("FINANCING_MOCK", "").strip().lower() in ("1", "true", "yes", "on")
TIMEOUT_S = 30 # fail fast β€” local fallback is instant, don't make users wait
class BackendError(RuntimeError):
"""Inference backend unreachable or returned an error."""
def health() -> dict:
if MOCK:
return {"status": "mock"}
try:
resp = httpx.get(f"{API_URL}/health", timeout=10, follow_redirects=True)
resp.raise_for_status()
return resp.json()
except Exception:
return {"status": "unreachable"}
def genie_summary(path_key: str, profile_sentence: str, matches: list[dict]) -> tuple[str, bool]:
"""Personalized recommendation text for this answer path.
Returns (markdown_text, was_cached). Raises BackendError on failure.
"""
if MOCK:
top = matches[0]
runner = matches[1] if len(matches) > 1 else None
text = (
f"*Poof!* The scrolls are clear. As {profile_sentence.split(';')[0].strip()}, "
f"your strongest path is **{top['name']}** β€” {top['amount_label']}. "
f"It scores **{top['score']}%** against your answers: your stage and funding "
f"needs sit squarely inside this programme's range, and the door is open "
f"({top['deadline_label']}). Start with: {top['apply'][0].lower()}."
)
if runner:
text += (
f"\n\nKeep **{runner['name']}** ({runner['score']}%) as your second wish β€” "
f"{runner['amount_label']}. Choose it if the first path stalls."
)
text += "\n\n*(mock genie β€” set FINANCING_MOCK=0 and deploy Modal for the real one)*"
return text, True
try:
resp = httpx.post(
f"{API_URL}/genie",
json={
"path_key": path_key,
"profile_sentence": profile_sentence,
"matches": matches,
},
timeout=TIMEOUT_S,
follow_redirects=True,
)
resp.raise_for_status()
data = resp.json()
return data["summary"], bool(data.get("cached"))
except httpx.HTTPStatusError as e:
raise BackendError(f"Backend error {e.response.status_code}: "
f"{e.response.text[:300]}") from e
except httpx.HTTPError as e:
raise BackendError(f"Cannot reach the Genie backend at {API_URL} ({e})") from e