def predict(model_name: str) -> Response: # pylint: disable=unused-variable """make a prediction using the specified model and return the results""" if request.method == "OPTIONS": return Response(response="", status=200) model = app.predictors.get(model_name.lower()) if model is None: raise ServerError("unknown model: {}".format(model_name), status_code=400) data = request.get_json() log_blob = { "model": model_name, "inputs": data, "cached": False, "outputs": {} } # See if we hit or not. In theory this could result in false positives. pre_hits = _caching_prediction.cache_info().hits # pylint: disable=no-value-for-parameter try: if cache_size > 0: # lru_cache insists that all function arguments be hashable, # so unfortunately we have to stringify the data. prediction = _caching_prediction(model, json.dumps(data)) else: # if cache_size is 0, skip caching altogether prediction = model.predict_json(data) except KeyError as err: raise ServerError("Required JSON field not found: " + err.args[0], status_code=400) post_hits = _caching_prediction.cache_info().hits # pylint: disable=no-value-for-parameter # Add to database and get permalink if demo_db is not None: try: perma_id = demo_db.add_result(headers=dict(request.headers), model_name=model_name, inputs=data, outputs=prediction) if perma_id is not None: slug = int_to_slug(perma_id) prediction["slug"] = slug log_blob["slug"] = slug except Exception: # pylint: disable=broad-except # TODO(joelgrus): catch more specific errors logger.exception("Unable to add result to database", exc_info=True) if post_hits > pre_hits: # Cache hit, so insert an artifical pause log_blob["cached"] = True time.sleep(0.25) # The model predictions are extremely verbose, so we only log the most human-readable # parts of them. if model_name == "machine-comprehension": log_blob["outputs"]["best_span_str"] = prediction["best_span_str"] elif model_name == "coreference-resolution": log_blob["outputs"]["clusters"] = prediction["clusters"] log_blob["outputs"]["document"] = prediction["document"] elif model_name == "textual-entailment": log_blob["outputs"]["label_probs"] = prediction["label_probs"] elif model_name == "named-entity-recognition": log_blob["outputs"]["tags"] = prediction["tags"] elif model_name == "semantic-role-labeling": verbs = [] elif model_name == "crf_srl": verbs = [] elif model_name == "frame_crf_srl": verbs = [] for verb in prediction["verbs"]: # Don't want to log boring verbs with no semantic parses. good_tags = [tag for tag in verb["tags"] if tag != "0"] if len(good_tags) > 1: verbs.append({ "verb": verb["verb"], "description": verb["description"] }) log_blob["outputs"]["verbs"] = verbs logger.info("prediction: %s", json.dumps(log_blob)) print(log_blob) return jsonify(prediction)
def predict(model_name: str) -> Response: # pylint: disable=unused-variable """make a prediction using the specified model and return the results""" if request.method == "OPTIONS": return Response(response="", status=200) # Do log if no argument is specified record_to_database = request.args.get("record", "true").lower() != "false" # Do use the cache if no argument is specified use_cache = request.args.get("cache", "true").lower() != "false" model = app.predictors.get(model_name.lower()) if model is None: raise ServerError("unknown model: {}".format(model_name), status_code=400) data = request.get_json() log_blob = {"model": model_name, "inputs": data, "cached": False, "outputs": {}} # Record the number of cache hits before we hit the cache so we can tell whether we hit or not. # In theory this could result in false positives. pre_hits = _caching_prediction.cache_info().hits # pylint: disable=no-value-for-parameter try: if use_cache and cache_size > 0: # lru_cache insists that all function arguments be hashable, # so unfortunately we have to stringify the data. prediction = _caching_prediction(model, json.dumps(data)) else: # if cache_size is 0, skip caching altogether prediction = model.predict_json(data) except KeyError as err: raise ServerError("Required JSON field not found: " + err.args[0], status_code=400) post_hits = _caching_prediction.cache_info().hits # pylint: disable=no-value-for-parameter if record_to_database and demo_db is not None: try: perma_id = None perma_id = demo_db.add_result(headers=dict(request.headers), model_name=model_name, inputs=data, outputs=prediction) if perma_id is not None: slug = int_to_slug(perma_id) prediction["slug"] = slug log_blob["slug"] = slug except Exception: # pylint: disable=broad-except # TODO(joelgrus): catch more specific errors logger.exception("Unable to add result to database", exc_info=True) if use_cache and post_hits > pre_hits: # Cache hit, so insert an artifical pause log_blob["cached"] = True time.sleep(0.25) # The model predictions are extremely verbose, so we only log the most human-readable # parts of them. if model_name == "machine-comprehension": log_blob["outputs"]["best_span_str"] = prediction["best_span_str"] elif model_name == "coreference-resolution": log_blob["outputs"]["clusters"] = prediction["clusters"] log_blob["outputs"]["document"] = prediction["document"] elif model_name == "textual-entailment": log_blob["outputs"]["label_probs"] = prediction["label_probs"] elif model_name == "named-entity-recognition": log_blob["outputs"]["tags"] = prediction["tags"] elif model_name == "semantic-role-labeling": verbs = [] for verb in prediction["verbs"]: # Don't want to log boring verbs with no semantic parses. good_tags = [tag for tag in verb["tags"] if tag != "0"] if len(good_tags) > 1: verbs.append({"verb": verb["verb"], "description": verb["description"]}) log_blob["outputs"]["verbs"] = verbs elif model_name == "constituency-parsing": log_blob["outputs"]["trees"] = prediction["trees"] logger.info("prediction: %s", json.dumps(log_blob)) print(log_blob) return jsonify(prediction)