RadGraph-IT 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. radgraph_it-1.0.0.dist-info/METADATA +159 -0
  2. radgraph_it-1.0.0.dist-info/RECORD +39 -0
  3. radgraph_it-1.0.0.dist-info/WHEEL +4 -0
  4. radgraph_it-1.0.0.dist-info/entry_points.txt +2 -0
  5. radgraph_it-1.0.0.dist-info/licenses/LICENSE +23 -0
  6. radgraph_it-1.0.0.dist-info/licenses/LICENSES/Third-Party.md +41 -0
  7. radgraphit/__init__.py +47 -0
  8. radgraphit/api.py +168 -0
  9. radgraphit/artifacts/__init__.py +5 -0
  10. radgraphit/artifacts/manifest.py +290 -0
  11. radgraphit/artifacts/registry.py +24 -0
  12. radgraphit/artifacts/resolver.py +200 -0
  13. radgraphit/cli.py +131 -0
  14. radgraphit/core/__init__.py +1 -0
  15. radgraphit/core/errors.py +46 -0
  16. radgraphit/core/models.py +116 -0
  17. radgraphit/inference/__init__.py +5 -0
  18. radgraphit/inference/backends/__init__.py +1 -0
  19. radgraphit/inference/backends/base.py +13 -0
  20. radgraphit/inference/backends/dygie_v2/__init__.py +11 -0
  21. radgraphit/inference/backends/dygie_v2/backend.py +32 -0
  22. radgraphit/inference/backends/dygie_v2/device.py +46 -0
  23. radgraphit/inference/backends/dygie_v2/feedforward.py +25 -0
  24. radgraphit/inference/backends/dygie_v2/loader.py +165 -0
  25. radgraphit/inference/backends/dygie_v2/model.py +101 -0
  26. radgraphit/inference/backends/dygie_v2/ner_head.py +75 -0
  27. radgraphit/inference/backends/dygie_v2/pruner.py +27 -0
  28. radgraphit/inference/backends/dygie_v2/relation_head.py +147 -0
  29. radgraphit/inference/backends/dygie_v2/span_extractor.py +51 -0
  30. radgraphit/inference/backends/dygie_v2/spans.py +20 -0
  31. radgraphit/inference/backends/dygie_v2/tokenizer_embedder.py +123 -0
  32. radgraphit/inference/backends/dygie_v2/transformer_block.py +62 -0
  33. radgraphit/inference/backends/dygie_v2/vocab.py +123 -0
  34. radgraphit/inference/decoder.py +53 -0
  35. radgraphit/inference/service.py +80 -0
  36. radgraphit/inference/tokenizer.py +60 -0
  37. radgraphit/py.typed +0 -0
  38. radgraphit/serialization/__init__.py +15 -0
  39. radgraphit/serialization/radgraph_xl.py +135 -0
