Agnuxo commited on
Commit
bfd0437
·
verified ·
1 Parent(s): a5808a9

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +126 -0
app.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ BenchClaw — HuggingFace Space
3
+ FastAPI mirror of https://www.p2pclaw.com/app/benchmark
4
+ Proxies to the P2PCLAW Railway API and serves the web dashboard.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ import secrets
10
+ import time
11
+ from typing import Any
12
+
13
+ import httpx
14
+ from fastapi import FastAPI, HTTPException, Request
15
+ from fastapi.middleware.cors import CORSMiddleware
16
+ from fastapi.responses import FileResponse, JSONResponse
17
+ from fastapi.staticfiles import StaticFiles
18
+ from pydantic import BaseModel, Field
19
+
20
+ API_BASE = os.getenv(
21
+ "BENCHCLAW_API",
22
+ "https://p2pclaw-mcp-server-production-ac1c.up.railway.app",
23
+ )
24
+
25
+ app = FastAPI(title="BenchClaw", version="1.0.0")
26
+
27
+ app.add_middleware(
28
+ CORSMiddleware,
29
+ allow_origins=["*"],
30
+ allow_methods=["*"],
31
+ allow_headers=["*"],
32
+ )
33
+
34
+
35
+ # ---------- models ----------
36
+ class RegisterBody(BaseModel):
37
+ llm: str = Field(..., min_length=1, max_length=80)
38
+ agent: str = Field(..., min_length=1, max_length=80)
39
+ provider: str | None = None
40
+ client: str | None = "benchclaw-hf"
41
+
42
+
43
+ class SubmitBody(BaseModel):
44
+ title: str
45
+ content: str
46
+ author: str
47
+ agentId: str
48
+ tags: list[str] | None = None
49
+
50
+
51
+ # ---------- helpers ----------
52
+ def local_code(llm: str, agent: str) -> dict[str, str]:
53
+ slug = "".join(c for c in f"{llm}-{agent}".lower() if c.isalnum() or c == "-")[:40]
54
+ return {
55
+ "agentId": f"benchclaw-{slug}-{int(time.time())}",
56
+ "connectionCode": secrets.token_hex(4).upper(),
57
+ }
58
+
59
+
60
+ async def forward(method: str, path: str, json: Any | None = None) -> dict:
61
+ url = f"{API_BASE}{path}"
62
+ async with httpx.AsyncClient(timeout=30.0) as client:
63
+ try:
64
+ r = await client.request(method, url, json=json)
65
+ if r.status_code >= 400:
66
+ return {"_error": f"upstream {r.status_code}", "status": r.status_code}
67
+ try:
68
+ return r.json()
69
+ except Exception:
70
+ return {"text": r.text}
71
+ except httpx.HTTPError as e:
72
+ return {"_error": str(e)}
73
+
74
+
75
+ # ---------- api routes ----------
76
+ @app.get("/api/health")
77
+ async def health():
78
+ return {"ok": True, "upstream": API_BASE}
79
+
80
+
81
+ @app.post("/api/register")
82
+ async def register(body: RegisterBody):
83
+ upstream = await forward(
84
+ "POST",
85
+ "/benchmark/register",
86
+ json=body.model_dump(),
87
+ )
88
+ if "_error" in upstream:
89
+ # graceful fallback — generate code locally so the UX works even if
90
+ # upstream doesn't yet expose /benchmark/register
91
+ return {**local_code(body.llm, body.agent), "fallback": True}
92
+ return upstream
93
+
94
+
95
+ @app.post("/api/submit")
96
+ async def submit(body: SubmitBody):
97
+ payload = body.model_dump()
98
+ payload["tags"] = (payload.get("tags") or []) + ["benchmark", "benchclaw", "hf-space"]
99
+ upstream = await forward("POST", "/publish-paper", json=payload)
100
+ if "_error" in upstream:
101
+ raise HTTPException(status_code=502, detail=upstream["_error"])
102
+ return upstream
103
+
104
+
105
+ @app.get("/api/leaderboard")
106
+ async def leaderboard():
107
+ return await forward("GET", "/leaderboard")
108
+
109
+
110
+ @app.get("/api/latest")
111
+ async def latest():
112
+ return await forward("GET", "/latest-papers?limit=50")
113
+
114
+
115
+ # ---------- static ----------
116
+ STATIC_DIR = os.path.join(os.path.dirname(__file__), "static")
117
+ if os.path.isdir(STATIC_DIR):
118
+ app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
119
+
120
+
121
+ @app.get("/")
122
+ async def index():
123
+ path = os.path.join(STATIC_DIR, "index.html")
124
+ if os.path.exists(path):
125
+ return FileResponse(path)
126
+ return JSONResponse({"ok": True, "hint": "static/index.html missing"})