File size: 2,613 Bytes
33d7314
 
 
 
 
 
 
 
 
00746d1
33d7314
 
 
 
 
 
 
 
 
 
 
 
 
 
00746d1
 
 
 
 
 
 
33d7314
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from __future__ import annotations

import argparse
import json
import os
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import urlparse

from llm import llm_status
from report import build_report


PROJECT_ROOT = Path(__file__).resolve().parents[1]
WEB_ROOT = PROJECT_ROOT / "web"


class TideHandler(SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=str(WEB_ROOT), **kwargs)

    def do_GET(self) -> None:
        route = urlparse(self.path).path
        if route == "/healthz":
            self._json_response(
                {
                    "status": "ok",
                    "service": "tide-api",
                    "llm": llm_status(PROJECT_ROOT / ".env"),
                }
            )
            return
        super().do_GET()

    def do_POST(self) -> None:
        route = urlparse(self.path).path
        if route != "/api/report":
            self.send_error(404, "Unknown route")
            return

        try:
            length = int(self.headers.get("content-length", "0"))
            payload = self.rfile.read(length)
            form_data = json.loads(payload.decode("utf-8"))
            report = build_report(form_data, PROJECT_ROOT)
        except Exception as exc:  # Keep local MVP errors visible to the browser.
            self._json_response({"ok": False, "error": str(exc)}, status=500)
            return

        self._json_response(report)

    def log_message(self, format: str, *args) -> None:
        print(f"{self.address_string()} - {format % args}")

    def _json_response(self, payload: dict, status: int = 200) -> None:
        body = json.dumps(payload, indent=2).encode("utf-8")
        self.send_response(status)
        self.send_header("content-type", "application/json; charset=utf-8")
        self.send_header("cache-control", "no-store")
        self.send_header("x-content-type-options", "nosniff")
        self.send_header("content-length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


def main() -> None:
    parser = argparse.ArgumentParser(description="Run the TIDE form MVP server.")
    parser.add_argument("--host", default=os.getenv("TIDE_HOST", "127.0.0.1"))
    parser.add_argument("--port", type=int, default=int(os.getenv("PORT", "8000")))
    args = parser.parse_args()

    server = ThreadingHTTPServer((args.host, args.port), TideHandler)
    print(f"TIDE form MVP running at http://{args.host}:{args.port}")
    server.serve_forever()


if __name__ == "__main__":
    main()