Files
agent-maxim/simple_dashboard.py

47 lines
10 KiB
Python

#!/usr/bin/env python3
import base64, json
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.request
HTML_CONTENT = base64.b64decode("PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9InJ1Ij4KPGhlYWQ+CiAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCwgbWF4aW11bS1zY2FsZT0xLjAsIHVzZXItc2NhbGFibGU9bm8iPgogICAgPHRpdGxlPkFnZW50IE1heGltPC90aXRsZT4KICAgIDxzdHlsZT4KICAgICAgICAqIHsgbWFyZ2luOiAwOyBwYWRkaW5nOiAwOyBib3gtc2l6aW5nOiBib3JkZXItYm94OyB9CiAgICAgICAgaHRtbCwgYm9keSB7IGhlaWdodDogMTAwZHZoOyBvdmVyZmxvdzogaGlkZGVuOyBmb250LWZhbWlseTogLWFwcGxlLXN5c3RlbSwgc2Fucy1zZXJpZjsgYmFja2dyb3VuZDogI2U1ZGRkNTsgfQogICAgICAgIC5hcHAgeyBwb3NpdGlvbjogZml4ZWQ7IGluc2V0OiAwOyBkaXNwbGF5OiBmbGV4OyBmbGV4LWRpcmVjdGlvbjogY29sdW1uOyB9CiAgICAgICAgLmhlYWRlciB7IGZsZXg6IDAgMCA1MnB4OyBiYWNrZ3JvdW5kOiAjMTI4QzdFOyBjb2xvcjogd2hpdGU7IHBhZGRpbmc6IDAgMTZweDsgZm9udC13ZWlnaHQ6IDYwMDsgZm9udC1zaXplOiAxOHB4OyBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyB9CiAgICAgICAgLmNoYXQtbWVzc2FnZXMgeyBmbGV4OiAxOyBvdmVyZmxvdy15OiBhdXRvOyBwYWRkaW5nOiAxMHB4OyB9CiAgICAgICAgLm1lc3NhZ2UgeyBtYXgtd2lkdGg6IDgwJTsgcGFkZGluZzogMTBweCAxNHB4OyBib3JkZXItcmFkaXVzOiAxNnB4OyBmb250LXNpemU6IDE2cHg7IG1hcmdpbi1ib3R0b206IDEwcHg7IH0KICAgICAgICAubWVzc2FnZS51c2VyIHsgbWFyZ2luLWxlZnQ6IGF1dG87IGJhY2tncm91bmQ6ICNkY2Y4YzY7IGJvcmRlci1ib3R0b20tcmlnaHQtcmFkaXVzOiA0cHg7IH0KICAgICAgICAubWVzc2FnZS5hZ2VudCB7IG1hcmdpbi1yaWdodDogYXV0bzsgYmFja2dyb3VuZDogI2YxZjFmMTsgYm9yZGVyLWJvdHRvbS1sZWZ0LXJhZGl1czogNHB4OyB9CiAgICAgICAgLm1lc3NhZ2UgLnRpbWUgeyBmb250LXNpemU6IDExcHg7IGNvbG9yOiAjODg4OyBtYXJnaW4tbGVmdDogNnB4OyB9CiAgICAgICAgLmxvYWRlciB7IGRpc3BsYXk6IG5vbmU7IHBhZGRpbmc6IDEwcHg7IHRleHQtYWxpZ246IGNlbnRlcjsgY29sb3I6ICM2NjY7IH0KICAgICAgICAubG9hZGVyLnZpc2libGUgeyBkaXNwbGF5OiBibG9jazsgfQogICAgICAgIC5pbnB1dC1jb250YWluZXIgeyBmbGV4OiAwIDAgYXV0bzsgZGlzcGxheTogZmxleDsgZ2FwOiA4cHg7IHBhZGRpbmc6IDEwcHg7IGJhY2tncm91bmQ6ICNmZmY7IGJvcmRlci10b3A6IDFweCBzb2xpZCAjZWVlOyB9CiAgICAgICAgLmNoYXQtaW5wdXQgeyBmbGV4OiAxOyByZXNpemU6IG5vbmU7IGJvcmRlci1yYWRpdXM6IDIwcHg7IGJvcmRlcjogMXB4IHNvbGlkICNkZGQ7IHBhZGRpbmc6IDEycHggMTZweDsgZm9udC1zaXplOiAxNnB4OyBtYXgtaGVpZ2h0OiAxMjBweDsgZm9udC1mYW1pbHk6IGluaGVyaXQ7IH0KICAgICAgICAuY2hhdC1pbnB1dDpmb2N1cyB7IG91dGxpbmU6IG5vbmU7IGJvcmRlci1jb2xvcjogIzEyOEM3RTsgfQogICAgICAgIC5zZW5kLWJ1dHRvbiB7IG1pbi13aWR0aDogNDRweDsgaGVpZ2h0OiA0NHB4OyBib3JkZXItcmFkaXVzOiAyMHB4OyBib3JkZXI6IG5vbmU7IGJhY2tncm91bmQ6ICMxMjhDN0U7IGNvbG9yOiB3aGl0ZTsgZm9udC1zaXplOiAxOHB4OyBjdXJzb3I6IHBvaW50ZXI7IH0KICAgICAgICAuc2VuZC1idXR0b246ZGlzYWJsZWQgeyBiYWNrZ3JvdW5kOiAjY2NjOyB9CiAgICA8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5PgogICAgPGRpdiBjbGFzcz0iYXBwIj4KICAgICAgICA8ZGl2IGNsYXNzPSJoZWFkZXIiPkFnZW50IE1heGltPC9kaXY+CiAgICAgICAgPGRpdiBjbGFzcz0iY2hhdC1tZXNzYWdlcyIgaWQ9Im1lc3NhZ2VzIj4KICAgICAgICAgICAgPGRpdiBpZD0idHlwaW5nIiBzdHlsZT0iZGlzcGxheTpub25lOyBwYWRkaW5nOiAxMHB4OyBjb2xvcjogIzY2NjsiPi4uLjwvZGl2PgogICAgICAgIDwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImxvYWRlciIgaWQ9ImxvYWRlciI+0JTRg9C80LDRji4uLjwvZGl2PgogICAgICAgIDxkaXYgY2xhc3M9ImlucHV0LWNvbnRhaW5lciI+CiAgICAgICAgICAgIDx0ZXh0YXJlYSBjbGFzcz0iY2hhdC1pbnB1dCIgaWQ9ImlucHV0IiBwbGFjZWhvbGRlcj0i0KHQvtC+0LHRidC10L3QuNC1Li4uIiByb3dzPSIxIj48L3RleHRhcmVhPgogICAgICAgICAgICA8YnV0dG9uIGNsYXNzPSJzZW5kLWJ1dHRvbiIgaWQ9InNlbmRCdG4iPuKepDwvYnV0dG9uPgogICAgICAgIDwvZGl2PgogICAgPC9kaXY+CiAgICA8c2NyaXB0PgogICAgICAgIGNvbnN0IEFQSV9VUkwgPSAnL3J1bnMnOwogICAgICAgIAogICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTUNvbnRlbnRMb2FkZWQnLCBmdW5jdGlvbigpIHsKICAgICAgICAgICAgY29uc3QgaW5wdXQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnaW5wdXQnKTsKICAgICAgICAgICAgY29uc3Qgc2VuZEJ0biA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzZW5kQnRuJyk7CiAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2VzRGl2ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ21lc3NhZ2VzJyk7CiAgICAgICAgICAgIGNvbnN0IGxvYWRlciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2FkZXInKTsKICAgICAgICAgICAgCiAgICAgICAgICAgIGZ1bmN0aW9uIGdldFRpbWUoKSB7CiAgICAgICAgICAgICAgICBjb25zdCBkID0gbmV3IERhdGUoKTsKICAgICAgICAgICAgICAgIHJldHVybiBkLmdldEhvdXJzKCkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpICsgJzonICsKICAgICAgICAgICAgICAgICAgICAgICBkLmdldE1pbnV0ZXMoKS50b1N0cmluZygpLnBhZFN0YXJ0KDIsICcwJyk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIGZ1bmN0aW9uIHNob3dUeXBpbmcoKSB7CiAgICAgICAgICAgICAgICBjb25zdCB0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3R5cGluZycpOwogICAgICAgICAgICAgICAgaWYgKHQpIHQuc3R5bGUuZGlzcGxheSA9ICdibG9jayc7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIGZ1bmN0aW9uIGhpZGVUeXBpbmcoKSB7CiAgICAgICAgICAgICAgICBjb25zdCB0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3R5cGluZycpOwogICAgICAgICAgICAgICAgaWYgKHQpIHQuc3R5bGUuZGlzcGxheSA9ICdub25lJzsKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgZnVuY3Rpb24gcGxheVNvdW5kKCkgewogICAgICAgICAgICAgICAgdHJ5IHsKICAgICAgICAgICAgICAgICAgICBjb25zdCBjdHggPSBuZXcgKHdpbmRvdy5BdWRpb0NvbnRleHQgfHwgd2luZG93LndlYmtpdEF1ZGlvQ29udGV4dCkoKTsKICAgICAgICAgICAgICAgICAgICBjb25zdCBvc2MgPSBjdHguY3JlYXRlT3NjaWxsYXRvcigpOwogICAgICAgICAgICAgICAgICAgIGNvbnN0IGdhaW4gPSBjdHguY3JlYXRlR2FpbigpOwogICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIG9zYy50eXBlID0gJ3NpbmUnOwogICAgICAgICAgICAgICAgICAgIG9zYy5mcmVxdWVuY3kuc2V0VmFsdWVBdFRpbWUoODgwLCBjdHguY3VycmVudFRpbWUpOwogICAgICAgICAgICAgICAgICAgIGdhaW4uZ2Fpbi5zZXRWYWx1ZUF0VGltZSgwLjA1LCBjdHguY3VycmVudFRpbWUpOwogICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIG9zYy5jb25uZWN0KGdhaW4pOwogICAgICAgICAgICAgICAgICAgIGdhaW4uY29ubmVjdChjdHguZGVzdGluYXRpb24pOwogICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgIG9zYy5zdGFydCgpOwogICAgICAgICAgICAgICAgICAgIG9zYy5zdG9wKGN0eC5jdXJyZW50VGltZSArIDAuMDgpOwogICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge30KICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgZnVuY3Rpb24gdmlicmF0ZSgpIHsKICAgICAgICAgICAgICAgIGlmIChuYXZpZ2F0b3IudmlicmF0ZSkgewogICAgICAgICAgICAgICAgICAgIG5hdmlnYXRvci52aWJyYXRlKDMwKTsKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgZnVuY3Rpb24gYWRkTWVzc2FnZSh0ZXh0LCB0eXBlKSB7CiAgICAgICAgICAgICAgICBjb25zdCBtc2cgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTsKICAgICAgICAgICAgICAgIG1zZy5jbGFzc05hbWUgPSAnbWVzc2FnZSAnICsgdHlwZTsKICAgICAgICAgICAgICAgIG1zZy5pbm5lckhUTUwgPSB0ZXh0ICsgJyA8c3BhbiBjbGFzcz0idGltZSI+JyArIGdldFRpbWUoKSArICc8L3NwYW4+JzsKICAgICAgICAgICAgICAgIG1lc3NhZ2VzRGl2LmFwcGVuZENoaWxkKG1zZyk7CiAgICAgICAgICAgICAgICBtZXNzYWdlc0Rpdi5zY3JvbGxUb3AgPSBtZXNzYWdlc0Rpdi5zY3JvbGxIZWlnaHQ7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIGZ1bmN0aW9uIHNlbmQoKSB7CiAgICAgICAgICAgICAgICBjb25zdCBtZXNzYWdlID0gaW5wdXQudmFsdWUudHJpbSgpOwogICAgICAgICAgICAgICAgaWYgKCFtZXNzYWdlKSByZXR1cm47CiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGlucHV0LnZhbHVlID0gJyc7CiAgICAgICAgICAgICAgICBhZGRNZXNzYWdlKG1lc3NhZ2UsICd1c2VyJyk7CiAgICAgICAgICAgICAgICBzaG93VHlwaW5nKCk7CiAgICAgICAgICAgICAgICBsb2FkZXIuY2xhc3NMaXN0LmFkZCgndmlzaWJsZScpOwogICAgICAgICAgICAgICAgbWVzc2FnZXNEaXYuc2Nyb2xsVG9wID0gbWVzc2FnZXNEaXYuc2Nyb2xsSGVpZ2h0OwogICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICBmZXRjaChBUElfVVJMLCB7CiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnUE9TVCcsCiAgICAgICAgICAgICAgICAgICAgaGVhZGVyczogeydDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbjsgY2hhcnNldD11dGYtOCd9LAogICAgICAgICAgICAgICAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHtnb2FsOiBtZXNzYWdlfSkKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbihyZXMpIHsgcmV0dXJuIHJlcy5qc29uKCk7IH0pCiAgICAgICAgICAgICAgICAudGhlbihmdW5jdGlvbihkYXRhKSB7CiAgICAgICAgICAgICAgICAgICAgbG9hZGVyLmNsYXNzTGlzdC5yZW1vdmUoJ3Zpc2libGUnKTsKICAgICAgICAgICAgICAgICAgICBoaWRlVHlwaW5nKCk7CiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGV4dCA9IGRhdGEucmVzcG9uc2UgfHwgZGF0YS5yZXN1bHQgfHwgZGF0YS5tZXNzYWdlIHx8ICfQndC10YIg0L7RgtCy0LXRgtCwJzsKICAgICAgICAgICAgICAgICAgICBhZGRNZXNzYWdlKHRleHQsICdhZ2VudCcpOwogICAgICAgICAgICAgICAgICAgIHBsYXlTb3VuZCgpOwogICAgICAgICAgICAgICAgICAgIHZpYnJhdGUoKTsKICAgICAgICAgICAgICAgIH0pCiAgICAgICAgICAgICAgICAuY2F0Y2goZnVuY3Rpb24oZXJyKSB7CiAgICAgICAgICAgICAgICAgICAgbG9hZGVyLmNsYXNzTGlzdC5yZW1vdmUoJ3Zpc2libGUnKTsKICAgICAgICAgICAgICAgICAgICBoaWRlVHlwaW5nKCk7CiAgICAgICAgICAgICAgICAgICAgYWRkTWVzc2FnZSgn0J7RiNC40LHQutCwOiAnICsgZXJyLm1lc3NhZ2UsICdhZ2VudCcpOwogICAgICAgICAgICAgICAgfSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgCiAgICAgICAgICAgIHNlbmRCdG4uYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBzZW5kKTsKICAgICAgICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIGZ1bmN0aW9uKGUpIHsKICAgICAgICAgICAgICAgIGlmIChlLmtleSA9PT0gJ0VudGVyJyAmJiAhZS5zaGlmdEtleSkgewogICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTsKICAgICAgICAgICAgICAgICAgICBzZW5kKCk7CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0pOwogICAgICAgIH0pOwogICAgPC9zY3JpcHQ+CjwvYm9keT4KPC9odG1sPg==").decode("utf-8")
class DashboardHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/" or self.path == "":
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.end_headers()
self.wfile.write(HTML_CONTENT.encode("utf-8"))
else:
self.send_response(404)
self.end_headers()
def do_POST(self):
if self.path == "/runs":
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
try:
data = json.loads(body.decode("utf-8"))
goal = data.get("goal", "")
req = urllib.request.Request(
"http://localhost:8000/runs",
data=json.dumps({"goal": goal, "adapter": "agent"}, ensure_ascii=False).encode("utf-8"),
headers={"Content-Type": "application/json; charset=utf-8"},
method="POST"
)
with urllib.request.urlopen(req, timeout=120) as resp:
resp_data = json.loads(resp.read().decode("utf-8"))
self.send_response(200)
self.send_header("Content-Type", "application/json; charset=utf-8")
self.end_headers()
self.wfile.write(json.dumps(resp_data, ensure_ascii=False).encode("utf-8"))
except Exception as e:
self.send_response(500)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(json.dumps({"error": str(e)}).encode("utf-8"))
else:
self.send_response(404)
self.end_headers()
def log_message(self, *args): pass
HTTPServer(("0.0.0.0", 8610), DashboardHandler).serve_forever()