File size: 2,650 Bytes
77e1e28
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
"""FastAPI application for the Drug Target Validation Environment.

Endpoints:
    - POST /reset:  Reset the environment
    - POST /step:   Execute an action
    - GET  /state:  Get current environment state
    - GET  /schema: Get action/observation schemas
    - WS   /ws:     WebSocket endpoint for persistent sessions
    - GET  /        Demo UI
"""

import os
from pathlib import Path

try:
    from openenv.core.env_server.http_server import create_app
except Exception as e:  # pragma: no cover
    raise ImportError(
        "openenv is required for the web interface. "
        "Install dependencies with 'uv sync'"
    ) from e

from fastapi.responses import HTMLResponse
from models import DrugTargetAction, ValidationObservation
from .hackathon_environment import DrugTargetEnvironment

app = create_app(
    DrugTargetEnvironment,
    DrugTargetAction,
    ValidationObservation,
    env_name="drug_target_validation",
    max_concurrent_envs=int(os.environ.get("MAX_ENVS", "4")),
)

DEMO_HTML = Path(__file__).resolve().parent.parent / "demo.html"


@app.get("/", response_class=HTMLResponse)
async def demo_ui():
    if DEMO_HTML.exists():
        return HTMLResponse(content=DEMO_HTML.read_text(), status_code=200)
    return HTMLResponse(
        content=(
            "<h1>Drug Target Validation Env API</h1>"
            "<p>Visit /docs for API documentation.</p>"
        ),
        status_code=200,
    )


def main(host: str = "0.0.0.0", port: int = None):
    import uvicorn
    if port is None:
        port = int(os.environ.get("PORT", "8000"))
    uvicorn.run(app, host=host, port=port)


if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--host", default="0.0.0.0")
    parser.add_argument("--port", type=int, default=None)
    args = parser.parse_args()
    main(host=args.host, port=args.port)


# ── Mount the Gradio demo at /demo (env Space landing) ────────────────────
# Optional: the env Space ships a small Gradio Blocks UI at
# ``space/env/gradio_demo.py``; mounting it here means a single Docker
# image can serve both the OpenEnv HTTP API and the human-friendly
# demo. Failures are degraded silently so a server-only deploy (no
# gradio installed) still boots.
try:  # pragma: no cover - import-time best-effort
    import gradio as _gr  # type: ignore
    from space.env.gradio_demo import build_gradio_demo as _build_gradio_demo

    _demo = _build_gradio_demo()
    if isinstance(_demo, _gr.Blocks):
        _gr.mount_gradio_app(app, _demo, path="/demo")
except Exception:  # pragma: no cover
    pass