Spaces:
Paused
Paused
| from typing import Dict, Optional | |
| from fastapi import FastAPI | |
| from fastapi.responses import HTMLResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel | |
| from suspect_x_environment import SuspectXEnvironment | |
| app = FastAPI(title="Suspect X — AI Interrogation Room", version="1.0.0") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| env = SuspectXEnvironment() | |
| # ------------------------------------------------------------------ | |
| # Request models | |
| # ------------------------------------------------------------------ | |
| class ResetRequest(BaseModel): | |
| n_facts: int = 3 | |
| seed: Optional[int] = None | |
| difficulty: Optional[str] = None | |
| class StepRequest(BaseModel): | |
| session_id: str | |
| action_type: str # "question" | "suspect_answer" | "submit_accusation" | |
| content: Optional[str] = None | |
| accusation_json: Optional[Dict[str, str]] = None | |
| # ------------------------------------------------------------------ | |
| # Routes | |
| # ------------------------------------------------------------------ | |
| def root(): | |
| return """ | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Suspect X Environment - API Server</title> | |
| <style> | |
| :root { | |
| --primary: #4f46e5; | |
| --primary-hover: #4338ca; | |
| --bg: #0f172a; | |
| --surface: #1e293b; | |
| --text: #f8fafc; | |
| --text-muted: #94a3b8; | |
| --border: #334155; | |
| } | |
| body { | |
| font-family: 'Inter', system-ui, -apple-system, sans-serif; | |
| background-color: var(--bg); | |
| color: var(--text); | |
| margin: 0; | |
| padding: 0; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| background-color: var(--surface); | |
| border: 1px solid var(--border); | |
| border-radius: 12px; | |
| padding: 40px; | |
| max-width: 600px; | |
| width: 90%; | |
| box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 8px 10px -6px rgba(0, 0, 0, 0.5); | |
| text-align: center; | |
| } | |
| h1 { | |
| margin-top: 0; | |
| font-size: 2rem; | |
| font-weight: 700; | |
| background: linear-gradient(to right, #818cf8, #c084fc); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| p { | |
| color: var(--text-muted); | |
| line-height: 1.6; | |
| margin-bottom: 30px; | |
| } | |
| .endpoints { | |
| text-align: left; | |
| background: var(--bg); | |
| padding: 20px; | |
| border-radius: 8px; | |
| border: 1px solid var(--border); | |
| } | |
| .endpoints h2 { | |
| font-size: 1.2rem; | |
| margin-top: 0; | |
| margin-bottom: 15px; | |
| color: var(--text); | |
| } | |
| .endpoint { | |
| margin-bottom: 10px; | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .method { | |
| background: var(--primary); | |
| color: white; | |
| padding: 4px 8px; | |
| border-radius: 4px; | |
| font-size: 0.8rem; | |
| font-weight: 600; | |
| text-transform: uppercase; | |
| min-width: 45px; | |
| text-align: center; | |
| } | |
| .method.get { background: #10b981; } | |
| .method.post { background: #3b82f6; } | |
| code { | |
| font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; | |
| color: #e2e8f0; | |
| } | |
| .btn { | |
| display: inline-block; | |
| background-color: var(--primary); | |
| color: white; | |
| text-decoration: none; | |
| padding: 12px 24px; | |
| border-radius: 6px; | |
| font-weight: 600; | |
| margin-top: 30px; | |
| transition: background-color 0.2s; | |
| } | |
| .btn:hover { | |
| background-color: var(--primary-hover); | |
| } | |
| .badge { | |
| display: inline-block; | |
| background: rgba(79, 70, 229, 0.2); | |
| color: #818cf8; | |
| padding: 4px 12px; | |
| border-radius: 9999px; | |
| font-size: 0.875rem; | |
| font-weight: 500; | |
| margin-bottom: 20px; | |
| border: 1px solid rgba(79, 70, 229, 0.3); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="badge">OpenEnv Hackathon</div> | |
| <h1>Suspect X Environment</h1> | |
| <p>The high-fidelity adversarial interrogation environment is running successfully. This API serves as the backbone for the multi-agent RLHF training loop.</p> | |
| <div class="endpoints"> | |
| <h2>API Endpoints</h2> | |
| <div class="endpoint"> | |
| <span class="method post">POST</span> <code>/reset</code> | |
| </div> | |
| <div class="endpoint"> | |
| <span class="method post">POST</span> <code>/step</code> | |
| </div> | |
| <div class="endpoint"> | |
| <span class="method get">GET</span> <code>/state</code> | |
| </div> | |
| </div> | |
| <a href="/docs" class="btn">View API Documentation</a> | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| def reset(req: ResetRequest = ResetRequest()): | |
| return env.reset(n_facts=req.n_facts, seed=req.seed, difficulty=req.difficulty) | |
| def step(req: StepRequest): | |
| action = req.model_dump() | |
| return env.step(action) | |
| def state(): | |
| return env.state | |