@@ -0,0 +1,159 @@
1
+ Metadata-Version: 2.4
2
+ Name: RadGraph-IT
3
+ Version: 1.0.0
4
+ Summary: RadGraph graph inference for Italian radiology reports, with output in the canonical RadGraph-XL format.
5
+ Project-URL: Homepage, https://github.com/therabo/RadGraph-IT
6
+ Project-URL: Repository, https://github.com/therabo/RadGraph-IT
7
+ Project-URL: Issues, https://github.com/therabo/RadGraph-IT/issues
8
+ Project-URL: Changelog, https://github.com/therabo/RadGraph-IT/blob/main/CHANGELOG.md
9
+ Author: Daniel Rabottini, Edoardo Avenia, Rocco Angelella
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ License-File: LICENSES/Third-Party.md
13
+ Keywords: information-extraction,italian,nlp,radgraph,radiology
14
+ Classifier: Development Status :: 5 - Production/Stable
15
+ Classifier: Intended Audience :: Healthcare Industry
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Natural Language :: Italian
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: huggingface-hub>=0.23
28
+ Requires-Dist: nltk>=3.8
29
+ Requires-Dist: packaging>=23
30
+ Requires-Dist: torch>=2.1
31
+ Requires-Dist: transformers>=4.39
32
+ Provides-Extra: dev
33
+ Requires-Dist: build>=1.2; extra == 'dev'
34
+ Requires-Dist: mypy>=1.11; extra == 'dev'
35
+ Requires-Dist: pre-commit>=3.5; extra == 'dev'
36
+ Requires-Dist: pytest-cov>=5; extra == 'dev'
37
+ Requires-Dist: pytest>=8; extra == 'dev'
38
+ Requires-Dist: ruff==0.16.0; extra == 'dev'
39
+ Requires-Dist: safetensors>=0.4; extra == 'dev'
40
+ Requires-Dist: twine>=5; extra == 'dev'
41
+ Provides-Extra: safetensors
42
+ Requires-Dist: safetensors>=0.4; extra == 'safetensors'
43
+ Description-Content-Type: text/markdown
44
+
45
+ # RadGraph-IT 🇮🇹
46
+
47
+ **RadGraph** graph inference for **Italian** radiology reports, with output in the canonical
48
+ **RadGraph-XL** format.
49
+
50
+ `radgraphit` takes one or more Italian radiology reports, runs the Italian DyGIE v2 model
51
+ (PyTorch: shared encoder, span extractor, NER head, and relation head), and returns the graph of
52
+ entities and relations as the RadGraph-XL-compatible dictionary.
53
+
54
+ - **Package / import / CLI name:** `radgraphit` · **Python:** `>= 3.10` · **Device:** CPU or CUDA
55
+ - **Model:** downloaded automatically from pinned Hugging Face revisions on first use
56
+ (~445 MB / 424 MiB plus small tokenizer/config files, then cached)
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ pip install radgraphit
62
+ ```
63
+
64
+ ## Usage — Python API
65
+
66
+ ```python
67
+ from radgraphit import RadGraphIT
68
+
69
+ predictor = RadGraphIT()
70
+ annotations = predictor.predict(
71
+ "Non si evidenziano segni di pneumotorace dopo la rimozione del drenaggio toracico."
72
+ )
73
+ ```
74
+
75
+ `predict` accepts a **string** or a **sequence of strings** and preserves order.
76
+ `predictor(report)` is an alias for `predictor.predict(report)`:
77
+
78
+ ```python
79
+ annotations = predictor(["referto 1", "referto 2"]) # batch, order preserved
80
+ ```
81
+
82
+ ## Usage — CLI
83
+
84
+ ```bash
85
+ # report as an argument
86
+ radgraphit predict "Non si evidenzia pneumotorace."
87
+
88
+ # from a file (one report per line), or from stdin
89
+ radgraphit predict --input-file reports.txt
90
+ echo "Nessuna evidenza di pneumotorace." | radgraphit predict
91
+ ```
92
+
93
+ The result is written as JSON to stdout.
94
+
95
+ ## Output
96
+
97
+ For the input `["Non si evidenzia pneumotorace ..."]` the output has this shape (top-level keys
98
+ `"0"`, `"1"`, … in input order):
99
+
100
+ ```python
101
+ {
102
+ "0": {
103
+ "text": "<normalized tokens, space-separated>",
104
+ "entities": {
105
+ "1": {
106
+ "tokens": "<span tokens>",
107
+ "label": "Observation::definitely absent",
108
+ "start_ix": 3,
109
+ "end_ix": 3,
110
+ "relations": [["located_at", "2"]],
111
+ }
112
+ },
113
+ "data_source": None,
114
+ "data_split": "inference",
115
+ },
116
+ "1": {"...": "..."},
117
+ }
118
+ ```
119
+
120
+ - The indices (`start_ix`, `end_ix`) are **token-level, zero-based, and inclusive**.
121
+ - Relations are directed *source → target* lists `[label, target_entity_id]`.
122
+ - The output is deterministic: entities and relations are stably ordered.
123
+
124
+ ## Citation
125
+
126
+ The output format and the serializer derive from the official **RadGraph / RadGraph-XL** package
127
+ (see [`Third-Party`](LICENSES/Third-Party.md)). If you use this package, please cite
128
+ both this work and the RadGraph-XL paper:
129
+
130
+ ```bibtex
131
+ @software{radgraphit,
132
+ author = "Daniel Rabottini and Edoardo Avenia and Rocco Angelella",
133
+ title = "{RadGraph-IT}: {RadGraph} graph inference for {Italian} radiology reports",
134
+ year = "2026",
135
+ version = "1.0.0",
136
+ url = "https://github.com/therabo/RadGraph-IT",
137
+ }
138
+ ```
139
+
140
+ ```bibtex
141
+ @inproceedings{delbrouck-etal-2024-radgraph,
142
+ title = "{R}ad{G}raph-{XL}: A Large-Scale Expert-Annotated Dataset for Entity and Relation
143
+ Extraction from Radiology Reports",
144
+ author = "Delbrouck, Jean-Benoit and Chambon, Pierre and Chen, Zhihong and Varma, Maya and
145
+ Johnston, Andrew and Blankemeier, Louis and Van Veen, Dave and Bui, Tan and
146
+ Truong, Steven and Langlotz, Curtis",
147
+ booktitle = "Findings of the Association for Computational Linguistics ACL 2024",
148
+ year = "2024",
149
+ url = "https://aclanthology.org/2024.findings-acl.765",
150
+ pages = "12902--12915",
151
+ }
152
+ ```
153
+
154
+ ## License
155
+
156
+ See the [`MIT License`](LICENSE) and [`Third-Party`](LICENSES/Third-Party.md) notices.
157
+
158
+ > **Not a medical device.** The output is an automatic extraction of entities and relations from
159
+ > text and does not constitute a diagnosis, a report, or a clinical opinion.
@@ -0,0 +1,39 @@
1
+ radgraphit/__init__.py,sha256=axB-_vOQ0oxpkLfKcm-zugE9EAno__Q2Cs1vYpDuGz4,1253
2
+ radgraphit/api.py,sha256=gBSE9ghTwDGb_KZ9eMGQAMbEsjn_CIOkBKt1UqWByOg,6549
3
+ radgraphit/cli.py,sha256=Q7Ifzji1ae9NplUwtGc-kvnL3HAA1DHBISFNGBueUzM,4784
4
+ radgraphit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ radgraphit/artifacts/__init__.py,sha256=9s6PKiGZW26zn6F_BBJ_ApsV-XeP1KDrcjlnhKhBcrE,247
6
+ radgraphit/artifacts/manifest.py,sha256=PGnZKb1f28dpvcRd8ssP516Ry5XCD1KNAjm-SySZfqE,12702
7
+ radgraphit/artifacts/registry.py,sha256=4n6DHuoi3qDLiONQUVxVYqDpboF3k3_sEym6HxG554k,929
8
+ radgraphit/artifacts/resolver.py,sha256=4AfDPUAEQOu13BLd8IS5rJ8XP90OXUiq9t_CD71C-so,8078
9
+ radgraphit/core/__init__.py,sha256=spw93ti5KhNBlUCSKIjDK74nWhmTp7O3Z418DZAJb1Q,86
10
+ radgraphit/core/errors.py,sha256=BJgE1FP2sVINBAw--0nvlqKntS5rLnLZTl8W5i75pHo,1577
11
+ radgraphit/core/models.py,sha256=WlWLwzQeoSNasGzYH0BnvUsxtS3L3oWGSHUSjS_JhYA,3843
12
+ radgraphit/inference/__init__.py,sha256=ZXwhdEOAJ-B1nH8ZGEzVOmJk3ocqWgQQllMqiogApXY,255
13
+ radgraphit/inference/decoder.py,sha256=ls79WFJ4HQbh_FKHhDpFpvkQWk-Bi8Aal5GRrBssGBg,1689
14
+ radgraphit/inference/service.py,sha256=xNpdpxip9BVGR-FxvXJ_cJu3f0F1JsInslnQahYkPes,3364
15
+ radgraphit/inference/tokenizer.py,sha256=Er2ooK8jy-JqmDRfwIjknTc4lD8bmRwvgEqSH0R_IMg,2692
16
+ radgraphit/inference/backends/__init__.py,sha256=fxImXnfQFeAaa8RuUueZslnHLgsdSC6OYyCdhHY6A0o,96
17
+ radgraphit/inference/backends/base.py,sha256=W5noZOMATRabbKBHk3lLKlauLHVCJdCScIMBkYScXXA,590
18
+ radgraphit/inference/backends/dygie_v2/__init__.py,sha256=EqFi85Wz4aajgDLRO85AGdVKKsca3yljeebTJ95bk9U,492
19
+ radgraphit/inference/backends/dygie_v2/backend.py,sha256=ZvgJsIjJBKgnsEjWQVvw3XIbbTwuv82Y17kLdMpWDVY,1073
20
+ radgraphit/inference/backends/dygie_v2/device.py,sha256=66TtM3sEbnLvTGJSPgYDLnd4M_mam-RB7R5f48L7Lzk,1917
21
+ radgraphit/inference/backends/dygie_v2/feedforward.py,sha256=bNR5LM0MbOfyqa2eVSFbmOckdVDGgJbaRSFzBBYJwkk,797
22
+ radgraphit/inference/backends/dygie_v2/loader.py,sha256=PHh6mB6NGDog7vPB7JMzMKX_ZwjwpDPLKd-SBPQTjLw,6847
23
+ radgraphit/inference/backends/dygie_v2/model.py,sha256=JTLEORUALbn9sE33_pwgGki6K1VMezmadyAacgNeV-c,3689
24
+ radgraphit/inference/backends/dygie_v2/ner_head.py,sha256=797nBLytn5VmwWK1EEDOMunl_TvWhqaq05SFNng1QF4,3082
25
+ radgraphit/inference/backends/dygie_v2/pruner.py,sha256=nd7lH7d7Y82Sb2XtdG8sp9AwNV-Cy9pwYhPdJgpQ-DM,1022
26
+ radgraphit/inference/backends/dygie_v2/relation_head.py,sha256=XD1es7h57Z4AEpSuMYMXVSlmwNKWsqiK8OD2Txc7apc,6449
27
+ radgraphit/inference/backends/dygie_v2/span_extractor.py,sha256=ekB0BDtRlRzqmErM55UFPIBgqqXcaQk8s-0Rn8bubsY,2284
28
+ radgraphit/inference/backends/dygie_v2/spans.py,sha256=7i5MnVC5UK9yf1WBUlMB7E_WxAy1Z2EG3iyCf5UwHBg,804
29
+ radgraphit/inference/backends/dygie_v2/tokenizer_embedder.py,sha256=YQtTlIDNmMU6PjY8GQzz0DOygAU-cH_gkTUIt2iECbg,4948
30
+ radgraphit/inference/backends/dygie_v2/transformer_block.py,sha256=yHoOcemeR9eDiExD7WlP-nTWX-geNcAxrVmnYgPvxkE,2272
31
+ radgraphit/inference/backends/dygie_v2/vocab.py,sha256=xiHU0Tzij0fbDJUSp2ErB1n48pfFV9BWblGttR0ZpBY,5332
32
+ radgraphit/serialization/__init__.py,sha256=QCd8PjDTXaeO9ayJHNiE4CiSYPEFDug8hN7kR7ZqKOk,364
33
+ radgraphit/serialization/radgraph_xl.py,sha256=g3E7368G_-0Ue-N7Xad_e0CyundjDPDuQ51a47402ck,5965
34
+ radgraph_it-1.0.0.dist-info/METADATA,sha256=Zl4fb4tByGUgIfNgcJW79i02f_OYjIYl2uDsc6-wevs,5682
35
+ radgraph_it-1.0.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
36
+ radgraph_it-1.0.0.dist-info/entry_points.txt,sha256=xxBQ-WlmPXumfg3tNJNKk7VIpamQX4v8UmIpmFnYNxQ,51
37
+ radgraph_it-1.0.0.dist-info/licenses/LICENSE,sha256=5KhNHP1ryGIP_aYYWPUNBQ0PUnLPKGznCAb-95svTbc,1185
38
+ radgraph_it-1.0.0.dist-info/licenses/LICENSES/Third-Party.md,sha256=k63tiwV1ZJTDPC4cX20jEBjbzV_1xDjIj_svU16XTJU,2019
39
+ radgraph_it-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ radgraphit = radgraphit.cli:main
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Rabottini (therabo)
4
+ Copyright (c) 2026 Edoardo Avenia (edoardoavenia)
5
+ Copyright (c) 2026 Rocco Angelella (roccoangelella)
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
@@ -0,0 +1,41 @@
1
+ # Third-Party
2
+
3
+ This file collects provenance and attributions. It does **not** declare weights, datasets, or
4
+ clinical texts redistributable, and it does **not** automatically copy any third-party license. The
5
+ package code itself is licensed under MIT (see the root `LICENSE` file); this file concerns the
6
+ third-party components it builds on.
7
+
8
+ ## RadGraph-XL output format and serializer
9
+
10
+ The output dictionary and the serialization logic (`postprocess_reports` / `get_entity`) derive from
11
+ the official **RadGraph / RadGraph-XL** package from Stanford AIMI / StanfordMIMI.
12
+
13
+ - Upstream repository: `radgraph` package (Stanford), distributed under the MIT license.
14
+
15
+ Citation:
16
+
17
+ > Delbrouck et al. "RadGraph-XL: A Large-Scale Expert-Annotated Dataset for Entity and Relation
18
+ > Extraction from Radiology Reports." Findings of the ACL 2024, pp. 12902–12915.
19
+ > https://aclanthology.org/2024.findings-acl.765
20
+
21
+ ## Inference backend (`dygie_v2`)
22
+
23
+ An inference-only PyTorch port of the Italian v2 model (internal project "RadGraph-XL-IT",
24
+ `training_v2`), which is itself a pure-PyTorch reimplementation of the DyGIE++ architecture
25
+ (NER + relations) without AllenNLP.
26
+
27
+ - DyGIE / DyGIE++ architecture: Wadden et al., "Entity, Relation, and Event Extraction with
28
+ Contextualized Span Representations", EMNLP 2019.
29
+ - Pre-trained encoder: fetched at runtime from the Hugging Face Hub (e.g. `IVN-RIN/medBIT-r3-plus`);
30
+ subject to the license of its own repository on the Hub. Not redistributed by this package.
31
+
32
+ ## Model, weights, and data
33
+
34
+ The model weights, the datasets, and any clinical text are **not** included in this repository or in
35
+ the wheel/sdist, and are not declared redistributable. The model bundle is hosted separately on the
36
+ Hugging Face Hub and is subject to the licenses/terms declared in that repository.
37
+
38
+ ## Runtime dependencies
39
+
40
+ `torch`, `transformers`, `nltk`, `huggingface_hub` are subject to their respective licenses
41
+ (BSD-3-Clause, Apache-2.0, Apache-2.0, Apache-2.0 respectively, unless changed upstream).
radgraphit/__init__.py ADDED
@@ -0,0 +1,47 @@
1
+ """radgraphit — RadGraph-XL inference for Italian radiology reports.
2
+
3
+ Public API::
4
+
5
+ from radgraphit import RadGraphIT
6
+
7
+ Importing this package has no side effects: no network I/O, no model download, no logging to
8
+ stdout, and no torch import. Everything model-related is loaded lazily on first use.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import logging
14
+
15
+ from .api import RadGraphIT
16
+ from .core.errors import (
17
+ BackendError,
18
+ CheckpointError,
19
+ DeviceError,
20
+ InvalidReportError,
21
+ ManifestError,
22
+ ModelConfigurationError,
23
+ ModelNotConfiguredError,
24
+ ModelNotFoundError,
25
+ RadGraphITError,
26
+ )
27
+
28
+ # A library must not configure logging handlers for the application; attach a NullHandler so that
29
+ # emitting logs never prints a "No handlers could be found" warning if the app hasn't configured
30
+ # logging (see https://docs.python.org/3/howto/logging.html#library-config).
31
+ logging.getLogger("radgraphit").addHandler(logging.NullHandler())
32
+
33
+ __version__ = "1.0.0"
34
+
35
+ __all__ = [
36
+ "BackendError",
37
+ "CheckpointError",
38
+ "DeviceError",
39
+ "InvalidReportError",
40
+ "ManifestError",
41
+ "ModelConfigurationError",
42
+ "ModelNotConfiguredError",
43
+ "ModelNotFoundError",
44
+ "RadGraphIT",
45
+ "RadGraphITError",
46
+ "__version__",
47
+ ]
radgraphit/api.py ADDED
@@ -0,0 +1,168 @@
1
+ """The public facade: :class:`RadGraphIT`.
2
+
3
+ Small, typed, stable, and free of import-time side effects. Constructing a ``RadGraphIT`` performs
4
+ no network I/O; the model artifact is resolved and loaded lazily on first ``predict`` (or an
5
+ explicit :meth:`load`). Importing this module does not import torch or huggingface_hub.
6
+
7
+ Usage::
8
+
9
+ from radgraphit import RadGraphIT
10
+
11
+ predictor = RadGraphIT.from_local("/path/to/model", device="auto")
12
+ annotations = predictor.predict([
13
+ "Non si evidenziano segni di pneumotorace dopo la rimozione del drenaggio toracico."
14
+ ])
15
+
16
+ The standard Hub-backed path is::
17
+
18
+ predictor = RadGraphIT(device="auto") # or RadGraphIT.from_pretrained(...)
19
+ annotations = predictor.predict("Nessuna evidenza di pneumotorace.")
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import functools
25
+ import logging
26
+ from collections.abc import Callable, Sequence
27
+ from typing import TYPE_CHECKING
28
+
29
+ from .artifacts import registry
30
+ from .core.errors import BackendError
31
+ from .core.models import InferenceBackend, ReportPrediction
32
+ from .inference.service import InferenceService
33
+
34
+ if TYPE_CHECKING:
35
+ from .artifacts.resolver import ResolvedModel
36
+
37
+ logger = logging.getLogger("radgraphit")
38
+
39
+
40
+ def _resolve_pretrained(
41
+ model_id: str, revision: str, cache_dir: str | None, local_files_only: bool
42
+ ) -> ResolvedModel:
43
+ # Imported lazily so `import radgraphit` never pulls in huggingface_hub.
44
+ from .artifacts import resolver
45
+
46
+ return resolver.resolve_pretrained(
47
+ model_id, revision=revision, cache_dir=cache_dir, local_files_only=local_files_only
48
+ )
49
+
50
+
51
+ def _resolve_local(path: str) -> ResolvedModel:
52
+ from .artifacts import resolver
53
+
54
+ return resolver.resolve_local(path)
55
+
56
+
57
+ def _build_backend(resolved: ResolvedModel, device: str) -> InferenceBackend:
58
+ backend_name = resolved.manifest.backend
59
+ if backend_name == "dygie_v2":
60
+ # Imported lazily so torch/transformers load only when a model is actually built.
61
+ from .inference.backends.dygie_v2 import load_backend
62
+
63
+ return load_backend(
64
+ config_path=resolved.config_path,
65
+ vocab_path=resolved.vocab_path,
66
+ weights_path=resolved.weights_path,
67
+ device=device,
68
+ encoder_revision=resolved.manifest.encoder_revision,
69
+ )
70
+ raise BackendError(
71
+ f"Model manifest requests backend {backend_name!r}, which this version of radgraphit does "
72
+ f"not support (supported: {sorted(registry.SUPPORTED_BACKENDS)})."
73
+ )
74
+
75
+
76
+ class RadGraphIT:
77
+ """Predict RadGraph-XL graphs for Italian radiology reports."""
78
+
79
+ def __init__(
80
+ self,
81
+ *,
82
+ device: str = "auto",
83
+ model_id: str | None = None,
84
+ revision: str | None = None,
85
+ cache_dir: str | None = None,
86
+ local_files_only: bool = False,
87
+ ):
88
+ """Configure a predictor backed by the default (Hugging Face Hub) model.
89
+
90
+ No network I/O happens here — the artifact is downloaded and the model built lazily on the
91
+ first :meth:`predict`. Passing ``model_id``/``revision`` overrides the registry defaults.
92
+ The default model is a public, ungated Hub repository, so no authentication is required.
93
+ """
94
+ self._device = device
95
+ self._service: InferenceService | None = None
96
+ resolved_model_id = model_id if model_id is not None else registry.DEFAULT_MODEL_ID
97
+ resolved_revision = revision if revision is not None else registry.DEFAULT_REVISION
98
+ self._resolve: Callable[[], ResolvedModel] = functools.partial(
99
+ _resolve_pretrained, resolved_model_id, resolved_revision, cache_dir, local_files_only
100
+ )
101
+
102
+ @classmethod
103
+ def from_pretrained(
104
+ cls,
105
+ model_id: str = registry.DEFAULT_MODEL_ID,
106
+ *,
107
+ revision: str = registry.DEFAULT_REVISION,
108
+ cache_dir: str | None = None,
109
+ device: str = "auto",
110
+ local_files_only: bool = False,
111
+ ) -> RadGraphIT:
112
+ """Standard path: resolve the model from the Hugging Face Hub (lazily, on first predict).
113
+
114
+ ``revision`` is pinned explicitly (commit sha or tag). The default model is a public,
115
+ ungated Hub repository, so no authentication is required.
116
+ """
117
+ return cls(
118
+ device=device,
119
+ model_id=model_id,
120
+ revision=revision,
121
+ cache_dir=cache_dir,
122
+ local_files_only=local_files_only,
123
+ )
124
+
125
+ @classmethod
126
+ def from_local(cls, path: str, *, device: str = "auto") -> RadGraphIT:
127
+ """Development / offline path: load a manifest-verified bundle from a local directory."""
128
+ instance = cls(device=device)
129
+ instance._resolve = functools.partial(_resolve_local, path)
130
+ return instance
131
+
132
+ @classmethod
133
+ def from_service(cls, service: InferenceService, *, device: str = "auto") -> RadGraphIT:
134
+ """Advanced/testing: build a predictor around a pre-constructed service (e.g. a custom or
135
+ fake backend). Skips all artifact resolution and loading."""
136
+ instance = cls(device=device)
137
+ instance._service = service
138
+ return instance
139
+
140
+ def load(self) -> RadGraphIT:
141
+ """Eagerly resolve and load the model. Returns ``self`` for chaining. Optional — the model
142
+ is otherwise loaded on first :meth:`predict`."""
143
+ self._ensure_loaded()
144
+ return self
145
+
146
+ def _ensure_loaded(self) -> InferenceService:
147
+ if self._service is None:
148
+ resolved = self._resolve()
149
+ backend = _build_backend(resolved, self._device)
150
+ self._service = InferenceService(backend)
151
+ logger.debug("RadGraphIT model loaded (backend=%s)", resolved.manifest.backend)
152
+ return self._service
153
+
154
+ def predict(self, reports: str | Sequence[str]) -> dict[str, object]:
155
+ """Annotate one report (``str``) or several (``Sequence[str]``).
156
+
157
+ Returns the canonical RadGraph-XL dictionary, keyed by input order (``"0"``, ``"1"``, …).
158
+ See the README for the exact output shape.
159
+ """
160
+ return self._ensure_loaded().predict(reports)
161
+
162
+ def predict_graphs(self, reports: str | Sequence[str]) -> list[ReportPrediction]:
163
+ """Advanced: return the typed internal graphs instead of the RadGraph-XL dict."""
164
+ return self._ensure_loaded().predict_graphs(reports)
165
+
166
+ def __call__(self, reports: str | Sequence[str]) -> dict[str, object]:
167
+ """Alias for :meth:`predict`, for compatibility with the upstream callable interface."""
168
+ return self.predict(reports)
@@ -0,0 +1,5 @@
1
+ """Model artifact handling: the default-location registry, the manifest, and the resolver.
2
+
3
+ Importing this package pulls in ``huggingface_hub`` (a lightweight, torch-free dependency) but
4
+ never torch. It performs no network I/O at import time.
5
+ """