m-newhauser's picture
Upload folder using huggingface_hub
99412aa verified
Raw
History Blame
3.97 kB
"""Span attributes demo: entities carry per-span attribute groups (sentiment,
role, assertion, impact), single- or multi-label, scoped with applies_to.
MOCK until GLiNER 2.5 ships. Response contract:
{"spans": [{"start", "end", "text", "label", "score",
"attributes": {"<group>": [{"label": str, "score": float}]}}]}
Multi-label groups return several entries in the group list.
"""
import json
import os
MOCK = os.environ.get("GLINER_MOCK", "1") == "1"
MODEL_ID = os.environ.get("MODEL_ID", "fastino/gliner2.5")
MODEL_URL = os.environ.get("MODEL_URL", f"https://huggingface.co/{MODEL_ID}")
DEMO = {
"title": "Sentiment and role, <em>per span</em>",
"subtitle": "Document classification labels the whole review. GLiNER 2.5 attaches <strong>attributes to every entity</strong> it extracts.",
"model_name": "GLiNER 2.5",
"model_variant": "0.3B parameters, f32, CPU",
"code": (
'schema = (model.create_schema()\n'
' .entities({"product": "A product mentioned in the text",\n'
' "person": "A person by name",\n'
' "condition": "A medical condition"})\n'
' .entity_attributes({\n'
' "sentiment": AttributeGroup(\n'
' labels=["positive", "neutral", "negative"],\n'
' applies_to=["product"], qualify_labels=True),\n'
' "role": AttributeGroup(\n'
' labels=["executive", "employee", "customer", "analyst"],\n'
' applies_to=["person"]),\n'
' "assertion": AttributeGroup(\n'
' labels=["present", "absent", "possible", "historical"],\n'
' applies_to=["condition"]),\n'
' "impact": AttributeGroup(\n'
' labels=["blocks_work", "data_loss", "security_risk"],\n'
' multi_label=True, threshold=0.40)}))\n'
'model.extract(text, schema)'
),
"examples": [
{"chip": "Mixed review",
"text": "The screen is gorgeous and the keyboard feels great, but the battery is disappointing and the fan noise is unacceptable.",
"fixture": "review.json"},
{"chip": "Org announcement",
"text": "CEO Maya Chen announced that CFO Daniel Okafor will lead the acquisition, while analyst Priya Nair briefed reporters.",
"fixture": "org.json"},
{"chip": "Clinical note",
"text": "Patient denies chest pain. No evidence of pneumonia. Possible mild anemia; history of hypertension noted.",
"fixture": "clinical.json"},
{"chip": "Support ticket",
"text": "The export button silently deletes rows, which blocked our quarterly report and risks losing audited data.",
"fixture": "support.json"},
],
}
_HERE = os.path.dirname(os.path.abspath(__file__))
def warmup():
if MOCK:
for ex in DEMO["examples"]:
_fixture(ex["fixture"], ex["text"])
else:
_load_real()
def infer(data):
text = (data.get("text") or "").replace("\r", "")
if not text.strip():
return {"spans": []}
if MOCK:
return _infer_mock(text)
return _infer_real(text)
def _fixture(name, expect_text=None):
with open(os.path.join(_HERE, "fixtures", name)) as f:
out = json.load(f)
if expect_text is not None:
for sp in out.get("spans", []):
assert expect_text[sp["start"]:sp["end"]] == sp["text"], \
f"{name}: bad offsets for {sp['text']!r}"
return out
def _infer_mock(text):
for ex in DEMO["examples"]:
if ex["text"] == text:
return _fixture(ex["fixture"])
return {"spans": []}
_model = None
def _load_real():
global _model
from gliner import GLiNER
_model = GLiNER.from_pretrained(MODEL_ID, token=os.environ.get("HF_TOKEN"))
def _infer_real(text):
raise NotImplementedError("wire up GLiNER 2.5 here, keep the response shape")