outis 0.1.0__tar.gz

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 (156) hide show
  1. outis-0.1.0/LICENSE +201 -0
  2. outis-0.1.0/NOTICE +25 -0
  3. outis-0.1.0/PKG-INFO +276 -0
  4. outis-0.1.0/README.md +232 -0
  5. outis-0.1.0/pyproject.toml +114 -0
  6. outis-0.1.0/setup.cfg +4 -0
  7. outis-0.1.0/src/outis/__init__.py +4 -0
  8. outis-0.1.0/src/outis/analysis.py +334 -0
  9. outis-0.1.0/src/outis/api.py +764 -0
  10. outis-0.1.0/src/outis/cli.py +45 -0
  11. outis-0.1.0/src/outis/data/__init__.py +1 -0
  12. outis-0.1.0/src/outis/data/annotation_policy.py +121 -0
  13. outis-0.1.0/src/outis/data/annotation_policy_ages.py +44 -0
  14. outis-0.1.0/src/outis/data/annotation_policy_care_sites.py +108 -0
  15. outis-0.1.0/src/outis/data/annotation_policy_eponyms.py +30 -0
  16. outis-0.1.0/src/outis/data/annotation_policy_facility_names.py +25 -0
  17. outis-0.1.0/src/outis/data/annotation_policy_fhir.py +47 -0
  18. outis-0.1.0/src/outis/data/annotation_policy_places.py +60 -0
  19. outis-0.1.0/src/outis/data/annotation_policy_reports.py +39 -0
  20. outis-0.1.0/src/outis/data/annotation_policy_spoken.py +65 -0
  21. outis-0.1.0/src/outis/data/annotation_policy_targeted.py +71 -0
  22. outis-0.1.0/src/outis/data/annotation_policy_transcripts.py +33 -0
  23. outis-0.1.0/src/outis/data/challenge.py +270 -0
  24. outis-0.1.0/src/outis/data/corpus_quality.py +429 -0
  25. outis-0.1.0/src/outis/data/generators/__init__.py +1 -0
  26. outis-0.1.0/src/outis/data/generators/alias_contrastive.py +765 -0
  27. outis-0.1.0/src/outis/data/generators/augment.py +521 -0
  28. outis-0.1.0/src/outis/data/generators/base.py +547 -0
  29. outis-0.1.0/src/outis/data/generators/compositional.py +570 -0
  30. outis-0.1.0/src/outis/data/generators/context.py +267 -0
  31. outis-0.1.0/src/outis/data/generators/coverage.py +398 -0
  32. outis-0.1.0/src/outis/data/generators/generalization.py +1450 -0
  33. outis-0.1.0/src/outis/data/generators/name_contrastive.py +902 -0
  34. outis-0.1.0/src/outis/data/generators/narrative.py +520 -0
  35. outis-0.1.0/src/outis/data/generators/nominal_alias.py +1224 -0
  36. outis-0.1.0/src/outis/data/generators/place_sources.py +185 -0
  37. outis-0.1.0/src/outis/data/generators/places.py +1160 -0
  38. outis-0.1.0/src/outis/data/generators/places_contexts.py +622 -0
  39. outis-0.1.0/src/outis/data/generators/remediation.py +1204 -0
  40. outis-0.1.0/src/outis/data/generators/remediation_development.py +613 -0
  41. outis-0.1.0/src/outis/data/v12/__init__.py +1 -0
  42. outis-0.1.0/src/outis/data/v12/contexts.py +262 -0
  43. outis-0.1.0/src/outis/data/v12/development.py +663 -0
  44. outis-0.1.0/src/outis/data/v12/synthetic.py +555 -0
  45. outis-0.1.0/src/outis/data/v13/__init__.py +1 -0
  46. outis-0.1.0/src/outis/data/v13/contexts.py +735 -0
  47. outis-0.1.0/src/outis/data/v13/replay.py +291 -0
  48. outis-0.1.0/src/outis/data/v13/synthetic.py +284 -0
  49. outis-0.1.0/src/outis/detection/__init__.py +1 -0
  50. outis-0.1.0/src/outis/detection/deberta_attention.py +158 -0
  51. outis-0.1.0/src/outis/detection/decoding.py +338 -0
  52. outis-0.1.0/src/outis/detection/hf_encoder.py +217 -0
  53. outis-0.1.0/src/outis/entities.py +68 -0
  54. outis-0.1.0/src/outis/evaluation/__init__.py +1 -0
  55. outis-0.1.0/src/outis/evaluation/evaluate.py +619 -0
  56. outis-0.1.0/src/outis/evaluation/report.py +606 -0
  57. outis-0.1.0/src/outis/evaluation/report_html.py +732 -0
  58. outis-0.1.0/src/outis/evaluation/report_progress.py +150 -0
  59. outis-0.1.0/src/outis/evaluation/runtime.py +73 -0
  60. outis-0.1.0/src/outis/formats/__init__.py +1 -0
  61. outis-0.1.0/src/outis/formats/files.py +861 -0
  62. outis-0.1.0/src/outis/formats/structured.py +395 -0
  63. outis-0.1.0/src/outis/operations.py +87 -0
  64. outis-0.1.0/src/outis/paths.py +40 -0
  65. outis-0.1.0/src/outis/policy.py +373 -0
  66. outis-0.1.0/src/outis/replacement/__init__.py +1 -0
  67. outis-0.1.0/src/outis/replacement/names/__init__.py +5 -0
  68. outis-0.1.0/src/outis/replacement/names/age.py +63 -0
  69. outis-0.1.0/src/outis/replacement/names/aliases.py +100 -0
  70. outis-0.1.0/src/outis/replacement/names/identity.py +103 -0
  71. outis-0.1.0/src/outis/replacement/names/nickname.py +521 -0
  72. outis-0.1.0/src/outis/replacement/names/person.py +270 -0
  73. outis-0.1.0/src/outis/replacement/names/record.py +105 -0
  74. outis-0.1.0/src/outis/replacement/nicknames.py +154 -0
  75. outis-0.1.0/src/outis/replacement/surrogates.py +856 -0
  76. outis-0.1.0/src/outis/replacement/transform.py +596 -0
  77. outis-0.1.0/src/outis/service.py +444 -0
  78. outis-0.1.0/src/outis/types.py +40 -0
  79. outis-0.1.0/src/outis.egg-info/PKG-INFO +276 -0
  80. outis-0.1.0/src/outis.egg-info/SOURCES.txt +154 -0
  81. outis-0.1.0/src/outis.egg-info/dependency_links.txt +1 -0
  82. outis-0.1.0/src/outis.egg-info/entry_points.txt +2 -0
  83. outis-0.1.0/src/outis.egg-info/requires.txt +18 -0
  84. outis-0.1.0/src/outis.egg-info/top_level.txt +1 -0
  85. outis-0.1.0/tests/test_alias_contrastive_synthetic.py +438 -0
  86. outis-0.1.0/tests/test_analysis.py +230 -0
  87. outis-0.1.0/tests/test_annotation_policy_ages.py +24 -0
  88. outis-0.1.0/tests/test_annotation_policy_care_sites.py +96 -0
  89. outis-0.1.0/tests/test_annotation_policy_eponyms.py +22 -0
  90. outis-0.1.0/tests/test_annotation_policy_facility_names.py +27 -0
  91. outis-0.1.0/tests/test_annotation_policy_fhir.py +43 -0
  92. outis-0.1.0/tests/test_annotation_policy_places.py +61 -0
  93. outis-0.1.0/tests/test_annotation_policy_reports.py +32 -0
  94. outis-0.1.0/tests/test_annotation_policy_spoken.py +52 -0
  95. outis-0.1.0/tests/test_annotation_policy_targeted.py +72 -0
  96. outis-0.1.0/tests/test_annotation_policy_transcripts.py +26 -0
  97. outis-0.1.0/tests/test_annotation_policy_v2.py +145 -0
  98. outis-0.1.0/tests/test_api.py +486 -0
  99. outis-0.1.0/tests/test_api_extensions.py +616 -0
  100. outis-0.1.0/tests/test_augment_synthetic.py +87 -0
  101. outis-0.1.0/tests/test_author13_care_sites.py +531 -0
  102. outis-0.1.0/tests/test_author14_targeted_gaps.py +569 -0
  103. outis-0.1.0/tests/test_author15_name_mentions.py +206 -0
  104. outis-0.1.0/tests/test_author16_transcripts.py +327 -0
  105. outis-0.1.0/tests/test_author17_lab_pathology.py +278 -0
  106. outis-0.1.0/tests/test_author18_radiology.py +336 -0
  107. outis-0.1.0/tests/test_author19_spoken_phi.py +362 -0
  108. outis-0.1.0/tests/test_author20_fhir.py +319 -0
  109. outis-0.1.0/tests/test_author21_care_site_boundaries.py +404 -0
  110. outis-0.1.0/tests/test_author22_word_surnames.py +427 -0
  111. outis-0.1.0/tests/test_author23_age_contexts.py +222 -0
  112. outis-0.1.0/tests/test_author24_instrument_eponyms.py +230 -0
  113. outis-0.1.0/tests/test_compositional_synthetic.py +171 -0
  114. outis-0.1.0/tests/test_context_synthetic.py +62 -0
  115. outis-0.1.0/tests/test_corpus_quality.py +368 -0
  116. outis-0.1.0/tests/test_coverage_synthetic.py +82 -0
  117. outis-0.1.0/tests/test_deberta_attention.py +125 -0
  118. outis-0.1.0/tests/test_evaluate.py +321 -0
  119. outis-0.1.0/tests/test_evaluator_manifest_counts.py +105 -0
  120. outis-0.1.0/tests/test_files.py +451 -0
  121. outis-0.1.0/tests/test_generalization_synthetic.py +398 -0
  122. outis-0.1.0/tests/test_hf_encoder.py +220 -0
  123. outis-0.1.0/tests/test_hf_runtime_compatibility.py +52 -0
  124. outis-0.1.0/tests/test_name_contrastive_synthetic.py +382 -0
  125. outis-0.1.0/tests/test_name_quote_boundaries.py +150 -0
  126. outis-0.1.0/tests/test_narrative_synthetic.py +149 -0
  127. outis-0.1.0/tests/test_nickname_declaration_padding.py +51 -0
  128. outis-0.1.0/tests/test_nickname_declarations.py +119 -0
  129. outis-0.1.0/tests/test_nickname_declarations_independent.py +297 -0
  130. outis-0.1.0/tests/test_nickname_replacement.py +438 -0
  131. outis-0.1.0/tests/test_nominal_alias_synthetic.py +646 -0
  132. outis-0.1.0/tests/test_normalize_ages2.py +80 -0
  133. outis-0.1.0/tests/test_package_layout.py +37 -0
  134. outis-0.1.0/tests/test_places_synthetic.py +529 -0
  135. outis-0.1.0/tests/test_policy.py +240 -0
  136. outis-0.1.0/tests/test_policy_ages.py +45 -0
  137. outis-0.1.0/tests/test_remediation_development.py +200 -0
  138. outis-0.1.0/tests/test_remediation_synthetic.py +237 -0
  139. outis-0.1.0/tests/test_replacement.py +989 -0
  140. outis-0.1.0/tests/test_report.py +485 -0
  141. outis-0.1.0/tests/test_report_progress.py +318 -0
  142. outis-0.1.0/tests/test_report_timing.py +115 -0
  143. outis-0.1.0/tests/test_service_extensions.py +461 -0
  144. outis-0.1.0/tests/test_service_model_selection.py +143 -0
  145. outis-0.1.0/tests/test_structured.py +335 -0
  146. outis-0.1.0/tests/test_synthetic.py +117 -0
  147. outis-0.1.0/tests/test_takeover_date_intervals.py +669 -0
  148. outis-0.1.0/tests/test_takeover_eval_bank.py +297 -0
  149. outis-0.1.0/tests/test_takeover_facility_at.py +227 -0
  150. outis-0.1.0/tests/test_takeover_field_labels_and_sampling.py +100 -0
  151. outis-0.1.0/tests/test_takeover_training_mixture.py +739 -0
  152. outis-0.1.0/tests/test_train_hf.py +469 -0
  153. outis-0.1.0/tests/test_transform.py +635 -0
  154. outis-0.1.0/tests/test_v12_development.py +267 -0
  155. outis-0.1.0/tests/test_v12_synthetic.py +184 -0
  156. outis-0.1.0/tests/test_v13_synthetic.py +281 -0
