Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from typing import Optional | |
| import tensorflow as tf | |
| import os | |
| BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| MODEL_DIR_DEFAULT = os.path.join(BASE_DIR, 'data', 'model', 'sentiment_cnn') | |
| # Cache di processo (il modello viene caricato una volta sola) | |
| _INFER: Optional[tf.types.experimental.ConcreteFunction] = None | |
| _MODEL_DIR_LOADED: Optional[str] = None | |
| def _load_infer(model_dir: str) -> tf.types.experimental.ConcreteFunction: | |
| """ | |
| Load SavedModel once and return serving function. | |
| TF 2.12 compatible, expects signature 'serving_default'. | |
| """ | |
| sm = tf.saved_model.load(model_dir) | |
| return sm.signatures["serving_default"] | |
| def _get_infer(model_dir: str) -> tf.types.experimental.ConcreteFunction: | |
| global _INFER, _MODEL_DIR_LOADED | |
| model_dir = str(model_dir) | |
| if _INFER is None or _MODEL_DIR_LOADED != model_dir: | |
| _INFER = _load_infer(model_dir) | |
| _MODEL_DIR_LOADED = model_dir | |
| return _INFER | |
| def _predict_prob_positive(text: str, model_dir: str) -> float: | |
| infer = _get_infer(model_dir) | |
| x = tf.constant([text], dtype=tf.string) | |
| out = infer(text=x) | |
| # Output key stabilized by our exporter | |
| y = out["prob"] | |
| return float(y.numpy()[0][0]) | |
| def binary_classification(text: str): | |
| """ | |
| IDENTICAL behavior to legacy: | |
| - if text is empty -> ({"error": "Sentence is required"}, 415) | |
| - else -> {"positive": "0.xx", "negative": "0.yy"} (strings, 2 decimals) | |
| """ | |
| try: | |
| if text == "": | |
| raise Exception | |
| except: | |
| return {"error": "Sentence is required"}, 415 | |
| prob_pos = _predict_prob_positive(text, MODEL_DIR_DEFAULT) | |
| positive = prob_pos | |
| negative = 1.0 - positive | |
| labels = { | |
| "positive": f"{positive:.2f}", | |
| "negative": f"{negative:.2f}", | |
| } | |
| return labels | |