| import json |
| from pathlib import Path |
| from typing import Any |
|
|
| import numpy as np |
| import onnxruntime as ort |
|
|
|
|
| def _stringify(value: Any) -> str: |
| if value is None: |
| return "" |
| if isinstance(value, list): |
| return ", ".join(_stringify(item) for item in value if _stringify(item)) |
| if isinstance(value, dict): |
| return json.dumps(value, separators=(",", ":")) |
| return str(value) |
|
|
|
|
| def _normalize_unicode_codepoint_v1(text: str) -> str: |
| parts: list[str] = [] |
| ascii_run = "" |
|
|
| def flush_ascii() -> None: |
| nonlocal ascii_run |
| if ascii_run: |
| parts.append(ascii_run) |
| ascii_run = "" |
|
|
| for char in text: |
| codepoint = ord(char) |
| if codepoint < 128: |
| ascii_run += char |
| elif char.isalnum(): |
| flush_ascii() |
| parts.append(f"u{codepoint:04x}") |
| else: |
| ascii_run += " " |
| flush_ascii() |
| return " ".join(parts) |
|
|
|
|
| def _field_text(property_payload: dict[str, Any]) -> str: |
| semantic = property_payload.get("semantic") if isinstance(property_payload.get("semantic"), dict) else {} |
| source = property_payload.get("x-mockgen-source") if isinstance(property_payload.get("x-mockgen-source"), dict) else {} |
| sap_annotations = ( |
| source.get("sapAnnotations") |
| or source.get("sourceAnnotations") |
| or source.get("annotations") |
| or source.get("annotationSummary") |
| or source.get("sap_annotations_summary") |
| ) |
| fields = [ |
| ("property_name", property_payload.get("name") or property_payload.get("property_name")), |
| ("label", semantic.get("label") or property_payload.get("label")), |
| ("entity_type_name", property_payload.get("entity") or property_payload.get("entity_type_name")), |
| ("neighbor_properties", semantic.get("related") or property_payload.get("related") or property_payload.get("neighbor_properties")), |
| ("type", property_payload.get("type")), |
| ("sap_annotations_summary", sap_annotations), |
| ("locale", source.get("locale") or property_payload.get("locale")), |
| ] |
| return " [SEP] ".join( |
| f"{field}: {text_value}" |
| for field, value in fields |
| if (text_value := _stringify(value).strip()) |
| ) |
|
|
|
|
| def _input_text(value: Any) -> str: |
| if isinstance(value, str): |
| stripped = value.strip() |
| if stripped.startswith("{"): |
| try: |
| parsed = json.loads(stripped) |
| if isinstance(parsed, dict): |
| return _field_text(parsed) |
| except json.JSONDecodeError: |
| pass |
| parsed_lines = _parse_field_card(stripped) |
| if parsed_lines: |
| return _field_text(parsed_lines) |
| return value |
| if isinstance(value, dict): |
| return _field_text(value) |
| raise TypeError("inputs must be a classifier text string or a property metadata object") |
|
|
|
|
| def _parse_field_card(text: str) -> dict[str, Any] | None: |
| aliases = { |
| "entity": "entity", |
| "entity_type": "entity", |
| "entity_type_name": "entity", |
| "field": "name", |
| "name": "name", |
| "property": "name", |
| "property_name": "name", |
| "label": "label", |
| "type": "type", |
| "related": "related", |
| "neighbors": "related", |
| "neighbor_properties": "related", |
| } |
| parsed: dict[str, Any] = {} |
| for raw_line in text.splitlines(): |
| if ":" not in raw_line: |
| continue |
| key, raw_value = raw_line.split(":", 1) |
| normalized_key = key.strip().lower().replace(" ", "_").replace("-", "_") |
| target = aliases.get(normalized_key) |
| if not target: |
| continue |
| value = raw_value.strip() |
| if not value: |
| continue |
| parsed[target] = [part.strip() for part in value.split(",") if part.strip()] if target == "related" else value |
| return parsed if {"entity", "name", "type"}.issubset(parsed) else None |
|
|
|
|
| def _softmax(scores: np.ndarray) -> np.ndarray: |
| shifted = scores - np.max(scores) |
| exp = np.exp(shifted) |
| return exp / exp.sum() |
|
|
|
|
| class EndpointHandler: |
| def __init__(self, path: str = ""): |
| root = Path(path or ".") |
| report = json.loads((root / "export-report.json").read_text(encoding="utf8")) |
| self.labels = report["labels"] |
| self.input_normalizer = report.get("inputNormalizer", "unicode-codepoint-v1") |
| self.session = ort.InferenceSession(str(root / "classifier.onnx"), providers=["CPUExecutionProvider"]) |
|
|
| def __call__(self, data: dict[str, Any]) -> list[dict[str, Any]]: |
| payload = data.get("inputs", data) |
| text = _input_text(payload) |
| if self.input_normalizer == "unicode-codepoint-v1": |
| text = _normalize_unicode_codepoint_v1(text) |
| outputs = self.session.run(None, {"text": np.array([[text]], dtype=object)}) |
| raw_scores = np.asarray(outputs[1] if len(outputs) > 1 else outputs[0]).reshape(-1).astype(float) |
| scores = raw_scores if np.isclose(raw_scores.sum(), 1.0, atol=1e-3) else _softmax(raw_scores) |
| ranked = sorted( |
| ( |
| {"label": self.labels[index] if index < len(self.labels) else "unknown", "score": float(score)} |
| for index, score in enumerate(scores[: len(self.labels)]) |
| ), |
| key=lambda item: item["score"], |
| reverse=True, |
| ) |
| top_k = int(data.get("top_k", 5)) |
| return ranked[:top_k] |
|
|