abhishekgahlot's picture
openjev-server 0.2.0 with demos
0a2e8cf verified
Raw
History Blame Contribute Delete
4.9 kB
"""`openjev serve | calibrate | bench | version`."""
from __future__ import annotations
import argparse
import asyncio
import json
import logging
import sys
from pathlib import Path
from . import __version__
from .backends import make_backend
from .config import PROFILES_DIR, Settings, load_profile
from .readout import Readout
def _serve(a):
s = Settings(**{k: v for k, v in vars(a).items() if v is not None and k in Settings.model_fields})
logging.basicConfig(level=s.log_level, format="%(message)s")
profile = load_profile(
s.profile, {"perms": a.perms, "temp": a.temp, "noul_t": a.noul_t, "assistant_prefix": a.assistant_prefix, "letter_prefix": a.letter_prefix}
)
try:
backend, extra = make_backend(s, profile)
except ValueError as e:
sys.exit(str(e))
readout = Readout(backend, profile)
from .backends.probe import probe
found = asyncio.run(backend.start())
report = asyncio.run(
probe(readout, backend, letter_prefix_used=found.get("letter_prefix", ""), exact=found.get("exact_readout"), vision=found.get("vision"))
)
found.update(report)
logging.getLogger("openjev").info(json.dumps({"model_probe": found}))
if "problem" in report and not a.force:
sys.exit(f"refusing to serve: {report['problem']} (start with --force to serve anyway)")
import uvicorn
from .server import build_app
app = build_app(readout, token=s.token, model_dir=s.model, backend_name=s.backend, extra_version={**extra, "model_probe": found})
logging.getLogger("openjev").info(
json.dumps({"serving": f"http://{s.host}:{s.port}/v1/systemone", "backend": s.backend, "model": s.model, "profile": profile.to_dict()})
)
uvicorn.run(app, host=s.host, port=s.port, log_level="warning", access_log=False)
def _calibrate(a):
from .calibrate import collect, fit, write_profile
with open(a.dev) as f:
rows = [json.loads(line) for line in f if line.strip()]
collected = asyncio.run(collect(rows, a.endpoint, a.token, a.concurrency))
result = fit(collected)
print(json.dumps(result, indent=1))
base = Path(a.base) if Path(a.base).exists() else PROFILES_DIR / f"{a.base}.json"
out = Path(a.out)
write_profile(base, result, out.stem, out)
print(f"profile written: {out} (serve it with --profile {out})")
def main(argv=None):
ap = argparse.ArgumentParser(prog="openjev", description=f"openjev-server {__version__}: a decision API over any open model")
sub = ap.add_subparsers(dest="cmd", required=True)
s = sub.add_parser("serve", help="serve POST /v1/systemone")
s.add_argument("--backend", choices=["vllm", "mlx"])
s.add_argument("--model", help="tokenizer / model dir (vllm) or the MLX model dir (mlx)")
s.add_argument("--vllm-url", dest="vllm_url")
s.add_argument("--served-model-name", dest="served_model_name")
s.add_argument("--host")
s.add_argument("--port", type=int)
s.add_argument("--token")
s.add_argument("--profile", help="profile name under profiles/ or a JSON path")
s.add_argument("--perms", type=int, help="average over N option orders (accuracy mode; costs latency)")
s.add_argument("--temp", type=float)
s.add_argument("--noul-t", dest="noul_t", type=float)
s.add_argument("--no-prefix-cache", dest="prefix_cache", action="store_false", default=None)
s.add_argument(
"--assistant-prefix",
dest="assistant_prefix",
help="text at the start of the assistant turn before the readout (e.g. an empty think block for models that always reason first)",
)
s.add_argument("--letter-prefix", dest="letter_prefix", choices=["auto", "", " "], help="label token form: bare 'A', space-prefixed ' A', or auto")
s.add_argument("--force", action="store_true", help="serve even when the startup probe reports a problem")
s.set_defaults(fn=_serve)
c = sub.add_parser("calibrate", help="fit temperature and yes/no scale on development rows against a running server")
c.add_argument("--dev", required=True, help="JSONL: {state, questions: {id: question}, gold}")
c.add_argument("--endpoint", default="http://localhost:3000")
c.add_argument("--token", default="")
c.add_argument("--base", default="uncalibrated", help="profile the server is running")
c.add_argument("--out", required=True, help="where to write the fitted profile JSON")
c.add_argument("--concurrency", type=int, default=8)
c.set_defaults(fn=_calibrate)
b = sub.add_parser("bench", help="latency / throughput of a running server")
b.set_defaults(fn=lambda a: __import__("openjev_server.bench", fromlist=["main"]).main(a.rest))
b.add_argument("rest", nargs=argparse.REMAINDER)
v = sub.add_parser("version")
v.set_defaults(fn=lambda a: print(__version__))
a = ap.parse_args(argv)
a.fn(a)
if __name__ == "__main__":
main()