edshield 0.2.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.
- edshield-0.2.0/LICENSE +201 -0
- edshield-0.2.0/PKG-INFO +229 -0
- edshield-0.2.0/README.md +186 -0
- edshield-0.2.0/edshield/__init__.py +150 -0
- edshield-0.2.0/edshield/cli.py +63 -0
- edshield-0.2.0/edshield/deid.py +241 -0
- edshield-0.2.0/edshield/models.jsonl +6 -0
- edshield-0.2.0/edshield/ner.py +276 -0
- edshield-0.2.0/edshield/policies/coppa.yaml +29 -0
- edshield-0.2.0/edshield/policies/ferpa.yaml +31 -0
- edshield-0.2.0/edshield/policies/research.yaml +26 -0
- edshield-0.2.0/edshield/rules.py +430 -0
- edshield-0.2.0/edshield/service.py +73 -0
- edshield-0.2.0/edshield/types.py +108 -0
- edshield-0.2.0/edshield.egg-info/PKG-INFO +229 -0
- edshield-0.2.0/edshield.egg-info/SOURCES.txt +29 -0
- edshield-0.2.0/edshield.egg-info/dependency_links.txt +1 -0
- edshield-0.2.0/edshield.egg-info/entry_points.txt +2 -0
- edshield-0.2.0/edshield.egg-info/requires.txt +31 -0
- edshield-0.2.0/edshield.egg-info/top_level.txt +1 -0
- edshield-0.2.0/pyproject.toml +43 -0
- edshield-0.2.0/setup.cfg +4 -0
- edshield-0.2.0/tests/test_authority.py +148 -0
- edshield-0.2.0/tests/test_deid.py +166 -0
- edshield-0.2.0/tests/test_demo_offline.py +17 -0
- edshield-0.2.0/tests/test_demo_parity.py +178 -0
- edshield-0.2.0/tests/test_indirect.py +86 -0
- edshield-0.2.0/tests/test_ner.py +216 -0
- edshield-0.2.0/tests/test_pipeline_scripts.py +138 -0
- edshield-0.2.0/tests/test_rules.py +126 -0
- edshield-0.2.0/tests/test_service.py +72 -0
edshield-0.2.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.
|
edshield-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edshield
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Local-first student-privacy layer for AI in education: PII detection and FERPA/COPPA de-identification that runs on-device.
|
|
5
|
+
Author-email: Hemang Nagar <hi@hemangnagar.dev>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/hemangnagar/edshield
|
|
8
|
+
Keywords: education,FERPA,COPPA,PII,de-identification,NER,on-device,edtech
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Topic :: Education
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
License-File: LICENSE
|
|
16
|
+
Requires-Dist: pyyaml>=6
|
|
17
|
+
Requires-Dist: faker>=20
|
|
18
|
+
Provides-Extra: hf
|
|
19
|
+
Requires-Dist: transformers>=4.40; extra == "hf"
|
|
20
|
+
Requires-Dist: torch>=2.1; extra == "hf"
|
|
21
|
+
Requires-Dist: sentencepiece>=0.2; extra == "hf"
|
|
22
|
+
Requires-Dist: protobuf; extra == "hf"
|
|
23
|
+
Provides-Extra: onnx
|
|
24
|
+
Requires-Dist: onnxruntime>=1.17; extra == "onnx"
|
|
25
|
+
Requires-Dist: onnx>=1.16; extra == "onnx"
|
|
26
|
+
Provides-Extra: service
|
|
27
|
+
Requires-Dist: fastapi>=0.110; extra == "service"
|
|
28
|
+
Requires-Dist: uvicorn>=0.29; extra == "service"
|
|
29
|
+
Provides-Extra: train
|
|
30
|
+
Requires-Dist: transformers>=4.40; extra == "train"
|
|
31
|
+
Requires-Dist: torch>=2.1; extra == "train"
|
|
32
|
+
Requires-Dist: datasets>=2.18; extra == "train"
|
|
33
|
+
Requires-Dist: accelerate>=0.28; extra == "train"
|
|
34
|
+
Requires-Dist: seqeval>=1.2; extra == "train"
|
|
35
|
+
Requires-Dist: sentencepiece>=0.2; extra == "train"
|
|
36
|
+
Requires-Dist: protobuf; extra == "train"
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
39
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
40
|
+
Requires-Dist: fastapi>=0.110; extra == "dev"
|
|
41
|
+
Requires-Dist: httpx>=0.27; extra == "dev"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# edshield
|
|
45
|
+
|
|
46
|
+
**Local-first student-privacy layer for AI in education.**
|
|
47
|
+
Detects and removes student PII from essays, tutoring transcripts and chat messages before the text reaches any language model. Runs on a laptop CPU, Apple Silicon, or inside a Chromebook browser. No cloud, no student text leaves the device. Apache-2.0.
|
|
48
|
+
|
|
49
|
+
**[Try the live demo](https://hemangnagar.github.io/edshield/)**: it runs in your browser, and the text you paste stays on your device. Models: [edshield/piilo-deberta-v3-small](https://huggingface.co/edshield/piilo-deberta-v3-small) and its [browser export](https://huggingface.co/edshield/piilo-deberta-v3-small-onnx).
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
from edshield import extract_pii, deidentify
|
|
53
|
+
|
|
54
|
+
text = "Hi, this is Marcus. My email is marcus.t2012@gmail.com and my Discord is @marcus_hoops."
|
|
55
|
+
|
|
56
|
+
print([(e.label, e.text) for e in extract_pii(text).entities])
|
|
57
|
+
# [('NAME_STUDENT', 'Marcus'), ('EMAIL', 'marcus.t2012@gmail.com'), ('USERNAME', 'marcus_hoops')]
|
|
58
|
+
|
|
59
|
+
print(deidentify(text, policy="coppa").deidentified_text)
|
|
60
|
+
# Hi, this is [CHILD]. My email is [EMAIL] and my Discord is @[USERNAME].
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Why
|
|
64
|
+
|
|
65
|
+
Every AI tutor, writing assistant and classroom chatbot sends student text to a model. FERPA, COPPA and a growing set of state laws (NY Ed Law 2-d, Illinois SOPPA, California SOPIPA) say identifiable student data cannot be handed to a third party without consent, and district AI policies are now saying it outright. Today each vendor and each research group rebuilds the same de-identification pipeline privately. edshield is the shared, open one.
|
|
66
|
+
|
|
67
|
+
The design follows [OpenMed](https://github.com/maziyarpanahi/openmed): small fine-tuned encoders for the domain, a rule layer for the identifiers where regex plus validation beats a neural model, policy profiles named after the regulation, and runtimes for Python, ONNX and the browser.
|
|
68
|
+
|
|
69
|
+
## What it does
|
|
70
|
+
|
|
71
|
+
| Layer | Covers | Needs a model? |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| Rules | EMAIL, PHONE_NUM, URL_PERSONAL, USERNAME, ID_NUM, STREET_ADDRESS, SSN, DATE, and names introduced with a cue ("my name is…", a signature) | No |
|
|
74
|
+
| Rules, beyond PIILO | NAME_RELATED (family, friends, teachers), SCHOOL, LOCATION, AGE, IP_ADDRESS, DEVICE_ID, GEO | No |
|
|
75
|
+
| Model | The authority for NAME_STUDENT, ID_NUM and STREET_ADDRESS, plus a second opinion on every other label | Yes (PIILO-trained encoder) |
|
|
76
|
+
| Propagation | Once a name is found, every other mention of it in the document is caught | No |
|
|
77
|
+
| Policies | `ferpa`, `coppa`, `research` decide which labels to act on, the confidence floor, and the method per label (mask, surrogate, hash, date-shift) | No |
|
|
78
|
+
| Verifier | Refuses to return output if any acted-on value still appears verbatim | No |
|
|
79
|
+
| Audit record | Policy, version, detector and counts for every document, with no student data in it | No |
|
|
80
|
+
|
|
81
|
+
When a model is loaded, the rules for NAME_STUDENT, ID_NUM and STREET_ADDRESS are switched off: they are recall-oriented fallbacks that over-flag ordinary essay text. Without a model the rules cover every label. `analyze_text(..., model_authority=())` runs both layers on everything.
|
|
82
|
+
|
|
83
|
+
**Loading a model.** The default model is [edshield/piilo-deberta-v3-small](https://huggingface.co/edshield/piilo-deberta-v3-small) on the Hugging Face Hub. edshield downloads nothing unless you allow it, so fetch the model once:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install "edshield[hf]"
|
|
87
|
+
EDSHIELD_ALLOW_DOWNLOAD=1 edshield extract essay.txt # PowerShell: $env:EDSHIELD_ALLOW_DOWNLOAD = "1"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
After that it loads from the Hugging Face cache with no network and the variable is not needed. Without the variable, models load from disk only: a directory you pass, the `local_path` in `edshield/models.jsonl`, or the cache. If you name a model (`model_name=...` or `EDSHIELD_MODEL`) and it cannot be loaded, edshield raises `ModelUnavailableError` rather than quietly doing less. If you name none and the default is not installed, the rules run alone and a `RuntimeWarning` says so; pass `model_name="rules"` to choose that on purpose.
|
|
91
|
+
|
|
92
|
+
**Recall-first decoding.** `analyze_text(..., o_threshold=0.99)` marks a token as an entity whenever P(O) < 0.99 instead of taking the most likely class. It is off by default: on held-out PIILO essays it lowered precision from 0.69 to 0.57 with recall already at 1.00.
|
|
93
|
+
|
|
94
|
+
Label schema is the seven types of the [PIILO corpus](https://the-learning-agency-lab.com/learning-exchange/piilo-dataset/) (The Learning Agency Lab, CC BY 4.0), so models trained on it drop straight in.
|
|
95
|
+
|
|
96
|
+
## Install
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
pip install edshield # rules, policies, CLI. No torch.
|
|
100
|
+
pip install "edshield[hf]" # + PyTorch model inference
|
|
101
|
+
pip install "edshield[service]" # + REST service
|
|
102
|
+
pip install "edshield[train,onnx]" # + training and ONNX/browser export
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
From a clone, use `pip install -e ".[dev]"` instead.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
edshield redact essay.txt --policy ferpa
|
|
109
|
+
edshield extract essay.txt --model rules
|
|
110
|
+
edshield serve --port 8080 # POST /pii/extract, POST /pii/deidentify
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Demo
|
|
114
|
+
|
|
115
|
+
Live at **https://hemangnagar.github.io/edshield/**, or from a clone:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
python -m http.server 8000 -d demo
|
|
119
|
+
# open http://localhost:8000
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Three synthetic samples (essay, tutoring transcript, chatbot message), three policies, and a detector switch. "Rules only" runs entirely from the page's own JavaScript, with no network. "Rules + on-device model" runs an ONNX model in the browser through Transformers.js, so the same layer works on a Chromebook with no backend. The model file (205 MB) is fetched once from the Hugging Face Hub and cached by the browser; the text is never uploaded. To run the model with no network at all, put a copy in `demo/models/piilo-deberta-v3-small-onnx` and the page uses that instead.
|
|
123
|
+
|
|
124
|
+
## Benchmarks
|
|
125
|
+
|
|
126
|
+
All numbers are span-level from `eval/evaluate.py`; F5 weights recall 5:1, as the PIILO competition did.
|
|
127
|
+
|
|
128
|
+
**Real student essays.** 680 PIILO documents held out from training of `piilo-deberta-v3-small` (DeBERTa-v3-small, 3 epochs), in the corpus's natural mix: 581 of them contain no PII at all.
|
|
129
|
+
|
|
130
|
+
| Detector | Precision | Recall | F5 | Missed entities |
|
|
131
|
+
|---|---|---|---|---|
|
|
132
|
+
| Rules only | 0.538 | 0.388 | 0.392 | 101 of 165 |
|
|
133
|
+
| Rules + model | 0.642 | 1.000 | 0.979 | 0 of 165 |
|
|
134
|
+
| Rules + INT8 model (browser) | 0.639 | 1.000 | 0.979 | 0 of 165 |
|
|
135
|
+
|
|
136
|
+
The browser file is 205 MB against 566 MB at full precision. It is measured with `eval/evaluate_onnx.py`. Quantizing every layer gives 172 MB but missed 8 of the 165 (precision 0.692, recall 0.952), so the export leaves the first two encoder layers at full precision. That setting was chosen on this same set, so the row is a little optimistic; on the synthetic K-12 hard set below, which played no part in the choice, the browser file lets 324 of 1,433 through against 319 for the full model.
|
|
137
|
+
|
|
138
|
+
| Rules + model, by label | Precision | Recall | n |
|
|
139
|
+
|---|---|---|---|
|
|
140
|
+
| NAME_STUDENT | 0.656 | 1.000 | 143 |
|
|
141
|
+
| URL_PERSONAL | 0.381 | 1.000 | 8 |
|
|
142
|
+
| ID_NUM | 0.700 | 1.000 | 7 |
|
|
143
|
+
| EMAIL | 1.000 | 1.000 | 4 |
|
|
144
|
+
| USERNAME | 1.000 | 1.000 | 2 |
|
|
145
|
+
| STREET_ADDRESS | 0.500 | 1.000 | 1 |
|
|
146
|
+
|
|
147
|
+
The rare labels have a handful of examples each, so their rows say little. Most name false positives are names of people other than the essay's author (personas, lecturers, friends), which PIILO does not label but which a privacy tool should remove. Reports are in `eval/results/`.
|
|
148
|
+
|
|
149
|
+
**Synthetic K-12 writing.** PIILO is adult writing, so `eval/k12_bench.py` generates short essays, tutoring transcripts and chat messages in children's registers, covering every label. "Got through" counts identifiers that no flag of any label touched.
|
|
150
|
+
|
|
151
|
+
| Set | Detector | Identifiers | Got through |
|
|
152
|
+
|---|---|---|---|
|
|
153
|
+
| Cued: worded the way the rules expect | Rules + model | 1,445 | 0 |
|
|
154
|
+
| Hard: the way children type | Rules + model | 1,433 | 319 (22%) |
|
|
155
|
+
| Hard | Rules only | 1,433 | 1,100 (77%) |
|
|
156
|
+
|
|
157
|
+
The hard set is the honest baseline. What gets through is mostly lowercase schools and towns, ages in chat shorthand, spoken dates and streets without a house number. [docs/COVERAGE.md](docs/COVERAGE.md) has the breakdown and maps each identifier type in FERPA and COPPA to what edshield does.
|
|
158
|
+
|
|
159
|
+
**Synthetic transcripts and essays.** Rules only, 500 documents (`eval/synthetic_bench.py --n 500 --seed 1`). The generator's sentences use the same cues the rules look for, so read this as a regression check, not as expected accuracy on real text:
|
|
160
|
+
|
|
161
|
+
| Label | Precision | Recall | F5 |
|
|
162
|
+
|---|---|---|---|
|
|
163
|
+
| EMAIL | 1.000 | 1.000 | 1.000 |
|
|
164
|
+
| PHONE_NUM | 1.000 | 1.000 | 1.000 |
|
|
165
|
+
| USERNAME | 1.000 | 1.000 | 1.000 |
|
|
166
|
+
| URL_PERSONAL | 1.000 | 1.000 | 1.000 |
|
|
167
|
+
| ID_NUM | 0.926 | 1.000 | 0.997 |
|
|
168
|
+
| STREET_ADDRESS | 1.000 | 0.945 | 0.947 |
|
|
169
|
+
| NAME_STUDENT | 1.000 | 0.761 | 0.768 |
|
|
170
|
+
| **overall** | **0.994** | **0.903** | **0.906** |
|
|
171
|
+
|
|
172
|
+
Names are the gap, and the reason the model layer exists: rules only catch names the writer introduces, so a friend mentioned in passing is missed.
|
|
173
|
+
|
|
174
|
+
## Train a model
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
pip install kaggle
|
|
178
|
+
kaggle competitions download -c pii-detection-removal-from-educational-data
|
|
179
|
+
unzip pii-detection-removal-from-educational-data.zip -d data/piilo
|
|
180
|
+
|
|
181
|
+
python eval/synthetic_bench.py --n 2000 --out data/synthetic.json # augmentation for rare labels
|
|
182
|
+
python training/prepare_piilo.py --input data/piilo/train.json --out data/piilo_hf --extra data/synthetic.json
|
|
183
|
+
python training/train.py --data data/piilo_hf --base microsoft/deberta-v3-small --out models/piilo-deberta-v3-small --epochs 3
|
|
184
|
+
python eval/evaluate.py --input data/piilo_hf/validation.json --model models/piilo-deberta-v3-small --device cuda
|
|
185
|
+
python training/export_onnx.py --model models/piilo-deberta-v3-small --out demo/models/piilo-deberta-v3-small-onnx
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`train.py` uses the recall tricks that won the competition: down-weighted O class, a P(O) threshold instead of argmax at inference, long context with stride, synthetic augmentation. `edshield/models.jsonl` is the manifest; add a line per published model. `training/publish_hub.py` uploads a model and its card from `hub/` to the Hugging Face Hub.
|
|
189
|
+
|
|
190
|
+
## Layout
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
edshield/ runtime: rules.py, ner.py, deid.py, policies/, cli.py, service.py, models.jsonl (model manifest)
|
|
194
|
+
training/ prepare_piilo.py, train.py, export_onnx.py, publish_hub.py
|
|
195
|
+
hub/ model cards for the Hugging Face Hub
|
|
196
|
+
eval/ evaluate.py (F5 + leak count), evaluate_onnx.py, synthetic_bench.py, results/
|
|
197
|
+
demo/ single-file browser demo; a model in demo/models/ is used in place of the Hub
|
|
198
|
+
tests/ pytest
|
|
199
|
+
docs/ COVERAGE.md: what is detected, how well, and what can be claimed
|
|
200
|
+
.github/ GitHub Actions: tests on every push, the demo to GitHub Pages, releases to PyPI
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Roadmap
|
|
204
|
+
|
|
205
|
+
- [x] Rule layer with validators, name propagation, leak verifier
|
|
206
|
+
- [x] FERPA / COPPA / research policies
|
|
207
|
+
- [x] Browser demo, REST service, CLI
|
|
208
|
+
- [x] First PIILO-trained encoder (DeBERTa-v3-small) and its ONNX INT8 export published to the Hub
|
|
209
|
+
- [ ] DeBERTa-v3-base and ModernBERT-base
|
|
210
|
+
- [ ] Browser benchmark on a Chromebook
|
|
211
|
+
- [ ] Transcript models: teacher/tutor discourse moves (TalkMoves, NCTE), argumentative elements (PERSUADE)
|
|
212
|
+
- [ ] MLX backend and a Swift package
|
|
213
|
+
- [ ] MCP server and agent skills
|
|
214
|
+
|
|
215
|
+
## For research contributors
|
|
216
|
+
|
|
217
|
+
The corpus is public, the metric is defined, and the winning recipes are documented. That makes this a good place for a first applied-ML paper: fine-tune a model on PIILO, compare it with ChatGPT and Presidio on `eval/evaluate.py`, measure what leaks, and publish. Open an issue with the experiment you want to run; results that beat the current manifest entry get merged and credited in the model card.
|
|
218
|
+
|
|
219
|
+
## What this is not
|
|
220
|
+
|
|
221
|
+
Running edshield does not by itself make a product FERPA- or COPPA-compliant. It removes direct identifiers with measured recall; the institution still owns the reasonable-determination review, the consent process, and the data-handling agreement. Never paste real student data into a cloud-hosted agent to test this; use the synthetic samples.
|
|
222
|
+
|
|
223
|
+
## Credits
|
|
224
|
+
|
|
225
|
+
[The Learning Agency Lab](https://the-learning-agency-lab.com/) and Vanderbilt University for the PIILO corpus; [OpenMed](https://github.com/maziyarpanahi/openmed) for the pattern; Hugging Face `transformers` and Transformers.js; Faker.
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
Apache-2.0. Model weights carry the license of their training data (PIILO is CC BY 4.0).
|
edshield-0.2.0/README.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# edshield
|
|
2
|
+
|
|
3
|
+
**Local-first student-privacy layer for AI in education.**
|
|
4
|
+
Detects and removes student PII from essays, tutoring transcripts and chat messages before the text reaches any language model. Runs on a laptop CPU, Apple Silicon, or inside a Chromebook browser. No cloud, no student text leaves the device. Apache-2.0.
|
|
5
|
+
|
|
6
|
+
**[Try the live demo](https://hemangnagar.github.io/edshield/)**: it runs in your browser, and the text you paste stays on your device. Models: [edshield/piilo-deberta-v3-small](https://huggingface.co/edshield/piilo-deberta-v3-small) and its [browser export](https://huggingface.co/edshield/piilo-deberta-v3-small-onnx).
|
|
7
|
+
|
|
8
|
+
```python
|
|
9
|
+
from edshield import extract_pii, deidentify
|
|
10
|
+
|
|
11
|
+
text = "Hi, this is Marcus. My email is marcus.t2012@gmail.com and my Discord is @marcus_hoops."
|
|
12
|
+
|
|
13
|
+
print([(e.label, e.text) for e in extract_pii(text).entities])
|
|
14
|
+
# [('NAME_STUDENT', 'Marcus'), ('EMAIL', 'marcus.t2012@gmail.com'), ('USERNAME', 'marcus_hoops')]
|
|
15
|
+
|
|
16
|
+
print(deidentify(text, policy="coppa").deidentified_text)
|
|
17
|
+
# Hi, this is [CHILD]. My email is [EMAIL] and my Discord is @[USERNAME].
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Why
|
|
21
|
+
|
|
22
|
+
Every AI tutor, writing assistant and classroom chatbot sends student text to a model. FERPA, COPPA and a growing set of state laws (NY Ed Law 2-d, Illinois SOPPA, California SOPIPA) say identifiable student data cannot be handed to a third party without consent, and district AI policies are now saying it outright. Today each vendor and each research group rebuilds the same de-identification pipeline privately. edshield is the shared, open one.
|
|
23
|
+
|
|
24
|
+
The design follows [OpenMed](https://github.com/maziyarpanahi/openmed): small fine-tuned encoders for the domain, a rule layer for the identifiers where regex plus validation beats a neural model, policy profiles named after the regulation, and runtimes for Python, ONNX and the browser.
|
|
25
|
+
|
|
26
|
+
## What it does
|
|
27
|
+
|
|
28
|
+
| Layer | Covers | Needs a model? |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| Rules | EMAIL, PHONE_NUM, URL_PERSONAL, USERNAME, ID_NUM, STREET_ADDRESS, SSN, DATE, and names introduced with a cue ("my name is…", a signature) | No |
|
|
31
|
+
| Rules, beyond PIILO | NAME_RELATED (family, friends, teachers), SCHOOL, LOCATION, AGE, IP_ADDRESS, DEVICE_ID, GEO | No |
|
|
32
|
+
| Model | The authority for NAME_STUDENT, ID_NUM and STREET_ADDRESS, plus a second opinion on every other label | Yes (PIILO-trained encoder) |
|
|
33
|
+
| Propagation | Once a name is found, every other mention of it in the document is caught | No |
|
|
34
|
+
| Policies | `ferpa`, `coppa`, `research` decide which labels to act on, the confidence floor, and the method per label (mask, surrogate, hash, date-shift) | No |
|
|
35
|
+
| Verifier | Refuses to return output if any acted-on value still appears verbatim | No |
|
|
36
|
+
| Audit record | Policy, version, detector and counts for every document, with no student data in it | No |
|
|
37
|
+
|
|
38
|
+
When a model is loaded, the rules for NAME_STUDENT, ID_NUM and STREET_ADDRESS are switched off: they are recall-oriented fallbacks that over-flag ordinary essay text. Without a model the rules cover every label. `analyze_text(..., model_authority=())` runs both layers on everything.
|
|
39
|
+
|
|
40
|
+
**Loading a model.** The default model is [edshield/piilo-deberta-v3-small](https://huggingface.co/edshield/piilo-deberta-v3-small) on the Hugging Face Hub. edshield downloads nothing unless you allow it, so fetch the model once:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install "edshield[hf]"
|
|
44
|
+
EDSHIELD_ALLOW_DOWNLOAD=1 edshield extract essay.txt # PowerShell: $env:EDSHIELD_ALLOW_DOWNLOAD = "1"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
After that it loads from the Hugging Face cache with no network and the variable is not needed. Without the variable, models load from disk only: a directory you pass, the `local_path` in `edshield/models.jsonl`, or the cache. If you name a model (`model_name=...` or `EDSHIELD_MODEL`) and it cannot be loaded, edshield raises `ModelUnavailableError` rather than quietly doing less. If you name none and the default is not installed, the rules run alone and a `RuntimeWarning` says so; pass `model_name="rules"` to choose that on purpose.
|
|
48
|
+
|
|
49
|
+
**Recall-first decoding.** `analyze_text(..., o_threshold=0.99)` marks a token as an entity whenever P(O) < 0.99 instead of taking the most likely class. It is off by default: on held-out PIILO essays it lowered precision from 0.69 to 0.57 with recall already at 1.00.
|
|
50
|
+
|
|
51
|
+
Label schema is the seven types of the [PIILO corpus](https://the-learning-agency-lab.com/learning-exchange/piilo-dataset/) (The Learning Agency Lab, CC BY 4.0), so models trained on it drop straight in.
|
|
52
|
+
|
|
53
|
+
## Install
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install edshield # rules, policies, CLI. No torch.
|
|
57
|
+
pip install "edshield[hf]" # + PyTorch model inference
|
|
58
|
+
pip install "edshield[service]" # + REST service
|
|
59
|
+
pip install "edshield[train,onnx]" # + training and ONNX/browser export
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
From a clone, use `pip install -e ".[dev]"` instead.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
edshield redact essay.txt --policy ferpa
|
|
66
|
+
edshield extract essay.txt --model rules
|
|
67
|
+
edshield serve --port 8080 # POST /pii/extract, POST /pii/deidentify
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Demo
|
|
71
|
+
|
|
72
|
+
Live at **https://hemangnagar.github.io/edshield/**, or from a clone:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python -m http.server 8000 -d demo
|
|
76
|
+
# open http://localhost:8000
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Three synthetic samples (essay, tutoring transcript, chatbot message), three policies, and a detector switch. "Rules only" runs entirely from the page's own JavaScript, with no network. "Rules + on-device model" runs an ONNX model in the browser through Transformers.js, so the same layer works on a Chromebook with no backend. The model file (205 MB) is fetched once from the Hugging Face Hub and cached by the browser; the text is never uploaded. To run the model with no network at all, put a copy in `demo/models/piilo-deberta-v3-small-onnx` and the page uses that instead.
|
|
80
|
+
|
|
81
|
+
## Benchmarks
|
|
82
|
+
|
|
83
|
+
All numbers are span-level from `eval/evaluate.py`; F5 weights recall 5:1, as the PIILO competition did.
|
|
84
|
+
|
|
85
|
+
**Real student essays.** 680 PIILO documents held out from training of `piilo-deberta-v3-small` (DeBERTa-v3-small, 3 epochs), in the corpus's natural mix: 581 of them contain no PII at all.
|
|
86
|
+
|
|
87
|
+
| Detector | Precision | Recall | F5 | Missed entities |
|
|
88
|
+
|---|---|---|---|---|
|
|
89
|
+
| Rules only | 0.538 | 0.388 | 0.392 | 101 of 165 |
|
|
90
|
+
| Rules + model | 0.642 | 1.000 | 0.979 | 0 of 165 |
|
|
91
|
+
| Rules + INT8 model (browser) | 0.639 | 1.000 | 0.979 | 0 of 165 |
|
|
92
|
+
|
|
93
|
+
The browser file is 205 MB against 566 MB at full precision. It is measured with `eval/evaluate_onnx.py`. Quantizing every layer gives 172 MB but missed 8 of the 165 (precision 0.692, recall 0.952), so the export leaves the first two encoder layers at full precision. That setting was chosen on this same set, so the row is a little optimistic; on the synthetic K-12 hard set below, which played no part in the choice, the browser file lets 324 of 1,433 through against 319 for the full model.
|
|
94
|
+
|
|
95
|
+
| Rules + model, by label | Precision | Recall | n |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| NAME_STUDENT | 0.656 | 1.000 | 143 |
|
|
98
|
+
| URL_PERSONAL | 0.381 | 1.000 | 8 |
|
|
99
|
+
| ID_NUM | 0.700 | 1.000 | 7 |
|
|
100
|
+
| EMAIL | 1.000 | 1.000 | 4 |
|
|
101
|
+
| USERNAME | 1.000 | 1.000 | 2 |
|
|
102
|
+
| STREET_ADDRESS | 0.500 | 1.000 | 1 |
|
|
103
|
+
|
|
104
|
+
The rare labels have a handful of examples each, so their rows say little. Most name false positives are names of people other than the essay's author (personas, lecturers, friends), which PIILO does not label but which a privacy tool should remove. Reports are in `eval/results/`.
|
|
105
|
+
|
|
106
|
+
**Synthetic K-12 writing.** PIILO is adult writing, so `eval/k12_bench.py` generates short essays, tutoring transcripts and chat messages in children's registers, covering every label. "Got through" counts identifiers that no flag of any label touched.
|
|
107
|
+
|
|
108
|
+
| Set | Detector | Identifiers | Got through |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| Cued: worded the way the rules expect | Rules + model | 1,445 | 0 |
|
|
111
|
+
| Hard: the way children type | Rules + model | 1,433 | 319 (22%) |
|
|
112
|
+
| Hard | Rules only | 1,433 | 1,100 (77%) |
|
|
113
|
+
|
|
114
|
+
The hard set is the honest baseline. What gets through is mostly lowercase schools and towns, ages in chat shorthand, spoken dates and streets without a house number. [docs/COVERAGE.md](docs/COVERAGE.md) has the breakdown and maps each identifier type in FERPA and COPPA to what edshield does.
|
|
115
|
+
|
|
116
|
+
**Synthetic transcripts and essays.** Rules only, 500 documents (`eval/synthetic_bench.py --n 500 --seed 1`). The generator's sentences use the same cues the rules look for, so read this as a regression check, not as expected accuracy on real text:
|
|
117
|
+
|
|
118
|
+
| Label | Precision | Recall | F5 |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| EMAIL | 1.000 | 1.000 | 1.000 |
|
|
121
|
+
| PHONE_NUM | 1.000 | 1.000 | 1.000 |
|
|
122
|
+
| USERNAME | 1.000 | 1.000 | 1.000 |
|
|
123
|
+
| URL_PERSONAL | 1.000 | 1.000 | 1.000 |
|
|
124
|
+
| ID_NUM | 0.926 | 1.000 | 0.997 |
|
|
125
|
+
| STREET_ADDRESS | 1.000 | 0.945 | 0.947 |
|
|
126
|
+
| NAME_STUDENT | 1.000 | 0.761 | 0.768 |
|
|
127
|
+
| **overall** | **0.994** | **0.903** | **0.906** |
|
|
128
|
+
|
|
129
|
+
Names are the gap, and the reason the model layer exists: rules only catch names the writer introduces, so a friend mentioned in passing is missed.
|
|
130
|
+
|
|
131
|
+
## Train a model
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pip install kaggle
|
|
135
|
+
kaggle competitions download -c pii-detection-removal-from-educational-data
|
|
136
|
+
unzip pii-detection-removal-from-educational-data.zip -d data/piilo
|
|
137
|
+
|
|
138
|
+
python eval/synthetic_bench.py --n 2000 --out data/synthetic.json # augmentation for rare labels
|
|
139
|
+
python training/prepare_piilo.py --input data/piilo/train.json --out data/piilo_hf --extra data/synthetic.json
|
|
140
|
+
python training/train.py --data data/piilo_hf --base microsoft/deberta-v3-small --out models/piilo-deberta-v3-small --epochs 3
|
|
141
|
+
python eval/evaluate.py --input data/piilo_hf/validation.json --model models/piilo-deberta-v3-small --device cuda
|
|
142
|
+
python training/export_onnx.py --model models/piilo-deberta-v3-small --out demo/models/piilo-deberta-v3-small-onnx
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`train.py` uses the recall tricks that won the competition: down-weighted O class, a P(O) threshold instead of argmax at inference, long context with stride, synthetic augmentation. `edshield/models.jsonl` is the manifest; add a line per published model. `training/publish_hub.py` uploads a model and its card from `hub/` to the Hugging Face Hub.
|
|
146
|
+
|
|
147
|
+
## Layout
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
edshield/ runtime: rules.py, ner.py, deid.py, policies/, cli.py, service.py, models.jsonl (model manifest)
|
|
151
|
+
training/ prepare_piilo.py, train.py, export_onnx.py, publish_hub.py
|
|
152
|
+
hub/ model cards for the Hugging Face Hub
|
|
153
|
+
eval/ evaluate.py (F5 + leak count), evaluate_onnx.py, synthetic_bench.py, results/
|
|
154
|
+
demo/ single-file browser demo; a model in demo/models/ is used in place of the Hub
|
|
155
|
+
tests/ pytest
|
|
156
|
+
docs/ COVERAGE.md: what is detected, how well, and what can be claimed
|
|
157
|
+
.github/ GitHub Actions: tests on every push, the demo to GitHub Pages, releases to PyPI
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Roadmap
|
|
161
|
+
|
|
162
|
+
- [x] Rule layer with validators, name propagation, leak verifier
|
|
163
|
+
- [x] FERPA / COPPA / research policies
|
|
164
|
+
- [x] Browser demo, REST service, CLI
|
|
165
|
+
- [x] First PIILO-trained encoder (DeBERTa-v3-small) and its ONNX INT8 export published to the Hub
|
|
166
|
+
- [ ] DeBERTa-v3-base and ModernBERT-base
|
|
167
|
+
- [ ] Browser benchmark on a Chromebook
|
|
168
|
+
- [ ] Transcript models: teacher/tutor discourse moves (TalkMoves, NCTE), argumentative elements (PERSUADE)
|
|
169
|
+
- [ ] MLX backend and a Swift package
|
|
170
|
+
- [ ] MCP server and agent skills
|
|
171
|
+
|
|
172
|
+
## For research contributors
|
|
173
|
+
|
|
174
|
+
The corpus is public, the metric is defined, and the winning recipes are documented. That makes this a good place for a first applied-ML paper: fine-tune a model on PIILO, compare it with ChatGPT and Presidio on `eval/evaluate.py`, measure what leaks, and publish. Open an issue with the experiment you want to run; results that beat the current manifest entry get merged and credited in the model card.
|
|
175
|
+
|
|
176
|
+
## What this is not
|
|
177
|
+
|
|
178
|
+
Running edshield does not by itself make a product FERPA- or COPPA-compliant. It removes direct identifiers with measured recall; the institution still owns the reasonable-determination review, the consent process, and the data-handling agreement. Never paste real student data into a cloud-hosted agent to test this; use the synthetic samples.
|
|
179
|
+
|
|
180
|
+
## Credits
|
|
181
|
+
|
|
182
|
+
[The Learning Agency Lab](https://the-learning-agency-lab.com/) and Vanderbilt University for the PIILO corpus; [OpenMed](https://github.com/maziyarpanahi/openmed) for the pattern; Hugging Face `transformers` and Transformers.js; Faker.
|
|
183
|
+
|
|
184
|
+
## License
|
|
185
|
+
|
|
186
|
+
Apache-2.0. Model weights carry the license of their training data (PIILO is CC BY 4.0).
|