| 486 | } |
| 487 | |
| 488 | |
| 489 | class PaperFlowGuiHandler(BaseHTTPRequestHandler): |
| 490 | server_version = "PaperFlowGUI/0.1" |
| 491 | |
| 492 | def _send_json(self, payload: Dict[str, Any], status: int = 200) -> None: |
| 493 | data = _json_bytes(payload) |
| 494 | self.send_response(status) |
| 495 | self.send_header("Content-Type", "application/json; charset=utf-8") |
| 496 | self.send_header("Content-Length", str(len(data))) |
| 497 | self.send_header("Cache-Control", "no-store") |
| 498 | self.end_headers() |
| 499 | self.wfile.write(data) |
| 500 | |
| 501 | def _send_file(self, path: Path) -> None: |
| 502 | if not path.exists() or not path.is_file(): |
| 503 | self._send_json({"ok": False, "error": "Not found"}, status=HTTPStatus.NOT_FOUND) |
| 504 | return |
| 505 | data = path.read_bytes() |
| 506 | mime = mimetypes.guess_type(str(path))[0] or "application/octet-stream" |
| 507 | if mime.startswith("text/") or mime in {"application/javascript", "application/json"}: |
| 508 | mime = f"{mime}; charset=utf-8" |
| 509 | self.send_response(200) |
| 510 | self.send_header("Content-Type", mime) |
| 511 | self.send_header("Content-Length", str(len(data))) |
| 512 | self.send_header("Cache-Control", "no-store") |
| 513 | self.end_headers() |
| 514 | self.wfile.write(data) |
| 515 | |
| 516 | def _handle_api(self, routes: Dict[str, ApiHandler], body: Dict[str, Any] | None = None) -> None: |
| 517 | path, query_params = _query(self.path) |
| 518 | route = routes.get(path) |
| 519 | if route is None: |
| 520 | self._send_json({"ok": False, "error": f"Unknown API route: {path}"}, status=HTTPStatus.NOT_FOUND) |
| 521 | return |
| 522 | try: |
| 523 | payload = route(query_params, body or {}) |
| 524 | self._send_json({"ok": True, **payload}) |
| 525 | except Exception as exc: |
| 526 | self._send_json({"ok": False, "error": str(exc)}, status=HTTPStatus.BAD_REQUEST) |
| 527 | |
| 528 | def _send_sse_event(self, event: str, payload: Dict[str, Any]) -> None: |
| 529 | self.wfile.write(_sse_bytes(event, payload)) |
| 530 | self.wfile.flush() |
| 531 | |
| 532 | def _handle_wiki_ask_stream(self, body: Dict[str, Any]) -> None: |
| 533 | self.send_response(200) |
| 534 | self.send_header("Content-Type", "text/event-stream; charset=utf-8") |
| 535 | self.send_header("Cache-Control", "no-store") |
| 536 | self.send_header("Connection", "close") |
| 537 | self.end_headers() |
| 538 | try: |
| 539 | response_language = _response_language(body) |
| 540 | status_text = ( |
| 541 | "Searching local Wiki and citation sources" |
| 542 | if response_language == "en" |
| 543 | else "正在检索本地 Wiki 与引用来源" |
| 544 | ) |
| 545 | self._send_sse_event("status", {"text": status_text}) |
nothing calls this directly
no outgoing calls
no test coverage detected