outis-0.1.0/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
outis-0.1.0/NOTICE ADDED
@@ -0,0 +1,25 @@
1
+ Outis
2
+ Copyright 2026
3
+
4
+ The default detector is fine-tuned from DeBERTa-v3-base, Copyright Microsoft
5
+ Corporation, licensed under the MIT License.
6
+ Source: https://huggingface.co/microsoft/deberta-v3-base
7
+
8
+ Earlier detector checkpoints, and candidates that may still be trained, are
9
+ fine-tuned from ModernBERT-base, Copyright Answer.AI, licensed under the Apache
10
+ License, Version 2.0.
11
+ Source: https://huggingface.co/answerdotai/ModernBERT-base
12
+
13
+ The optional `generators` extra uses OpenAI Privacy Filter (`opf`), Copyright
14
+ OpenAI, licensed under the Apache License, Version 2.0, pinned to commit
15
+ f7f00ca7fb869683eb732c010299d901457f19c3, only to compute token offsets for
16
+ legacy corpus statistics.
17
+ Source: https://github.com/openai/privacy-filter
18
+
19
+ PyTorch, Hugging Face Transformers, FastAPI, Uvicorn, tiktoken and other
20
+ dependencies retain their respective licenses. No externally sourced clinical
21
+ training dataset is included or downloaded.
22
+
23
+ Project-authored synthetic corpus text and annotations are dedicated to the
24
+ public domain under CC0 1.0 Universal:
25
+ https://creativecommons.org/publicdomain/zero/1.0/
outis-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,276 @@
1
+ Metadata-Version: 2.4
2
+ Name: outis
3
+ Version: 0.1.0
4
+ Summary: Local clinical PHI detection, redaction and consistent synthetic replacement
5
+ Author: Eric Hauser
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/ewhauser/outis
8
+ Project-URL: Documentation, https://github.com/ewhauser/outis/tree/main/docs
9
+ Project-URL: Changelog, https://github.com/ewhauser/outis/blob/main/CHANGELOG.md
10
+ Project-URL: Issues, https://github.com/ewhauser/outis/issues
11
+ Keywords: de-identification,phi,clinical-nlp,ner,privacy,hipaa
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Healthcare Industry
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
22
+ Requires-Python: >=3.11
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ License-File: NOTICE
26
+ Requires-Dist: torch>=2.6
27
+ Requires-Dist: transformers>=5.6
28
+ Requires-Dist: safetensors>=0.5
29
+ Requires-Dist: huggingface-hub>=0.35
30
+ Requires-Dist: fastapi>=0.115
31
+ Requires-Dist: uvicorn[standard]>=0.30
32
+ Requires-Dist: pydantic>=2.10
33
+ Requires-Dist: python-dateutil>=2.9
34
+ Requires-Dist: tiktoken>=0.9
35
+ Requires-Dist: numpy>=2.0
36
+ Requires-Dist: regex>=2024.11
37
+ Requires-Dist: defusedxml>=0.7
38
+ Requires-Dist: sentencepiece>=0.2
39
+ Requires-Dist: protobuf>=5
40
+ Provides-Extra: pdf
41
+ Requires-Dist: pypdf>=6.19.0; extra == "pdf"
42
+ Requires-Dist: reportlab>=4; extra == "pdf"
43
+ Dynamic: license-file
44
+
45
+ # Outis
46
+
47
+ [![CI](https://github.com/ewhauser/outis/actions/workflows/ci.yml/badge.svg)](https://github.com/ewhauser/outis/actions/workflows/ci.yml)
48
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
49
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](pyproject.toml)
50
+
51
+ Local PHI detection, typed redaction and patient-consistent synthetic
52
+ replacement for English clinical text.
53
+
54
+ Outis is Greek for "nobody": the name Odysseus gave the Cyclops.
55
+
56
+ The detector is a fully fine-tuned
57
+ [DeBERTa-v3-base](https://huggingface.co/microsoft/deberta-v3-base) token
58
+ classifier with a constrained BIOES decoder. There is no rule layer: every
59
+ detected span comes from the model. Everything runs on your machine; no text
60
+ is sent to a hosted service. It ships as a Python library, a CLI and a FastAPI
61
+ server.
62
+
63
+ - **Model:** [ewhauser/outis-deberta-v3-base](https://huggingface.co/ewhauser/outis-deberta-v3-base) on Hugging Face
64
+ - **Training data:** [ewhauser/outis-synthetic-phi](https://huggingface.co/datasets/ewhauser/outis-synthetic-phi), the synthetic
65
+ corpora the model was trained and selected on
66
+
67
+ > [!IMPORTANT]
68
+ > This is research software. It has **not** met all of its [evaluation targets](docs/evaluation.md), and it has been evaluated only on
69
+ > synthetic and public benchmark text, never on real clinical records. It does
70
+ > not by itself provide HIPAA Safe Harbor or Expert Determination
71
+ > de-identification. See [Limitations](#limitations).
72
+
73
+ ## Features
74
+
75
+ - **14 PHI types**: NAME, DATE, AGE, ADDRESS, LOCATION, FACILITY, PHONE, EMAIL,
76
+ URL, IP, MRN, SSN, ACCOUNT and ID.
77
+ - **Redaction or replacement**: typed markers or masks, or fictional values that
78
+ stay consistent per patient. Dates shift by a stable per-patient offset that
79
+ preserves intervals.
80
+ - **Model-only detection**: one fine-tuned encoder, decoded to exact original
81
+ character offsets.
82
+ - **Configurable policies**: per-type actions, custom identifier rules, linked
83
+ messages, explicit restoration, and JSON, CSV, XML and plain-text file input.
84
+ - **Local by design**: loopback-only by default, optional API key, no request
85
+ logging, `Cache-Control: no-store` on responses.
86
+
87
+ ## Quickstart
88
+
89
+ Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).
90
+
91
+ ```sh
92
+ git clone https://github.com/ewhauser/outis.git
93
+ cd outis
94
+ uv sync
95
+ ```
96
+
97
+ The default model's configuration and tokenizer are in
98
+ `models/deid-deberta-v3-base`. Download its 736 MB weight file from
99
+ [Hugging Face](https://huggingface.co/ewhauser/outis-deberta-v3-base):
100
+
101
+ ```sh
102
+ uv run hf download ewhauser/outis-deberta-v3-base hf/model.safetensors --local-dir models/deid-deberta-v3-base
103
+ ```
104
+
105
+ Add the `pdf` extra (`uv sync --extra pdf`) for PDF file input.
106
+
107
+ ### Python
108
+
109
+ Run it with `uv run python`.
110
+
111
+ ```python
112
+ from outis import Deidentifier
113
+
114
+ deid = Deidentifier(secret=b"application-secret-at-least-32-bytes")
115
+
116
+ result = deid.deidentify("Mara Calder was seen on 2024-02-28.", mode="redact")
117
+ print(result["text"])
118
+
119
+ synthetic = deid.deidentify(
120
+ "Mara Calder was seen on 2024-02-28.",
121
+ mode="synthetic",
122
+ patient_id="internal-patient-42",
123
+ )
124
+ print(synthetic["text"])
125
+ ```
126
+
127
+ Each result contains the transformed text and, for every entity, its type,
128
+ original character offsets, replacement and score. It also lists any warnings
129
+ and the model version.
130
+
131
+ ### HTTP API
132
+
133
+ ```sh
134
+ uv run scripts/serve_local.py --port 8000
135
+ ```
136
+
137
+ ```sh
138
+ curl http://127.0.0.1:8000/v1/deidentify \
139
+ -H 'Content-Type: application/json' \
140
+ -d '{"text":"Patient Mara Calder, DOB 1974-06-13. Creatinine 1.2 mg/dL.","mode":"redact"}'
141
+ ```
142
+
143
+ Interactive docs are served at `http://127.0.0.1:8000/docs`, and the OpenAPI
144
+ schema at `/openapi.json`. The local launcher creates and reuses a replacement
145
+ secret in `.cache/local-api-secret`. For other deployments, see
146
+ [deployment](docs/deployment.md).
147
+
148
+ ### CLI
149
+
150
+ ```sh
151
+ uv run outis text --input note.txt --mode redact
152
+ ```
153
+
154
+ ## How it works
155
+
156
+ ```
157
+ text ─▶ DeBERTa-v3-base token classifier (overlapping 512-token windows)
158
+ └─▶ constrained BIOES decoder ─▶ spans at original offsets ─▶ redact / replace
159
+ ```
160
+
161
+ The default model was fine-tuned on about 116,000 synthetic notes from 46
162
+ banks written by this project's generators and independent synthetic authors. No real
163
+ clinical data was used for training. See the [model card](MODEL_CARD.md).
164
+
165
+ ## Results
166
+
167
+ All results come from synthetic text. None of them measures accuracy on real
168
+ clinical notes.
169
+
170
+ ### Public benchmarks
171
+
172
+ Every model is scored the same way, under this project's annotation policy
173
+ ([details](docs/external-verification.md)). ↑ means higher is better, ↓ lower
174
+ is better; the best result in each row is in bold.
175
+
176
+ | Benchmark | Measure | Outis | [MedDeID](https://huggingface.co/stighellemans/meddeid-english-synth) | [GLiNER-PII](https://huggingface.co/nvidia/gliner-PII)\* |
177
+ |---|---|---:|---:|---:|
178
+ | [ASQ-PHI](https://doi.org/10.17632/csz5dzp7nx.1)<br>1,051 search queries | PHI characters masked ↑ | **99.94%** | 99.66% | 98.57% |
179
+ | | Non-PHI text removed ↓ | **0.18%** | 0.91% | 2.43% |
180
+ | | Notes fully masked ↑ | **99.52%** | 97.60% | 94.47% |
181
+ | [MedDeID English](https://huggingface.co/datasets/stighellemans/meddeid-english-synthetic-benchmark)<br>300 notes | PHI characters masked ↑ | **99.27%** | 99.19% | 94.87% |
182
+ | | Non-PHI text removed ↓ | **0.01%** | 0.15% | 0.64% |
183
+ | | Notes fully masked ↑ | **95.00%** | 93.00% | 69.67% |
184
+ | [Technetium-I](https://huggingface.co/datasets/temlm-foundation/Technetium-I)<br>5,000-note sample | PHI characters masked ↑ | 99.65% | 99.65% | not run |
185
+ | | Non-PHI text removed ↓ | **0.57%** | 1.14% | not run |
186
+ | | Notes fully masked ↑ | 84.60% | 84.60% | not run |
187
+
188
+ \* `nvidia/gliner-PII` with one added zero-shot label for hospitals.
189
+
190
+ We have looked at Outis's failures on ASQ-PHI and MedDeID English while
191
+ developing it, so those two are not fully independent tests; Technetium-I has
192
+ not been inspected. Per-identifier results are in the
193
+ [full comparison](benchmarks/results/COMPARISON.md).
194
+
195
+ ### Held-out synthetic notes
196
+
197
+ On 2,400 synthetic notes from an author whose writing was never used in
198
+ training:
199
+
200
+ | Measure | Result |
201
+ |---|---:|
202
+ | Direct identifiers masked (names, record numbers, phone numbers, emails, addresses and similar) | 99.64% |
203
+ | Names masked (95% lower bound) | 99.79% (99.71%) |
204
+ | Indirect identifiers masked (dates, ages over 89, places, facilities) | 98.97% |
205
+ | Detected spans that are real PHI | 99.63% |
206
+ | Exact type and boundary match (F1) | 97.34% |
207
+ | Notes with every identifier masked* | 86.25% |
208
+
209
+ \* Counts ages over 89, the ages HIPAA's Safe Harbor method lists as
210
+ identifiers; ages of 89 and under stay in the output by default. The model
211
+ detects every age, so setting the request policy's `ages` option to `all`
212
+ removes younger ages too (see the [API guide](docs/api.md)). Counting every
213
+ age, 81.90% of notes are fully masked.
214
+
215
+ On these same notes MedDeID masked 86.08% of direct identifiers and GLiNER-PII
216
+ 79.09%. The notes follow this project's annotation conventions, which this
217
+ model was trained on, so that gap overstates its advantage; the public
218
+ benchmarks above are the fair comparison.
219
+
220
+ A separate test of real place names (2,352 notes) masked 98.81% of city and
221
+ care-site name characters, but tagged a bare state or country in 4% of notes
222
+ that contained no PHI.
223
+
224
+ How these numbers are computed is described in
225
+ [evaluation methodology](docs/evaluation.md).
226
+
227
+ ## Limitations
228
+
229
+ - **Not yet measured on real notes.** Held-out synthetic authors are the best
230
+ available evidence; real institutional notes may differ substantially.
231
+ - **Synthetic evaluation only.** Training and internal test text comes from
232
+ this project's own generators. Real institutional formats, rare identifying
233
+ narratives and unseen identity styles are not measured.
234
+ - **Scope.** English plain text only. OCR, scanned images, audio and
235
+ multilingual text are out of scope.
236
+ - **Some options return PHI.** Restoration mappings, sensitive entity analysis
237
+ and per-type `keep` deliberately return original values. Treat those
238
+ responses as PHI.
239
+ - **Scores are not calibrated.** Model scores are not safety probabilities.
240
+ - **Replacement is not anonymity.** Fictional values can resemble real people,
241
+ and date shifting changes seasonal context. Surrogates do not guarantee
242
+ resistance to re-identification.
243
+
244
+ Use human review and an appropriate privacy determination before releasing
245
+ any output.
246
+
247
+ ## Documentation
248
+
249
+ | Guide | Contents |
250
+ |---|---|
251
+ | [Evaluation methodology](docs/evaluation.md) | Targets, any-label masking and how models are compared |
252
+ | [API guide](docs/api.md) | Endpoints, policies, masks, structured data, files, WebSockets |
253
+ | [Synthetic replacement](docs/replacement.md) | Secrets, patient anchors, date shifting, identity linking |
254
+ | [Deployment](docs/deployment.md) | Launcher, default model, batch limits, security controls |
255
+ | [Model card](MODEL_CARD.md) | Architecture, training data, evaluation, risks |
256
+ | [Training](docs/training.md) | Training candidates and generating corpora |
257
+ | [External verification](docs/external-verification.md) | Public benchmark protocol and results |
258
+ | [Annotation policy](docs/annotation-policy-v2.md) | Span conventions for every entity type |
259
+ | [Places addendum](docs/annotation-policy-v2-places.md) | Real localities, care-site abbreviations and public references |
260
+
261
+ ## Contributing
262
+
263
+ See [CONTRIBUTING.md](CONTRIBUTING.md). Report security issues privately, as
264
+ described in [SECURITY.md](SECURITY.md). Never put real PHI in an issue, pull
265
+ request or test fixture.
266
+
267
+ ## Citation
268
+
269
+ If you use this project, please cite it using [CITATION.cff](CITATION.cff).
270
+
271
+ ## License
272
+
273
+ Source code and the fine-tuned model are licensed under
274
+ [Apache-2.0](LICENSE). Generated synthetic corpus text and annotations are
275
+ dedicated to the public domain under CC0-1.0. The DeBERTa-v3-base base model
276
+ is MIT-licensed; see [NOTICE](NOTICE).