Spaces:
Sleeping
Sleeping
| """ | |
| FastAPI application for the PLL Cyberattack Detection OpenEnv. | |
| Exposes HTTP endpoints for environment interaction: | |
| POST /reset — Reset environment with task_id | |
| POST /step — Submit an action and advance one step | |
| GET /state — Get current internal state | |
| GET /health — Health check (returns 200) | |
| GET /tasks — List available tasks | |
| """ | |
| import asyncio | |
| from typing import Any, Dict, Optional | |
| from fastapi import FastAPI, HTTPException, Request | |
| from pydantic import BaseModel | |
| from src.models import Observation, Action, Reward, State | |
| from src.env import PLLAttackEnv | |
| app = FastAPI( | |
| title="PLL Cyberattack Detection OpenEnv", | |
| description="OpenEnv for AI-driven cyberattack detection on SRF-PLLs", | |
| version="1.0.0", | |
| ) | |
| env = PLLAttackEnv() | |
| env_lock = asyncio.Lock() | |
| class ResetRequest(BaseModel): | |
| task_id: int = 0 | |
| seed: Optional[int] = None | |
| class StepResponse(BaseModel): | |
| observation: Observation | |
| reward: Reward | |
| done: bool | |
| info: Dict[str, Any] | |
| async def reset(req: Request): | |
| """Reset the environment and return initial observation.""" | |
| async with env_lock: | |
| try: | |
| body = await req.body() | |
| if body: | |
| data = await req.json() | |
| request = ResetRequest(**data) | |
| else: | |
| request = ResetRequest() | |
| except Exception: | |
| request = ResetRequest() | |
| return env.reset(task_id=request.task_id, seed=request.seed) | |
| async def step(action: Action): | |
| async with env_lock: | |
| if env.attack_generator is None: | |
| raise HTTPException(status_code=400, detail="Call /reset before /step") | |
| obs, reward, done, info = env.step(action) | |
| return StepResponse(observation=obs, reward=reward, done=done, info=info) | |
| async def get_state(): | |
| async with env_lock: | |
| return env.get_state() | |
| async def health(): | |
| """Health check endpoint.""" | |
| return { | |
| "status": "ok", | |
| "version": "1.0.0", | |
| "environment": "pll-cyberattack-detection", | |
| "tasks_available": 3, | |
| "episode_active": env.attack_generator is not None, | |
| "current_step": env.step_count, | |
| } | |
| async def list_tasks(): | |
| """List all available tasks.""" | |
| return { | |
| "tasks": [ | |
| { | |
| "id": 0, | |
| "name": "sinusoidal_fdi", | |
| "difficulty": "easy", | |
| "description": "Detect sinusoidal FDI attack" | |
| }, | |
| { | |
| "id": 1, | |
| "name": "multi_attack_classification", | |
| "difficulty": "medium", | |
| "description": "Classify attack type from observations" | |
| }, | |
| { | |
| "id": 2, | |
| "name": "stealthy_attack_detection", | |
| "difficulty": "hard", | |
| "description": "Detect stealthy attack before PLL lock loss" | |
| }, | |
| ] | |
| } | |