File size: 6,304 Bytes
08ab15f
 
 
 
 
 
 
d33bb4f
08ab15f
 
d33bb4f
f84a7bc
08ab15f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d33bb4f
08ab15f
 
d33bb4f
 
 
 
 
 
 
 
08ab15f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f84a7bc
 
 
 
 
08ab15f
 
d33bb4f
 
 
 
 
 
 
 
 
 
 
 
 
08ab15f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
from __future__ import annotations

import json
import os
from http import HTTPStatus
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import parse_qs, urlparse

from persona_dataset import PersonaDatasetError, dataset_metadata, dataset_status, sample_personas
from silicon_logs import log_status, recent_runs, record_run
from silicon_llm import build_silicon_prompt_preview, resolve_openai_api_key, run_silicon_llm_sampling


APP_DIR = Path(__file__).resolve().parent
STATIC_DIR = APP_DIR / "static" / "immersive"


def read_body(handler: BaseHTTPRequestHandler) -> dict:
    length = int(handler.headers.get("content-length") or 0)
    if length <= 0:
        return {}
    raw = handler.rfile.read(length).decode("utf-8")
    return json.loads(raw) if raw else {}


def write_json(handler: BaseHTTPRequestHandler, payload: dict, status: HTTPStatus = HTTPStatus.OK) -> None:
    data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
    handler.send_response(status)
    handler.send_header("content-type", "application/json; charset=utf-8")
    handler.send_header("content-length", str(len(data)))
    handler.end_headers()
    handler.wfile.write(data)


def content_type(path: Path) -> str:
    suffix = path.suffix.lower()
    return {
        ".html": "text/html; charset=utf-8",
        ".js": "text/javascript; charset=utf-8",
        ".css": "text/css; charset=utf-8",
        ".json": "application/json; charset=utf-8",
        ".svg": "image/svg+xml",
        ".png": "image/png",
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".webp": "image/webp",
    }.get(suffix, "application/octet-stream")


def serve_file(handler: BaseHTTPRequestHandler, path: Path) -> None:
    if not path.exists() or not path.is_file():
        handler.send_error(HTTPStatus.NOT_FOUND)
        return
    data = path.read_bytes()
    handler.send_response(HTTPStatus.OK)
    handler.send_header("content-type", content_type(path))
    handler.send_header("content-length", str(len(data)))
    handler.end_headers()
    handler.wfile.write(data)


class Handler(BaseHTTPRequestHandler):
    def log_message(self, fmt: str, *args: object) -> None:
        print("%s - - %s" % (self.address_string(), fmt % args), flush=True)

    def do_GET(self) -> None:
        parsed = urlparse(self.path)
        path = parsed.path
        if path == "/api/status":
            return write_json(
                self,
                {
                    "ok": True,
                    "openai_api_key_set": bool(resolve_openai_api_key()),
                    "dataset": dataset_status(),
                    "logs": log_status(),
                },
            )
        if path == "/api/logs/status":
            return write_json(self, log_status())
        if path == "/api/logs/recent":
            token = os.getenv("SILICON_LOG_READ_TOKEN", "").strip()
            provided = parse_qs(parsed.query).get("token", [""])[0]
            if not token or provided != token:
                return write_json(self, {"error": "log read token required", "status": log_status()}, HTTPStatus.FORBIDDEN)
            return write_json(self, {"runs": recent_runs(20), "status": log_status()})
        if path == "/api/persona-dataset/metadata":
            try:
                return write_json(self, dataset_metadata())
            except PersonaDatasetError as exc:
                return write_json(self, {"available": False, "error": str(exc), "status": dataset_status()})
        if path in {"/", "/silicon", "/silicon/"}:
            return serve_file(self, STATIC_DIR / "index.html")
        target = (STATIC_DIR / path.lstrip("/")).resolve()
        if STATIC_DIR.resolve() in target.parents or target == STATIC_DIR.resolve():
            return serve_file(self, target)
        self.send_error(HTTPStatus.NOT_FOUND)

    def do_POST(self) -> None:
        parsed = urlparse(self.path)
        payload = read_body(self)
        if parsed.path == "/api/persona-dataset/sample":
            try:
                return write_json(self, sample_personas(payload))
            except PersonaDatasetError as exc:
                return write_json(self, {"error": str(exc), "status": dataset_status()}, HTTPStatus.BAD_REQUEST)
        if parsed.path == "/api/silicon/prompt-preview":
            try:
                return write_json(self, build_silicon_prompt_preview(payload))
            except ValueError as exc:
                return write_json(self, {"error": str(exc)}, HTTPStatus.BAD_REQUEST)
        if parsed.path == "/api/silicon/llm-run":
            try:
                result = run_silicon_llm_sampling(payload)
                try:
                    result["runLog"] = record_run(
                        payload,
                        result,
                        client={
                            "userAgent": self.headers.get("user-agent", "")[:240],
                            "referer": self.headers.get("referer", "")[:240],
                        },
                    )
                except Exception as log_exc:  # noqa: BLE001
                    result["runLogError"] = f"{type(log_exc).__name__}: {log_exc}"
                return write_json(self, result)
            except ValueError as exc:
                return write_json(self, {"error": str(exc)}, HTTPStatus.BAD_REQUEST)
            except RuntimeError as exc:
                return write_json(self, {"error": str(exc)}, HTTPStatus.BAD_REQUEST)
        self.send_error(HTTPStatus.NOT_FOUND)


def main() -> int:
    import argparse

    parser = argparse.ArgumentParser()
    parser.add_argument("--host", default=os.getenv("HOST", "127.0.0.1"))
    parser.add_argument("--port", type=int, default=int(os.getenv("PORT", "8765")))
    args = parser.parse_args()
    server = ThreadingHTTPServer((args.host, args.port), Handler)
    print(f"Silicon Sampling Lab running at http://{args.host}:{args.port}", flush=True)
    print(f"OpenAI API key available: {bool(resolve_openai_api_key())}", flush=True)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nShutting down.", flush=True)
    finally:
        server.server_close()
    return 0


if __name__ == "__main__":
    raise SystemExit(main())