Raymond1122's picture
add serve.py
db16a11 verified
Raw History Blame Contribute Delete
4.04 kB
"""metask-jev-4b HTTP server — TypeSafe /v1/systemone compatible.
POST /v1/systemone
body: {"state": str|obj, "questions": {"decision": {type, instructions, criteria}}}
resp: {"answers": {"decision": {
"type": "choice"|"noul"|"score",
"probabilities": {option: p}, # choice/score
"noul": P(true), # noul
}}}
GET /health -> {"ok": true}
"""
import argparse
import json
import sys
from pathlib import Path
from flask import Flask, jsonify, request
sys.path.insert(0, str(Path(__file__).resolve().parent))
from jev_scorer import load_model, score # noqa: E402
TEMPERATURE = {"choice": 1.7875, "noul": 2.25, "score": 2.05}
app = Flask(__name__)
_state = {}
def get_model(model_path):
if "model" not in _state:
_state["model"], _state["tok"], _state["dev"] = load_model(model_path)
print(f"[serve] model loaded on {_state['dev']}", flush=True)
return _state["model"], _state["tok"]
@app.route("/health")
def health():
return jsonify(ok=True, model="metask-jev-4b")
@app.route("/v1/systemone", methods=["POST"])
def systemone():
body = request.get_json(force=True)
model, tok = get_model(_state.get("model_path", ""))
questions = body.get("questions", {})
state = body.get("state", "")
if not isinstance(state, str):
state = json.dumps(state, ensure_ascii=False)
answers = {}
for name, q in questions.items():
qtype = q["type"]
crit = q.get("criteria") or {}
if qtype == "noul":
schema = {"decision": {
"description": q.get("instructions", ""),
"type": "boolean", "choices": [False, True],
"choice_descriptions": {"false": crit.get("false", "No"),
"true": crit.get("true", "Yes")}}}
T = TEMPERATURE["noul"]
elif qtype == "score":
labels = [str(i) for i in range(len(crit))]
schema = {"decision": {
"description": q.get("instructions", ""),
"type": "enum", "choices": labels,
"choice_descriptions": dict(zip(labels, crit))}}
T = TEMPERATURE["score"]
else:
labels = list(crit.keys()) if isinstance(crit, dict) else list(crit)
schema = {"decision": {
"description": q.get("instructions", ""),
"type": "enum", "choices": labels,
"choice_descriptions": {k: (crit.get(k) or k) for k in labels}}}
T = TEMPERATURE["choice"]
try:
r = score(model, tok, state, schema, temperature=T, max_input_tokens=4096)
except ValueError as e:
if "limit is" in str(e):
return jsonify(error=f"422 over context limit: {e}"), 422
return jsonify(error=str(e)), 500
probs = r["probabilities"]
if qtype == "noul":
answers[name] = {"type": "noul", "noul": float(probs.get("true", 0.0)),
"probabilities": probs}
else:
answers[name] = {"type": qtype, "probabilities": probs}
return jsonify(answers=answers)
def build_prompt(tok, state, schema, max_input_tokens):
"""Re-exported for card Quickstart: vendored official prepare_prompts."""
from jev_schema import prepare_prompts
return prepare_prompts(tok, state, schema, max_input_tokens)
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("--port", type=int, default=8000)
ap.add_argument("--model", default="wayfind/metask-jev-4b-policy-mix",
help="HF repo id or path to model_path.txt")
args = ap.parse_args()
mp = Path(args.model)
if mp.exists() and mp.is_file(): # model_path.txt written by install.sh
args.model = mp.read_text().strip()
_state["model_path"] = args.model
print(f"[serve] starting on :{args.port}, model={args.model}", flush=True)
app.run(host="0.0.0.0", port=args.port, threaded=True)