Spaces:
Paused
Paused
File size: 2,850 Bytes
9b48f64 |
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 |
import os
import tempfile
from typing import Optional
import requests
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
ROBOT_IP = os.getenv("ROBOT_IP", "127.0.0.1")
ROBOT_PORT = int(os.getenv("ROBOT_PORT", "31950"))
OT_API_VERSION = os.getenv("OT_API_VERSION", "3")
TIMEOUT_SEC = float(os.getenv("HTTP_TIMEOUT", "30"))
app = FastAPI(title="Opentrons Protocol Analyzer API")
class AnalyzeRequest(BaseModel):
protocol_text: str = Field(..., description="Python protocol source code")
filename: str = Field("protocol.py", description="Filename to send to robot-server")
class AnalyzeResponse(BaseModel):
ok: bool
status_code: int
data: Optional[dict] = None
error: Optional[dict] = None
def _post_protocol_file(filepath: str, filename: str) -> requests.Response:
endpoint = f"http://{ROBOT_IP}:{ROBOT_PORT}/protocols"
headers = {"Opentrons-Version": OT_API_VERSION}
with open(filepath, "rb") as f:
files = {"files": (filename, f, "text/x-python")}
return requests.post(endpoint, headers=headers, files=files, timeout=TIMEOUT_SEC)
@app.get("/health")
def health():
# FastAPIの生存確認(robot-serverの生存確認は別endpointに分ける)
return {"ok": True}
@app.get("/robot/health")
def robot_health():
# robot-serverが上がってるか軽く確認
try:
r = requests.get(f"http://{ROBOT_IP}:{ROBOT_PORT}/health", timeout=5)
return {"ok": r.ok, "status_code": r.status_code, "text": r.text[:2000]}
except requests.RequestException as e:
raise HTTPException(status_code=503, detail=f"robot-server unreachable: {e}")
@app.post("/analyze", response_model=AnalyzeResponse)
def analyze(req: AnalyzeRequest):
text = (req.protocol_text or "").strip()
if not text:
raise HTTPException(status_code=400, detail="protocol_text is empty")
fd, path = tempfile.mkstemp(prefix="protocol_", suffix=".py")
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
f.write(text)
try:
resp = _post_protocol_file(path, req.filename)
except requests.RequestException as e:
raise HTTPException(status_code=503, detail=f"robot-server request failed: {e}")
# robot-serverはJSONを返す想定
try:
payload = resp.json()
except ValueError:
# JSONじゃなければそのまま返す
raise HTTPException(status_code=502, detail=f"non-json from robot-server: {resp.text[:2000]}")
if resp.status_code >= 400:
return AnalyzeResponse(ok=False, status_code=resp.status_code, error=payload)
return AnalyzeResponse(ok=True, status_code=resp.status_code, data=payload)
finally:
try:
os.remove(path)
except OSError:
pass
|