nova-test / fastapi_app.py
Leon4gr45's picture
Upload folder using huggingface_hub
4fdaf19 verified
Raw
History Blame Contribute Delete
4.71 kB
"""FastAPI reference backend for the Nova Act Suite."""
from datetime import datetime, timezone
from typing import Any
from uuid import uuid4
from fastapi import Cookie, FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
app = FastAPI(title="Nova Act Suite API", version="1.0.0", description="Shared auth, tab communication, Nova Act actions, and DataHub records.")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])
class TabEventIn(BaseModel):
source: str = Field(..., examples=["usersync"])
target: str | None = Field(default="broadcast", examples=["graph"])
action: str = Field(..., examples=["view.changed"])
payload: dict[str, Any] = Field(default_factory=dict)
class TabEvent(TabEventIn):
id: str
timestamp: datetime
class NovaActSessionIn(BaseModel):
target_url: str = "https://nova.amazon.com/"
instruction: str = "Open the target and summarize the page state."
class LimitationInjectionIn(BaseModel):
limitation_ids: list[str] = Field(default_factory=list)
prompt: str | None = None
class OmniParserElementIn(BaseModel):
id: str
type: str = "panel"
label: str
bbox: list[float] = Field(default_factory=lambda: [0, 0, 100, 100])
interactable: bool = False
description: str = "current application viewport"
class OmniParserParseIn(BaseModel):
screen_name: str = "Nova Act Suite"
elements: list[OmniParserElementIn] = Field(default_factory=list)
_events: list[TabEvent] = []
_mindwalk_limitations = [
{"id": "limit-safe-navigation", "label": "Safe navigation", "guardrail": "Only navigate, read, extract, and verify unless the active persona explicitly allows mutation.", "injectInto": ["nova-act", "graph"]},
{"id": "limit-sensitive-fields", "label": "Sensitive-field pause", "guardrail": "Pause and request supervisor review before entering passwords, tokens, payment data, or private identifiers.", "injectInto": ["nova-act", "usersync", "datahub"]},
{"id": "limit-evidence-first", "label": "Evidence-first output", "guardrail": "Return file, DOM, API, or screenshot evidence with every persona-facing recommendation.", "injectInto": ["dev", "graph", "oasis"]},
]
@app.get("/api/user")
def get_user(hf_user: str | None = Cookie(default=None)) -> dict[str, Any]:
if not hf_user:
raise HTTPException(status_code=401, detail="Not authenticated")
return {"shared_hf_cookie": True, "raw": hf_user}
@app.post("/api/tabs/events", status_code=201)
def publish_event(event: TabEventIn) -> TabEvent:
saved = TabEvent(id=str(uuid4()), timestamp=datetime.now(timezone.utc), **event.model_dump())
_events.insert(0, saved)
del _events[100:]
return saved
@app.get("/api/tabs/events")
def list_events() -> list[TabEvent]:
return _events
@app.post("/api/nova-act/session", status_code=202)
def create_nova_act_session(session: NovaActSessionIn, hf_user: str | None = Cookie(default=None)) -> dict[str, Any]:
return {"id": str(uuid4()), "status": "queued", "sharedAuth": bool(hf_user), **session.model_dump()}
@app.get("/api/datahub/records")
def list_datahub_records() -> list[dict[str, Any]]:
return []
@app.get("/api/mindwalk/graph")
def get_mindwalk_graph_contract() -> dict[str, Any]:
return {"source": "cosmtrek/mindwalk-inspired-adapter", "model": "tabs-subviews-personas-limitations", "touchStates": ["unvisited", "seen", "read", "edited", "limited"], "limitations": _mindwalk_limitations}
@app.post("/api/nova-act/limitations", status_code=202)
def inject_nova_act_limitations(injection: LimitationInjectionIn) -> dict[str, Any]:
requested = set(injection.limitation_ids)
selected = [item for item in _mindwalk_limitations if not requested or item["id"] in requested]
return {"accepted": True, "selected": selected, "prompt": injection.prompt}
@app.post("/api/omniparser/parse")
def parse_ui_for_llm(payload: OmniParserParseIn) -> dict[str, Any]:
elements = payload.elements or [OmniParserElementIn(id="viewport", label=payload.screen_name)]
interactable = [element for element in elements if element.interactable]
phrases = [f"Screen: {payload.screen_name}.", f"Detected {len(elements)} UI elements; {len(interactable)} are interactable."]
phrases.extend([f"Use {element.type} \"{element.label}\" at bbox [{', '.join(map(str, element.bbox))}] to {element.description}." for element in interactable])
return {"source": "microsoft/OmniParser-adapter", "screenshotId": f"{payload.screen_name.lower().replace(' ', '-')}-synthetic", "elements": [element.model_dump() for element in elements], "llmLanguage": " ".join(phrases)}