| from dotenv import load_dotenv |
| load_dotenv() |
|
|
| from fastapi import FastAPI, Request |
| from fastapi.responses import JSONResponse, HTMLResponse, RedirectResponse |
| from fastapi.middleware.cors import CORSMiddleware |
| from starlette.middleware.base import BaseHTTPMiddleware |
| from pydantic import BaseModel |
| from typing import Optional, List |
| import uvicorn |
| import os |
| from pathlib import Path |
| from environment.env import VoiceAuthenticityEnv |
|
|
|
|
| |
| class HFSpacesMiddleware(BaseHTTPMiddleware): |
| """Remove restrictive frame headers so HF Spaces iframe works.""" |
| async def dispatch(self, request: Request, call_next): |
| response = await call_next(request) |
| |
| response.headers["X-Frame-Options"] = "ALLOWALL" |
| response.headers["Access-Control-Allow-Origin"] = "*" |
| |
| try: |
| del response.headers["content-security-policy"] |
| except KeyError: |
| pass |
| return response |
|
|
|
|
| app = FastAPI( |
| title="Voice Authenticity OpenEnv", |
| description="Multi-step agentic environment for detecting synthetic speech", |
| version="2.0.0" |
| ) |
|
|
| |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| |
| app.add_middleware(HFSpacesMiddleware) |
|
|
| TASKS = [ |
| "clean_detection", |
| "compressed_detection", |
| "adversarial_detection", |
| "streaming_detection", |
| "phonecall_detection", |
| "realtime_detection", |
| ] |
|
|
| envs = {task: VoiceAuthenticityEnv(task) for task in TASKS} |
| current_task = "clean_detection" |
|
|
|
|
| class ActionRequest(BaseModel): |
| action_type: str = "final_classify" |
| label: int = 0 |
| confidence: float = 0.5 |
| reasoning: str = "" |
| focus: List[str] = [] |
| task_name: Optional[str] = None |
|
|
|
|
| |
| |
| _APP_DIR = Path(__file__).resolve().parent |
| DASHBOARD_PATH = _APP_DIR / "Dashboard.html" |
|
|
|
|
| def _load_dashboard() -> str: |
| """Load dashboard HTML fresh every time to avoid stale caches in dev.""" |
| if not DASHBOARD_PATH.exists(): |
| raise FileNotFoundError( |
| f"Dashboard.html not found at {DASHBOARD_PATH}" |
| ) |
| return DASHBOARD_PATH.read_text(encoding="utf-8") |
|
|
|
|
| @app.get("/", response_class=HTMLResponse) |
| def root_interface(): |
| try: |
| html = _load_dashboard() |
| return HTMLResponse( |
| content=html, |
| headers={ |
| "X-Frame-Options": "ALLOWALL", |
| "Content-Security-Policy": "frame-ancestors *", |
| }, |
| ) |
| except FileNotFoundError as e: |
| return HTMLResponse( |
| content=f"<h2>Dashboard not found</h2><p>{e}</p>", |
| status_code=404 |
| ) |
|
|
|
|
| @app.get("/web", response_class=HTMLResponse) |
| def web_interface(): |
| try: |
| html = _load_dashboard() |
| return HTMLResponse( |
| content=html, |
| headers={ |
| "X-Frame-Options": "ALLOWALL", |
| "Content-Security-Policy": "frame-ancestors *", |
| }, |
| ) |
| except FileNotFoundError as e: |
| return HTMLResponse( |
| content=f"<h2>Dashboard not found</h2><p>{e}</p>", |
| status_code=404 |
| ) |
|
|
|
|
| @app.post("/reset") |
| def reset(request: dict = {}): |
| global current_task |
| task = request.get("task_name", current_task) if request else current_task |
| if task not in envs: |
| task = "clean_detection" |
| current_task = task |
| seed = request.get("seed") if request else None |
| obs = envs[current_task].reset(seed=seed) |
| return JSONResponse({ |
| "observation": obs.dict(), |
| "done": False, |
| "reward": 0.05, |
| "info": {} |
| }) |
|
|
|
|
| @app.post("/step") |
| def step(action: ActionRequest): |
| global current_task |
| task = action.task_name or current_task |
| if task not in envs: |
| task = current_task |
| action_dict = { |
| "action_type": action.action_type, |
| "label": action.label, |
| "confidence": action.confidence, |
| "reasoning": action.reasoning, |
| "focus": action.focus, |
| } |
| obs, reward, done, info = envs[task].step(action_dict) |
| return JSONResponse({ |
| "observation": obs.dict(), |
| "reward": reward, |
| "done": done, |
| "info": info |
| }) |
|
|
|
|
| @app.get("/state") |
| def state(): |
| return JSONResponse(envs[current_task].state()) |
|
|
|
|
| @app.get("/health") |
| def health(): |
| return {"status": "healthy", "service": "voice-authenticity-openenv"} |
|
|
|
|
| @app.get("/info") |
| def info(): |
| return { |
| "name": "voice-authenticity-openenv", |
| "version": "2.0.0", |
| "status": "running", |
| "tasks": TASKS, |
| "web": "/web", |
| "docs": "/docs" |
| } |
|
|
|
|
| def main(): |
| uvicorn.run(app, host="0.0.0.0", port=7860) |
|
|
|
|
| if __name__ == "__main__": |
| main() |