ver0.1
This commit is contained in:
@@ -4,10 +4,13 @@
|
||||
- Exposes `GET /labels.json`, which parses the repo's
|
||||
`app/resources/consumable_classifier_labels.yaml` and returns its label
|
||||
list so the page can prefill the candidate-consumables input.
|
||||
- ``--live`` 使用 dev 依赖 ``livereload``:修改本目录下 HTML/JS/CSS
|
||||
或更新 ``labels.json``/YAML 后,浏览器自动刷新(需 ``uv run --group dev``)。
|
||||
|
||||
Run:
|
||||
python scripts/demo_client/server.py # 127.0.0.1:38081
|
||||
python scripts/demo_client/server.py -p 9000 # custom port
|
||||
uv run --group dev python scripts/demo_client/server.py --live
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -16,6 +19,8 @@ import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from http import HTTPStatus
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
@@ -24,6 +29,8 @@ from typing import Any
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
REPO_ROOT = SCRIPT_DIR.parents[1]
|
||||
LABELS_YAML = REPO_ROOT / "app" / "resources" / "consumable_classifier_labels.yaml"
|
||||
# ``--live`` 模式写入静态 `labels.json`,与 livereload 兼容(勿提交,见 .gitignore)
|
||||
LABELS_JSON_ARTIFACT = SCRIPT_DIR / "labels.json"
|
||||
|
||||
|
||||
def _load_labels_with_pyyaml(path: Path) -> list[str] | None:
|
||||
@@ -85,6 +92,66 @@ def load_labels() -> list[str]:
|
||||
return labels
|
||||
|
||||
|
||||
def write_labels_json_artifact() -> None:
|
||||
body = json.dumps({"labels": load_labels()}, ensure_ascii=False) + "\n"
|
||||
LABELS_JSON_ARTIFACT.write_text(body, encoding="utf-8")
|
||||
|
||||
|
||||
def _spawn_labels_yaml_poll() -> None:
|
||||
p = LABELS_YAML
|
||||
state: list[float] = [0.0]
|
||||
if p.is_file():
|
||||
state[0] = p.stat().st_mtime
|
||||
|
||||
def loop() -> None:
|
||||
while True:
|
||||
time.sleep(1.0)
|
||||
if not p.is_file():
|
||||
continue
|
||||
m = p.stat().st_mtime
|
||||
if m > state[0]:
|
||||
state[0] = m
|
||||
try:
|
||||
write_labels_json_artifact()
|
||||
except OSError as e:
|
||||
print(
|
||||
f"[demo-client] labels.json 写入失败: {e}",
|
||||
file=sys.stderr,
|
||||
)
|
||||
|
||||
threading.Thread(target=loop, daemon=True, name="DemoClientLabelsYamlWatch").start()
|
||||
|
||||
|
||||
def run_livereload(host: str, port: int) -> None:
|
||||
try:
|
||||
from livereload import Server
|
||||
except ImportError as exc: # pragma: no cover
|
||||
print(
|
||||
"``--live`` 需要 dev 依赖。请执行: uv sync --group dev",
|
||||
file=sys.stderr,
|
||||
)
|
||||
raise SystemExit(1) from exc
|
||||
|
||||
write_labels_json_artifact()
|
||||
_spawn_labels_yaml_poll()
|
||||
server = Server()
|
||||
server.watch(str(SCRIPT_DIR))
|
||||
if LABELS_YAML.is_file():
|
||||
server.watch(str(LABELS_YAML))
|
||||
url = f"http://{host}:{port}/"
|
||||
print(f"Demo client (livereload) at {url}")
|
||||
print(f" static dir : {SCRIPT_DIR}")
|
||||
print(f" labels yaml: {LABELS_YAML} -> {LABELS_JSON_ARTIFACT.name}")
|
||||
print("Press Ctrl+C to stop.")
|
||||
server.serve(
|
||||
root=str(SCRIPT_DIR),
|
||||
host=host,
|
||||
port=port,
|
||||
open_url=False,
|
||||
debug=False,
|
||||
)
|
||||
|
||||
|
||||
class DemoHandler(SimpleHTTPRequestHandler):
|
||||
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||
super().__init__(*args, directory=str(SCRIPT_DIR), **kwargs)
|
||||
@@ -110,14 +177,9 @@ class DemoHandler(SimpleHTTPRequestHandler):
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Operation room demo client server")
|
||||
parser.add_argument("--host", default="127.0.0.1")
|
||||
parser.add_argument("-p", "--port", type=int, default=38081)
|
||||
args = parser.parse_args()
|
||||
|
||||
server = ThreadingHTTPServer((args.host, args.port), DemoHandler)
|
||||
url = f"http://{args.host}:{args.port}/"
|
||||
def run_plain(host: str, port: int) -> None:
|
||||
server = ThreadingHTTPServer((host, port), DemoHandler)
|
||||
url = f"http://{host}:{port}/"
|
||||
print(f"Demo client serving at {url}")
|
||||
print(f" static dir : {SCRIPT_DIR}")
|
||||
print(f" labels yaml: {LABELS_YAML}")
|
||||
@@ -130,5 +192,21 @@ def main() -> None:
|
||||
server.server_close()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Operation room demo client server")
|
||||
parser.add_argument("--host", default="127.0.0.1")
|
||||
parser.add_argument("-p", "--port", type=int, default=38081)
|
||||
parser.add_argument(
|
||||
"--live",
|
||||
action="store_true",
|
||||
help="浏览器热重载(需 uv sync --group dev;会生成同目录 labels.json)",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if args.live:
|
||||
run_livereload(args.host, args.port)
|
||||
else:
|
||||
run_plain(args.host, args.port)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user