|
| 1 | +"""Local web/ with the PROD backend proxied behind it. |
| 2 | +
|
| 3 | +Serves the working-tree frontend while forwarding /health /papers /figures |
| 4 | +/pages/* /query /demo/chat to the live deployment — full end-to-end testing |
| 5 | +of uncommitted client code against the real model and corpus, no deploy. |
| 6 | +""" |
| 7 | + |
| 8 | +import functools |
| 9 | +import http.server |
| 10 | +import urllib.error |
| 11 | +import urllib.request |
| 12 | +from pathlib import Path |
| 13 | + |
| 14 | +PROD = "https://spectrarag-ar6wxit42a-ew.a.run.app" |
| 15 | +ROOT = str(Path(__file__).resolve().parents[1] / "web") |
| 16 | + |
| 17 | + |
| 18 | +class H(http.server.SimpleHTTPRequestHandler): |
| 19 | + protocol_version = "HTTP/1.0" # close-delimited responses, safe for SSE relay |
| 20 | + |
| 21 | + def _proxy(self) -> None: |
| 22 | + data = None |
| 23 | + if self.command == "POST": |
| 24 | + data = self.rfile.read(int(self.headers.get("Content-Length", 0))) |
| 25 | + req = urllib.request.Request(PROD + self.path, data=data, method=self.command) |
| 26 | + req.add_header("Content-Type", self.headers.get("Content-Type", "application/json")) |
| 27 | + try: |
| 28 | + with urllib.request.urlopen(req, timeout=180) as r: |
| 29 | + self.send_response(r.status) |
| 30 | + self.send_header("Content-Type", r.headers.get("Content-Type", "application/json")) |
| 31 | + self.end_headers() |
| 32 | + while True: |
| 33 | + chunk = r.read(1024) |
| 34 | + if not chunk: |
| 35 | + break |
| 36 | + self.wfile.write(chunk) |
| 37 | + self.wfile.flush() |
| 38 | + except urllib.error.HTTPError as e: |
| 39 | + body = e.read() |
| 40 | + self.send_response(e.code) |
| 41 | + self.send_header("Content-Type", "application/json") |
| 42 | + self.send_header("Content-Length", str(len(body))) |
| 43 | + self.end_headers() |
| 44 | + self.wfile.write(body) |
| 45 | + |
| 46 | + def do_GET(self) -> None: |
| 47 | + if self.path.startswith(("/health", "/papers", "/figures", "/pages/")): |
| 48 | + return self._proxy() |
| 49 | + super().do_GET() |
| 50 | + |
| 51 | + def do_POST(self) -> None: |
| 52 | + if self.path.startswith(("/query", "/demo/chat")): |
| 53 | + return self._proxy() |
| 54 | + self.send_error(404) |
| 55 | + |
| 56 | + |
| 57 | +http.server.ThreadingHTTPServer( |
| 58 | + ("127.0.0.1", 8765), functools.partial(H, directory=ROOT) |
| 59 | +).serve_forever() |
0 commit comments