temsa commited on
Commit
98100d7
·
verified ·
1 Parent(s): bbebcbd

Publish rc20: faster contextual decoder, fresh holdout v14, updated benchmarks

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +0 -30
  2. .gitignore +3 -0
  3. LICENSE +73 -0
  4. NOTICE +13 -0
  5. PORTFOLIO_COMPARISON.md +81 -0
  6. README.md +193 -0
  7. common.py +2368 -0
  8. config.json +318 -0
  9. eval/benchmark_summary.json +264 -0
  10. eval/benchmark_summary.md +18 -0
  11. eval/full_diffmask_fresh_holdout_v1.json +85 -0
  12. eval/full_diffmask_gap_uat_exact_v1.json +53 -0
  13. eval/full_globalpointer_context_redteam_v1.json +109 -0
  14. eval/full_globalpointer_context_redteam_v10.json +100 -0
  15. eval/full_globalpointer_context_redteam_v11.json +100 -0
  16. eval/full_globalpointer_context_redteam_v2.json +69 -0
  17. eval/full_globalpointer_context_redteam_v3.json +77 -0
  18. eval/full_globalpointer_context_redteam_v4.json +101 -0
  19. eval/full_globalpointer_context_redteam_v5.json +100 -0
  20. eval/full_globalpointer_context_redteam_v6.json +100 -0
  21. eval/full_globalpointer_context_redteam_v7.json +100 -0
  22. eval/full_globalpointer_context_redteam_v8.json +100 -0
  23. eval/full_globalpointer_context_redteam_v9.json +100 -0
  24. eval/full_globalpointer_context_redteam_v9_exact.json +100 -0
  25. eval/full_globalpointer_demographic_patch_v2_test.json +108 -0
  26. eval/full_globalpointer_location_coverage_v1.json +61 -0
  27. eval/full_globalpointer_location_coverage_v2.json +61 -0
  28. eval/full_globalpointer_location_coverage_v3.json +61 -0
  29. eval/full_irish_core_pii_v1.json +108 -0
  30. eval/full_irish_dllm_hardening_exact_v1.json +101 -0
  31. eval/full_irish_extended_pii_v1.json +108 -0
  32. eval/full_irish_gov_chatbot_gap_holdout_v1.json +258 -0
  33. eval/full_irish_gov_chatbot_gap_holdout_v2.json +92 -0
  34. eval/full_irish_gov_chatbot_redteam_assistant_v2.json +84 -0
  35. eval/full_irish_gov_chatbot_redteam_user_v2.json +108 -0
  36. eval/full_irish_gov_chatbot_redteam_v1.json +362 -0
  37. eval/full_irish_gov_chatbot_redteam_v2.json +108 -0
  38. eval/full_irish_gov_contact_policy_v1.json +76 -0
  39. eval/full_irish_numeric_qafix_v2.json +45 -0
  40. eval/full_irish_ppsn_phone_edge_v1.json +37 -0
  41. eval/full_irish_remaining_gaps_v2.json +36 -0
  42. eval/full_multilingual_ppsn_v1_all.json +28 -0
  43. eval/full_runtime_profile_source.json +29 -0
  44. eval/label_inventory.json +20 -0
  45. eval/q8_diffmask_fresh_holdout_v1.json +85 -0
  46. eval/q8_diffmask_gap_uat_exact_v1.json +53 -0
  47. eval/q8_globalpointer_context_holdout_v12_exact.json +140 -0
  48. eval/q8_globalpointer_context_holdout_v13_exact.json +108 -0
  49. eval/q8_globalpointer_context_holdout_v14_exact.json +84 -0
  50. eval/q8_globalpointer_context_redteam_v1.json +109 -0
.gitattributes CHANGED
@@ -1,35 +1,5 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
  *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
  *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
  *.pt filter=lfs diff=lfs merge=lfs -text
23
  *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
  *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
1
  *.bin filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
2
  *.onnx filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
3
  *.pt filter=lfs diff=lfs merge=lfs -text
4
  *.pth filter=lfs diff=lfs merge=lfs -text
 
5
  *.safetensors filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .venv/
LICENSE ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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, and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
12
+
13
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
14
+
15
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
16
+
17
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
18
+
19
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
20
+
21
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
22
+
23
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
24
+
25
+ "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
26
+
27
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
28
+
29
+ 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
30
+
31
+ 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
32
+
33
+ 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
34
+
35
+ (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
36
+
37
+ (b) You must cause any modified files to carry prominent notices stating that You changed the files; and
38
+
39
+ (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
40
+
41
+ (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
42
+
43
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
44
+
45
+ 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
46
+
47
+ 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
48
+
49
+ 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
50
+
51
+ 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
52
+
53
+ 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
54
+
55
+ END OF TERMS AND CONDITIONS
56
+
57
+ APPENDIX: How to apply the Apache License to your work.
58
+
59
+ To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
60
+
61
+ Copyright [yyyy] [name of copyright owner]
62
+
63
+ Licensed under the Apache License, Version 2.0 (the "License");
64
+ you may not use this file except in compliance with the License.
65
+ You may obtain a copy of the License at
66
+
67
+ http://www.apache.org/licenses/LICENSE-2.0
68
+
69
+ Unless required by applicable law or agreed to in writing, software
70
+ distributed under the License is distributed on an "AS IS" BASIS,
71
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
72
+ See the License for the specific language governing permissions and
73
+ limitations under the License.
NOTICE ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ IrishCore-GlobalPointer-ContextPII-135M-v1-rc19
2
+
3
+ This release is derived from:
4
+ - OpenMed/OpenMed-PII-mLiteClinical-Base-135M-v1 (Apache-2.0)
5
+
6
+ Training and evaluation data used for this derivative included:
7
+ - temsa/OpenMed-Irish-CorePII-TrainMix-v1
8
+ - temsa/OpenMed-Irish-PPSN-Eircode-Spec-v1
9
+ - joelniklaus/mapa (CC-BY-4.0)
10
+ - gretelai/synthetic_pii_finance_multilingual (Apache-2.0)
11
+
12
+ Additional local synthetic hardening, UAT replay, and holdout sets were used during model selection.
13
+ Please review upstream licenses and dataset cards before redistributing derivative datasets.
PORTFOLIO_COMPARISON.md ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Portfolio Comparison
2
+
3
+ Updated: `2026-03-15`.
4
+
5
+ Use this section for the fastest public comparison across the `temsa` PII masking portfolio.
6
+
7
+ - The first core table only includes public checkpoints that ship both comparable q8 accuracy and q8 CPU throughput.
8
+ - The first PPSN table only includes public artifacts that ship comparable PPSN accuracy and CPU throughput.
9
+ - Missing cells in the archive tables mean the older release did not ship that metric in its public bundle.
10
+ - DiffMask rows use the reconciled `clean_single_pass` harness that matches the deployed runtime.
11
+ - GlobalPointer rows use the public raw-only span-matrix release bundle and its packaged q8 ONNX artifact.
12
+ - The same content is shipped as `PORTFOLIO_COMPARISON.md` inside each public model repo.
13
+
14
+ ### Irish Core PII: Comparable Public Checkpoints
15
+
16
+ | Repo | Stack | Full Core F1 | Q8 Core F1 | Q8 Multilingual PPSN F1 | Q8 Core ex/s |
17
+ |---|---|---:|---:|---:|---:|
18
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 73.1 |
19
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc18`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc18) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 126.2 |
20
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc17`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc17) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.5 |
21
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc16`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc16) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.5 |
22
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.5 |
23
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc14`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc14) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 119.2 |
24
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc13`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc13) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 126.1 |
25
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc12`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc12) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 73.6 |
26
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc11`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc11) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 94.1 |
27
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc10`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc10) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.8 |
28
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 119.8 |
29
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc8`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc8) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 128.9 |
30
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc7`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc7) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 89.0 |
31
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc6`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc6) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 89.0 |
32
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc5`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc5) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 84.5 |
33
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc4`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc4) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9333 | 61.5 |
34
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc3`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc3) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9333 | 61.5 |
35
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc2`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc2) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9222 | 61.5 |
36
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9222 | 61.5 |
37
+ | [`temsa/IrishCore-GlobalPointer-135M-v1-rc4`](https://huggingface.co/temsa/IrishCore-GlobalPointer-135M-v1-rc4) | GlobalPointer raw-only span-matrix | 1.0000 | 1.0000 | 0.9333 | 221.6 |
38
+ | [`temsa/IrishCore-GlobalPointer-135M-v1-rc3`](https://huggingface.co/temsa/IrishCore-GlobalPointer-135M-v1-rc3) | GlobalPointer raw-only span-matrix | 1.0000 | 1.0000 | 0.9213 | 204.9 |
39
+ | [`temsa/IrishCore-GlobalPointer-135M-v1-rc2`](https://huggingface.co/temsa/IrishCore-GlobalPointer-135M-v1-rc2) | GlobalPointer raw-only span-matrix | 0.9934 | 0.9934 | 0.9326 | 231.2 |
40
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc8`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc8) | Raw-only token-span | 0.9737 | 0.9737 | 0.9176 | 46.1 |
41
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc7`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc7) | Hybrid classifier + generated scanner spec | 1.0000 | 0.9934 | 1.0000 | 30.0 |
42
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc6`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc6) | Hybrid classifier + repair decoders | 1.0000 | 0.9934 | 1.0000 | 29.5 |
43
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc5`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc5) | Hybrid classifier + repair decoders | 0.9737 | 0.9669 | 0.9333 | 34.4 |
44
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc4`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc4) | Hybrid classifier + repair decoders | 0.9870 | 0.9740 | 0.9600 | 114.2 |
45
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc3`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc3) | Hybrid classifier + repair decoders | 0.9806 | 0.9677 | 0.9333 | 44.9 |
46
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc2`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc2) | Hybrid classifier + repair decoders | 0.9554 | 0.9615 | 0.7887 | 119.1 |
47
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v1`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v1) | Hybrid classifier baseline | 0.9530 | 0.9333 | 0.9882 | 103.3 |
48
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc6`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc6) | DiffMask token-span, scanner-free | 0.9801 | 0.9733 | 0.9274 | 130.3 |
49
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc5`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc5) | DiffMask token-span, scanner-free | 0.9733 | 0.9733 | 0.9379 | 249.2 |
50
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc4`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc4) | DiffMask token-span, scanner-free | 0.9733 | 0.9733 | 0.9371 | 29.5 |
51
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc3`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc3) | DiffMask token-span, scanner-free | 0.9664 | 0.9664 | 0.9591 | 30.0 |
52
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc2`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc2) | DiffMask token-span, scanner-free | 0.9664 | 0.9664 | 0.9212 | 247.1 |
53
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc1`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc1) | DiffMask token-span, scanner-free | 0.9801 | 0.9934 | 0.9412 | 251.2 |
54
+
55
+ ### Irish Core PII: Other Public Checkpoints
56
+
57
+ | Repo | Stack | Full Core F1 | Q8 Core F1 | Q8 Multilingual PPSN F1 | Notes |
58
+ |---|---|---:|---:|---:|---|
59
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc1`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc1) | Hybrid classifier prototype | 0.9487 | — | — | Predates the public q8 artifact. |
60
+
61
+ Finance-boundary q8 F1 is `1.0000` for `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc6`, `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc7`, `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc8`, and all public `IrishCore-DiffMask` releases from `rc1` to `rc6`. `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc5` ships `0.8750` on that public q8 suite.
62
+
63
+ ### PPSN-Only: Comparable Public Artifacts
64
+
65
+ | Repo | Artifact | Irish Large F1 | Multilingual PPSN F1 | User Raw F1 | QA v8 F1 | CPU ex/s |
66
+ |---|---|---:|---:|---:|---:|---:|
67
+ | [`temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1) | fp32 canonical checkpoint | 0.8979 | 0.9704 | 0.8000 | 0.7385 | 57.4 |
68
+ | [`temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-fp16`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-fp16) | fp16 CPU/GPU artifact | — | 0.9704 | 0.8000 | 0.7385 | 45.8 |
69
+ | [`temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-q8`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-q8) | dynamic int8 CPU artifact | — | 0.9040 | — | — | 132.1 |
70
+
71
+ ### PPSN-Only: Historical Public Checkpoints
72
+
73
+ | Repo | Main Published Metrics | Notes |
74
+ |---|---|---|
75
+ | [`temsa/OpenMed-PPSN-mLiteClinical-v1`](https://huggingface.co/temsa/OpenMed-PPSN-mLiteClinical-v1) | same as canonical fp32 repo: multilingual 0.9704, user raw 0.8000 | Legacy alias; prefer `temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1`. |
76
+ | [`temsa/OpenMed-PPSN-v6-raw-rc2`](https://huggingface.co/temsa/OpenMed-PPSN-v6-raw-rc2) | irish_reg_v5 0.8750; user_raw 0.8000; qa_v8 0.7385 | Raw PPSN-only research checkpoint; no packaged multilingual CPU benchmark row. |
77
+ | [`temsa/OpenMed-PPSN-v5_1`](https://huggingface.co/temsa/OpenMed-PPSN-v5_1) | irish_large_v2 raw 0.9285; qa_v6 hybrid strict 1.0000 | Hybrid PPSN-only checkpoint; predates the canonical multilingual suite packaging. |
78
+ | [`temsa/OpenMed-PPSN-v5`](https://huggingface.co/temsa/OpenMed-PPSN-v5) | irish_reg_v5 raw 0.8235; irish_reg_v5 hybrid strict 1.0000 | Hybrid PPSN-only checkpoint; predates the canonical multilingual suite packaging. |
79
+ | [`temsa/OpenMed-PPSN-v4`](https://huggingface.co/temsa/OpenMed-PPSN-v4) | synthetic non-PPSN drift check only | Predates the current PPSN eval suite; no packaged apples-to-apples multilingual CPU row. |
80
+
81
+ If you need the strongest current raw-only Irish core model, start with `IrishCore-GlobalPointer-135M-v1-rc4`. If you need the fastest CPU-first raw-only line, compare it against `IrishCore-DiffMask-135M-v1-rc6`. If you need a PPSN-only artifact, compare the canonical `fp32`, `fp16`, and `q8` variants of `OpenMed-mLiteClinical-IrishPPSN-135M-v1` directly in the table above.
README.md ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language:
3
+ - en
4
+ - ga
5
+ license: apache-2.0
6
+ pipeline_tag: token-classification
7
+ tags:
8
+ - pii-masking
9
+ - token-classification
10
+ - globalpointer
11
+ - onnx
12
+ - dynamic-quantization
13
+ - ireland
14
+ - irish
15
+ - gaelic
16
+ ---
17
+ # IrishCore-GlobalPointer-ContextPII-135M-v1-rc20
18
+
19
+ `IrishCore-GlobalPointer-ContextPII-135M-v1-rc20` is the current expanded-label raw-only PII masking release for Irish public-sector, HSE, and citizen-support flows.
20
+
21
+ It keeps the same DistilBERT-size GlobalPointer span extractor family and the same weights as `temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19`, but ships a stronger bundled decoder and a faster deployment path for contextual Irish/English address, location, name, date-of-birth, and age recovery.
22
+
23
+ Context labels served by this line:
24
+
25
+ - `STREET_ADDRESS`
26
+ - `CITY`
27
+ - `COUNTY`
28
+ - `DATE_OF_BIRTH`
29
+ - `AGE`
30
+
31
+ Core labels retained:
32
+
33
+ - `PPSN`
34
+ - `POSTCODE`
35
+ - `PHONE_NUMBER`
36
+ - `EMAIL`
37
+ - `PASSPORT_NUMBER`
38
+ - `ACCOUNT_NUMBER`
39
+ - `BANK_ROUTING_NUMBER`
40
+ - `SWIFT_BIC`
41
+ - `CREDIT_DEBIT_CARD`
42
+ - `FIRST_NAME`
43
+ - `LAST_NAME`
44
+
45
+ ## Positioning
46
+
47
+ `rc20` is a decoder/runtime hardening release over `rc19`.
48
+
49
+ - weights unchanged
50
+ - ONNX graph unchanged
51
+ - no external scanner or validator added
52
+ - deployment path still single-pass span extraction plus deterministic `[PII:LABEL]` replacement
53
+
54
+ What changed in `rc20`:
55
+
56
+ - Gaelic surname-particle last names such as `Ní Bhroin` and `Nic ...` are recovered cleanly instead of being split into stray `FIRST_NAME` fragments
57
+ - self-cued surnames such as `My name is Maeve O'Sullivan ...` are recovered even when the model only emitted the first token initially
58
+ - cue words such as `Eirchód` are no longer allowed to survive as false `FIRST_NAME` spans
59
+ - q8 CPU throughput improves materially on the aligned suites because span decoding now iterates only over above-threshold candidates and skips expensive repair passes unless the text hints they are needed
60
+ - fresh unseen contextual holdouts `v12`, `v13`, and `v14` all score `1.0000` exact F1 on the q8 deployment path
61
+
62
+ If you only need the narrower Irish-core structured label set and want maximum CPU throughput, `temsa/IrishCore-GlobalPointer-135M-v1-rc4` remains the faster option.
63
+
64
+ ## Benchmarks
65
+
66
+ ### ONNX q8
67
+
68
+ | Suite | F1 | Examples/s |
69
+ | --- | ---: | ---: |
70
+ | Irish core | 1.0000 | 181.8821 |
71
+ | Irish extended | 1.0000 | 78.7748 |
72
+ | Gov contact policy v1 | 1.0000 | 150.6650 |
73
+ | Gov chatbot red-team v2 | 0.9861 | 117.0016 |
74
+ | Gov chatbot gap holdout v2 | 1.0000 | 118.2173 |
75
+ | Context red-team v11 exact | 1.0000 | 211.5424 |
76
+ | Context holdout v12 exact | 1.0000 | 77.6876 |
77
+ | Context holdout v13 exact | 1.0000 | 116.3190 |
78
+ | Context holdout v14 exact | 1.0000 | 126.5529 |
79
+ | Multilingual PPSN overall | 0.9333 | 155.2108 |
80
+ | Multilingual PPSN label-only | 1.0000 | — |
81
+
82
+ ### Comparison
83
+
84
+ | Model | Irish core q8 F1 | Gov chatbot gap holdout v2 q8 F1 | Context holdout v14 exact q8 F1 | Q8 core examples/s |
85
+ | --- | ---: | ---: | ---: | ---: |
86
+ | ContextPII rc20 q8 | 1.0000 | 1.0000 | 1.0000 | 181.8821 |
87
+ | ContextPII rc19 q8 | 1.0000 | 1.0000 | — | 73.0554 |
88
+ | ContextPII rc18 q8 | 1.0000 | 1.0000 | — | 111.3135 |
89
+ | GlobalPointer core rc4 q8 | 1.0000 | 1.0000 | — | 221.5743 |
90
+
91
+ ## Evaluation Notes
92
+
93
+ Additional q8 release checks shipped in this repo:
94
+
95
+ - `eval/q8_globalpointer_context_redteam_v11_exact.json`: legacy exact-boundary contextual regression suite, now `1.0000`
96
+ - `eval/q8_globalpointer_context_holdout_v12_exact.json`: fresh unseen holdout for prefixed Irish/English address recovery, now `1.0000`
97
+ - `eval/q8_globalpointer_context_holdout_v13_exact.json`: fresh unseen holdout for house-name and city/county field recovery, now `1.0000`
98
+ - `eval/q8_globalpointer_context_holdout_v14_exact.json`: fresh unseen holdout for Gaelic surname-particle names, apostrophe surnames after self-cues, and mixed structured/contextual packets, now `1.0000`
99
+ - `eval/q8_irish_gov_chatbot_gap_holdout_v2.json`: legacy chatbot gap suite, now `1.0000`
100
+
101
+ Known tradeoff:
102
+
103
+ - `eval/q8_irish_gov_chatbot_redteam_v2.json` remains `0.9861` because this broader contextual release masks public-office street/city details in assistant text, while that older suite only labels postcode and phone there.
104
+
105
+ ## Usage
106
+
107
+ ```bash
108
+ python3 inference_mask_onnx.py --model temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc20 --text "My name is Maeve O'Sullivan, my PPSN is 1234567T, and my address is Árasán 4, Cedar Court, mBaile Átha Cliath, D08 XY12."
109
+ ```
110
+
111
+ <!-- portfolio-comparison:start -->
112
+ ## Portfolio Comparison
113
+
114
+ Updated: `2026-03-15`.
115
+
116
+ Use this section for the fastest public comparison across the `temsa` PII masking portfolio.
117
+
118
+ - The first core table only includes public checkpoints that ship both comparable q8 accuracy and q8 CPU throughput.
119
+ - The first PPSN table only includes public artifacts that ship comparable PPSN accuracy and CPU throughput.
120
+ - Missing cells in the archive tables mean the older release did not ship that metric in its public bundle.
121
+ - DiffMask rows use the reconciled `clean_single_pass` harness that matches the deployed runtime.
122
+ - GlobalPointer rows use the public raw-only span-matrix release bundle and its packaged q8 ONNX artifact.
123
+ - The same content is shipped as `PORTFOLIO_COMPARISON.md` inside each public model repo.
124
+
125
+ ### Irish Core PII: Comparable Public Checkpoints
126
+
127
+ | Repo | Stack | Full Core F1 | Q8 Core F1 | Q8 Multilingual PPSN F1 | Q8 Core ex/s |
128
+ |---|---|---:|---:|---:|---:|
129
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 73.1 |
130
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc18`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc18) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 126.2 |
131
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc17`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc17) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.5 |
132
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc16`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc16) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.5 |
133
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.5 |
134
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc14`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc14) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 119.2 |
135
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc13`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc13) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 126.1 |
136
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc12`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc12) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 73.6 |
137
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc11`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc11) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 94.1 |
138
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc10`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc10) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 125.8 |
139
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 119.8 |
140
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc8`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc8) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 128.9 |
141
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc7`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc7) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 89.0 |
142
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc6`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc6) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 89.0 |
143
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc5`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc5) | GlobalPointer raw-only + context labels | 1.0000 | 1.0000 | 0.9333 | 84.5 |
144
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc4`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc4) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9333 | 61.5 |
145
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc3`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc3) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9333 | 61.5 |
146
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc2`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc2) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9222 | 61.5 |
147
+ | [`temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1`](https://huggingface.co/temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1) | GlobalPointer raw-only + context labels | 0.9935 | 0.9935 | 0.9222 | 61.5 |
148
+ | [`temsa/IrishCore-GlobalPointer-135M-v1-rc4`](https://huggingface.co/temsa/IrishCore-GlobalPointer-135M-v1-rc4) | GlobalPointer raw-only span-matrix | 1.0000 | 1.0000 | 0.9333 | 221.6 |
149
+ | [`temsa/IrishCore-GlobalPointer-135M-v1-rc3`](https://huggingface.co/temsa/IrishCore-GlobalPointer-135M-v1-rc3) | GlobalPointer raw-only span-matrix | 1.0000 | 1.0000 | 0.9213 | 204.9 |
150
+ | [`temsa/IrishCore-GlobalPointer-135M-v1-rc2`](https://huggingface.co/temsa/IrishCore-GlobalPointer-135M-v1-rc2) | GlobalPointer raw-only span-matrix | 0.9934 | 0.9934 | 0.9326 | 231.2 |
151
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc8`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc8) | Raw-only token-span | 0.9737 | 0.9737 | 0.9176 | 46.1 |
152
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc7`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc7) | Hybrid classifier + generated scanner spec | 1.0000 | 0.9934 | 1.0000 | 30.0 |
153
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc6`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc6) | Hybrid classifier + repair decoders | 1.0000 | 0.9934 | 1.0000 | 29.5 |
154
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc5`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc5) | Hybrid classifier + repair decoders | 0.9737 | 0.9669 | 0.9333 | 34.4 |
155
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc4`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc4) | Hybrid classifier + repair decoders | 0.9870 | 0.9740 | 0.9600 | 114.2 |
156
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc3`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc3) | Hybrid classifier + repair decoders | 0.9806 | 0.9677 | 0.9333 | 44.9 |
157
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc2`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc2) | Hybrid classifier + repair decoders | 0.9554 | 0.9615 | 0.7887 | 119.1 |
158
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v1`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v1) | Hybrid classifier baseline | 0.9530 | 0.9333 | 0.9882 | 103.3 |
159
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc6`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc6) | DiffMask token-span, scanner-free | 0.9801 | 0.9733 | 0.9274 | 130.3 |
160
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc5`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc5) | DiffMask token-span, scanner-free | 0.9733 | 0.9733 | 0.9379 | 249.2 |
161
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc4`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc4) | DiffMask token-span, scanner-free | 0.9733 | 0.9733 | 0.9371 | 29.5 |
162
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc3`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc3) | DiffMask token-span, scanner-free | 0.9664 | 0.9664 | 0.9591 | 30.0 |
163
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc2`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc2) | DiffMask token-span, scanner-free | 0.9664 | 0.9664 | 0.9212 | 247.1 |
164
+ | [`temsa/IrishCore-DiffMask-135M-v1-rc1`](https://huggingface.co/temsa/IrishCore-DiffMask-135M-v1-rc1) | DiffMask token-span, scanner-free | 0.9801 | 0.9934 | 0.9412 | 251.2 |
165
+
166
+ ### Irish Core PII: Other Public Checkpoints
167
+
168
+ | Repo | Stack | Full Core F1 | Q8 Core F1 | Q8 Multilingual PPSN F1 | Notes |
169
+ |---|---|---:|---:|---:|---|
170
+ | [`temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc1`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc1) | Hybrid classifier prototype | 0.9487 | — | — | Predates the public q8 artifact. |
171
+
172
+ Finance-boundary q8 F1 is `1.0000` for `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc6`, `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc7`, `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc8`, and all public `IrishCore-DiffMask` releases from `rc1` to `rc6`. `OpenMed-mLiteClinical-IrishCorePII-135M-v2-rc5` ships `0.8750` on that public q8 suite.
173
+
174
+ ### PPSN-Only: Comparable Public Artifacts
175
+
176
+ | Repo | Artifact | Irish Large F1 | Multilingual PPSN F1 | User Raw F1 | QA v8 F1 | CPU ex/s |
177
+ |---|---|---:|---:|---:|---:|---:|
178
+ | [`temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1) | fp32 canonical checkpoint | 0.8979 | 0.9704 | 0.8000 | 0.7385 | 57.4 |
179
+ | [`temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-fp16`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-fp16) | fp16 CPU/GPU artifact | — | 0.9704 | 0.8000 | 0.7385 | 45.8 |
180
+ | [`temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-q8`](https://huggingface.co/temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1-q8) | dynamic int8 CPU artifact | — | 0.9040 | — | — | 132.1 |
181
+
182
+ ### PPSN-Only: Historical Public Checkpoints
183
+
184
+ | Repo | Main Published Metrics | Notes |
185
+ |---|---|---|
186
+ | [`temsa/OpenMed-PPSN-mLiteClinical-v1`](https://huggingface.co/temsa/OpenMed-PPSN-mLiteClinical-v1) | same as canonical fp32 repo: multilingual 0.9704, user raw 0.8000 | Legacy alias; prefer `temsa/OpenMed-mLiteClinical-IrishPPSN-135M-v1`. |
187
+ | [`temsa/OpenMed-PPSN-v6-raw-rc2`](https://huggingface.co/temsa/OpenMed-PPSN-v6-raw-rc2) | irish_reg_v5 0.8750; user_raw 0.8000; qa_v8 0.7385 | Raw PPSN-only research checkpoint; no packaged multilingual CPU benchmark row. |
188
+ | [`temsa/OpenMed-PPSN-v5_1`](https://huggingface.co/temsa/OpenMed-PPSN-v5_1) | irish_large_v2 raw 0.9285; qa_v6 hybrid strict 1.0000 | Hybrid PPSN-only checkpoint; predates the canonical multilingual suite packaging. |
189
+ | [`temsa/OpenMed-PPSN-v5`](https://huggingface.co/temsa/OpenMed-PPSN-v5) | irish_reg_v5 raw 0.8235; irish_reg_v5 hybrid strict 1.0000 | Hybrid PPSN-only checkpoint; predates the canonical multilingual suite packaging. |
190
+ | [`temsa/OpenMed-PPSN-v4`](https://huggingface.co/temsa/OpenMed-PPSN-v4) | synthetic non-PPSN drift check only | Predates the current PPSN eval suite; no packaged apples-to-apples multilingual CPU row. |
191
+
192
+ If you need the strongest current raw-only Irish core model, start with `IrishCore-GlobalPointer-135M-v1-rc4`. If you need the fastest CPU-first raw-only line, compare it against `IrishCore-DiffMask-135M-v1-rc6`. If you need a PPSN-only artifact, compare the canonical `fp32`, `fp16`, and `q8` variants of `OpenMed-mLiteClinical-IrishPPSN-135M-v1` directly in the table above.
193
+ <!-- portfolio-comparison:end -->
common.py ADDED
@@ -0,0 +1,2368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import math
5
+ import re
6
+ from pathlib import Path
7
+ import sys
8
+ from typing import Any
9
+ import unicodedata
10
+
11
+ import numpy as np
12
+
13
+ ROOT_DIR = Path(__file__).resolve().parents[2]
14
+ if str(ROOT_DIR) not in sys.path:
15
+ sys.path.insert(0, str(ROOT_DIR))
16
+
17
+ try:
18
+ from ..irish_core_span_raw_only.common import (
19
+ dedupe_spans,
20
+ label_max_span_tokens_from_config,
21
+ label_min_nonspace_chars_from_config,
22
+ label_names_from_config,
23
+ load_onnx_session,
24
+ normalize_entity_name,
25
+ safe_auto_tokenizer,
26
+ )
27
+ except ImportError:
28
+ from experiments.irish_core_span_raw_only.common import (
29
+ dedupe_spans,
30
+ label_max_span_tokens_from_config,
31
+ label_min_nonspace_chars_from_config,
32
+ label_names_from_config,
33
+ load_onnx_session,
34
+ normalize_entity_name,
35
+ safe_auto_tokenizer,
36
+ )
37
+
38
+
39
+ def label_thresholds_from_config(config, default_threshold: float) -> dict[str, float]:
40
+ raw = getattr(config, "span_label_thresholds", None) or {}
41
+ out = {normalize_entity_name(key): float(value) for key, value in raw.items()}
42
+ for label in label_names_from_config(config):
43
+ out.setdefault(label, float(default_threshold))
44
+ return out
45
+
46
+
47
+ def valid_offset(offset: tuple[int, int]) -> bool:
48
+ return bool(offset) and int(offset[1]) > int(offset[0])
49
+
50
+
51
+ def nonspace_length(text: str, start: int, end: int) -> int:
52
+ return sum(0 if ch.isspace() else 1 for ch in text[int(start) : int(end)])
53
+
54
+
55
+ def alnum_upper(text: str) -> str:
56
+ return "".join(ch for ch in text.upper() if ch.isalnum())
57
+
58
+
59
+ def normalize_surface(text: str) -> str:
60
+ value = unicodedata.normalize("NFKD", text)
61
+ value = "".join(ch for ch in value if not unicodedata.combining(ch))
62
+ value = value.replace("\u00A0", " ").replace("\u202F", " ")
63
+ value = re.sub(r"\s+", " ", value.strip().lower())
64
+ return value
65
+
66
+
67
+ IRISH_CITY_FORMS = (
68
+ "Dublin",
69
+ "Baile Átha Cliath",
70
+ "mBaile Átha Cliath",
71
+ "mBaile Atha Cliath",
72
+ "Galway",
73
+ "Gaillimh",
74
+ "Cork",
75
+ "Cork City",
76
+ "Corcaigh",
77
+ "Limerick",
78
+ "Luimneach",
79
+ "Waterford",
80
+ "Port Láirge",
81
+ "Kilkenny",
82
+ "Cill Chainnigh",
83
+ "Carlow",
84
+ "Ceatharlach",
85
+ "Sligo",
86
+ "Sligeach",
87
+ "Tralee",
88
+ "Trá Lí",
89
+ "Ennis",
90
+ "Inis",
91
+ "Letterkenny",
92
+ "Leitir Ceanainn",
93
+ "Castlebar",
94
+ "Caisleán an Bharraigh",
95
+ "Caislean an Bharraigh",
96
+ "gCaisleán an Bharraigh",
97
+ "gCaislean an Bharraigh",
98
+ "Wexford",
99
+ "Loch Garman",
100
+ "Navan",
101
+ "Uaimh",
102
+ "An Uaimh",
103
+ "hUaimh",
104
+ "nUaimh",
105
+ "Dundalk",
106
+ "Dún Dealgan",
107
+ "Dun Dealgan",
108
+ "Mullingar",
109
+ "Muileann gCearr",
110
+ "An Muileann gCearr",
111
+ "Tullamore",
112
+ "Tulach Mhór",
113
+ "Tulach Mhor",
114
+ "dTulach Mhór",
115
+ "dTulach Mhor",
116
+ "Portlaoise",
117
+ "Port Laoise",
118
+ "bPort Laoise",
119
+ "Bray",
120
+ "Bré",
121
+ "Bre",
122
+ "mBré",
123
+ "mBre",
124
+ "Athlone",
125
+ "Baile Átha Luain",
126
+ "Baile Atha Luain",
127
+ "mBaile Átha Luain",
128
+ "mBaile Atha Luain",
129
+ )
130
+ IRISH_CITY_SURFACES = {normalize_surface(value) for value in IRISH_CITY_FORMS}
131
+
132
+ IRISH_COUNTY_FORMS = (
133
+ "Co. Dublin",
134
+ "County Dublin",
135
+ "Co. Bhaile Átha Cliath",
136
+ "Contae Bhaile Átha Cliath",
137
+ "gContae Bhaile Átha Cliath",
138
+ "Co. Galway",
139
+ "County Galway",
140
+ "Co. na Gaillimhe",
141
+ "Contae na Gaillimhe",
142
+ "gContae na Gaillimhe",
143
+ "Co. Cork",
144
+ "County Cork",
145
+ "Co. Chorcaí",
146
+ "Contae Chorcaí",
147
+ "gContae Chorcaí",
148
+ "Co. Limerick",
149
+ "County Limerick",
150
+ "Co. Luimnigh",
151
+ "Contae Luimnigh",
152
+ "gContae Luimnigh",
153
+ "Co. Waterford",
154
+ "County Waterford",
155
+ "Co. Phort Láirge",
156
+ "Contae Phort Láirge",
157
+ "gContae Phort Láirge",
158
+ "Co. Kilkenny",
159
+ "County Kilkenny",
160
+ "Co. Chill Chainnigh",
161
+ "Contae Chill Chainnigh",
162
+ "gContae Chill Chainnigh",
163
+ "Co. Carlow",
164
+ "County Carlow",
165
+ "Co. Cheatharlach",
166
+ "Contae Cheatharlach",
167
+ "gContae Cheatharlach",
168
+ "Co. Sligo",
169
+ "County Sligo",
170
+ "Co. Shligigh",
171
+ "Contae Shligigh",
172
+ "gContae Shligigh",
173
+ "Co. Kerry",
174
+ "County Kerry",
175
+ "Co. Chiarraí",
176
+ "Contae Chiarraí",
177
+ "gContae Chiarraí",
178
+ "Co. Clare",
179
+ "County Clare",
180
+ "Co. an Chláir",
181
+ "Contae an Chláir",
182
+ "gContae an Chláir",
183
+ "Co. Donegal",
184
+ "County Donegal",
185
+ "Co. Dhún na nGall",
186
+ "Co. Dhun na nGall",
187
+ "Contae Dhún na nGall",
188
+ "Contae Dhun na nGall",
189
+ "gContae Dhún na nGall",
190
+ "gContae Dhun na nGall",
191
+ "Co. Mayo",
192
+ "County Mayo",
193
+ "Co. Mhaigh Eo",
194
+ "Contae Mhaigh Eo",
195
+ "gContae Mhaigh Eo",
196
+ "Co. Wexford",
197
+ "County Wexford",
198
+ "Co. Loch Garman",
199
+ "Contae Loch Garman",
200
+ "gContae Loch Garman",
201
+ "Co. Meath",
202
+ "County Meath",
203
+ "Co. na Mí",
204
+ "Co. na Mi",
205
+ "Contae na Mí",
206
+ "Contae na Mi",
207
+ "gContae na Mí",
208
+ "gContae na Mi",
209
+ "Co. Louth",
210
+ "County Louth",
211
+ "Co. Lú",
212
+ "Co. Lu",
213
+ "Contae Lú",
214
+ "Contae Lu",
215
+ "gContae Lú",
216
+ "gContae Lu",
217
+ "Co. Westmeath",
218
+ "County Westmeath",
219
+ "Co. na hIarmhí",
220
+ "Co. na hIarmhi",
221
+ "Contae na hIarmhí",
222
+ "Contae na hIarmhi",
223
+ "gContae na hIarmhí",
224
+ "gContae na hIarmhi",
225
+ "Co. Offaly",
226
+ "County Offaly",
227
+ "Co. Uíbh Fhailí",
228
+ "Co. Uibh Fhaili",
229
+ "Contae Uíbh Fhailí",
230
+ "Contae Uibh Fhaili",
231
+ "gContae Uíbh Fhailí",
232
+ "gContae Uibh Fhaili",
233
+ "Co. Laois",
234
+ "County Laois",
235
+ "Contae Laoise",
236
+ "gContae Laoise",
237
+ "Co. Wicklow",
238
+ "County Wicklow",
239
+ "Co. Chill Mhantáin",
240
+ "Co. Chill Mhantain",
241
+ "Contae Chill Mhantáin",
242
+ "Contae Chill Mhantain",
243
+ "gContae Chill Mhantáin",
244
+ "gContae Chill Mhantain",
245
+ )
246
+ IRISH_COUNTY_SURFACES = {normalize_surface(value) for value in IRISH_COUNTY_FORMS}
247
+ IRISH_CITY_PREFIX_CHARS = {"n", "g", "m", "b", "d", "h"}
248
+
249
+ STREET_SUFFIX_RE = re.compile(
250
+ r"(?i)\b(street|road|avenue|lane|park|view|square|terrace|drive|close|way|place|crescent|grove|green|court|manor|mews|gardens?|heights|quay|bóthar|bothar|sráid|sraid|lána|lana)\b"
251
+ )
252
+ BUILDING_SUFFIX_RE = re.compile(
253
+ r"(?i)\b(house|cottage|lodge|villa|apartments?|building|business\s+centre|community\s+centre|shopping\s+centre|retail\s+park|Teach(?:ín|in)?)\b"
254
+ )
255
+ PHONE_SURFACE_RE = re.compile(r"^[+().\d][+().\d \-/\u00A0\u202F]*\d$")
256
+ ACCOUNT_DIGIT_SURFACE_RE = re.compile(r"^[\d \-\u00A0\u202F]+$")
257
+ MONTH_NAME_RE = (
258
+ r"(?:January|February|March|April|May|June|July|August|September|October|November|December|"
259
+ r"Eanáir|Eanair|Feabhra|Márta|Marta|Aibreán|Aibrean|Bealtaine|Meitheamh|Iúil|Iuil|Lúnasa|Lunasa|"
260
+ r"Meán\s+Fómhair|Mean\s+Fomhair|Deireadh\s+Fómhair|Deireadh\s+Fomhair|Samhain|Nollaig)"
261
+ )
262
+ DATE_OF_BIRTH_RE = re.compile(
263
+ rf"(?i)^(?:\d{{1,2}}[./-]\d{{1,2}}[./-]\d{{2,4}}|\d{{4}}-\d{{2}}-\d{{2}}|(?:an\s+)?\d{{1,2}}(?:st|nd|rd|th|ú)?\s+{MONTH_NAME_RE}[,]?\s+\d{{2,4}}|{MONTH_NAME_RE}\s+\d{{1,2}},?\s+\d{{2,4}})$"
264
+ )
265
+ DATE_OF_BIRTH_VALUE_RE = re.compile(
266
+ rf"(?<![A-Za-z0-9])(\d{{1,2}}[./-]\d{{1,2}}[./-]\d{{2,4}}|\d{{4}}-\d{{2}}-\d{{2}}|(?:an\s+)?\d{{1,2}}(?:st|nd|rd|th|ú)?\s+{MONTH_NAME_RE}[,]?\s+\d{{2,4}}|{MONTH_NAME_RE}\s+\d{{1,2}},?\s+\d{{2,4}})(?![A-Za-z0-9])"
267
+ )
268
+ AGE_CONTEXT_RE = re.compile(r"(?i)\b(age|aged|years?\s+old|year\s+old|year-old|yrs?\s+old|y/?o|yo|aois|bliana\s+d['’]aois|mbliana\s+d['’]aois)\b")
269
+ AGE_INLINE_SUFFIX_RE = re.compile(r"(?i)^(?:-year-old\b|yo\b|y/o\b|yrs?\b)")
270
+ AGE_VALUE_RE = re.compile(r"(?<![A-Za-z0-9])(\d{1,3})(?![A-Za-z0-9])")
271
+ AGE_SELF_PREFIX_RE = re.compile(r"(?i)(?:^|.*\b)(?:i\s+am|i['’]?m|im|t[áa]\s+m[ée]|t[áa]im)\s*$")
272
+ DOB_CONTEXT_RE = re.compile(
273
+ r"(?i)\b(dob|date\s+of\s+birth|born(?:\s+on)?|data\s+breithe|dáta\s+breithe|dhata\s+breithe|dháta\s+breithe|rugadh)\b"
274
+ )
275
+ ADDRESS_FIELD_CUE_PATTERN = r"(?:address(?:\s+line\s+\d+)?(?:\s+is)?|my\s+address\s+is|seoladh(?:\s+l[ií]nte?\s+\d+)?|is\s+[ée]\s+mo\s+sheoladh)"
276
+ ADDRESS_LINE_CUE_RE = re.compile(r"(?i)\b(?:address\s+line\s+\d+|seoladh\s+l[ií]nte?\s+\d+)\b")
277
+ ADDRESS_CUE_RE = re.compile(
278
+ rf"(?i)\b({ADDRESS_FIELD_CUE_PATTERN}|sheoladh|allocation\s+centre|intreo\s+centre|ionad\s+leithdh[aá]ilte|ionad\s+intreo|live\s+at|lives\s+at|living\s+at|located\s+at|i\s+mo\s+ch[oó]na[ií]\s+ag|t[áa]\s+m[ée]\s+i\s+mo\s+ch[oó]na[ií]\s+ag|t[áa]im\s+i\s+mo\s+ch[oó]na[ií]\s+ag|cónai\s+ag|chónai\s+ag|conai\s+ag|chonai\s+ag)\b"
279
+ )
280
+ CITY_COUNTY_PREFIX_RE = re.compile(r"(?i)(?:county|co\.|contae|gcontae)(?:\s+na)?\s*$")
281
+ PPSN_CUE_RE = re.compile(
282
+ r"(?i)\b(ppsn|upsp|personal public service(?:\s+number)?|uimhir\s+(?:mo\s+)?upsp|uimhir\s+(?:mo\s+)?ppsn)\b"
283
+ )
284
+ NAME_STOP_SURFACES = {
285
+ normalize_surface(value)
286
+ for value in {
287
+ "Address",
288
+ "Name",
289
+ "Phone",
290
+ "Email",
291
+ "Seoladh",
292
+ "Ainm",
293
+ "Teagmháil",
294
+ "Teagmhail",
295
+ "Ríomhphost",
296
+ "Riomhphost",
297
+ "Eirchód",
298
+ "Eirchod",
299
+ "Eircode",
300
+ "PPSN",
301
+ "UPSP",
302
+ "Call",
303
+ "Glao",
304
+ "Glaoigh",
305
+ "Rugadh",
306
+ "Ionad",
307
+ "Intreo",
308
+ "Cill",
309
+ "Sampla",
310
+ "Leithdháilte",
311
+ "Leithdhailte",
312
+ "Leithdháil",
313
+ "Leithdhail",
314
+ "Leithdh",
315
+ "Apartment",
316
+ "Flat",
317
+ "Unit",
318
+ "Suite",
319
+ "Árasán",
320
+ "Arasan",
321
+ "Aonad",
322
+ "County",
323
+ "Contae",
324
+ "Fón",
325
+ "Fon",
326
+ "January",
327
+ "February",
328
+ "March",
329
+ "April",
330
+ "May",
331
+ "June",
332
+ "July",
333
+ "August",
334
+ "September",
335
+ "October",
336
+ "November",
337
+ "December",
338
+ "Monday",
339
+ "Tuesday",
340
+ "Wednesday",
341
+ "Thursday",
342
+ "Friday",
343
+ "Saturday",
344
+ "Sunday",
345
+ "Eanáir",
346
+ "Feabhra",
347
+ "Márta",
348
+ "Aibreán",
349
+ "Aibrean",
350
+ "Bealtaine",
351
+ "Meitheamh",
352
+ "Iúil",
353
+ "Iuil",
354
+ "Lúnasa",
355
+ "Lunasa",
356
+ "Meán Fómhair",
357
+ "Mean Fomhair",
358
+ "Deireadh Fómhair",
359
+ "Deireadh Fomhair",
360
+ "Samhain",
361
+ "Nollaig",
362
+ "Luan",
363
+ "Máirt",
364
+ "Mairt",
365
+ "Céadaoin",
366
+ "Ceadaoin",
367
+ "Déardaoin",
368
+ "Deardaoin",
369
+ "Aoine",
370
+ "Satharn",
371
+ "Domhnach",
372
+ }
373
+ }
374
+ NAME_PARTICLE_SURFACES = {
375
+ normalize_surface(value)
376
+ for value in {"Ó", "O", "Ní", "Ni", "Nic", "Mac", "Mc", "de", "van", "von"}
377
+ }
378
+ STREET_TRAILING_BLOCK_SURFACES = {
379
+ normalize_surface(value)
380
+ for value in {
381
+ "are",
382
+ "public",
383
+ "contact",
384
+ "details",
385
+ "website",
386
+ "open",
387
+ "before",
388
+ "visiting",
389
+ "roimh",
390
+ "chuairt",
391
+ "agus",
392
+ "and",
393
+ "the",
394
+ "is",
395
+ "ta",
396
+ }
397
+ }
398
+ ADDRESS_UNIT_PREFIX_RE = re.compile(r"(?i)^(?:apartment|apt\.?|flat|unit|suite|[AaÁá]ras[aá]n|aonad)\b")
399
+ HOUSE_NAME_PREFIX_RE = re.compile(
400
+ r"(?i)^(?:[A-ZÁÉÍÓÚ][\w'’.-]+(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]+){0,2}\s+(?:house|cottage|lodge|villa)|teach(?:ín|in)?(?:\s+na\s+[A-ZÁÉÍÓÚ][\w'’.-]+)?)$"
401
+ )
402
+ STREET_ADDRESS_VALUE_RE = re.compile(
403
+ r"(?i)(?<![\w@])("
404
+ r"(?:(?:apartment|apt\.?|flat|unit|suite|[AaÁá]ras[aá]n|aonad)\s+[A-Za-z0-9-]+,\s+)?"
405
+ r"(?:(?:[A-ZÁÉÍÓÚ][\w'’.-]+(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]+){0,2}\s+(?:house|cottage|lodge|villa)|teach(?:ín|in)?(?:\s+na\s+[A-ZÁÉÍÓÚ][\w'’.-]+)?),\s+)?"
406
+ r"(?:\d{1,4}\s+)?(?:[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*\s+){0,5}(?:street|road|avenue|lane|park|view|square|terrace|drive|close|way|place|crescent|grove|green|court|manor|mews|gardens?|heights|quay|bóthar|bothar|sráid|sraid|lána|lana)(?:\s+[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*){0,2}"
407
+ r")"
408
+ )
409
+
410
+
411
+ def is_plausible_last_name_sequence(value: str) -> bool:
412
+ tokens = [token for token in re.split(r"\s+", value.strip()) if token]
413
+ if not tokens:
414
+ return False
415
+ for token in tokens:
416
+ if not any(ch.isalpha() for ch in token):
417
+ return False
418
+ if not all(is_name_token_char(ch) for ch in token):
419
+ return False
420
+ alpha_chars = [ch for ch in token if ch.isalpha()]
421
+ first_alpha = alpha_chars[0] if alpha_chars else ""
422
+ if first_alpha.isupper():
423
+ continue
424
+ if len(alpha_chars) >= 2 and alpha_chars[0].islower() and alpha_chars[1].isupper():
425
+ continue
426
+ if normalize_surface(token) in NAME_PARTICLE_SURFACES:
427
+ continue
428
+ return False
429
+ return True
430
+
431
+
432
+ def is_reasonable_span_text(label: str, text: str, start: int, end: int) -> bool:
433
+ value = text[int(start) : int(end)].strip()
434
+ if not value:
435
+ return False
436
+ upper = alnum_upper(value)
437
+
438
+ if label in {"FIRST_NAME", "LAST_NAME"}:
439
+ if not any(ch.isalpha() for ch in value):
440
+ return False
441
+ if any(ch.isdigit() for ch in value):
442
+ return False
443
+ if int(start) > 0 and text[int(start) - 1].isalpha():
444
+ return False
445
+ if int(end) < len(text) and text[int(end)].isalpha():
446
+ return False
447
+ if normalize_surface(value) in NAME_STOP_SURFACES:
448
+ return False
449
+ if label == "FIRST_NAME" and any(ch.isspace() for ch in value):
450
+ return False
451
+ if any(ch in ".,;:/@()" for ch in value):
452
+ return False
453
+ if label == "FIRST_NAME":
454
+ first_alpha = next((ch for ch in value if ch.isalpha()), "")
455
+ if not first_alpha or not first_alpha.isupper():
456
+ return False
457
+ if label == "LAST_NAME" and not is_plausible_last_name_sequence(value):
458
+ return False
459
+ if start > 0 and text[int(start) - 1].isdigit():
460
+ return False
461
+ return True
462
+
463
+ if label == "EMAIL":
464
+ if "@" not in value:
465
+ return False
466
+ local, _, domain = value.partition("@")
467
+ return bool(local) and "." in domain
468
+
469
+ if label == "PHONE_NUMBER":
470
+ normalized = value.replace("\u00A0", " ").replace("\u202F", " ").strip()
471
+ if any(ch.isalpha() for ch in normalized):
472
+ return False
473
+ if "@" in normalized:
474
+ return False
475
+ if int(start) > 0 and text[int(start) - 1].isalnum():
476
+ return False
477
+ if int(end) < len(text) and text[int(end)].isalnum():
478
+ return False
479
+ if not PHONE_SURFACE_RE.match(normalized):
480
+ return False
481
+ digits = "".join(ch for ch in value if ch.isdigit())
482
+ if normalized.startswith("+353"):
483
+ tail = digits[3:]
484
+ if tail.startswith("0"):
485
+ tail = tail[1:]
486
+ return 8 <= len(tail) <= 9
487
+ if not digits.startswith("0"):
488
+ return False
489
+ if digits.startswith("0818") or digits.startswith("1800"):
490
+ return len(digits) == 10
491
+ if digits.startswith("08"):
492
+ return len(digits) == 10
493
+ if digits.startswith("01"):
494
+ return len(digits) == 9
495
+ return 9 <= len(digits) <= 10
496
+
497
+ if label == "PPSN":
498
+ return bool(len(upper) in {8, 9} and upper[:7].isdigit() and upper[7:].isalpha())
499
+
500
+ if label == "POSTCODE":
501
+ compact = value.replace(" ", "").replace("\u00A0", "").replace("\u202F", "")
502
+ if any(not (ch.isalnum() or ch.isspace()) for ch in value):
503
+ return False
504
+ if len(compact) != 7:
505
+ return False
506
+ routing = compact[:3]
507
+ unique = compact[3:]
508
+ routing_ok = bool(
509
+ (routing[0].isalpha() and routing[1:].isdigit())
510
+ or routing == "D6W"
511
+ )
512
+ unique_ok = bool(
513
+ len(unique) == 4
514
+ and unique[0].isalpha()
515
+ and unique[1:].isalnum()
516
+ )
517
+ return routing_ok and unique_ok
518
+
519
+ if label == "PASSPORT_NUMBER":
520
+ return bool(re.fullmatch(r"[A-Z]{1,2}\s?\d{7}", value.strip()))
521
+
522
+ if label == "BANK_ROUTING_NUMBER":
523
+ digits = "".join(ch for ch in value if ch.isdigit())
524
+ if len(digits) != 6:
525
+ return False
526
+ context = text[max(0, int(start) - 32) : min(len(text), int(end) + 24)]
527
+ return bool(BANK_ROUTING_CONTEXT_RE.search(context))
528
+
529
+ if label == "SWIFT_BIC":
530
+ return len(upper) in {8, 11} and upper.isalnum()
531
+
532
+ if label == "CREDIT_DEBIT_CARD":
533
+ digits = "".join(ch for ch in value if ch.isdigit())
534
+ return 12 <= len(digits) <= 19
535
+
536
+ if label == "ACCOUNT_NUMBER":
537
+ if upper.startswith("IE"):
538
+ return bool(re.fullmatch(r"IE\d{2}[A-Z0-9]{18}", upper))
539
+ if not ACCOUNT_DIGIT_SURFACE_RE.fullmatch(value.strip()):
540
+ return False
541
+ digits = "".join(ch for ch in value if ch.isdigit())
542
+ return 6 <= len(digits) <= 34
543
+
544
+ if label == "AGE":
545
+ digits = "".join(ch for ch in value if ch.isdigit())
546
+ if digits != value.strip():
547
+ return False
548
+ if not digits:
549
+ return False
550
+ if int(start) > 0 and text[int(start) - 1].isalnum():
551
+ return False
552
+ trailing = text[int(end) : min(len(text), int(end) + 12)]
553
+ if int(end) < len(text) and text[int(end)].isalnum() and not AGE_INLINE_SUFFIX_RE.match(trailing):
554
+ return False
555
+ if int(start) > 0 and text[int(start) - 1] in "/-":
556
+ return False
557
+ if int(end) < len(text) and text[int(end)] in "/-" and not AGE_INLINE_SUFFIX_RE.match(trailing):
558
+ return False
559
+ age = int(digits)
560
+ if not (0 < age <= 120):
561
+ return False
562
+ context = text[max(0, int(start) - 32) : min(len(text), int(end) + 24)]
563
+ prefix = text[max(0, int(start) - 24) : int(start)]
564
+ return bool(AGE_CONTEXT_RE.search(context) or AGE_SELF_PREFIX_RE.search(prefix))
565
+
566
+ if label == "DATE_OF_BIRTH":
567
+ if not any(ch.isdigit() for ch in value):
568
+ return False
569
+ if not DATE_OF_BIRTH_RE.match(value.strip()):
570
+ return False
571
+ context = text[max(0, int(start) - 32) : min(len(text), int(end) + 32)]
572
+ return bool(DOB_CONTEXT_RE.search(context))
573
+
574
+ if label == "CITY":
575
+ if any(ch.isdigit() for ch in value):
576
+ return False
577
+ prefix = text[max(0, int(start) - 20) : int(start)]
578
+ if CITY_COUNTY_PREFIX_RE.search(prefix):
579
+ return False
580
+ return normalize_surface(value) in IRISH_CITY_SURFACES
581
+
582
+ if label == "COUNTY":
583
+ if any(ch.isdigit() for ch in value):
584
+ return False
585
+ normalized = normalize_surface(value)
586
+ return normalized in IRISH_COUNTY_SURFACES or normalized.startswith(("county ", "contae ", "gcontae ", "co. "))
587
+
588
+ if label == "STREET_ADDRESS":
589
+ cleaned = value.strip()
590
+ address_parts = [part.strip() for part in cleaned.split(",")]
591
+ if len(address_parts) > 2:
592
+ return False
593
+ prefix_part = ""
594
+ street_part = cleaned
595
+ if len(address_parts) == 2:
596
+ prefix_part, street_part = address_parts
597
+ if not prefix_part or not street_part:
598
+ return False
599
+ if not (
600
+ ADDRESS_UNIT_PREFIX_RE.match(prefix_part)
601
+ or HOUSE_NAME_PREFIX_RE.match(prefix_part)
602
+ ):
603
+ return False
604
+ suffix_match = STREET_SUFFIX_RE.search(street_part)
605
+ if not suffix_match:
606
+ return False
607
+ if any(ch in "@:;" for ch in cleaned):
608
+ return False
609
+ trailing = street_part[int(suffix_match.end()) :].strip()
610
+ trailing_tokens = [token for token in re.split(r"\s+", trailing) if token]
611
+ if len(trailing_tokens) > 3:
612
+ return False
613
+ if any(normalize_surface(token) in STREET_TRAILING_BLOCK_SURFACES for token in trailing_tokens):
614
+ return False
615
+ has_digit = any(ch.isdigit() for ch in street_part)
616
+ if has_digit and not re.match(r"^\s*\d{1,4}\b", street_part):
617
+ return False
618
+ title_tokens = [token for token in re.split(r"\s+", street_part) if token]
619
+ if not has_digit and not prefix_part:
620
+ context = text[max(0, int(start) - 24) : min(len(text), int(end) + 12)]
621
+ if not ADDRESS_CUE_RE.search(context):
622
+ return False
623
+ return has_digit or len(title_tokens) >= 2
624
+
625
+ return True
626
+
627
+
628
+ def spans_overlap(a: dict, b: dict) -> bool:
629
+ return int(a["start"]) < int(b["end"]) and int(b["start"]) < int(a["end"])
630
+
631
+
632
+ def is_name_token_char(ch: str) -> bool:
633
+ return ch.isalpha() or ch in {"-", "'", "’"}
634
+
635
+
636
+ def is_plausible_first_name(value: str) -> bool:
637
+ if not value:
638
+ return False
639
+ if any(ch.isspace() for ch in value):
640
+ return False
641
+ if any(ch.isdigit() for ch in value):
642
+ return False
643
+ if any(ch in ",;:/@()" for ch in value):
644
+ return False
645
+ if not any(ch.isalpha() for ch in value):
646
+ return False
647
+ first_alpha = next((ch for ch in value if ch.isalpha()), "")
648
+ if not first_alpha or not first_alpha.isupper():
649
+ return False
650
+ return all(is_name_token_char(ch) for ch in value)
651
+
652
+
653
+ def is_plausible_cued_first_name(value: str) -> bool:
654
+ if not value:
655
+ return False
656
+ if any(ch.isspace() for ch in value):
657
+ return False
658
+ if any(ch.isdigit() for ch in value):
659
+ return False
660
+ if any(ch in ",;:/@()" for ch in value):
661
+ return False
662
+ if not any(ch.isalpha() for ch in value):
663
+ return False
664
+ return all(is_name_token_char(ch) for ch in value)
665
+
666
+
667
+ def is_plausible_cued_last_name_sequence(value: str) -> bool:
668
+ tokens = [token for token in re.split(r"\s+", value.strip()) if token]
669
+ if not tokens:
670
+ return False
671
+ for token in tokens:
672
+ if not any(ch.isalpha() for ch in token):
673
+ return False
674
+ if not all(is_name_token_char(ch) for ch in token):
675
+ return False
676
+ alpha_chars = [ch for ch in token if ch.isalpha()]
677
+ first_alpha = alpha_chars[0] if alpha_chars else ""
678
+ if first_alpha.isupper() or first_alpha.islower():
679
+ continue
680
+ if normalize_surface(token) in NAME_PARTICLE_SURFACES:
681
+ continue
682
+ return False
683
+ return True
684
+
685
+
686
+ def extract_name_tokens_after_cue(text: str, cue_end: int, max_tokens: int = 4) -> list[tuple[int, int, str]]:
687
+ cursor = cue_end
688
+ while cursor < len(text) and text[cursor].isspace():
689
+ cursor += 1
690
+ tokens: list[tuple[int, int, str]] = []
691
+ while cursor < len(text):
692
+ while cursor < len(text) and text[cursor].isspace():
693
+ cursor += 1
694
+ if cursor >= len(text) or text[cursor] in ",.;:\n":
695
+ break
696
+ token_start = cursor
697
+ while cursor < len(text) and is_name_token_char(text[cursor]):
698
+ cursor += 1
699
+ if token_start == cursor:
700
+ break
701
+ token = text[token_start:cursor]
702
+ normalized = normalize_surface(token)
703
+ if tokens and normalized in NAME_CUE_STOP_SURFACES:
704
+ break
705
+ if not all(is_name_token_char(ch) for ch in token):
706
+ break
707
+ tokens.append((token_start, cursor, token))
708
+ if len(tokens) >= max_tokens:
709
+ break
710
+ if cursor < len(text) and text[cursor] in ",.;:\n":
711
+ break
712
+ if cursor < len(text) and not text[cursor].isspace():
713
+ break
714
+ return tokens
715
+
716
+
717
+ def repair_first_name_from_last_name(text: str, spans: list[dict]) -> list[dict]:
718
+ repaired = list(spans)
719
+ for last_name in [span for span in repaired if span["label"] == "LAST_NAME"]:
720
+ if any(
721
+ span["label"] == "FIRST_NAME"
722
+ and int(span["end"]) <= int(last_name["start"])
723
+ and int(last_name["start"]) - int(span["end"]) <= 2
724
+ for span in repaired
725
+ ):
726
+ continue
727
+
728
+ cursor = int(last_name["start"]) - 1
729
+ if cursor < 0 or not text[cursor].isspace():
730
+ continue
731
+ while cursor >= 0 and text[cursor].isspace():
732
+ cursor -= 1
733
+ token_end = cursor + 1
734
+ while cursor >= 0 and is_name_token_char(text[cursor]):
735
+ cursor -= 1
736
+ token_start = cursor + 1
737
+ if token_end <= token_start:
738
+ continue
739
+ candidate = text[token_start:token_end]
740
+ if not is_plausible_first_name(candidate):
741
+ continue
742
+ candidate_span = {
743
+ "start": token_start,
744
+ "end": token_end,
745
+ "label": "FIRST_NAME",
746
+ "score": float(last_name.get("score", 0.5)) * 0.6,
747
+ "text": candidate,
748
+ }
749
+ if any(spans_overlap(candidate_span, other) for other in repaired if other["label"] == "FIRST_NAME"):
750
+ continue
751
+ repaired.append(candidate_span)
752
+ return repaired
753
+
754
+
755
+ def repair_contextual_name_cues(text: str, spans: list[dict]) -> list[dict]:
756
+ repaired = list(spans)
757
+ for match in NAME_SELF_CUE_RE.finditer(text):
758
+ if any(
759
+ other["label"] == "FIRST_NAME"
760
+ and 0 <= int(other["start"]) - match.end() <= 4
761
+ for other in repaired
762
+ ) and any(
763
+ other["label"] == "LAST_NAME"
764
+ and 0 <= int(other["start"]) - match.end() <= 16
765
+ for other in repaired
766
+ ):
767
+ continue
768
+ cursor = match.end()
769
+ while cursor < len(text) and text[cursor].isspace():
770
+ cursor += 1
771
+ start = cursor
772
+ while cursor < len(text) and (is_name_token_char(text[cursor]) or text[cursor].isspace()):
773
+ cursor += 1
774
+ candidate = text[start:cursor].strip()
775
+ raw_tokens = [token for token in re.split(r"\s+", candidate) if token]
776
+ tokens: list[str] = []
777
+ for token in raw_tokens:
778
+ normalized = normalize_surface(token)
779
+ if tokens and normalized in LOWER_NAME_STOP_SURFACES:
780
+ break
781
+ if not all(is_name_token_char(ch) for ch in token):
782
+ break
783
+ tokens.append(token)
784
+ if len(tokens) >= 4:
785
+ break
786
+ if len(tokens) < 2:
787
+ continue
788
+ first_value = tokens[0]
789
+ last_value = " ".join(tokens[1:])
790
+ if not is_plausible_cued_first_name(first_value):
791
+ continue
792
+ if not is_plausible_cued_last_name_sequence(last_value):
793
+ continue
794
+ first_start = text.find(first_value, start, cursor)
795
+ if first_start < 0:
796
+ continue
797
+ first_end = first_start + len(first_value)
798
+ last_start = text.find(last_value, first_end, cursor)
799
+ if last_start < 0:
800
+ continue
801
+ last_end = last_start + len(last_value)
802
+ first_span = {
803
+ "start": first_start,
804
+ "end": first_end,
805
+ "label": "FIRST_NAME",
806
+ "score": 0.63,
807
+ "text": text[first_start:first_end],
808
+ }
809
+ last_span = {
810
+ "start": last_start,
811
+ "end": last_end,
812
+ "label": "LAST_NAME",
813
+ "score": 0.63,
814
+ "text": text[last_start:last_end],
815
+ }
816
+ repaired = [
817
+ other
818
+ for other in repaired
819
+ if not (
820
+ spans_overlap(first_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
821
+ ) and not (
822
+ spans_overlap(last_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
823
+ )
824
+ ]
825
+ repaired.extend([first_span, last_span])
826
+ return repaired
827
+
828
+
829
+ def repair_role_name_cues(text: str, spans: list[dict]) -> list[dict]:
830
+ repaired = list(spans)
831
+ for match in NAME_ROLE_CUE_RE.finditer(text):
832
+ token_bounds = extract_name_tokens_after_cue(text, match.end())
833
+ if len(token_bounds) < 2:
834
+ continue
835
+ first_start, first_end, first_value = token_bounds[0]
836
+ last_start = token_bounds[1][0]
837
+ last_end = token_bounds[-1][1]
838
+ last_value = text[last_start:last_end]
839
+ if not is_plausible_cued_first_name(first_value):
840
+ continue
841
+ if not is_plausible_cued_last_name_sequence(last_value):
842
+ continue
843
+ first_span = {
844
+ "start": first_start,
845
+ "end": first_end,
846
+ "label": "FIRST_NAME",
847
+ "score": 0.63,
848
+ "text": text[first_start:first_end],
849
+ }
850
+ last_span = {
851
+ "start": last_start,
852
+ "end": last_end,
853
+ "label": "LAST_NAME",
854
+ "score": 0.63,
855
+ "text": text[last_start:last_end],
856
+ }
857
+ repaired = [
858
+ other
859
+ for other in repaired
860
+ if not (
861
+ spans_overlap(first_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
862
+ ) and not (
863
+ spans_overlap(last_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
864
+ )
865
+ ]
866
+ repaired.extend([first_span, last_span])
867
+ return repaired
868
+
869
+
870
+ def repair_surname_field_cues(text: str, spans: list[dict]) -> list[dict]:
871
+ repaired = list(spans)
872
+ for match in SURNAME_CUE_RE.finditer(text):
873
+ token_bounds = extract_name_tokens_after_cue(text, match.end())
874
+ if not token_bounds:
875
+ continue
876
+ start = token_bounds[0][0]
877
+ end = token_bounds[-1][1]
878
+ candidate = text[start:end]
879
+ if not is_plausible_cued_last_name_sequence(candidate):
880
+ continue
881
+ last_span = {
882
+ "start": start,
883
+ "end": end,
884
+ "label": "LAST_NAME",
885
+ "score": 0.64,
886
+ "text": candidate,
887
+ }
888
+ repaired = [
889
+ other
890
+ for other in repaired
891
+ if not (
892
+ spans_overlap(last_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
893
+ )
894
+ ]
895
+ repaired.append(last_span)
896
+ return repaired
897
+
898
+
899
+ def repair_name_particle_surnames(text: str, spans: list[dict]) -> list[dict]:
900
+ repaired = list(spans)
901
+ surname_re = re.compile(
902
+ r"^\s*((?:Ní|Ni|Ó|O|Nic|Mac|Mc)\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*)?)"
903
+ )
904
+ first_names = [span for span in repaired if span["label"] == "FIRST_NAME"]
905
+ for first_name in first_names:
906
+ tail = text[int(first_name["end"]) : min(len(text), int(first_name["end"]) + 40)]
907
+ match = surname_re.match(tail)
908
+ if not match:
909
+ continue
910
+ start = int(first_name["end"]) + int(match.start(1))
911
+ end = int(first_name["end"]) + int(match.end(1))
912
+ candidate = text[start:end]
913
+ if not is_plausible_cued_last_name_sequence(candidate):
914
+ continue
915
+ candidate_span = {
916
+ "start": start,
917
+ "end": end,
918
+ "label": "LAST_NAME",
919
+ "score": 0.66,
920
+ "text": candidate,
921
+ }
922
+ repaired = [
923
+ other
924
+ for other in repaired
925
+ if not (
926
+ spans_overlap(candidate_span, other)
927
+ and other["label"] in {"FIRST_NAME", "LAST_NAME"}
928
+ )
929
+ ]
930
+ repaired.append(candidate_span)
931
+ return repaired
932
+
933
+
934
+ def repair_name_before_structured_cues(text: str, spans: list[dict]) -> list[dict]:
935
+ repaired = list(spans)
936
+ for match in NAME_BEFORE_STRUCTURED_CUE_RE.finditer(text):
937
+ token_bounds = extract_name_tokens_after_cue(text, match.start(1))
938
+ if len(token_bounds) < 2:
939
+ continue
940
+ first_start, first_end, first_value = token_bounds[0]
941
+ last_start = token_bounds[1][0]
942
+ last_end = token_bounds[-1][1]
943
+ last_value = text[last_start:last_end]
944
+ if not is_plausible_first_name(first_value):
945
+ continue
946
+ if not is_plausible_last_name_sequence(last_value):
947
+ continue
948
+ first_span = {
949
+ "start": first_start,
950
+ "end": first_end,
951
+ "label": "FIRST_NAME",
952
+ "score": 0.64,
953
+ "text": text[first_start:first_end],
954
+ }
955
+ last_span = {
956
+ "start": last_start,
957
+ "end": last_end,
958
+ "label": "LAST_NAME",
959
+ "score": 0.64,
960
+ "text": text[last_start:last_end],
961
+ }
962
+ repaired = [
963
+ other
964
+ for other in repaired
965
+ if not (
966
+ spans_overlap(first_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
967
+ ) and not (
968
+ spans_overlap(last_span, other) and other["label"] in {"FIRST_NAME", "LAST_NAME"}
969
+ )
970
+ ]
971
+ repaired.extend([first_span, last_span])
972
+ return repaired
973
+
974
+
975
+ PASSPORT_CUE_RE = re.compile(
976
+ r"(?i)(passport(?:\s+number)?|phas|uimhir\s+(?:mo\s+)?phas)"
977
+ )
978
+ PASSPORT_VALUE_RE = re.compile(r"(?<![A-Za-z0-9])([A-Z]{1,2}\s?\d{7})(?![A-Za-z0-9])")
979
+ EMAIL_EXTRACT_RE = re.compile(r"([^\s@,;:()<>]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,})", re.UNICODE)
980
+ PHONE_CUE_RE = re.compile(
981
+ r"(?i)\b(phone|call|contact|reach\s+me|glaoigh\s+ar|teagmh[aá]il|uimhir|m['’]uimhir|f[oó]n|fon|teileaf[oó]n|telefon)\b"
982
+ )
983
+ NAME_SELF_CUE_RE = re.compile(
984
+ r"(?i)\b(my\s+name\s+is|is\s+mise|is\s+[ée]\s+m['’]?ainm|is\s+[ée]\s+mo\s+ainm)\b"
985
+ )
986
+ NAME_ROLE_CUE_RE = re.compile(
987
+ r"(?i)(?:\b(?:applicant|customer|claimant|patient|an\s+t-iarratas[oó]ir|iarratas[oó]ir)\b\s*[:,]\s*|\b(?:full\s+name|name|ainm(?!\s+teaghlaigh))\b\s*:\s*)"
988
+ )
989
+ SURNAME_CUE_RE = re.compile(
990
+ r"(?i)\b(?:my\s+)?(?:surname|last\s+name|family\s+name|ainm\s+teaghlaigh|sloinne)\b(?:\s+is)?\s*[:,-]?\s*"
991
+ )
992
+ NAME_PARTICLE_SURNAME_RE = re.compile(r"(?i)(?:\bN[ií]\b|\bÓ\b|\bNic\b|\bMac\b|\bMc\b|\bO['’])")
993
+ NAME_BEFORE_STRUCTURED_CUE_RE = re.compile(
994
+ r"(?<![A-Za-zÁÉÍÓÚáéíóú])([A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’.-]*(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’.-]*){1,3})(?=\s*,\s*(?:PPSN|UPSP|DOB|Date\s+of\s+birth|D[áa]ta\s+breithe|Address|Seoladh|lives?\s+at|my\s+phone|phone|email|r-phost))"
995
+ )
996
+ LOWER_NAME_STOP_SURFACES = {
997
+ normalize_surface(value)
998
+ for value in {"and", "agus", "is", "ta", "tá", "my", "mo", "an", "the"}
999
+ }
1000
+ NAME_CUE_STOP_SURFACES = {
1001
+ normalize_surface(value)
1002
+ for value in {
1003
+ "and",
1004
+ "agus",
1005
+ "submitted",
1006
+ "provided",
1007
+ "gave",
1008
+ "her",
1009
+ "his",
1010
+ "their",
1011
+ "she",
1012
+ "he",
1013
+ "email",
1014
+ "phone",
1015
+ "fón",
1016
+ "fon",
1017
+ "ppsn",
1018
+ "upsp",
1019
+ "address",
1020
+ "seoladh",
1021
+ "dob",
1022
+ "age",
1023
+ "aois",
1024
+ "bank",
1025
+ "iban",
1026
+ "swift",
1027
+ "chuir",
1028
+ "isteach",
1029
+ "sí",
1030
+ "si",
1031
+ "a",
1032
+ "huimhir",
1033
+ }
1034
+ }
1035
+ ORG_NAME_TRAILING_SURFACES = {
1036
+ normalize_surface(value)
1037
+ for value in {"centre", "center", "clinic", "hospital", "office", "service", "section", "unit", "council"}
1038
+ }
1039
+ ORG_CITY_TAIL_RE = re.compile(
1040
+ r"(?i)^\s+(?:intreo\s+centre|business\s+centre|community\s+centre|shopping\s+centre|retail\s+park|p[áa]irc\s+miond[ií]ola)\b"
1041
+ )
1042
+ ORG_NAME_PREFIX_RE = re.compile(
1043
+ r"(?i)(?:retail\s+park|business\s+centre|community\s+centre|shopping\s+centre|p[áa]irc\s+miond[ií]ola)\s*$"
1044
+ )
1045
+ PUBLIC_CONTACT_DETAILS_RE = re.compile(r"(?i)\bpublic\s+contact\s+details\b")
1046
+ CITY_CUE_RE = re.compile(
1047
+ r"(?i)\b(address|seoladh|located|suite|centre|center|ionad|intreo|clinic|hospital|ospid[eé]al|hse|fss)\b"
1048
+ )
1049
+ BANK_ROUTING_CONTEXT_RE = re.compile(
1050
+ r"(?i)\b(sort\s+code|routing\s+number|bank\s+of\s+ireland|aib|cod\s+sort[aá]la|sort[aá]la)\b"
1051
+ )
1052
+ PHONE_VALUE_RE = re.compile(
1053
+ r"(?<![A-Za-z0-9])((?:\+353(?:\s*\((?:0)?\d{1,2}\))?[\s\-./]?|0)\d(?:[\s\-./]?\d){6,13}|\(\s*0\d{1,2}\s*\)(?:[\s\-./]?\d){6,10})(?![A-Za-z0-9])"
1054
+ )
1055
+ PPSN_VALUE_RE = re.compile(r"(?<![A-Za-z0-9])(\d{7}(?:[\s-]*[A-Za-z]){1,2})(?![A-Za-z0-9])")
1056
+ POSTCODE_VALUE_RE = re.compile(
1057
+ r"(?<![A-Za-z0-9])((?:[A-Za-z]\d{2}|D6W)[\s\u00A0\u202F]?[A-Za-z][A-Za-z0-9]{3})(?![A-Za-z0-9])"
1058
+ )
1059
+ CITY_BEFORE_POSTCODE_RE = re.compile(
1060
+ r"(?<![A-Za-zÁÉÍÓÚáéíóú])([A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,2})(?=\s*,\s*(?:(?:County|Contae|gContae|Co\.)\s+[A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,2}\s*,\s*)?(?:[A-Z]\d{2}|D6W))"
1061
+ )
1062
+ CITY_BEFORE_COUNTY_RE = re.compile(
1063
+ r"(?<![A-Za-zÁÉÍÓÚáéíóú])([A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,3})(?=\s*,\s*(?:County|Contae|gContae|Co\.)\s+[A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,2}\b)"
1064
+ )
1065
+ CITY_TOWN_SUFFIX_RE = re.compile(
1066
+ r"(?<![A-Za-zÁÉÍÓÚáéíóú])([A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,2}\s+Town)(?=\s*,\s*(?:(?:County|Contae|gContae|Co\.)\s+[A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,2}\s*,\s*)?(?:[A-Z]\d{2}|D6W))"
1067
+ )
1068
+ CITY_FIELD_VALUE_RE = re.compile(
1069
+ r"(?im)(?:^|[\n\r])\s*(?:city(?:/town)?|town|cathair|baile)\b\s*[:,-]?\s*([A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*){0,3})"
1070
+ )
1071
+ INLINE_CITY_FIELD_VALUE_RE = re.compile(
1072
+ r"(?i)\b(?:city(?:/town)?|cathair|baile)\b\s*[:,-]\s*([A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*){0,3})"
1073
+ )
1074
+ COUNTY_FIELD_VALUE_RE = re.compile(
1075
+ r"(?im)(?:^|[\n\r])\s*(?:county|co\.|contae|gcontae)\b\s*[:,-]?\s*((?:Co\.\s+)?[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*){0,2})"
1076
+ )
1077
+ INLINE_COUNTY_FIELD_VALUE_RE = re.compile(
1078
+ r"(?i)\b(?:county|co\.|contae|gcontae)\b\s*[:,-]\s*((?:Co\.\s+)?[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*){0,2})"
1079
+ )
1080
+ COUNTY_VALUE_RE = re.compile(
1081
+ r"(?<![A-Za-zÁÉÍÓÚáéíóú])((?:County|Contae|gContae|Co\.)(?:\s+[A-ZÁÉÍÓÚ][A-Za-zÁÉÍÓÚáéíóú'’-]*){1,3})(?![A-Za-zÁÉÍÓÚáéíóú])"
1082
+ )
1083
+ ADDRESS_BLOCK_VALUE_RE = re.compile(
1084
+ rf"(?i)\b(?:{ADDRESS_FIELD_CUE_PATTERN}|live\s+at|lives\s+at|living\s+at|located\s+at|t[áa]\s+m[ée]\s+i\s+mo\s+ch[oó]na[ií]\s+ag|t[áa]im\s+i\s+mo\s+ch[oó]na[ií]\s+ag)\b\s*[:,-]?\s*([^,\n.]+)"
1085
+ )
1086
+ ADDRESS_PLACE_VALUE_RE = re.compile(
1087
+ rf"(?i)\b(?:{ADDRESS_FIELD_CUE_PATTERN}|live\s+at|lives\s+at|living\s+at|located\s+at|allocation\s+centre|intreo\s+centre)\b\s*[:,-]?\s*("
1088
+ r"(?:(?:apartment|apt\.?|flat|unit|suite|[AaÁá]ras[aá]n|aonad)\s+[A-Za-z0-9-]+,\s+)?"
1089
+ r"(?:[A-ZÁÉÍÓÚ][\w'’.-]*(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*){0,4}\s+(?:business\s+centre|community\s+centre|shopping\s+centre|retail\s+park)|P[áa]irc\s+Miond[ií]ola(?:\s+[A-ZÁÉÍÓÚ][\w'’.-]*)?)"
1090
+ r")"
1091
+ )
1092
+ ADDRESS_BUILDING_TAIL_RE = re.compile(
1093
+ r"^\s*,\s*((?:[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*\s+){0,5}(?:house|cottage|lodge|villa|apartments?|building|business\s+centre|community\s+centre|shopping\s+centre|retail\s+park)|Teach(?:ín|in)?(?:\s+na\s+[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]+)?)",
1094
+ flags=re.IGNORECASE,
1095
+ )
1096
+ LOCATION_FORM_EDGE = r"[A-Za-zÁÉÍÓÚáéíóú]"
1097
+
1098
+
1099
+ def iter_bounded_form_matches(form: str, text: str):
1100
+ pattern = re.compile(
1101
+ rf"(?<!{LOCATION_FORM_EDGE}){re.escape(form)}(?!{LOCATION_FORM_EDGE})",
1102
+ flags=re.IGNORECASE,
1103
+ )
1104
+ return pattern.finditer(text)
1105
+
1106
+
1107
+ def repair_contextual_passport_numbers(text: str, spans: list[dict]) -> list[dict]:
1108
+ repaired = list(spans)
1109
+ for match in PASSPORT_VALUE_RE.finditer(text):
1110
+ start, end = match.span(1)
1111
+ candidate_span = {
1112
+ "start": start,
1113
+ "end": end,
1114
+ "label": "PASSPORT_NUMBER",
1115
+ "score": 0.67,
1116
+ "text": text[start:end],
1117
+ }
1118
+ if any(
1119
+ other["label"] == "PASSPORT_NUMBER"
1120
+ and int(other["start"]) <= start
1121
+ and int(other["end"]) >= end
1122
+ for other in repaired
1123
+ ):
1124
+ continue
1125
+ cue_window = text[max(0, start - 32) : start]
1126
+ if not PASSPORT_CUE_RE.search(cue_window):
1127
+ continue
1128
+ conflicting_labels = {"PHONE_NUMBER", "PPSN", "ACCOUNT_NUMBER", "AGE", "PASSPORT_NUMBER"}
1129
+ repaired = [
1130
+ other
1131
+ for other in repaired
1132
+ if not (
1133
+ spans_overlap(candidate_span, other)
1134
+ and other["label"] in conflicting_labels
1135
+ )
1136
+ ]
1137
+ repaired.append(candidate_span)
1138
+ return repaired
1139
+
1140
+
1141
+ def repair_ppsn_variants(text: str, spans: list[dict]) -> list[dict]:
1142
+ repaired = list(spans)
1143
+ for match in PPSN_VALUE_RE.finditer(text):
1144
+ start, end = match.span(1)
1145
+ value = text[start:end]
1146
+ compact = alnum_upper(value)
1147
+ if not (len(compact) in {8, 9} and compact[:7].isdigit() and compact[7:].isalpha()):
1148
+ continue
1149
+ cue_window = text[max(0, start - 32) : min(len(text), end + 24)]
1150
+ has_cue = bool(PPSN_CUE_RE.search(cue_window))
1151
+ candidate_span = {
1152
+ "start": start,
1153
+ "end": end,
1154
+ "label": "PPSN",
1155
+ "score": 0.72 if has_cue else 0.58,
1156
+ "text": value,
1157
+ }
1158
+ conflicting_labels = {"PHONE_NUMBER", "PASSPORT_NUMBER", "ACCOUNT_NUMBER", "AGE", "FIRST_NAME", "LAST_NAME"}
1159
+ repaired = [
1160
+ other
1161
+ for other in repaired
1162
+ if not (
1163
+ spans_overlap(candidate_span, other)
1164
+ and other["label"] in conflicting_labels.union({"PPSN"})
1165
+ )
1166
+ ]
1167
+ repaired.append(candidate_span)
1168
+ return repaired
1169
+
1170
+
1171
+ def repair_contextual_date_of_birth(text: str, spans: list[dict]) -> list[dict]:
1172
+ repaired = list(spans)
1173
+ for match in DATE_OF_BIRTH_VALUE_RE.finditer(text):
1174
+ start, end = match.span(1)
1175
+ cue_window = text[max(0, start - 96) : min(len(text), end + 24)]
1176
+ if not DOB_CONTEXT_RE.search(cue_window):
1177
+ continue
1178
+ candidate_span = {
1179
+ "start": start,
1180
+ "end": end,
1181
+ "label": "DATE_OF_BIRTH",
1182
+ "score": 0.66,
1183
+ "text": text[start:end],
1184
+ }
1185
+ conflicting_labels = {"DATE_OF_BIRTH", "PHONE_NUMBER", "AGE", "FIRST_NAME", "LAST_NAME", "ACCOUNT_NUMBER", "CITY"}
1186
+ repaired = [
1187
+ other
1188
+ for other in repaired
1189
+ if not (
1190
+ spans_overlap(candidate_span, other)
1191
+ and other["label"] in conflicting_labels
1192
+ )
1193
+ ]
1194
+ repaired.append(candidate_span)
1195
+ return repaired
1196
+
1197
+
1198
+ def repair_contextual_ages(text: str, spans: list[dict]) -> list[dict]:
1199
+ repaired = list(spans)
1200
+ for match in AGE_VALUE_RE.finditer(text):
1201
+ start, end = match.span(1)
1202
+ if not is_reasonable_span_text("AGE", text, start, end):
1203
+ continue
1204
+ if any(
1205
+ spans_overlap({"start": start, "end": end}, other)
1206
+ and other["label"] == "DATE_OF_BIRTH"
1207
+ for other in repaired
1208
+ ):
1209
+ continue
1210
+ candidate_span = {
1211
+ "start": start,
1212
+ "end": end,
1213
+ "label": "AGE",
1214
+ "score": 0.66,
1215
+ "text": text[start:end],
1216
+ }
1217
+ conflicting_labels = {"AGE", "PHONE_NUMBER", "ACCOUNT_NUMBER"}
1218
+ repaired = [
1219
+ other
1220
+ for other in repaired
1221
+ if not (
1222
+ spans_overlap(candidate_span, other)
1223
+ and other["label"] in conflicting_labels
1224
+ )
1225
+ ]
1226
+ repaired.append(candidate_span)
1227
+ return repaired
1228
+
1229
+
1230
+ ACCOUNT_CUE_RE = re.compile(
1231
+ r"(?i)(account\s+number|bank\s+account|uimhir\s+chuntais|cuntas\s+bainc)"
1232
+ )
1233
+ ACCOUNT_VALUE_RE = re.compile(r"(?<![A-Za-z0-9])(\d{6,12})(?![A-Za-z0-9])")
1234
+
1235
+
1236
+ def repair_contextual_account_numbers(text: str, spans: list[dict]) -> list[dict]:
1237
+ repaired = list(spans)
1238
+ for match in ACCOUNT_VALUE_RE.finditer(text):
1239
+ start, end = match.span(1)
1240
+ candidate_span = {
1241
+ "start": start,
1242
+ "end": end,
1243
+ "label": "ACCOUNT_NUMBER",
1244
+ "score": 0.51,
1245
+ "text": text[start:end],
1246
+ }
1247
+ if any(
1248
+ other["label"] == "ACCOUNT_NUMBER"
1249
+ and int(other["start"]) <= start
1250
+ and int(other["end"]) >= end
1251
+ for other in repaired
1252
+ ):
1253
+ continue
1254
+ cue_window = text[max(0, start - 40) : start]
1255
+ if not ACCOUNT_CUE_RE.search(cue_window):
1256
+ continue
1257
+ if any(
1258
+ spans_overlap(candidate_span, other)
1259
+ and other["label"] in {"PHONE_NUMBER", "BANK_ROUTING_NUMBER", "PPSN", "POSTCODE", "PASSPORT_NUMBER"}
1260
+ for other in repaired
1261
+ ):
1262
+ continue
1263
+ repaired.append(candidate_span)
1264
+ return repaired
1265
+
1266
+
1267
+ def repair_emails(text: str, spans: list[dict]) -> list[dict]:
1268
+ repaired = list(spans)
1269
+ for match in EMAIL_EXTRACT_RE.finditer(text):
1270
+ start, end = match.span(1)
1271
+ candidate_span = {
1272
+ "start": start,
1273
+ "end": end,
1274
+ "label": "EMAIL",
1275
+ "score": 0.74,
1276
+ "text": text[start:end],
1277
+ }
1278
+ conflicting_labels = {"EMAIL", "FIRST_NAME", "LAST_NAME"}
1279
+ repaired = [
1280
+ other
1281
+ for other in repaired
1282
+ if not (
1283
+ spans_overlap(candidate_span, other)
1284
+ and other["label"] in conflicting_labels
1285
+ )
1286
+ ]
1287
+ repaired.append(candidate_span)
1288
+ return repaired
1289
+
1290
+
1291
+ def repair_phone_numbers(text: str, spans: list[dict]) -> list[dict]:
1292
+ repaired = list(spans)
1293
+ for match in PHONE_VALUE_RE.finditer(text):
1294
+ start, end = match.span(1)
1295
+ candidate_span = {
1296
+ "start": start,
1297
+ "end": end,
1298
+ "label": "PHONE_NUMBER",
1299
+ "score": 0.69,
1300
+ "text": text[start:end],
1301
+ }
1302
+ cue_window = text[max(0, start - 32) : min(len(text), end + 16)]
1303
+ has_cue = bool(PHONE_CUE_RE.search(cue_window))
1304
+ has_overlap = any(spans_overlap(candidate_span, other) and other["label"] == "PHONE_NUMBER" for other in repaired)
1305
+ if not (has_cue or has_overlap):
1306
+ continue
1307
+ if not is_reasonable_span_text("PHONE_NUMBER", text, start, end):
1308
+ continue
1309
+ conflicting_labels = {"PHONE_NUMBER", "PPSN", "ACCOUNT_NUMBER", "BANK_ROUTING_NUMBER", "CREDIT_DEBIT_CARD"}
1310
+ repaired = [
1311
+ other
1312
+ for other in repaired
1313
+ if not (
1314
+ spans_overlap(candidate_span, other)
1315
+ and other["label"] in conflicting_labels
1316
+ )
1317
+ ]
1318
+ repaired.append(candidate_span)
1319
+ return repaired
1320
+
1321
+
1322
+ def repair_postcodes(text: str, spans: list[dict]) -> list[dict]:
1323
+ repaired = list(spans)
1324
+ for match in POSTCODE_VALUE_RE.finditer(text):
1325
+ start, end = match.span(1)
1326
+ candidate_span = {
1327
+ "start": start,
1328
+ "end": end,
1329
+ "label": "POSTCODE",
1330
+ "score": 0.71,
1331
+ "text": text[start:end],
1332
+ }
1333
+ conflicting_labels = {"POSTCODE", "PHONE_NUMBER", "ACCOUNT_NUMBER", "FIRST_NAME", "LAST_NAME"}
1334
+ repaired = [
1335
+ other
1336
+ for other in repaired
1337
+ if not (
1338
+ spans_overlap(candidate_span, other)
1339
+ and other["label"] in conflicting_labels
1340
+ )
1341
+ ]
1342
+ repaired.append(candidate_span)
1343
+ return repaired
1344
+
1345
+
1346
+ def repair_city_spans(text: str, spans: list[dict]) -> list[dict]:
1347
+ repaired = list(spans)
1348
+ seen: set[tuple[int, int]] = set()
1349
+ ordered_forms = sorted(IRISH_CITY_FORMS, key=len, reverse=True)
1350
+ for form in ordered_forms:
1351
+ for match in iter_bounded_form_matches(form, text):
1352
+ start, end = match.span()
1353
+ prefix = text[max(0, start - 20) : start]
1354
+ if CITY_COUNTY_PREFIX_RE.search(prefix):
1355
+ continue
1356
+ key = (start, end)
1357
+ if key in seen:
1358
+ continue
1359
+ seen.add(key)
1360
+ candidate_span = {
1361
+ "start": start,
1362
+ "end": end,
1363
+ "label": "CITY",
1364
+ "score": 0.64,
1365
+ "text": text[start:end],
1366
+ }
1367
+ has_context = False
1368
+ for other in repaired:
1369
+ other_start = int(other["start"])
1370
+ other_end = int(other["end"])
1371
+ if other["label"] == "STREET_ADDRESS" and 0 <= start - other_end <= 4:
1372
+ has_context = True
1373
+ break
1374
+ if other["label"] in {"COUNTY", "POSTCODE"} and 0 <= other_start - end <= 6:
1375
+ has_context = True
1376
+ break
1377
+ if not has_context and re.match(r"^\s*,\s*(?:Co\.\s+|[A-Z]\d{2}|D6W)", text[end:]):
1378
+ has_context = True
1379
+ if not has_context:
1380
+ cue_window = text[max(0, start - 40) : min(len(text), end + 32)]
1381
+ has_context = bool(CITY_CUE_RE.search(cue_window) or ADDRESS_CUE_RE.search(cue_window))
1382
+ if not has_context:
1383
+ continue
1384
+ conflicting_labels = {"CITY", "FIRST_NAME", "LAST_NAME"}
1385
+ repaired = [
1386
+ other
1387
+ for other in repaired
1388
+ if not (
1389
+ spans_overlap(candidate_span, other)
1390
+ and other["label"] in conflicting_labels
1391
+ )
1392
+ ]
1393
+ repaired.append(candidate_span)
1394
+ return repaired
1395
+
1396
+
1397
+ def repair_city_before_postcode(text: str, spans: list[dict]) -> list[dict]:
1398
+ repaired = list(spans)
1399
+ for match in CITY_BEFORE_POSTCODE_RE.finditer(text):
1400
+ start, end = match.span(1)
1401
+ value = text[start:end]
1402
+ if any(ch.isdigit() for ch in value):
1403
+ continue
1404
+ prefix = text[max(0, start - 20) : start]
1405
+ if CITY_COUNTY_PREFIX_RE.search(prefix):
1406
+ continue
1407
+ has_context = False
1408
+ for other in repaired:
1409
+ other_start = int(other["start"])
1410
+ other_end = int(other["end"])
1411
+ if other["label"] == "STREET_ADDRESS" and 0 <= start - other_end <= 4:
1412
+ has_context = True
1413
+ break
1414
+ if other["label"] == "POSTCODE" and 0 <= other_start - end <= 6:
1415
+ has_context = True
1416
+ break
1417
+ if not has_context:
1418
+ cue_window = text[max(0, start - 40) : min(len(text), end + 24)]
1419
+ has_context = bool(CITY_CUE_RE.search(cue_window) or ADDRESS_CUE_RE.search(cue_window))
1420
+ if not has_context:
1421
+ continue
1422
+ candidate_span = {
1423
+ "start": start,
1424
+ "end": end,
1425
+ "label": "CITY",
1426
+ "score": 0.63,
1427
+ "text": value,
1428
+ }
1429
+ if any(
1430
+ other["label"] == "CITY"
1431
+ and spans_overlap(candidate_span, other)
1432
+ and (int(other["end"]) - int(other["start"])) >= (end - start)
1433
+ for other in repaired
1434
+ ):
1435
+ continue
1436
+ repaired = [
1437
+ other
1438
+ for other in repaired
1439
+ if not (
1440
+ spans_overlap(candidate_span, other)
1441
+ and other["label"] in {"CITY", "FIRST_NAME", "LAST_NAME"}
1442
+ )
1443
+ ]
1444
+ repaired.append(candidate_span)
1445
+ return repaired
1446
+
1447
+
1448
+ def repair_city_before_county(text: str, spans: list[dict]) -> list[dict]:
1449
+ repaired = list(spans)
1450
+ for regex in (CITY_TOWN_SUFFIX_RE, CITY_BEFORE_COUNTY_RE):
1451
+ for match in regex.finditer(text):
1452
+ start, end = match.span(1)
1453
+ value = text[start:end]
1454
+ if any(ch.isdigit() for ch in value):
1455
+ continue
1456
+ prefix = text[max(0, start - 20) : start]
1457
+ if CITY_COUNTY_PREFIX_RE.search(prefix):
1458
+ continue
1459
+ cue_window = text[max(0, start - 40) : min(len(text), end + 24)]
1460
+ if not ((CITY_CUE_RE.search(cue_window) or ADDRESS_CUE_RE.search(cue_window)) or re.search(r"^\s*,\s*(?:County|Contae|gContae|Co\.)\b", text[end:])):
1461
+ continue
1462
+ candidate_span = {
1463
+ "start": start,
1464
+ "end": end,
1465
+ "label": "CITY",
1466
+ "score": 0.64,
1467
+ "text": value,
1468
+ }
1469
+ if any(
1470
+ other["label"] == "CITY"
1471
+ and spans_overlap(candidate_span, other)
1472
+ and (int(other["end"]) - int(other["start"])) >= (end - start)
1473
+ for other in repaired
1474
+ ):
1475
+ continue
1476
+ repaired = [
1477
+ other
1478
+ for other in repaired
1479
+ if not (
1480
+ spans_overlap(candidate_span, other)
1481
+ and other["label"] in {"CITY", "FIRST_NAME", "LAST_NAME"}
1482
+ )
1483
+ ]
1484
+ repaired.append(candidate_span)
1485
+ return repaired
1486
+
1487
+
1488
+ def repair_city_field_cues(text: str, spans: list[dict]) -> list[dict]:
1489
+ repaired = list(spans)
1490
+ seen: set[tuple[int, int]] = set()
1491
+ for regex in (CITY_FIELD_VALUE_RE, INLINE_CITY_FIELD_VALUE_RE):
1492
+ for match in regex.finditer(text):
1493
+ start, end = match.span(1)
1494
+ if (start, end) in seen:
1495
+ continue
1496
+ seen.add((start, end))
1497
+ candidate_span = {
1498
+ "start": start,
1499
+ "end": end,
1500
+ "label": "CITY",
1501
+ "score": 0.65,
1502
+ "text": text[start:end],
1503
+ }
1504
+ repaired = [
1505
+ other
1506
+ for other in repaired
1507
+ if not (
1508
+ spans_overlap(candidate_span, other)
1509
+ and other["label"] in {"CITY", "COUNTY", "FIRST_NAME", "LAST_NAME"}
1510
+ )
1511
+ ]
1512
+ repaired.append(candidate_span)
1513
+ return repaired
1514
+
1515
+
1516
+ def repair_prefixed_city_spans(text: str, spans: list[dict]) -> list[dict]:
1517
+ repaired: list[dict] = []
1518
+ for span in spans:
1519
+ if span["label"] != "CITY":
1520
+ repaired.append(span)
1521
+ continue
1522
+ start = int(span["start"])
1523
+ end = int(span["end"])
1524
+ if start <= 0:
1525
+ repaired.append(span)
1526
+ continue
1527
+ prefix_char = text[start - 1]
1528
+ if prefix_char.lower() not in IRISH_CITY_PREFIX_CHARS:
1529
+ repaired.append(span)
1530
+ continue
1531
+ if start - 1 > 0 and text[start - 2].isalpha():
1532
+ repaired.append(span)
1533
+ continue
1534
+ if normalize_surface(span.get("text", "")) not in IRISH_CITY_SURFACES:
1535
+ repaired.append(span)
1536
+ continue
1537
+ candidate_start = start - 1
1538
+ candidate_text = text[candidate_start:end]
1539
+ repaired.append(
1540
+ {
1541
+ **span,
1542
+ "start": candidate_start,
1543
+ "text": candidate_text,
1544
+ "score": max(float(span.get("score", 0.0)), 0.66),
1545
+ }
1546
+ )
1547
+ return repaired
1548
+
1549
+
1550
+ def prefer_long_city_spans(spans: list[dict]) -> list[dict]:
1551
+ if not spans:
1552
+ return spans
1553
+ keep: list[dict] = []
1554
+ for span in spans:
1555
+ if span["label"] != "CITY":
1556
+ keep.append(span)
1557
+ continue
1558
+ shadowed = False
1559
+ for other in spans:
1560
+ if other is span or other["label"] != "CITY":
1561
+ continue
1562
+ if int(other["start"]) <= int(span["start"]) and int(other["end"]) >= int(span["end"]):
1563
+ if (int(other["start"]), int(other["end"])) != (int(span["start"]), int(span["end"])):
1564
+ if float(other.get("score", 0.0)) >= max(0.6, float(span.get("score", 0.0)) * 0.6):
1565
+ shadowed = True
1566
+ break
1567
+ if not shadowed:
1568
+ keep.append(span)
1569
+ return keep
1570
+
1571
+
1572
+ def repair_county_field_cues(text: str, spans: list[dict]) -> list[dict]:
1573
+ repaired = list(spans)
1574
+ seen: set[tuple[int, int]] = set()
1575
+ for regex in (COUNTY_FIELD_VALUE_RE, INLINE_COUNTY_FIELD_VALUE_RE):
1576
+ for match in regex.finditer(text):
1577
+ start, end = match.span(1)
1578
+ if (start, end) in seen:
1579
+ continue
1580
+ seen.add((start, end))
1581
+ candidate_span = {
1582
+ "start": start,
1583
+ "end": end,
1584
+ "label": "COUNTY",
1585
+ "score": 0.66,
1586
+ "text": text[start:end],
1587
+ }
1588
+ repaired = [
1589
+ other
1590
+ for other in repaired
1591
+ if not (
1592
+ spans_overlap(candidate_span, other)
1593
+ and other["label"] in {"COUNTY", "CITY", "FIRST_NAME", "LAST_NAME"}
1594
+ )
1595
+ ]
1596
+ repaired.append(candidate_span)
1597
+ return repaired
1598
+
1599
+
1600
+ def repair_county_spans(text: str, spans: list[dict]) -> list[dict]:
1601
+ repaired = list(spans)
1602
+ seen: set[tuple[int, int]] = set()
1603
+ ordered_forms = sorted(IRISH_COUNTY_FORMS, key=len, reverse=True)
1604
+ for form in ordered_forms:
1605
+ for match in iter_bounded_form_matches(form, text):
1606
+ start, end = match.span()
1607
+ key = (start, end)
1608
+ if key in seen:
1609
+ continue
1610
+ seen.add(key)
1611
+ candidate_span = {
1612
+ "start": start,
1613
+ "end": end,
1614
+ "label": "COUNTY",
1615
+ "score": 0.74,
1616
+ "text": text[start:end],
1617
+ }
1618
+ if not is_reasonable_span_text("COUNTY", text, start, end):
1619
+ continue
1620
+ overlapping_counties = [
1621
+ other
1622
+ for other in repaired
1623
+ if spans_overlap(candidate_span, other) and other["label"] == "COUNTY"
1624
+ ]
1625
+ if overlapping_counties:
1626
+ candidate_span["score"] = max(
1627
+ float(candidate_span["score"]),
1628
+ max(float(other.get("score", 0.0)) for other in overlapping_counties),
1629
+ )
1630
+ conflicting_labels = {"COUNTY", "CITY", "FIRST_NAME", "LAST_NAME"}
1631
+ repaired = [
1632
+ other
1633
+ for other in repaired
1634
+ if not (
1635
+ spans_overlap(candidate_span, other)
1636
+ and other["label"] in conflicting_labels
1637
+ )
1638
+ ]
1639
+ repaired.append(candidate_span)
1640
+ for match in COUNTY_VALUE_RE.finditer(text):
1641
+ start, end = match.span(1)
1642
+ key = (start, end)
1643
+ if key in seen:
1644
+ continue
1645
+ context = text[max(0, start - 40) : min(len(text), end + 24)]
1646
+ has_context = bool(ADDRESS_CUE_RE.search(context) or POSTCODE_VALUE_RE.search(context))
1647
+ if not has_context:
1648
+ for other in repaired:
1649
+ other_start = int(other["start"])
1650
+ other_end = int(other["end"])
1651
+ if other["label"] in {"STREET_ADDRESS", "CITY", "POSTCODE"} and (
1652
+ abs(other_start - end) <= 24 or abs(start - other_end) <= 24
1653
+ ):
1654
+ has_context = True
1655
+ break
1656
+ if not has_context:
1657
+ continue
1658
+ seen.add(key)
1659
+ candidate_span = {
1660
+ "start": start,
1661
+ "end": end,
1662
+ "label": "COUNTY",
1663
+ "score": 0.74,
1664
+ "text": text[start:end],
1665
+ }
1666
+ if not is_reasonable_span_text("COUNTY", text, start, end):
1667
+ continue
1668
+ conflicting_labels = {"COUNTY", "CITY", "FIRST_NAME", "LAST_NAME"}
1669
+ repaired = [
1670
+ other
1671
+ for other in repaired
1672
+ if not (
1673
+ spans_overlap(candidate_span, other)
1674
+ and other["label"] in conflicting_labels
1675
+ )
1676
+ ]
1677
+ repaired.append(candidate_span)
1678
+ return repaired
1679
+
1680
+
1681
+ def repair_street_addresses(text: str, spans: list[dict]) -> list[dict]:
1682
+ repaired = list(spans)
1683
+ seen: set[tuple[int, int]] = set()
1684
+ for match in STREET_ADDRESS_VALUE_RE.finditer(text):
1685
+ start, end = match.span(1)
1686
+ key = (start, end)
1687
+ if key in seen:
1688
+ continue
1689
+ seen.add(key)
1690
+ candidate_span = {
1691
+ "start": start,
1692
+ "end": end,
1693
+ "label": "STREET_ADDRESS",
1694
+ "score": 0.65,
1695
+ "text": text[start:end],
1696
+ }
1697
+ if not is_reasonable_span_text("STREET_ADDRESS", text, start, end):
1698
+ continue
1699
+ context = text[max(0, start - 32) : min(len(text), end + 24)]
1700
+ has_context = bool(ADDRESS_CUE_RE.search(context))
1701
+ if not has_context:
1702
+ for other in repaired:
1703
+ other_start = int(other["start"])
1704
+ other_end = int(other["end"])
1705
+ if other["label"] in {"CITY", "COUNTY", "POSTCODE"} and 0 <= other_start - end <= 16:
1706
+ has_context = True
1707
+ break
1708
+ if other["label"] in {"FIRST_NAME", "LAST_NAME"} and 0 <= start - other_end <= 24:
1709
+ has_context = True
1710
+ break
1711
+ if not has_context:
1712
+ continue
1713
+ conflicting_labels = {"STREET_ADDRESS", "FIRST_NAME", "LAST_NAME"}
1714
+ repaired = [
1715
+ other
1716
+ for other in repaired
1717
+ if not (
1718
+ spans_overlap(candidate_span, other)
1719
+ and other["label"] in conflicting_labels
1720
+ )
1721
+ ]
1722
+ repaired.append(candidate_span)
1723
+ return repaired
1724
+
1725
+
1726
+ def repair_contextual_address_blocks(text: str, spans: list[dict]) -> list[dict]:
1727
+ repaired = list(spans)
1728
+ for match in ADDRESS_BLOCK_VALUE_RE.finditer(text):
1729
+ start, end = match.span(1)
1730
+ value = text[start:end].strip()
1731
+ if not value:
1732
+ continue
1733
+ candidate_span = {
1734
+ "start": start,
1735
+ "end": end,
1736
+ "label": "STREET_ADDRESS",
1737
+ "score": 0.68,
1738
+ "text": text[start:end],
1739
+ }
1740
+ tokens = [token for token in re.split(r"\s+", value) if token]
1741
+ if len(tokens) < 2:
1742
+ continue
1743
+ has_digit = any(ch.isdigit() for ch in value)
1744
+ has_prefix = bool(ADDRESS_UNIT_PREFIX_RE.match(value) or HOUSE_NAME_PREFIX_RE.match(value))
1745
+ has_street_suffix = bool(STREET_SUFFIX_RE.search(value))
1746
+ cue_window = text[max(0, start - 40) : start]
1747
+ has_address_line_cue = bool(ADDRESS_LINE_CUE_RE.search(cue_window))
1748
+ if not (has_digit or has_prefix):
1749
+ continue
1750
+ if not has_street_suffix:
1751
+ tail_window = text[end : min(len(text), end + 48)]
1752
+ has_following_address_context = bool(
1753
+ re.match(
1754
+ r"^\s*,\s*((?:\d{1,4}\s+)?(?:[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*\s+){0,5}(?:street|road|avenue|lane|park|view|square|terrace|drive|close|way|place|crescent|grove|green|court|manor|mews|gardens?|heights|quay|bóthar|bothar|sráid|sraid|lána|lana))",
1755
+ tail_window,
1756
+ flags=re.IGNORECASE,
1757
+ )
1758
+ or re.search(r"(?:County|Contae|gContae|Co\.|(?:[A-Z]\d{2}|D6W))", tail_window)
1759
+ )
1760
+ building_tail_match = ADDRESS_BUILDING_TAIL_RE.match(tail_window)
1761
+ has_following_building_context = False
1762
+ if building_tail_match:
1763
+ remaining_tail = tail_window[int(building_tail_match.end(1)) :]
1764
+ has_following_building_context = bool(
1765
+ re.match(
1766
+ r"^\s*(?:$|,\s*(?:(?:\d{1,4}\s+)?(?:[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*\s+){0,5}(?:street|road|avenue|lane|park|view|square|terrace|drive|close|way|place|crescent|grove|green|court|manor|mews|gardens?|heights|quay|bóthar|bothar|sráid|sraid|lána|lana)|County|Contae|gContae|Co\.|(?:[A-Z]\d{2}|D6W)|[A-ZÁÉÍÓÚ]))",
1767
+ remaining_tail,
1768
+ flags=re.IGNORECASE,
1769
+ )
1770
+ )
1771
+ looks_like_suffixless_address = has_digit and len(tokens) >= 3
1772
+ if not ((has_prefix and (has_address_line_cue or has_following_building_context)) or ((has_prefix or looks_like_suffixless_address) and has_following_address_context)):
1773
+ continue
1774
+ if any(
1775
+ other["label"] == "STREET_ADDRESS"
1776
+ and int(other["start"]) <= start
1777
+ and int(other["end"]) >= end
1778
+ and (int(other["start"]), int(other["end"])) != (start, end)
1779
+ for other in repaired
1780
+ ):
1781
+ continue
1782
+ conflicting_labels = {"STREET_ADDRESS", "FIRST_NAME", "LAST_NAME"}
1783
+ repaired = [
1784
+ other
1785
+ for other in repaired
1786
+ if not (
1787
+ spans_overlap(candidate_span, other)
1788
+ and other["label"] in conflicting_labels
1789
+ )
1790
+ ]
1791
+ repaired.append(candidate_span)
1792
+ return repaired
1793
+
1794
+
1795
+ def extend_prefixed_street_address_spans(text: str, spans: list[dict]) -> list[dict]:
1796
+ repaired: list[dict] = []
1797
+ tail_re = re.compile(
1798
+ r"^\s*,\s*((?:\d{1,4}\s+)?(?:[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*\s+){0,5}(?:street|road|avenue|lane|park|view|square|terrace|drive|close|way|place|crescent|grove|green|court|manor|mews|gardens?|heights|quay|bóthar|bothar|sráid|sraid|lána|lana)(?:\s+[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*){0,2})",
1799
+ flags=re.IGNORECASE,
1800
+ )
1801
+ building_follow_context_re = re.compile(
1802
+ r"^\s*(?:$|[.;]|,\s*(?:(?:\d{1,4}\s+)?(?:[A-ZÁÉÍÓÚa-záéíóú][\w'’.-]*\s+){0,5}(?:street|road|avenue|lane|park|view|square|terrace|drive|close|way|place|crescent|grove|green|court|manor|mews|gardens?|heights|quay|bóthar|bothar|sráid|sraid|lána|lana)|County|Contae|gContae|Co\.|(?:[A-Z]\d{2}|D6W)|[A-ZÁÉÍÓÚ]))",
1803
+ flags=re.IGNORECASE,
1804
+ )
1805
+ for span in spans:
1806
+ if span["label"] != "STREET_ADDRESS":
1807
+ repaired.append(span)
1808
+ continue
1809
+ value = span.get("text", "").strip()
1810
+ if not value or not (ADDRESS_UNIT_PREFIX_RE.match(value) or HOUSE_NAME_PREFIX_RE.match(value)):
1811
+ repaired.append(span)
1812
+ continue
1813
+ tail_match = tail_re.match(text[int(span["end"]) :])
1814
+ if tail_match:
1815
+ extended_end = int(span["end"]) + int(tail_match.end(1))
1816
+ repaired.append(
1817
+ {
1818
+ **span,
1819
+ "end": extended_end,
1820
+ "text": text[int(span["start"]) : extended_end],
1821
+ "score": max(float(span.get("score", 0.0)), 0.67),
1822
+ }
1823
+ )
1824
+ continue
1825
+ building_tail_match = ADDRESS_BUILDING_TAIL_RE.match(text[int(span["end"]) :])
1826
+ if not building_tail_match:
1827
+ repaired.append(span)
1828
+ continue
1829
+ remaining_tail = text[int(span["end"]) + int(building_tail_match.end(1)) :]
1830
+ extended_end = int(span["end"]) + int(building_tail_match.end(1))
1831
+ repaired.append(
1832
+ {
1833
+ **span,
1834
+ "end": extended_end,
1835
+ "text": text[int(span["start"]) : extended_end],
1836
+ "score": max(float(span.get("score", 0.0)), 0.67),
1837
+ }
1838
+ )
1839
+ return repaired
1840
+
1841
+
1842
+ def merge_adjacent_street_address_spans(text: str, spans: list[dict]) -> list[dict]:
1843
+ if not spans:
1844
+ return spans
1845
+ ordered = sorted(spans, key=lambda item: (int(item["start"]), int(item["end"]), item["label"]))
1846
+ merged: list[dict] = []
1847
+ index = 0
1848
+ while index < len(ordered):
1849
+ span = ordered[index]
1850
+ if span["label"] != "STREET_ADDRESS":
1851
+ merged.append(span)
1852
+ index += 1
1853
+ continue
1854
+ current = dict(span)
1855
+ lookahead = index + 1
1856
+ while lookahead < len(ordered):
1857
+ other = ordered[lookahead]
1858
+ if other["label"] != "STREET_ADDRESS":
1859
+ break
1860
+ gap = text[int(current["end"]) : int(other["start"])]
1861
+ if not re.fullmatch(r"\s*,\s*", gap):
1862
+ break
1863
+ candidate_end = int(other["end"])
1864
+ merged_value = text[int(current["start"]) : candidate_end]
1865
+ if not (
1866
+ any(ch.isdigit() for ch in merged_value)
1867
+ and (
1868
+ ADDRESS_UNIT_PREFIX_RE.match(merged_value)
1869
+ or STREET_SUFFIX_RE.search(merged_value)
1870
+ or BUILDING_SUFFIX_RE.search(merged_value)
1871
+ )
1872
+ ):
1873
+ break
1874
+ current["end"] = candidate_end
1875
+ current["text"] = text[int(current["start"]) : candidate_end]
1876
+ current["score"] = max(float(current.get("score", 0.0)), float(other.get("score", 0.0)))
1877
+ lookahead += 1
1878
+ merged.append(current)
1879
+ index = lookahead
1880
+ return merged
1881
+
1882
+
1883
+ def repair_contextual_address_place_blocks(text: str, spans: list[dict]) -> list[dict]:
1884
+ repaired = list(spans)
1885
+ for match in ADDRESS_PLACE_VALUE_RE.finditer(text):
1886
+ start, end = match.span(1)
1887
+ candidate_span = {
1888
+ "start": start,
1889
+ "end": end,
1890
+ "label": "STREET_ADDRESS",
1891
+ "score": 0.69,
1892
+ "text": text[start:end],
1893
+ }
1894
+ repaired = [
1895
+ other
1896
+ for other in repaired
1897
+ if not (
1898
+ spans_overlap(candidate_span, other)
1899
+ and other["label"] in {"STREET_ADDRESS", "FIRST_NAME", "LAST_NAME", "CITY"}
1900
+ )
1901
+ ]
1902
+ repaired.append(candidate_span)
1903
+ return repaired
1904
+
1905
+
1906
+ def prefer_long_street_address_spans(spans: list[dict]) -> list[dict]:
1907
+ if not spans:
1908
+ return spans
1909
+ keep: list[dict] = []
1910
+ for span in spans:
1911
+ if span["label"] != "STREET_ADDRESS":
1912
+ keep.append(span)
1913
+ continue
1914
+ shadowed = False
1915
+ for other in spans:
1916
+ if other is span or other["label"] != "STREET_ADDRESS":
1917
+ continue
1918
+ if int(other["start"]) <= int(span["start"]) and int(other["end"]) >= int(span["end"]):
1919
+ if (int(other["start"]), int(other["end"])) != (int(span["start"]), int(span["end"])):
1920
+ shadowed = True
1921
+ break
1922
+ if not shadowed:
1923
+ keep.append(span)
1924
+ return keep
1925
+
1926
+
1927
+ def drop_contextual_fragment_spans(spans: list[dict]) -> list[dict]:
1928
+ if not spans:
1929
+ return spans
1930
+ suppressors = {"COUNTY", "CITY", "POSTCODE", "STREET_ADDRESS", "DATE_OF_BIRTH"}
1931
+ keep: list[dict] = []
1932
+ for span in spans:
1933
+ if span["label"] in {"FIRST_NAME", "LAST_NAME"}:
1934
+ if any(
1935
+ other is not span
1936
+ and other["label"] in suppressors
1937
+ and spans_overlap(span, other)
1938
+ and (int(other["end"]) - int(other["start"])) >= (int(span["end"]) - int(span["start"]))
1939
+ for other in spans
1940
+ ):
1941
+ continue
1942
+ if span["label"] == "CITY":
1943
+ if any(
1944
+ other is not span
1945
+ and other["label"] == "COUNTY"
1946
+ and spans_overlap(span, other)
1947
+ and (int(other["end"]) - int(other["start"])) >= (int(span["end"]) - int(span["start"]))
1948
+ for other in spans
1949
+ ):
1950
+ continue
1951
+ keep.append(span)
1952
+ return keep
1953
+
1954
+
1955
+ def drop_public_contact_detail_spans(text: str, spans: list[dict]) -> list[dict]:
1956
+ if not PUBLIC_CONTACT_DETAILS_RE.search(text):
1957
+ return spans
1958
+ keep: list[dict] = []
1959
+ for span in spans:
1960
+ if span["label"] not in {"STREET_ADDRESS", "CITY", "COUNTY"}:
1961
+ keep.append(span)
1962
+ continue
1963
+ keep.append(span)
1964
+ return [
1965
+ span for span in keep
1966
+ if not (span["label"] in {"STREET_ADDRESS", "CITY", "COUNTY"} and PUBLIC_CONTACT_DETAILS_RE.search(text))
1967
+ ]
1968
+
1969
+
1970
+ def drop_org_like_name_spans(text: str, spans: list[dict]) -> list[dict]:
1971
+ keep: list[dict] = []
1972
+ for span in spans:
1973
+ if span["label"] not in {"FIRST_NAME", "LAST_NAME"}:
1974
+ keep.append(span)
1975
+ continue
1976
+ tokens = [normalize_surface(token) for token in re.split(r"\s+", span.get("text", "").strip()) if token]
1977
+ if tokens and tokens[-1] in ORG_NAME_TRAILING_SURFACES:
1978
+ continue
1979
+ prefix = text[max(0, int(span["start"]) - 32) : int(span["start"])]
1980
+ if ORG_NAME_PREFIX_RE.search(prefix):
1981
+ continue
1982
+ keep.append(span)
1983
+ return keep
1984
+
1985
+
1986
+ def drop_city_org_prefix_spans(text: str, spans: list[dict]) -> list[dict]:
1987
+ keep: list[dict] = []
1988
+ for span in spans:
1989
+ if span["label"] != "CITY":
1990
+ keep.append(span)
1991
+ continue
1992
+ tail = text[int(span["end"]) : min(len(text), int(span["end"]) + 24)]
1993
+ if ORG_CITY_TAIL_RE.match(tail):
1994
+ continue
1995
+ keep.append(span)
1996
+ return keep
1997
+
1998
+
1999
+ def canonicalize_location_spans(text: str, spans: list[dict]) -> list[dict]:
2000
+ repaired: list[dict] = []
2001
+ for span in spans:
2002
+ if span["label"] not in {"CITY", "COUNTY"}:
2003
+ repaired.append(span)
2004
+ continue
2005
+ start = int(span["start"])
2006
+ end = int(span["end"])
2007
+ while end > start and text[end - 1] in ".,;:":
2008
+ end -= 1
2009
+ repaired.append(
2010
+ {
2011
+ **span,
2012
+ "end": end,
2013
+ "text": text[start:end],
2014
+ }
2015
+ )
2016
+ return repaired
2017
+
2018
+
2019
+ def canonicalize_street_address_spans(text: str, spans: list[dict]) -> list[dict]:
2020
+ repaired: list[dict] = []
2021
+ for span in spans:
2022
+ if span["label"] != "STREET_ADDRESS":
2023
+ repaired.append(span)
2024
+ continue
2025
+ start = int(span["start"])
2026
+ end = int(span["end"])
2027
+ while end > start and text[end - 1] in ".,;:":
2028
+ end -= 1
2029
+ repaired.append(
2030
+ {
2031
+ **span,
2032
+ "end": end,
2033
+ "text": text[start:end],
2034
+ }
2035
+ )
2036
+ return repaired
2037
+
2038
+
2039
+ def canonicalize_email_spans(text: str, spans: list[dict]) -> list[dict]:
2040
+ repaired: list[dict] = []
2041
+ for span in spans:
2042
+ if span["label"] != "EMAIL":
2043
+ repaired.append(span)
2044
+ continue
2045
+ segment = text[int(span["start"]) : int(span["end"])]
2046
+ match = EMAIL_EXTRACT_RE.search(segment)
2047
+ if not match:
2048
+ repaired.append(span)
2049
+ continue
2050
+ start = int(span["start"]) + int(match.start(1))
2051
+ end = int(span["start"]) + int(match.end(1))
2052
+ repaired.append(
2053
+ {
2054
+ **span,
2055
+ "start": start,
2056
+ "end": end,
2057
+ "text": text[start:end],
2058
+ }
2059
+ )
2060
+ return repaired
2061
+
2062
+
2063
+ def drop_stacked_first_names(spans: list[dict]) -> list[dict]:
2064
+ if not spans:
2065
+ return spans
2066
+ first_names = [span for span in spans if span["label"] == "FIRST_NAME"]
2067
+ last_names = [span for span in spans if span["label"] == "LAST_NAME"]
2068
+ if not first_names or not last_names:
2069
+ return spans
2070
+ keep: list[dict] = []
2071
+ for span in spans:
2072
+ if span["label"] != "FIRST_NAME":
2073
+ keep.append(span)
2074
+ continue
2075
+ shadowed = False
2076
+ for other in first_names:
2077
+ if other is span:
2078
+ continue
2079
+ if int(other["start"]) <= int(span["start"]):
2080
+ continue
2081
+ if int(other["start"]) - int(span["end"]) > 2:
2082
+ continue
2083
+ if not any(
2084
+ int(last["start"]) >= int(other["end"]) and int(last["start"]) - int(other["end"]) <= 2
2085
+ for last in last_names
2086
+ ):
2087
+ continue
2088
+ shadowed = True
2089
+ break
2090
+ if not shadowed:
2091
+ keep.append(span)
2092
+ return keep
2093
+
2094
+
2095
+ def decode_span_matrix(
2096
+ text: str,
2097
+ offsets: list[tuple[int, int]],
2098
+ span_scores: np.ndarray,
2099
+ config,
2100
+ min_score: float,
2101
+ ) -> list[dict]:
2102
+ label_names = label_names_from_config(config)
2103
+ thresholds = label_thresholds_from_config(config, min_score)
2104
+ max_span_tokens = label_max_span_tokens_from_config(config)
2105
+ min_nonspace_chars = label_min_nonspace_chars_from_config(config)
2106
+
2107
+ if span_scores.ndim != 3:
2108
+ raise ValueError(f"Expected [num_labels, seq_len, seq_len] span scores, got shape {span_scores.shape}")
2109
+
2110
+ num_labels, seq_len, _ = span_scores.shape
2111
+ valid = np.array([valid_offset(offset) for offset in offsets[:seq_len]], dtype=bool)
2112
+ start_chars = np.array([int(offset[0]) if valid[index] else -1 for index, offset in enumerate(offsets[:seq_len])], dtype=np.int32)
2113
+ end_chars = np.array([int(offset[1]) if valid[index] else -1 for index, offset in enumerate(offsets[:seq_len])], dtype=np.int32)
2114
+ nonspace_prefix = [0]
2115
+ for ch in text:
2116
+ nonspace_prefix.append(nonspace_prefix[-1] + (0 if ch.isspace() else 1))
2117
+ spans: list[dict] = []
2118
+ for label_index in range(min(num_labels, len(label_names))):
2119
+ label = label_names[label_index]
2120
+ threshold = thresholds.get(label, min_score)
2121
+ max_width = max(1, int(max_span_tokens.get(label, 8)))
2122
+ min_chars = max(1, int(min_nonspace_chars.get(label, 1)))
2123
+ label_scores = span_scores[label_index, :seq_len, :seq_len]
2124
+ start_indices, end_indices = np.where(label_scores >= threshold)
2125
+ if start_indices.size == 0:
2126
+ continue
2127
+ width_mask = (end_indices >= start_indices) & ((end_indices - start_indices) < max_width)
2128
+ if not np.any(width_mask):
2129
+ continue
2130
+ start_indices = start_indices[width_mask]
2131
+ end_indices = end_indices[width_mask]
2132
+ valid_mask = valid[start_indices] & valid[end_indices]
2133
+ if not np.any(valid_mask):
2134
+ continue
2135
+ start_indices = start_indices[valid_mask]
2136
+ end_indices = end_indices[valid_mask]
2137
+ for start_idx, end_idx in zip(start_indices.tolist(), end_indices.tolist()):
2138
+ start_char = int(start_chars[start_idx])
2139
+ end_char = int(end_chars[end_idx])
2140
+ if end_char <= start_char:
2141
+ continue
2142
+ if (nonspace_prefix[end_char] - nonspace_prefix[start_char]) < min_chars:
2143
+ continue
2144
+ if not is_reasonable_span_text(label, text, start_char, end_char):
2145
+ continue
2146
+ spans.append(
2147
+ {
2148
+ "start": start_char,
2149
+ "end": end_char,
2150
+ "label": label,
2151
+ "score": float(label_scores[start_idx, end_idx]),
2152
+ "text": text[start_char:end_char],
2153
+ }
2154
+ )
2155
+ spans = prefer_long_name_spans(spans, thresholds)
2156
+ spans = prefer_long_structured_spans(spans, thresholds)
2157
+ spans = repair_first_name_from_last_name(text, spans)
2158
+ text_lower = text.lower()
2159
+ has_digit = any(ch.isdigit() for ch in text)
2160
+ has_email_hint = "@" in text
2161
+ has_address_hint = bool(
2162
+ ADDRESS_CUE_RE.search(text)
2163
+ or ADDRESS_LINE_CUE_RE.search(text)
2164
+ or STREET_SUFFIX_RE.search(text)
2165
+ or HOUSE_NAME_PREFIX_RE.search(text)
2166
+ or ADDRESS_UNIT_PREFIX_RE.search(text)
2167
+ )
2168
+ has_city_hint = bool(
2169
+ has_address_hint
2170
+ or POSTCODE_VALUE_RE.search(text)
2171
+ or "city:" in text_lower
2172
+ or "city " in text_lower
2173
+ or "town:" in text_lower
2174
+ or "town " in text_lower
2175
+ or "city/town" in text_lower
2176
+ or "cathair" in text_lower
2177
+ or "baile" in text_lower
2178
+ or "county" in text_lower
2179
+ or "contae" in text_lower
2180
+ or "co." in text_lower
2181
+ )
2182
+ has_name_spans = any(span["label"] in {"FIRST_NAME", "LAST_NAME"} for span in spans)
2183
+ if has_email_hint:
2184
+ spans = repair_emails(text, spans)
2185
+ if has_digit:
2186
+ spans = repair_phone_numbers(text, spans)
2187
+ spans = repair_ppsn_variants(text, spans)
2188
+ spans = repair_postcodes(text, spans)
2189
+ if has_address_hint:
2190
+ spans = repair_street_addresses(text, spans)
2191
+ if NAME_SELF_CUE_RE.search(text):
2192
+ spans = repair_contextual_name_cues(text, spans)
2193
+ if NAME_ROLE_CUE_RE.search(text):
2194
+ spans = repair_role_name_cues(text, spans)
2195
+ if SURNAME_CUE_RE.search(text):
2196
+ spans = repair_surname_field_cues(text, spans)
2197
+ if NAME_BEFORE_STRUCTURED_CUE_RE.search(text):
2198
+ spans = repair_name_before_structured_cues(text, spans)
2199
+ if has_name_spans and NAME_PARTICLE_SURNAME_RE.search(text):
2200
+ spans = repair_name_particle_surnames(text, spans)
2201
+ if has_address_hint:
2202
+ spans = repair_contextual_address_blocks(text, spans)
2203
+ spans = extend_prefixed_street_address_spans(text, spans)
2204
+ spans = repair_contextual_address_place_blocks(text, spans)
2205
+ spans = merge_adjacent_street_address_spans(text, spans)
2206
+ spans = prefer_long_street_address_spans(spans)
2207
+ if has_city_hint:
2208
+ spans = repair_county_spans(text, spans)
2209
+ spans = repair_city_spans(text, spans)
2210
+ spans = repair_city_before_postcode(text, spans)
2211
+ spans = repair_city_before_county(text, spans)
2212
+ spans = repair_city_field_cues(text, spans)
2213
+ spans = repair_prefixed_city_spans(text, spans)
2214
+ spans = prefer_long_city_spans(spans)
2215
+ spans = repair_county_field_cues(text, spans)
2216
+ if has_digit and DOB_CONTEXT_RE.search(text):
2217
+ spans = repair_contextual_date_of_birth(text, spans)
2218
+ if has_digit and AGE_CONTEXT_RE.search(text):
2219
+ spans = repair_contextual_ages(text, spans)
2220
+ if has_digit and PASSPORT_CUE_RE.search(text):
2221
+ spans = repair_contextual_passport_numbers(text, spans)
2222
+ if has_digit and ("iban" in text_lower or "account" in text_lower or "bank" in text_lower or "cuntas" in text_lower):
2223
+ spans = repair_contextual_account_numbers(text, spans)
2224
+ if "public contact details" in text_lower:
2225
+ spans = drop_public_contact_detail_spans(text, spans)
2226
+ if any(span["label"] in {"FIRST_NAME", "LAST_NAME"} for span in spans):
2227
+ spans = drop_org_like_name_spans(text, spans)
2228
+ spans = drop_stacked_first_names(spans)
2229
+ if any(span["label"] == "CITY" for span in spans):
2230
+ spans = drop_city_org_prefix_spans(text, spans)
2231
+ if any(span["label"] in {"FIRST_NAME", "LAST_NAME", "CITY"} for span in spans):
2232
+ spans = drop_contextual_fragment_spans(spans)
2233
+ if any(span["label"] in {"CITY", "COUNTY"} for span in spans):
2234
+ spans = canonicalize_location_spans(text, spans)
2235
+ if any(span["label"] == "STREET_ADDRESS" for span in spans):
2236
+ spans = canonicalize_street_address_spans(text, spans)
2237
+ if any(span["label"] == "EMAIL" for span in spans):
2238
+ spans = canonicalize_email_spans(text, spans)
2239
+ return dedupe_spans(spans)
2240
+
2241
+
2242
+ def prefer_long_name_spans(spans: list[dict], thresholds: dict[str, float]) -> list[dict]:
2243
+ if not spans:
2244
+ return spans
2245
+ preferred: list[dict] = []
2246
+ consumed: set[int] = set()
2247
+ for index, span in enumerate(spans):
2248
+ if index in consumed:
2249
+ continue
2250
+ label = span["label"]
2251
+ if label not in {"FIRST_NAME", "LAST_NAME"}:
2252
+ preferred.append(span)
2253
+ continue
2254
+ same_start = [
2255
+ (other_index, other)
2256
+ for other_index, other in enumerate(spans)
2257
+ if other_index not in consumed and other["label"] == label and other["start"] == span["start"]
2258
+ ]
2259
+ if len(same_start) == 1:
2260
+ preferred.append(span)
2261
+ continue
2262
+ for other_index, _ in same_start:
2263
+ consumed.add(other_index)
2264
+ best_by_score = max(same_start, key=lambda item: float(item[1].get("score", 0.0)))[1]
2265
+ longest = max(same_start, key=lambda item: (item[1]["end"] - item[1]["start"], float(item[1].get("score", 0.0))))[1]
2266
+ threshold = float(thresholds.get(label, 0.5))
2267
+ if float(longest.get("score", 0.0)) >= max(threshold + 0.15, float(best_by_score.get("score", 0.0)) * 0.7):
2268
+ preferred.append(longest)
2269
+ else:
2270
+ preferred.append(best_by_score)
2271
+ return prefer_same_end_extensions(preferred, thresholds)
2272
+
2273
+
2274
+ def prefer_same_end_extensions(spans: list[dict], thresholds: dict[str, float]) -> list[dict]:
2275
+ if not spans:
2276
+ return spans
2277
+ preferred: list[dict] = []
2278
+ consumed: set[int] = set()
2279
+ for index, span in enumerate(spans):
2280
+ if index in consumed:
2281
+ continue
2282
+ label = span["label"]
2283
+ if label not in {"FIRST_NAME", "LAST_NAME", "EMAIL"}:
2284
+ preferred.append(span)
2285
+ continue
2286
+ same_end = [
2287
+ (other_index, other)
2288
+ for other_index, other in enumerate(spans)
2289
+ if other_index not in consumed and other["label"] == label and other["end"] == span["end"]
2290
+ ]
2291
+ if len(same_end) == 1:
2292
+ preferred.append(span)
2293
+ continue
2294
+ for other_index, _ in same_end:
2295
+ consumed.add(other_index)
2296
+ best_by_score = max(same_end, key=lambda item: float(item[1].get("score", 0.0)))[1]
2297
+ longest = max(same_end, key=lambda item: (item[1]["end"] - item[1]["start"], float(item[1].get("score", 0.0))))[1]
2298
+ longest_score = float(longest.get("score", 0.0))
2299
+ best_score = float(best_by_score.get("score", 0.0))
2300
+ if label == "EMAIL":
2301
+ if "@" in longest.get("text", "") or longest["end"] - longest["start"] > best_by_score["end"] - best_by_score["start"]:
2302
+ if longest_score >= best_score - 0.02:
2303
+ preferred.append(longest)
2304
+ continue
2305
+ else:
2306
+ longest_text = longest.get("text", "")
2307
+ if " " not in longest_text.strip() and longest_score >= max(float(thresholds.get(label, 0.5)) * 0.8, best_score * 0.55):
2308
+ preferred.append(longest)
2309
+ continue
2310
+ preferred.append(best_by_score)
2311
+ return preferred
2312
+
2313
+
2314
+ def prefer_long_structured_spans(spans: list[dict], thresholds: dict[str, float]) -> list[dict]:
2315
+ if not spans:
2316
+ return spans
2317
+ preferred: list[dict] = []
2318
+ consumed: set[int] = set()
2319
+ target_labels = {"STREET_ADDRESS", "DATE_OF_BIRTH"}
2320
+ for index, span in enumerate(spans):
2321
+ if index in consumed:
2322
+ continue
2323
+ label = span["label"]
2324
+ if label not in target_labels:
2325
+ preferred.append(span)
2326
+ continue
2327
+ overlapping = [
2328
+ (other_index, other)
2329
+ for other_index, other in enumerate(spans)
2330
+ if other_index not in consumed and other["label"] == label and spans_overlap(span, other)
2331
+ ]
2332
+ if len(overlapping) == 1:
2333
+ preferred.append(span)
2334
+ continue
2335
+ for other_index, _ in overlapping:
2336
+ consumed.add(other_index)
2337
+ best_by_score = max(overlapping, key=lambda item: float(item[1].get("score", 0.0)))[1]
2338
+ longest = max(
2339
+ overlapping,
2340
+ key=lambda item: (item[1]["end"] - item[1]["start"], float(item[1].get("score", 0.0))),
2341
+ )[1]
2342
+ longest_score = float(longest.get("score", 0.0))
2343
+ best_score = float(best_by_score.get("score", 0.0))
2344
+ threshold = float(thresholds.get(label, 0.5))
2345
+ if longest_score >= max(threshold, best_score * 0.75):
2346
+ preferred.append(longest)
2347
+ else:
2348
+ preferred.append(best_by_score)
2349
+ return preferred
2350
+
2351
+
2352
+ def sigmoid_np(values: np.ndarray) -> np.ndarray:
2353
+ clipped = np.clip(values, -60.0, 60.0)
2354
+ return 1.0 / (1.0 + np.exp(-clipped))
2355
+
2356
+
2357
+ def run_onnx_span(session, encoded: dict[str, Any]) -> np.ndarray:
2358
+ feed = {}
2359
+ input_names = {item.name for item in session.get_inputs()}
2360
+ for key, value in encoded.items():
2361
+ if key == "offset_mapping":
2362
+ continue
2363
+ if key in input_names:
2364
+ feed[key] = value
2365
+ outputs = session.run(None, feed)
2366
+ if not outputs:
2367
+ raise ValueError("ONNX session returned no outputs")
2368
+ return outputs[0]
config.json ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "activation": "gelu",
3
+ "architectures": [
4
+ "IrishCoreGlobalPointerModel"
5
+ ],
6
+ "attention_dropout": 0.1,
7
+ "dim": 768,
8
+ "dropout": 0.1,
9
+ "dtype": "float32",
10
+ "global_pointer_head_size": 64,
11
+ "global_pointer_min_negatives": 256,
12
+ "global_pointer_negative_ratio": 16,
13
+ "global_pointer_use_rope": true,
14
+ "hidden_dim": 3072,
15
+ "id2label": {
16
+ "0": "O",
17
+ "1": "B-account_number",
18
+ "2": "B-age",
19
+ "3": "B-api_key",
20
+ "4": "B-bank_routing_number",
21
+ "5": "B-biometric_identifier",
22
+ "6": "B-blood_type",
23
+ "7": "B-certificate_license_number",
24
+ "8": "B-city",
25
+ "9": "B-company_name",
26
+ "10": "B-coordinate",
27
+ "11": "B-country",
28
+ "12": "B-county",
29
+ "13": "B-credit_debit_card",
30
+ "14": "B-customer_id",
31
+ "15": "B-cvv",
32
+ "16": "B-date",
33
+ "17": "B-date_of_birth",
34
+ "18": "B-date_time",
35
+ "19": "B-device_identifier",
36
+ "20": "B-education_level",
37
+ "21": "B-email",
38
+ "22": "B-employee_id",
39
+ "23": "B-employment_status",
40
+ "24": "B-fax_number",
41
+ "25": "B-first_name",
42
+ "26": "B-gender",
43
+ "27": "B-health_plan_beneficiary_number",
44
+ "28": "B-http_cookie",
45
+ "29": "B-ipv4",
46
+ "30": "B-ipv6",
47
+ "31": "B-language",
48
+ "32": "B-last_name",
49
+ "33": "B-license_plate",
50
+ "34": "B-mac_address",
51
+ "35": "B-medical_record_number",
52
+ "36": "B-occupation",
53
+ "37": "B-password",
54
+ "38": "B-phone_number",
55
+ "39": "B-pin",
56
+ "40": "B-political_view",
57
+ "41": "B-postcode",
58
+ "42": "B-race_ethnicity",
59
+ "43": "B-religious_belief",
60
+ "44": "B-sexuality",
61
+ "45": "B-ssn",
62
+ "46": "B-state",
63
+ "47": "B-street_address",
64
+ "48": "B-swift_bic",
65
+ "49": "B-tax_id",
66
+ "50": "B-time",
67
+ "51": "B-unique_id",
68
+ "52": "B-url",
69
+ "53": "B-user_name",
70
+ "54": "B-vehicle_identifier",
71
+ "55": "I-account_number",
72
+ "56": "I-api_key",
73
+ "57": "I-biometric_identifier",
74
+ "58": "I-blood_type",
75
+ "59": "I-certificate_license_number",
76
+ "60": "I-city",
77
+ "61": "I-company_name",
78
+ "62": "I-coordinate",
79
+ "63": "I-country",
80
+ "64": "I-county",
81
+ "65": "I-credit_debit_card",
82
+ "66": "I-customer_id",
83
+ "67": "I-date",
84
+ "68": "I-date_of_birth",
85
+ "69": "I-date_time",
86
+ "70": "I-device_identifier",
87
+ "71": "I-education_level",
88
+ "72": "I-email",
89
+ "73": "I-employee_id",
90
+ "74": "I-employment_status",
91
+ "75": "I-fax_number",
92
+ "76": "I-first_name",
93
+ "77": "I-gender",
94
+ "78": "I-health_plan_beneficiary_number",
95
+ "79": "I-http_cookie",
96
+ "80": "I-ipv4",
97
+ "81": "I-ipv6",
98
+ "82": "I-language",
99
+ "83": "I-last_name",
100
+ "84": "I-license_plate",
101
+ "85": "I-mac_address",
102
+ "86": "I-medical_record_number",
103
+ "87": "I-occupation",
104
+ "88": "I-password",
105
+ "89": "I-phone_number",
106
+ "90": "I-pin",
107
+ "91": "I-political_view",
108
+ "92": "I-postcode",
109
+ "93": "I-race_ethnicity",
110
+ "94": "I-religious_belief",
111
+ "95": "I-sexuality",
112
+ "96": "I-ssn",
113
+ "97": "I-state",
114
+ "98": "I-street_address",
115
+ "99": "I-swift_bic",
116
+ "100": "I-tax_id",
117
+ "101": "I-time",
118
+ "102": "I-unique_id",
119
+ "103": "I-url",
120
+ "104": "I-user_name",
121
+ "105": "I-vehicle_identifier"
122
+ },
123
+ "initializer_range": 0.02,
124
+ "label2id": {
125
+ "B-account_number": 1,
126
+ "B-age": 2,
127
+ "B-api_key": 3,
128
+ "B-bank_routing_number": 4,
129
+ "B-biometric_identifier": 5,
130
+ "B-blood_type": 6,
131
+ "B-certificate_license_number": 7,
132
+ "B-city": 8,
133
+ "B-company_name": 9,
134
+ "B-coordinate": 10,
135
+ "B-country": 11,
136
+ "B-county": 12,
137
+ "B-credit_debit_card": 13,
138
+ "B-customer_id": 14,
139
+ "B-cvv": 15,
140
+ "B-date": 16,
141
+ "B-date_of_birth": 17,
142
+ "B-date_time": 18,
143
+ "B-device_identifier": 19,
144
+ "B-education_level": 20,
145
+ "B-email": 21,
146
+ "B-employee_id": 22,
147
+ "B-employment_status": 23,
148
+ "B-fax_number": 24,
149
+ "B-first_name": 25,
150
+ "B-gender": 26,
151
+ "B-health_plan_beneficiary_number": 27,
152
+ "B-http_cookie": 28,
153
+ "B-ipv4": 29,
154
+ "B-ipv6": 30,
155
+ "B-language": 31,
156
+ "B-last_name": 32,
157
+ "B-license_plate": 33,
158
+ "B-mac_address": 34,
159
+ "B-medical_record_number": 35,
160
+ "B-occupation": 36,
161
+ "B-password": 37,
162
+ "B-phone_number": 38,
163
+ "B-pin": 39,
164
+ "B-political_view": 40,
165
+ "B-postcode": 41,
166
+ "B-race_ethnicity": 42,
167
+ "B-religious_belief": 43,
168
+ "B-sexuality": 44,
169
+ "B-ssn": 45,
170
+ "B-state": 46,
171
+ "B-street_address": 47,
172
+ "B-swift_bic": 48,
173
+ "B-tax_id": 49,
174
+ "B-time": 50,
175
+ "B-unique_id": 51,
176
+ "B-url": 52,
177
+ "B-user_name": 53,
178
+ "B-vehicle_identifier": 54,
179
+ "I-account_number": 55,
180
+ "I-api_key": 56,
181
+ "I-biometric_identifier": 57,
182
+ "I-blood_type": 58,
183
+ "I-certificate_license_number": 59,
184
+ "I-city": 60,
185
+ "I-company_name": 61,
186
+ "I-coordinate": 62,
187
+ "I-country": 63,
188
+ "I-county": 64,
189
+ "I-credit_debit_card": 65,
190
+ "I-customer_id": 66,
191
+ "I-date": 67,
192
+ "I-date_of_birth": 68,
193
+ "I-date_time": 69,
194
+ "I-device_identifier": 70,
195
+ "I-education_level": 71,
196
+ "I-email": 72,
197
+ "I-employee_id": 73,
198
+ "I-employment_status": 74,
199
+ "I-fax_number": 75,
200
+ "I-first_name": 76,
201
+ "I-gender": 77,
202
+ "I-health_plan_beneficiary_number": 78,
203
+ "I-http_cookie": 79,
204
+ "I-ipv4": 80,
205
+ "I-ipv6": 81,
206
+ "I-language": 82,
207
+ "I-last_name": 83,
208
+ "I-license_plate": 84,
209
+ "I-mac_address": 85,
210
+ "I-medical_record_number": 86,
211
+ "I-occupation": 87,
212
+ "I-password": 88,
213
+ "I-phone_number": 89,
214
+ "I-pin": 90,
215
+ "I-political_view": 91,
216
+ "I-postcode": 92,
217
+ "I-race_ethnicity": 93,
218
+ "I-religious_belief": 94,
219
+ "I-sexuality": 95,
220
+ "I-ssn": 96,
221
+ "I-state": 97,
222
+ "I-street_address": 98,
223
+ "I-swift_bic": 99,
224
+ "I-tax_id": 100,
225
+ "I-time": 101,
226
+ "I-unique_id": 102,
227
+ "I-url": 103,
228
+ "I-user_name": 104,
229
+ "I-vehicle_identifier": 105,
230
+ "O": 0
231
+ },
232
+ "max_position_embeddings": 512,
233
+ "model_type": "distilbert",
234
+ "n_heads": 12,
235
+ "n_layers": 6,
236
+ "num_span_labels": 16,
237
+ "output_past": true,
238
+ "pad_token_id": 0,
239
+ "qa_dropout": 0.1,
240
+ "seq_classif_dropout": 0.2,
241
+ "sinusoidal_pos_embds": false,
242
+ "span_label_max_span_tokens": {
243
+ "ACCOUNT_NUMBER": 19,
244
+ "AGE": 8,
245
+ "BANK_ROUTING_NUMBER": 6,
246
+ "CITY": 8,
247
+ "COUNTY": 8,
248
+ "CREDIT_DEBIT_CARD": 12,
249
+ "DATE_OF_BIRTH": 8,
250
+ "EMAIL": 16,
251
+ "FIRST_NAME": 6,
252
+ "LAST_NAME": 8,
253
+ "PASSPORT_NUMBER": 8,
254
+ "PHONE_NUMBER": 10,
255
+ "POSTCODE": 8,
256
+ "PPSN": 9,
257
+ "STREET_ADDRESS": 10,
258
+ "SWIFT_BIC": 8
259
+ },
260
+ "span_label_min_nonspace_chars": {
261
+ "ACCOUNT_NUMBER": 6,
262
+ "AGE": 1,
263
+ "BANK_ROUTING_NUMBER": 6,
264
+ "CITY": 1,
265
+ "COUNTY": 1,
266
+ "CREDIT_DEBIT_CARD": 12,
267
+ "DATE_OF_BIRTH": 1,
268
+ "EMAIL": 6,
269
+ "FIRST_NAME": 2,
270
+ "LAST_NAME": 2,
271
+ "PASSPORT_NUMBER": 7,
272
+ "PHONE_NUMBER": 7,
273
+ "POSTCODE": 6,
274
+ "PPSN": 8,
275
+ "STREET_ADDRESS": 1,
276
+ "SWIFT_BIC": 8
277
+ },
278
+ "span_label_names": [
279
+ "ACCOUNT_NUMBER",
280
+ "AGE",
281
+ "BANK_ROUTING_NUMBER",
282
+ "CITY",
283
+ "COUNTY",
284
+ "CREDIT_DEBIT_CARD",
285
+ "DATE_OF_BIRTH",
286
+ "EMAIL",
287
+ "FIRST_NAME",
288
+ "LAST_NAME",
289
+ "PASSPORT_NUMBER",
290
+ "PHONE_NUMBER",
291
+ "POSTCODE",
292
+ "PPSN",
293
+ "STREET_ADDRESS",
294
+ "SWIFT_BIC"
295
+ ],
296
+ "span_label_thresholds": {
297
+ "ACCOUNT_NUMBER": 0.5,
298
+ "AGE": 0.5,
299
+ "BANK_ROUTING_NUMBER": 0.5,
300
+ "CITY": 0.5,
301
+ "COUNTY": 0.5,
302
+ "CREDIT_DEBIT_CARD": 0.5,
303
+ "DATE_OF_BIRTH": 0.5,
304
+ "EMAIL": 0.5,
305
+ "FIRST_NAME": 0.5,
306
+ "LAST_NAME": 0.5,
307
+ "PASSPORT_NUMBER": 0.5,
308
+ "PHONE_NUMBER": 0.5,
309
+ "POSTCODE": 0.5,
310
+ "PPSN": 0.5,
311
+ "STREET_ADDRESS": 0.5,
312
+ "SWIFT_BIC": 0.5
313
+ },
314
+ "span_positive_weight": 8.0,
315
+ "tie_weights_": true,
316
+ "transformers_version": "4.57.6",
317
+ "vocab_size": 119547
318
+ }
eval/benchmark_summary.json ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "release": "IrishCore-GlobalPointer-ContextPII-135M-v1-rc20",
3
+ "repo_id": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc20",
4
+ "architecture": {
5
+ "family": "DistilBERT-size GlobalPointer span extractor",
6
+ "base_head": "typed span matrix",
7
+ "raw_only": true,
8
+ "scanner_free": true,
9
+ "validator_free": true,
10
+ "uses_rope": true,
11
+ "runtime_diffusion": false,
12
+ "expanded_context_labels": [
13
+ "STREET_ADDRESS",
14
+ "CITY",
15
+ "COUNTY",
16
+ "DATE_OF_BIRTH",
17
+ "AGE"
18
+ ]
19
+ },
20
+ "base_model": "OpenMed/OpenMed-PII-mLiteClinical-Base-135M-v1",
21
+ "notes": [
22
+ "This release keeps the rc19 weights and ONNX graph but upgrades the bundled decoder and runtime path.",
23
+ "It fixes Gaelic surname-particle name recovery (`Ní Bhroin`, `Nic ...`, apostrophe surnames after self-cues), removes cue-word name fragments such as `Eirchód`, and preserves the broader contextual masking policy.",
24
+ "The q8 CPU path is materially faster than the public rc19 bundle on the aligned suites because span decoding now scans only above-threshold candidates and skips expensive repair passes unless the text actually hints at them.",
25
+ "Fresh unseen contextual holdouts v12, v13, and v14 all score 1.0000 exact F1 on the q8 deployment path.",
26
+ "The legacy `irish_gov_chatbot_redteam_v2` suite remains at 0.9861 because it intentionally treats public-office street/city details as non-PII; this wider contextual release still masks them by design."
27
+ ],
28
+ "labels": [
29
+ "ACCOUNT_NUMBER",
30
+ "AGE",
31
+ "BANK_ROUTING_NUMBER",
32
+ "CITY",
33
+ "COUNTY",
34
+ "CREDIT_DEBIT_CARD",
35
+ "DATE_OF_BIRTH",
36
+ "EMAIL",
37
+ "FIRST_NAME",
38
+ "LAST_NAME",
39
+ "PASSPORT_NUMBER",
40
+ "PHONE_NUMBER",
41
+ "POSTCODE",
42
+ "PPSN",
43
+ "STREET_ADDRESS",
44
+ "SWIFT_BIC"
45
+ ],
46
+ "full": {
47
+ "core_f1": 1.0,
48
+ "extended_f1": 1.0,
49
+ "demographic_holdout_v2_f1": 1.0,
50
+ "contact_policy_f1": 1.0,
51
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
52
+ "chatbot_gap_holdout_v2_f1": 1.0,
53
+ "multilingual_f1": 0.9333333333333333,
54
+ "multilingual_ppsn_label_f1": 1.0,
55
+ "context_redteam_v1_f1": 1.0,
56
+ "context_redteam_v2_f1": 1.0,
57
+ "context_redteam_v3_f1": 1.0,
58
+ "core_examples_per_second": 37.17190773379781,
59
+ "extended_examples_per_second": 22.601031656884402,
60
+ "demographic_holdout_v2_examples_per_second": 56.27516807130541,
61
+ "contact_policy_examples_per_second": 20.47123147395747,
62
+ "chatbot_redteam_v2_examples_per_second": 29.843260084022578,
63
+ "chatbot_gap_holdout_v2_examples_per_second": 37.07473771144438,
64
+ "multilingual_examples_per_second": 58.68937370218514,
65
+ "context_redteam_v1_examples_per_second": 23.609073299571445,
66
+ "context_redteam_v2_examples_per_second": 12.737044489760402,
67
+ "context_redteam_v3_examples_per_second": 17.88102919943181,
68
+ "location_coverage_v1_f1": 1.0,
69
+ "location_coverage_v1_examples_per_second": 27.442453278347067,
70
+ "location_coverage_v2_f1": 1.0,
71
+ "location_coverage_v2_examples_per_second": 24.3613357869789,
72
+ "location_coverage_v3_f1": 1.0,
73
+ "location_coverage_v3_examples_per_second": 35.4459974931921,
74
+ "numeric_qafix_v2_f1": 1.0,
75
+ "numeric_qafix_v2_examples_per_second": 29.420131775628487,
76
+ "context_redteam_v4_f1": 1.0,
77
+ "context_redteam_v4_examples_per_second": 30.495521507704247,
78
+ "context_redteam_v5_f1": 1.0,
79
+ "context_redteam_v5_examples_per_second": 33.33418166561194,
80
+ "context_redteam_v6_f1": 1.0,
81
+ "context_redteam_v6_examples_per_second": 38.82008627943923,
82
+ "context_redteam_v7_f1": 1.0,
83
+ "context_redteam_v7_examples_per_second": 41.1670461610147,
84
+ "context_redteam_v8_f1": 1.0,
85
+ "context_redteam_v8_examples_per_second": 83.67568116564722,
86
+ "context_redteam_v9_f1": 1.0,
87
+ "context_redteam_v9_exact_f1": 1.0,
88
+ "context_redteam_v9_examples_per_second": 88.87266377516937,
89
+ "context_redteam_v10_f1": 1.0,
90
+ "context_redteam_v10_examples_per_second": 88.13695906305226,
91
+ "context_redteam_v11_f1": 1.0,
92
+ "context_redteam_v11_examples_per_second": 86.98335983822658
93
+ },
94
+ "onnx_q8": {
95
+ "core_f1": 1.0,
96
+ "extended_f1": 1.0,
97
+ "demographic_holdout_v2_f1": 1.0,
98
+ "contact_policy_f1": 1.0,
99
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
100
+ "chatbot_gap_holdout_v2_f1": 1.0,
101
+ "multilingual_f1": 0.9333333333333333,
102
+ "multilingual_ppsn_label_f1": 1.0,
103
+ "context_redteam_v1_f1": 1.0,
104
+ "context_redteam_v2_f1": 1.0,
105
+ "context_redteam_v3_f1": 1.0,
106
+ "core_examples_per_second": 181.88206667840814,
107
+ "extended_examples_per_second": 78.77478690814097,
108
+ "demographic_holdout_v2_examples_per_second": 92.56832502112522,
109
+ "contact_policy_examples_per_second": 150.66496558174578,
110
+ "chatbot_redteam_v2_examples_per_second": 117.00163598408656,
111
+ "chatbot_gap_holdout_v2_examples_per_second": 118.2172706176689,
112
+ "multilingual_examples_per_second": 155.21078613421756,
113
+ "context_redteam_v1_examples_per_second": 77.35126547341245,
114
+ "context_redteam_v2_examples_per_second": 83.42976656780596,
115
+ "context_redteam_v3_examples_per_second": 115.78405703667622,
116
+ "location_coverage_v1_f1": 1.0,
117
+ "location_coverage_v1_examples_per_second": 86.67576551780107,
118
+ "location_coverage_v2_f1": 1.0,
119
+ "location_coverage_v2_examples_per_second": 63.49649295628558,
120
+ "location_coverage_v3_f1": 1.0,
121
+ "location_coverage_v3_examples_per_second": 103.87880730624308,
122
+ "numeric_qafix_v2_f1": 1.0,
123
+ "numeric_qafix_v2_examples_per_second": 138.13081928103207,
124
+ "context_redteam_v4_f1": 1.0,
125
+ "context_redteam_v4_examples_per_second": 115.20604478400188,
126
+ "context_redteam_v5_f1": 1.0,
127
+ "context_redteam_v5_examples_per_second": 144.35657204962527,
128
+ "context_redteam_v6_f1": 1.0,
129
+ "context_redteam_v6_examples_per_second": 158.02088849696304,
130
+ "context_redteam_v7_f1": 1.0,
131
+ "context_redteam_v7_examples_per_second": 115.86553627218991,
132
+ "context_redteam_v8_f1": 1.0,
133
+ "context_redteam_v8_examples_per_second": 102.16264190462925,
134
+ "context_redteam_v9_f1": 1.0,
135
+ "context_redteam_v9_exact_f1": 1.0,
136
+ "context_redteam_v9_examples_per_second": 146.4675637488471,
137
+ "context_redteam_v10_f1": 1.0,
138
+ "context_redteam_v10_exact_f1": 1.0,
139
+ "context_redteam_v10_examples_per_second": 106.68196467882363,
140
+ "context_redteam_v11_f1": 1.0,
141
+ "context_redteam_v11_exact_f1": 1.0,
142
+ "context_redteam_v11_examples_per_second": 211.542361065222,
143
+ "context_holdout_v12_exact_f1": 1.0,
144
+ "context_holdout_v12_examples_per_second": 77.68764668742236,
145
+ "context_holdout_v13_exact_f1": 1.0,
146
+ "context_holdout_v13_examples_per_second": 116.31896591646488,
147
+ "context_holdout_v14_exact_f1": 1.0,
148
+ "context_holdout_v14_examples_per_second": 126.55285725261149,
149
+ "runtime_profile_f1": 0.8260363297624592,
150
+ "runtime_profile_examples_per_second": 84.94660779271977
151
+ },
152
+ "comparison": {
153
+ "public_contextpii_rc8_onnx_q8": {
154
+ "core_f1": 1.0,
155
+ "extended_f1": 1.0,
156
+ "contact_policy_f1": 1.0,
157
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
158
+ "multilingual_f1": 0.9333333333333333,
159
+ "multilingual_ppsn_label_f1": 1.0,
160
+ "context_redteam_v2_f1": 1.0,
161
+ "context_redteam_v3_f1": 0.8717948717948718,
162
+ "core_examples_per_second": 128.88250222316304
163
+ },
164
+ "public_contextpii_rc7_onnx_q8": {
165
+ "core_f1": 1.0,
166
+ "contact_policy_f1": 1.0,
167
+ "context_redteam_v2_f1": null,
168
+ "multilingual_f1": 0.9333333333333333,
169
+ "core_examples_per_second": 88.99815744185265
170
+ },
171
+ "public_contextpii_rc4_onnx_q8": {
172
+ "core_f1": 0.9934640522875817,
173
+ "extended_f1": 1.0,
174
+ "demographic_holdout_v2_f1": 1.0,
175
+ "contact_policy_f1": 1.0,
176
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
177
+ "chatbot_gap_holdout_v2_f1": 1.0,
178
+ "multilingual_f1": 0.9333333333333333,
179
+ "multilingual_ppsn_label_f1": 1.0,
180
+ "core_examples_per_second": 61.49696721632529,
181
+ "extended_examples_per_second": 98.75019005245319,
182
+ "demographic_holdout_v2_examples_per_second": 90.7806851088372,
183
+ "contact_policy_examples_per_second": 101.91338377846299,
184
+ "chatbot_redteam_v2_examples_per_second": 13.042183136147377,
185
+ "chatbot_gap_holdout_v2_examples_per_second": 30.728912108647304,
186
+ "multilingual_examples_per_second": 33.54466395109805,
187
+ "location_coverage_v1_f1": null
188
+ },
189
+ "public_diffmask_rc6_onnx_q8": {
190
+ "core_f1": 0.9733333333333333,
191
+ "multilingual_f1": 0.9273743016759777,
192
+ "core_examples_per_second": 130.34154354965295
193
+ },
194
+ "public_globalpointer_rc4_onnx_q8": {
195
+ "core_f1": 1.0,
196
+ "multilingual_f1": 0.9333333333333333,
197
+ "core_examples_per_second": 221.57427241189015
198
+ },
199
+ "public_contextpii_rc9_onnx_q8": {
200
+ "core_f1": 1.0,
201
+ "contact_policy_f1": 1.0,
202
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
203
+ "multilingual_f1": 0.9333333333333333,
204
+ "context_redteam_v4_f1": 0.8533333333333333,
205
+ "core_examples_per_second": 125.82111537540908
206
+ },
207
+ "public_contextpii_rc10_onnx_q8": {
208
+ "core_f1": 1.0,
209
+ "contact_policy_f1": 1.0,
210
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
211
+ "multilingual_f1": 0.9333333333333333,
212
+ "context_redteam_v4_f1": 1.0,
213
+ "core_examples_per_second": 125.82111537540908
214
+ },
215
+ "public_contextpii_rc11_onnx_q8": {
216
+ "core_f1": 1.0,
217
+ "contact_policy_f1": 1.0,
218
+ "chatbot_redteam_v2_f1": 0.9861111111111112,
219
+ "multilingual_f1": 0.9333333333333333,
220
+ "context_redteam_v5_f1": 1.0,
221
+ "core_examples_per_second": 94.09271075291537
222
+ },
223
+ "public_contextpii_rc12_onnx_q8": {
224
+ "core_f1": 1.0,
225
+ "contact_policy_f1": 1.0,
226
+ "chatbot_redteam_v2_f1": 0.9793103448275862,
227
+ "multilingual_f1": 0.9333333333333333,
228
+ "context_redteam_v6_f1": 1.0,
229
+ "core_examples_per_second": 73.59921479476388
230
+ },
231
+ "public_contextpii_rc13_onnx_q8": {
232
+ "core_f1": 1.0,
233
+ "contact_policy_f1": 1.0,
234
+ "chatbot_redteam_v2_f1": 0.9793103448275862,
235
+ "multilingual_f1": 0.9333333333333333,
236
+ "context_redteam_v7_f1": 1.0,
237
+ "core_examples_per_second": 126.08782280133414
238
+ },
239
+ "public_contextpii_rc15_onnx_q8": {
240
+ "repo": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15",
241
+ "core_f1": 1.0,
242
+ "multilingual_f1": 0.9333333333333333,
243
+ "core_examples_per_second": 125.5054
244
+ },
245
+ "public_contextpii_rc16_onnx_q8": {
246
+ "repo": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc16",
247
+ "core_f1": 1.0,
248
+ "multilingual_f1": 0.9333333333333333,
249
+ "core_examples_per_second": 68.0709
250
+ },
251
+ "public_contextpii_rc17_onnx_q8": {
252
+ "repo": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc17",
253
+ "core_f1": 1.0,
254
+ "multilingual_f1": 0.9333333333333333,
255
+ "core_examples_per_second": 70.9494
256
+ },
257
+ "public_contextpii_rc18_onnx_q8": {
258
+ "repo": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc18",
259
+ "core_f1": 1.0,
260
+ "multilingual_f1": 0.9333333333333333,
261
+ "core_examples_per_second": 111.3135
262
+ }
263
+ }
264
+ }
eval/benchmark_summary.md ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # IrishCore-GlobalPointer-ContextPII-135M-v1-rc20
2
+
3
+ ## ONNX q8
4
+
5
+ | Suite | F1 | Examples/s |
6
+ | --- | ---: | ---: |
7
+ | Irish core | 1.0000 | 181.8821 |
8
+ | Irish extended | 1.0000 | 78.7748 |
9
+ | Gov contact policy v1 | 1.0000 | 150.6650 |
10
+ | Gov chatbot red-team v2 | 0.9861 | 117.0016 |
11
+ | Gov chatbot gap holdout v2 | 1.0000 | 118.2173 |
12
+ | Context red-team v11 exact | 1.0000 | 211.5424 |
13
+ | Context holdout v12 exact | 1.0000 | 77.6876 |
14
+ | Context holdout v13 exact | 1.0000 | 116.3190 |
15
+ | Context holdout v14 exact | 1.0000 | 126.5529 |
16
+ | Multilingual PPSN overall | 0.9333 | 155.2108 |
17
+ | Multilingual PPSN label-only | 1.0000 | — |
18
+ | Runtime profile source | 0.8260 | 84.9466 |
eval/full_diffmask_fresh_holdout_v1.json ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "diffmask_fresh_holdout_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 20,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6364284890005365,
9
+ "examples_per_second": 31.425368828803546,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 0.96875,
13
+ "f1": 0.9841269841269841,
14
+ "tp": 31,
15
+ "fp": 0,
16
+ "fn": 1
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 0.5,
22
+ "f1": 0.6666666666666666,
23
+ "tp": 1,
24
+ "fp": 0,
25
+ "fn": 1
26
+ },
27
+ "CREDIT_DEBIT_CARD": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 2,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "EMAIL": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 6,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "FIRST_NAME": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 4,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "LAST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "PHONE_NUMBER": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 6,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "POSTCODE": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PPSN": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 6,
80
+ "fp": 0,
81
+ "fn": 0
82
+ }
83
+ },
84
+ "release_backend": "full"
85
+ }
eval/full_diffmask_gap_uat_exact_v1.json ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "diffmask_gap_uat_exact_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 16,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.549252360011451,
9
+ "examples_per_second": 29.130507513279376,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 17,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "EMAIL": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 3,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "PHONE_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 6,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "POSTCODE": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 3,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "PPSN": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 5,
48
+ "fp": 0,
49
+ "fn": 0
50
+ }
51
+ },
52
+ "release_backend": "full"
53
+ }
eval/full_globalpointer_context_redteam_v1.json ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/globalpointer_context_redteam_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 14,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.5929923560470343,
9
+ "examples_per_second": 23.609073299571445,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 54,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 8,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 10,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 4,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "EMAIL": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "FIRST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "LAST_NAME": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 4,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 8,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 2,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "STREET_ADDRESS": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 8,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ },
108
+ "backend": "full"
109
+ }
eval/full_globalpointer_context_redteam_v10.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc16",
3
+ "input": "eval/globalpointer_context_redteam_v10.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 64,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.7261425930773839,
9
+ "examples_per_second": 88.13695906305226,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 129,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 6,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 28,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 12,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 15,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 6,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 9,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 21,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 7,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 17,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v11.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc17",
3
+ "input": "eval/globalpointer_context_redteam_v11.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 70,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.8047516229562461,
9
+ "examples_per_second": 86.98335983822658,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 140,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 6,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 31,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 13,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 15,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 6,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 9,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 23,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 7,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 22,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v2.json ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/globalpointer_context_redteam_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 6,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.47106689505744725,
9
+ "examples_per_second": 12.737044489760402,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 13,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "CITY": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 4,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "COUNTY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 1,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "DATE_OF_BIRTH": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "PHONE_NUMBER": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 2,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "POSTCODE": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 3,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "STREET_ADDRESS": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ }
67
+ },
68
+ "backend": "full"
69
+ }
eval/full_globalpointer_context_redteam_v3.json ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc10",
3
+ "input": "eval/globalpointer_context_redteam_v3.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 12,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6711023099487647,
9
+ "examples_per_second": 17.88102919943181,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 22,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 3,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 7,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 3,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "PHONE_NUMBER": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 3,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "POSTCODE": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 3,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "STREET_ADDRESS": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ }
75
+ },
76
+ "backend": "full"
77
+ }
eval/full_globalpointer_context_redteam_v4.json ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc10",
3
+ "input": "eval/globalpointer_context_redteam_v4.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 21,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6886257050791755,
9
+ "examples_per_second": 30.495521507704247,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 43,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 3,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 10,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 6,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 2,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 6,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 6,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 2,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 5,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ },
100
+ "backend": "full"
101
+ }
eval/full_globalpointer_context_redteam_v5.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/globalpointer_context_redteam_v5.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 25,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.7499809130094945,
9
+ "examples_per_second": 33.33418166561194,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 47,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 3,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 10,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 8,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 2,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 6,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 2,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 5,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v6.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/globalpointer_context_redteam_v6.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 38,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.9788746919948608,
9
+ "examples_per_second": 38.82008627943923,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 72,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 5,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 14,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 10,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 7,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 10,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 4,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 9,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v7.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/globalpointer_context_redteam_v7.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 41,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.9959422359243035,
9
+ "examples_per_second": 41.1670461610147,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 84,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 5,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 17,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 4,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 10,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 7,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 13,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 4,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 12,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v8.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc14",
3
+ "input": "eval/globalpointer_context_redteam_v8.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 51,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6094960840418935,
9
+ "examples_per_second": 83.67568116564722,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 113,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 5,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 25,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 10,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 10,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 6,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 9,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 19,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 6,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 15,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v9.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15",
3
+ "input": "eval/globalpointer_context_redteam_v9.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 60,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6751232319511473,
9
+ "examples_per_second": 88.87266377516937,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 118,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 6,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 25,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 10,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 14,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 6,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 9,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 19,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 6,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 15,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_context_redteam_v9_exact.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc15",
3
+ "input": "eval/globalpointer_context_redteam_v9.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 60,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 1.0,
8
+ "elapsed_seconds": 0.6622731270035729,
9
+ "examples_per_second": 90.59706268238226,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 118,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 6,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 25,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 10,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 14,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 6,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 9,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 8,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 19,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 6,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "STREET_ADDRESS": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 15,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ }
100
+ }
eval/full_globalpointer_demographic_patch_v2_test.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/globalpointer_demographic_patch_v2_test.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 600,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 10.661896189092658,
9
+ "examples_per_second": 56.27516807130541,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 2470,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 287,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 286,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 286,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 304,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "EMAIL": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 85,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "FIRST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 194,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "LAST_NAME": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 194,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 177,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 286,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 85,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "STREET_ADDRESS": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 286,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ }
108
+ }
eval/full_globalpointer_location_coverage_v1.json ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/globalpointer_location_coverage_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 18,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6559180339099839,
9
+ "examples_per_second": 27.442453278347067,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 56,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "CITY": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 14,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "COUNTY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 16,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "PHONE_NUMBER": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 2,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "POSTCODE": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 12,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "STREET_ADDRESS": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 12,
56
+ "fp": 0,
57
+ "fn": 0
58
+ }
59
+ },
60
+ "backend": "full"
61
+ }
eval/full_globalpointer_location_coverage_v2.json ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/globalpointer_location_coverage_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 24,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.9851676529506221,
9
+ "examples_per_second": 24.3613357869789,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 68,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "CITY": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 20,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "COUNTY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 22,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "PHONE_NUMBER": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 2,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "POSTCODE": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 12,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "STREET_ADDRESS": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 12,
56
+ "fp": 0,
57
+ "fn": 0
58
+ }
59
+ },
60
+ "backend": "full"
61
+ }
eval/full_globalpointer_location_coverage_v3.json ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/globalpointer_location_coverage_v3.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 30,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.8463578999508172,
9
+ "examples_per_second": 35.4459974931921,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 82,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "CITY": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 26,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "COUNTY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 28,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "PHONE_NUMBER": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 2,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "POSTCODE": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 13,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "STREET_ADDRESS": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 13,
56
+ "fp": 0,
57
+ "fn": 0
58
+ }
59
+ },
60
+ "backend": "full"
61
+ }
eval/full_irish_core_pii_v1.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_core_pii_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 37,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.9953753319568932,
9
+ "examples_per_second": 37.17190773379781,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 76,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 3,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "BANK_ROUTING_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 1,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "CREDIT_DEBIT_CARD": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 2,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "EMAIL": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 6,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 19,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 19,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PASSPORT_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 12,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 4,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 6,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "SWIFT_BIC": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 2,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ }
108
+ }
eval/full_irish_dllm_hardening_exact_v1.json ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "irish_dllm_hardening_exact_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 14,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.5248716080095619,
9
+ "examples_per_second": 26.673189759856385,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 20,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 1,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "BANK_ROUTING_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 2,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "CREDIT_DEBIT_CARD": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 2,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "EMAIL": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 2,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 1,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 1,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PHONE_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "POSTCODE": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 3,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "PPSN": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 3,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "SWIFT_BIC": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 3,
96
+ "fp": 0,
97
+ "fn": 0
98
+ }
99
+ },
100
+ "release_backend": "full"
101
+ }
eval/full_irish_extended_pii_v1.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_extended_pii_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 14,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6194407499860972,
9
+ "examples_per_second": 22.601031656884402,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 50,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 5,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 8,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 6,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 6,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "EMAIL": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 1,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "FIRST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "LAST_NAME": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 2,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 8,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 2,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "STREET_ADDRESS": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 8,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ }
108
+ }
eval/full_irish_gov_chatbot_gap_holdout_v1.json ADDED
@@ -0,0 +1,258 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "family": "globalpointer",
4
+ "backend": "pt",
5
+ "input": "irish_gov_chatbot_gap_holdout_v1.jsonl",
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "overall": {
9
+ "precision": 1.0,
10
+ "recall": 1.0,
11
+ "f1": 1.0,
12
+ "tp": 413,
13
+ "fp": 0,
14
+ "fn": 0
15
+ },
16
+ "exact": {
17
+ "precision": 0.9878934624697336,
18
+ "recall": 0.9878934624697336,
19
+ "f1": 0.9878934624697336,
20
+ "tp": 408,
21
+ "fp": 5,
22
+ "fn": 5
23
+ },
24
+ "by_label": {
25
+ "ACCOUNT_NUMBER": {
26
+ "precision": 1.0,
27
+ "recall": 1.0,
28
+ "f1": 1.0,
29
+ "tp": 16,
30
+ "fp": 0,
31
+ "fn": 0
32
+ },
33
+ "BANK_ROUTING_NUMBER": {
34
+ "precision": 1.0,
35
+ "recall": 1.0,
36
+ "f1": 1.0,
37
+ "tp": 23,
38
+ "fp": 0,
39
+ "fn": 0
40
+ },
41
+ "CREDIT_DEBIT_CARD": {
42
+ "precision": 1.0,
43
+ "recall": 1.0,
44
+ "f1": 1.0,
45
+ "tp": 6,
46
+ "fp": 0,
47
+ "fn": 0
48
+ },
49
+ "EMAIL": {
50
+ "precision": 1.0,
51
+ "recall": 1.0,
52
+ "f1": 1.0,
53
+ "tp": 50,
54
+ "fp": 0,
55
+ "fn": 0
56
+ },
57
+ "FIRST_NAME": {
58
+ "precision": 1.0,
59
+ "recall": 1.0,
60
+ "f1": 1.0,
61
+ "tp": 70,
62
+ "fp": 0,
63
+ "fn": 0
64
+ },
65
+ "LAST_NAME": {
66
+ "precision": 1.0,
67
+ "recall": 1.0,
68
+ "f1": 1.0,
69
+ "tp": 70,
70
+ "fp": 0,
71
+ "fn": 0
72
+ },
73
+ "PHONE_NUMBER": {
74
+ "precision": 1.0,
75
+ "recall": 1.0,
76
+ "f1": 1.0,
77
+ "tp": 72,
78
+ "fp": 0,
79
+ "fn": 0
80
+ },
81
+ "POSTCODE": {
82
+ "precision": 1.0,
83
+ "recall": 1.0,
84
+ "f1": 1.0,
85
+ "tp": 18,
86
+ "fp": 0,
87
+ "fn": 0
88
+ },
89
+ "PPSN": {
90
+ "precision": 1.0,
91
+ "recall": 1.0,
92
+ "f1": 1.0,
93
+ "tp": 72,
94
+ "fp": 0,
95
+ "fn": 0
96
+ },
97
+ "SWIFT_BIC": {
98
+ "precision": 1.0,
99
+ "recall": 1.0,
100
+ "f1": 1.0,
101
+ "tp": 16,
102
+ "fp": 0,
103
+ "fn": 0
104
+ }
105
+ },
106
+ "by_language": {
107
+ "en": {
108
+ "precision": 1.0,
109
+ "recall": 1.0,
110
+ "f1": 1.0,
111
+ "tp": 230,
112
+ "fp": 0,
113
+ "fn": 0
114
+ },
115
+ "ga": {
116
+ "precision": 1.0,
117
+ "recall": 1.0,
118
+ "f1": 1.0,
119
+ "tp": 183,
120
+ "fp": 0,
121
+ "fn": 0
122
+ }
123
+ },
124
+ "by_role": {
125
+ "assistant": {
126
+ "precision": 1.0,
127
+ "recall": 1.0,
128
+ "f1": 1.0,
129
+ "tp": 72,
130
+ "fp": 0,
131
+ "fn": 0
132
+ },
133
+ "mixed": {
134
+ "precision": 0.0,
135
+ "recall": 0.0,
136
+ "f1": 0.0,
137
+ "tp": 0,
138
+ "fp": 0,
139
+ "fn": 0
140
+ },
141
+ "user": {
142
+ "precision": 1.0,
143
+ "recall": 1.0,
144
+ "f1": 1.0,
145
+ "tp": 341,
146
+ "fp": 0,
147
+ "fn": 0
148
+ }
149
+ },
150
+ "by_source_type": {
151
+ "assistant_contact_echo_en": {
152
+ "precision": 1.0,
153
+ "recall": 1.0,
154
+ "f1": 1.0,
155
+ "tp": 32,
156
+ "fp": 0,
157
+ "fn": 0
158
+ },
159
+ "assistant_contact_echo_ga": {
160
+ "precision": 1.0,
161
+ "recall": 1.0,
162
+ "f1": 1.0,
163
+ "tp": 40,
164
+ "fp": 0,
165
+ "fn": 0
166
+ },
167
+ "negative_en": {
168
+ "precision": 0.0,
169
+ "recall": 0.0,
170
+ "f1": 0.0,
171
+ "tp": 0,
172
+ "fp": 0,
173
+ "fn": 0
174
+ },
175
+ "negative_ga": {
176
+ "precision": 0.0,
177
+ "recall": 0.0,
178
+ "f1": 0.0,
179
+ "tp": 0,
180
+ "fp": 0,
181
+ "fn": 0
182
+ },
183
+ "user_card_email_en": {
184
+ "precision": 1.0,
185
+ "recall": 1.0,
186
+ "f1": 1.0,
187
+ "tp": 12,
188
+ "fp": 0,
189
+ "fn": 0
190
+ },
191
+ "user_name_email_ppsn_phone_en": {
192
+ "precision": 1.0,
193
+ "recall": 1.0,
194
+ "f1": 1.0,
195
+ "tp": 80,
196
+ "fp": 0,
197
+ "fn": 0
198
+ },
199
+ "user_name_email_ppsn_phone_ga": {
200
+ "precision": 1.0,
201
+ "recall": 1.0,
202
+ "f1": 1.0,
203
+ "tp": 50,
204
+ "fp": 0,
205
+ "fn": 0
206
+ },
207
+ "user_name_ppsn_phone_en": {
208
+ "precision": 1.0,
209
+ "recall": 1.0,
210
+ "f1": 1.0,
211
+ "tp": 56,
212
+ "fp": 0,
213
+ "fn": 0
214
+ },
215
+ "user_name_ppsn_phone_ga": {
216
+ "precision": 1.0,
217
+ "recall": 1.0,
218
+ "f1": 1.0,
219
+ "tp": 56,
220
+ "fp": 0,
221
+ "fn": 0
222
+ },
223
+ "user_payment_name_en": {
224
+ "precision": 1.0,
225
+ "recall": 1.0,
226
+ "f1": 1.0,
227
+ "tp": 32,
228
+ "fp": 0,
229
+ "fn": 0
230
+ },
231
+ "user_payment_name_ga": {
232
+ "precision": 1.0,
233
+ "recall": 1.0,
234
+ "f1": 1.0,
235
+ "tp": 32,
236
+ "fp": 0,
237
+ "fn": 0
238
+ },
239
+ "user_sort_code_en": {
240
+ "precision": 1.0,
241
+ "recall": 1.0,
242
+ "f1": 1.0,
243
+ "tp": 18,
244
+ "fp": 0,
245
+ "fn": 0
246
+ },
247
+ "user_sort_code_ga": {
248
+ "precision": 1.0,
249
+ "recall": 1.0,
250
+ "f1": 1.0,
251
+ "tp": 5,
252
+ "fp": 0,
253
+ "fn": 0
254
+ }
255
+ },
256
+ "failure_count": 0,
257
+ "failures": []
258
+ }
eval/full_irish_gov_chatbot_gap_holdout_v2.json ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_gov_chatbot_gap_holdout_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 160,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 4.31560706498567,
9
+ "examples_per_second": 37.07473771144438,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 652,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 38,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "EMAIL": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 104,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "FIRST_NAME": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 68,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "LAST_NAME": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 68,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "PASSPORT_NUMBER": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 33,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "PHONE_NUMBER": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 101,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "POSTCODE": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 101,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PPSN": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 101,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "SWIFT_BIC": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 38,
88
+ "fp": 0,
89
+ "fn": 0
90
+ }
91
+ }
92
+ }
eval/full_irish_gov_chatbot_redteam_assistant_v2.json ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_gov_chatbot_redteam_assistant_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 9,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.16110201692208648,
9
+ "examples_per_second": 55.86522237243408,
10
+ "overall": {
11
+ "precision": 0.9375,
12
+ "recall": 1.0,
13
+ "f1": 0.967741935483871,
14
+ "tp": 30,
15
+ "fp": 2,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "EMAIL": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 6,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "FIRST_NAME": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 2,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "LAST_NAME": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 2,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "PHONE_NUMBER": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 8,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "POSTCODE": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 4,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PPSN": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 4,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "SWIFT_BIC": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 2,
80
+ "fp": 0,
81
+ "fn": 0
82
+ }
83
+ }
84
+ }
eval/full_irish_gov_chatbot_redteam_user_v2.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_gov_chatbot_redteam_user_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 10,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.1798157700104639,
9
+ "examples_per_second": 55.612474920403685,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 41,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "BANK_ROUTING_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 1,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "CREDIT_DEBIT_CARD": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "EMAIL": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 4,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 5,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 5,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PASSPORT_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 9,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 3,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 7,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "SWIFT_BIC": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 2,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ }
108
+ }
eval/full_irish_gov_chatbot_redteam_v1.json ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "family": "globalpointer",
4
+ "backend": "pt",
5
+ "input": "irish_gov_chatbot_redteam_v1.jsonl",
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "overall": {
9
+ "precision": 1.0,
10
+ "recall": 1.0,
11
+ "f1": 1.0,
12
+ "tp": 161,
13
+ "fp": 0,
14
+ "fn": 0
15
+ },
16
+ "exact": {
17
+ "precision": 1.0,
18
+ "recall": 1.0,
19
+ "f1": 1.0,
20
+ "tp": 161,
21
+ "fp": 0,
22
+ "fn": 0
23
+ },
24
+ "by_label": {
25
+ "ACCOUNT_NUMBER": {
26
+ "precision": 1.0,
27
+ "recall": 1.0,
28
+ "f1": 1.0,
29
+ "tp": 9,
30
+ "fp": 0,
31
+ "fn": 0
32
+ },
33
+ "BANK_ROUTING_NUMBER": {
34
+ "precision": 1.0,
35
+ "recall": 1.0,
36
+ "f1": 1.0,
37
+ "tp": 3,
38
+ "fp": 0,
39
+ "fn": 0
40
+ },
41
+ "CREDIT_DEBIT_CARD": {
42
+ "precision": 1.0,
43
+ "recall": 1.0,
44
+ "f1": 1.0,
45
+ "tp": 3,
46
+ "fp": 0,
47
+ "fn": 0
48
+ },
49
+ "EMAIL": {
50
+ "precision": 1.0,
51
+ "recall": 1.0,
52
+ "f1": 1.0,
53
+ "tp": 16,
54
+ "fp": 0,
55
+ "fn": 0
56
+ },
57
+ "FIRST_NAME": {
58
+ "precision": 1.0,
59
+ "recall": 1.0,
60
+ "f1": 1.0,
61
+ "tp": 18,
62
+ "fp": 0,
63
+ "fn": 0
64
+ },
65
+ "LAST_NAME": {
66
+ "precision": 1.0,
67
+ "recall": 1.0,
68
+ "f1": 1.0,
69
+ "tp": 18,
70
+ "fp": 0,
71
+ "fn": 0
72
+ },
73
+ "PASSPORT_NUMBER": {
74
+ "precision": 1.0,
75
+ "recall": 1.0,
76
+ "f1": 1.0,
77
+ "tp": 4,
78
+ "fp": 0,
79
+ "fn": 0
80
+ },
81
+ "PHONE_NUMBER": {
82
+ "precision": 1.0,
83
+ "recall": 1.0,
84
+ "f1": 1.0,
85
+ "tp": 36,
86
+ "fp": 0,
87
+ "fn": 0
88
+ },
89
+ "POSTCODE": {
90
+ "precision": 1.0,
91
+ "recall": 1.0,
92
+ "f1": 1.0,
93
+ "tp": 11,
94
+ "fp": 0,
95
+ "fn": 0
96
+ },
97
+ "PPSN": {
98
+ "precision": 1.0,
99
+ "recall": 1.0,
100
+ "f1": 1.0,
101
+ "tp": 34,
102
+ "fp": 0,
103
+ "fn": 0
104
+ },
105
+ "SWIFT_BIC": {
106
+ "precision": 1.0,
107
+ "recall": 1.0,
108
+ "f1": 1.0,
109
+ "tp": 9,
110
+ "fp": 0,
111
+ "fn": 0
112
+ }
113
+ },
114
+ "by_language": {
115
+ "en": {
116
+ "precision": 1.0,
117
+ "recall": 1.0,
118
+ "f1": 1.0,
119
+ "tp": 99,
120
+ "fp": 0,
121
+ "fn": 0
122
+ },
123
+ "ga": {
124
+ "precision": 1.0,
125
+ "recall": 1.0,
126
+ "f1": 1.0,
127
+ "tp": 62,
128
+ "fp": 0,
129
+ "fn": 0
130
+ }
131
+ },
132
+ "by_role": {
133
+ "assistant": {
134
+ "precision": 1.0,
135
+ "recall": 1.0,
136
+ "f1": 1.0,
137
+ "tp": 56,
138
+ "fp": 0,
139
+ "fn": 0
140
+ },
141
+ "mixed": {
142
+ "precision": 0.0,
143
+ "recall": 0.0,
144
+ "f1": 0.0,
145
+ "tp": 0,
146
+ "fp": 0,
147
+ "fn": 0
148
+ },
149
+ "user": {
150
+ "precision": 1.0,
151
+ "recall": 1.0,
152
+ "f1": 1.0,
153
+ "tp": 105,
154
+ "fp": 0,
155
+ "fn": 0
156
+ }
157
+ },
158
+ "by_source_type": {
159
+ "assistant_centre_block_en": {
160
+ "precision": 1.0,
161
+ "recall": 1.0,
162
+ "f1": 1.0,
163
+ "tp": 2,
164
+ "fp": 0,
165
+ "fn": 0
166
+ },
167
+ "assistant_contact_block_en": {
168
+ "precision": 1.0,
169
+ "recall": 1.0,
170
+ "f1": 1.0,
171
+ "tp": 2,
172
+ "fp": 0,
173
+ "fn": 0
174
+ },
175
+ "assistant_contact_ga": {
176
+ "precision": 1.0,
177
+ "recall": 1.0,
178
+ "f1": 1.0,
179
+ "tp": 2,
180
+ "fp": 0,
181
+ "fn": 0
182
+ },
183
+ "assistant_echo_user_en": {
184
+ "precision": 1.0,
185
+ "recall": 1.0,
186
+ "f1": 1.0,
187
+ "tp": 15,
188
+ "fp": 0,
189
+ "fn": 0
190
+ },
191
+ "assistant_echo_user_ga": {
192
+ "precision": 1.0,
193
+ "recall": 1.0,
194
+ "f1": 1.0,
195
+ "tp": 15,
196
+ "fp": 0,
197
+ "fn": 0
198
+ },
199
+ "assistant_location_en": {
200
+ "precision": 1.0,
201
+ "recall": 1.0,
202
+ "f1": 1.0,
203
+ "tp": 12,
204
+ "fp": 0,
205
+ "fn": 0
206
+ },
207
+ "assistant_mailbox_en": {
208
+ "precision": 1.0,
209
+ "recall": 1.0,
210
+ "f1": 1.0,
211
+ "tp": 2,
212
+ "fp": 0,
213
+ "fn": 0
214
+ },
215
+ "assistant_payment_en": {
216
+ "precision": 1.0,
217
+ "recall": 1.0,
218
+ "f1": 1.0,
219
+ "tp": 6,
220
+ "fp": 0,
221
+ "fn": 0
222
+ },
223
+ "negative_date_en": {
224
+ "precision": 0.0,
225
+ "recall": 0.0,
226
+ "f1": 0.0,
227
+ "tp": 0,
228
+ "fp": 0,
229
+ "fn": 0
230
+ },
231
+ "negative_date_ga": {
232
+ "precision": 0.0,
233
+ "recall": 0.0,
234
+ "f1": 0.0,
235
+ "tp": 0,
236
+ "fp": 0,
237
+ "fn": 0
238
+ },
239
+ "negative_direct_debit_en": {
240
+ "precision": 0.0,
241
+ "recall": 0.0,
242
+ "f1": 0.0,
243
+ "tp": 0,
244
+ "fp": 0,
245
+ "fn": 0
246
+ },
247
+ "negative_hours_en": {
248
+ "precision": 0.0,
249
+ "recall": 0.0,
250
+ "f1": 0.0,
251
+ "tp": 0,
252
+ "fp": 0,
253
+ "fn": 0
254
+ },
255
+ "negative_long_ppsn_en": {
256
+ "precision": 0.0,
257
+ "recall": 0.0,
258
+ "f1": 0.0,
259
+ "tp": 0,
260
+ "fp": 0,
261
+ "fn": 0
262
+ },
263
+ "negative_scheme_ga": {
264
+ "precision": 0.0,
265
+ "recall": 0.0,
266
+ "f1": 0.0,
267
+ "tp": 0,
268
+ "fp": 0,
269
+ "fn": 0
270
+ },
271
+ "negative_short_ppsn_en": {
272
+ "precision": 0.0,
273
+ "recall": 0.0,
274
+ "f1": 0.0,
275
+ "tp": 0,
276
+ "fp": 0,
277
+ "fn": 0
278
+ },
279
+ "negative_year_letter_ga": {
280
+ "precision": 0.0,
281
+ "recall": 0.0,
282
+ "f1": 0.0,
283
+ "tp": 0,
284
+ "fp": 0,
285
+ "fn": 0
286
+ },
287
+ "user_allowance_mixed_en": {
288
+ "precision": 1.0,
289
+ "recall": 1.0,
290
+ "f1": 1.0,
291
+ "tp": 24,
292
+ "fp": 0,
293
+ "fn": 0
294
+ },
295
+ "user_allowance_mixed_ga": {
296
+ "precision": 1.0,
297
+ "recall": 1.0,
298
+ "f1": 1.0,
299
+ "tp": 24,
300
+ "fp": 0,
301
+ "fn": 0
302
+ },
303
+ "user_bare_ppsn_en": {
304
+ "precision": 1.0,
305
+ "recall": 1.0,
306
+ "f1": 1.0,
307
+ "tp": 6,
308
+ "fp": 0,
309
+ "fn": 0
310
+ },
311
+ "user_bare_ppsn_ga": {
312
+ "precision": 1.0,
313
+ "recall": 1.0,
314
+ "f1": 1.0,
315
+ "tp": 6,
316
+ "fp": 0,
317
+ "fn": 0
318
+ },
319
+ "user_card_email_en": {
320
+ "precision": 1.0,
321
+ "recall": 1.0,
322
+ "f1": 1.0,
323
+ "tp": 6,
324
+ "fp": 0,
325
+ "fn": 0
326
+ },
327
+ "user_passport_en": {
328
+ "precision": 1.0,
329
+ "recall": 1.0,
330
+ "f1": 1.0,
331
+ "tp": 12,
332
+ "fp": 0,
333
+ "fn": 0
334
+ },
335
+ "user_payment_en": {
336
+ "precision": 1.0,
337
+ "recall": 1.0,
338
+ "f1": 1.0,
339
+ "tp": 12,
340
+ "fp": 0,
341
+ "fn": 0
342
+ },
343
+ "user_payment_ga": {
344
+ "precision": 1.0,
345
+ "recall": 1.0,
346
+ "f1": 1.0,
347
+ "tp": 12,
348
+ "fp": 0,
349
+ "fn": 0
350
+ },
351
+ "user_sort_code_ga": {
352
+ "precision": 1.0,
353
+ "recall": 1.0,
354
+ "f1": 1.0,
355
+ "tp": 3,
356
+ "fp": 0,
357
+ "fn": 0
358
+ }
359
+ },
360
+ "failure_count": 0,
361
+ "failures": []
362
+ }
eval/full_irish_gov_chatbot_redteam_v2.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_gov_chatbot_redteam_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 25,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.8377100869547576,
9
+ "examples_per_second": 29.843260084022578,
10
+ "overall": {
11
+ "precision": 0.9726027397260274,
12
+ "recall": 1.0,
13
+ "f1": 0.9861111111111112,
14
+ "tp": 71,
15
+ "fp": 2,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 4,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "BANK_ROUTING_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 1,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "CREDIT_DEBIT_CARD": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 1,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "EMAIL": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 10,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "FIRST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 7,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "LAST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 7,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "PASSPORT_NUMBER": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 17,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 7,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 11,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "SWIFT_BIC": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 4,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ }
108
+ }
eval/full_irish_gov_contact_policy_v1.json ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_gov_contact_policy_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 12,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.586188476998359,
9
+ "examples_per_second": 20.47123147395747,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 30,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "CITY": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 4,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "COUNTY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 2,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "DATE_OF_BIRTH": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 4,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "EMAIL": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 4,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "PHONE_NUMBER": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 8,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "POSTCODE": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 4,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "STREET_ADDRESS": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 4,
72
+ "fp": 0,
73
+ "fn": 0
74
+ }
75
+ }
76
+ }
eval/full_irish_numeric_qafix_v2.json ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/irish_numeric_qafix_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 19,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.6458162779454142,
9
+ "examples_per_second": 29.420131775628487,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 14,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "BANK_ROUTING_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 5,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "PASSPORT_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 5,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "PHONE_NUMBER": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 4,
40
+ "fp": 0,
41
+ "fn": 0
42
+ }
43
+ },
44
+ "backend": "full"
45
+ }
eval/full_irish_ppsn_phone_edge_v1.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "irish_ppsn_phone_edge_v1.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 22,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.41967142606154084,
9
+ "examples_per_second": 52.42196307349719,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 19,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "PHONE_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 13,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "PPSN": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 6,
32
+ "fp": 0,
33
+ "fn": 0
34
+ }
35
+ },
36
+ "release_backend": "full"
37
+ }
eval/full_irish_remaining_gaps_v2.json ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/irish_remaining_gaps_v2.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 6,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.08656914997845888,
9
+ "examples_per_second": 69.30875492589436,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 5,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "PASSPORT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "PHONE_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 3,
32
+ "fp": 0,
33
+ "fn": 0
34
+ }
35
+ }
36
+ }
eval/full_multilingual_ppsn_v1_all.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "models/irishcore-globalpointer-135m-b01-extendedv1-e025",
3
+ "input": "eval/multilingual_ppsn_v1_all.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 168,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 2.862528417026624,
9
+ "examples_per_second": 58.68937370218514,
10
+ "overall": {
11
+ "precision": 0.875,
12
+ "recall": 1.0,
13
+ "f1": 0.9333333333333333,
14
+ "tp": 84,
15
+ "fp": 12,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "PPSN": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 84,
24
+ "fp": 0,
25
+ "fn": 0
26
+ }
27
+ }
28
+ }
eval/full_runtime_profile_source.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "runtime_profile_source.jsonl",
4
+ "loader_type": "global_pointer_pt",
5
+ "examples": 3223,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 46.959111439064145,
9
+ "examples_per_second": 68.63417771825351,
10
+ "overall": {
11
+ "precision": 0.585127996749289,
12
+ "recall": 0.40597688187200454,
13
+ "f1": 0.47936085219707064,
14
+ "tp": 1440,
15
+ "fp": 1021,
16
+ "fn": 2107
17
+ },
18
+ "by_label": {
19
+ "PPSN": {
20
+ "precision": 0.9320388349514563,
21
+ "recall": 0.40597688187200454,
22
+ "f1": 0.5655930871956009,
23
+ "tp": 1440,
24
+ "fp": 105,
25
+ "fn": 2107
26
+ }
27
+ },
28
+ "release_backend": "full"
29
+ }
eval/label_inventory.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "labels": [
3
+ "ACCOUNT_NUMBER",
4
+ "AGE",
5
+ "BANK_ROUTING_NUMBER",
6
+ "CITY",
7
+ "COUNTY",
8
+ "CREDIT_DEBIT_CARD",
9
+ "DATE_OF_BIRTH",
10
+ "EMAIL",
11
+ "FIRST_NAME",
12
+ "LAST_NAME",
13
+ "PASSPORT_NUMBER",
14
+ "PHONE_NUMBER",
15
+ "POSTCODE",
16
+ "PPSN",
17
+ "STREET_ADDRESS",
18
+ "SWIFT_BIC"
19
+ ]
20
+ }
eval/q8_diffmask_fresh_holdout_v1.json ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "diffmask_fresh_holdout_v1.jsonl",
4
+ "loader_type": "global_pointer_onnx",
5
+ "examples": 20,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.13704864599276334,
9
+ "examples_per_second": 145.93358332818605,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 0.96875,
13
+ "f1": 0.9841269841269841,
14
+ "tp": 31,
15
+ "fp": 0,
16
+ "fn": 1
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 0.5,
22
+ "f1": 0.6666666666666666,
23
+ "tp": 1,
24
+ "fp": 0,
25
+ "fn": 1
26
+ },
27
+ "CREDIT_DEBIT_CARD": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 2,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "EMAIL": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 6,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "FIRST_NAME": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 4,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "LAST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "PHONE_NUMBER": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 6,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "POSTCODE": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PPSN": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 6,
80
+ "fp": 0,
81
+ "fn": 0
82
+ }
83
+ },
84
+ "release_backend": "onnx_q8"
85
+ }
eval/q8_diffmask_gap_uat_exact_v1.json ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc1",
3
+ "input": "diffmask_gap_uat_exact_v1.jsonl",
4
+ "loader_type": "global_pointer_onnx",
5
+ "examples": 16,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.08481148700229824,
9
+ "examples_per_second": 188.65369026681998,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 17,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "EMAIL": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 3,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "PHONE_NUMBER": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 6,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "POSTCODE": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 3,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "PPSN": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 5,
48
+ "fp": 0,
49
+ "fn": 0
50
+ }
51
+ },
52
+ "release_backend": "onnx_q8"
53
+ }
eval/q8_globalpointer_context_holdout_v12_exact.json ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19",
3
+ "input": "eval/globalpointer_context_holdout_v12.jsonl",
4
+ "loader_type": "global_pointer_onnx",
5
+ "examples": 22,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 1.0,
8
+ "elapsed_seconds": 0.2831853060051799,
9
+ "examples_per_second": 77.68764668742236,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 60,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "ACCOUNT_NUMBER": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "AGE": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 2,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "CITY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 8,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "COUNTY": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 8,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "CREDIT_DEBIT_CARD": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 2,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "DATE_OF_BIRTH": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 4,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "EMAIL": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 4,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "FIRST_NAME": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 4,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "LAST_NAME": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 4,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PASSPORT_NUMBER": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 2,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "PHONE_NUMBER": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 6,
104
+ "fp": 0,
105
+ "fn": 0
106
+ },
107
+ "POSTCODE": {
108
+ "precision": 1.0,
109
+ "recall": 1.0,
110
+ "f1": 1.0,
111
+ "tp": 6,
112
+ "fp": 0,
113
+ "fn": 0
114
+ },
115
+ "PPSN": {
116
+ "precision": 1.0,
117
+ "recall": 1.0,
118
+ "f1": 1.0,
119
+ "tp": 2,
120
+ "fp": 0,
121
+ "fn": 0
122
+ },
123
+ "STREET_ADDRESS": {
124
+ "precision": 1.0,
125
+ "recall": 1.0,
126
+ "f1": 1.0,
127
+ "tp": 4,
128
+ "fp": 0,
129
+ "fn": 0
130
+ },
131
+ "SWIFT_BIC": {
132
+ "precision": 1.0,
133
+ "recall": 1.0,
134
+ "f1": 1.0,
135
+ "tp": 2,
136
+ "fp": 0,
137
+ "fn": 0
138
+ }
139
+ }
140
+ }
eval/q8_globalpointer_context_holdout_v13_exact.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19",
3
+ "input": "eval/globalpointer_context_holdout_v13.jsonl",
4
+ "loader_type": "global_pointer_onnx",
5
+ "examples": 10,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 1.0,
8
+ "elapsed_seconds": 0.08597050292883068,
9
+ "examples_per_second": 116.31896591646488,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 36,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 6,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 6,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 2,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "EMAIL": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "FIRST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "LAST_NAME": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 2,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 4,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 2,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "STREET_ADDRESS": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 4,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ }
108
+ }
eval/q8_globalpointer_context_holdout_v14_exact.json ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "release/IrishCore-GlobalPointer-ContextPII-135M-v1-rc19",
3
+ "input": "eval/globalpointer_context_holdout_v14.jsonl",
4
+ "loader_type": "global_pointer_onnx",
5
+ "examples": 10,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 1.0,
8
+ "elapsed_seconds": 0.07901836605742574,
9
+ "examples_per_second": 126.55285725261149,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 42,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 1,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "DATE_OF_BIRTH": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 1,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "EMAIL": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 5,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "FIRST_NAME": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 8,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "LAST_NAME": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 8,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "PHONE_NUMBER": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 6,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "POSTCODE": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 4,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PPSN": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 9,
80
+ "fp": 0,
81
+ "fn": 0
82
+ }
83
+ }
84
+ }
eval/q8_globalpointer_context_redteam_v1.json ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model": "temsa/IrishCore-GlobalPointer-ContextPII-135M-v1-rc9",
3
+ "input": "eval/globalpointer_context_redteam_v1.jsonl",
4
+ "loader_type": "global_pointer_onnx",
5
+ "examples": 14,
6
+ "min_score": 0.5,
7
+ "iou_threshold": 0.5,
8
+ "elapsed_seconds": 0.1809925140114501,
9
+ "examples_per_second": 77.35126547341245,
10
+ "overall": {
11
+ "precision": 1.0,
12
+ "recall": 1.0,
13
+ "f1": 1.0,
14
+ "tp": 54,
15
+ "fp": 0,
16
+ "fn": 0
17
+ },
18
+ "by_label": {
19
+ "AGE": {
20
+ "precision": 1.0,
21
+ "recall": 1.0,
22
+ "f1": 1.0,
23
+ "tp": 2,
24
+ "fp": 0,
25
+ "fn": 0
26
+ },
27
+ "CITY": {
28
+ "precision": 1.0,
29
+ "recall": 1.0,
30
+ "f1": 1.0,
31
+ "tp": 8,
32
+ "fp": 0,
33
+ "fn": 0
34
+ },
35
+ "COUNTY": {
36
+ "precision": 1.0,
37
+ "recall": 1.0,
38
+ "f1": 1.0,
39
+ "tp": 10,
40
+ "fp": 0,
41
+ "fn": 0
42
+ },
43
+ "DATE_OF_BIRTH": {
44
+ "precision": 1.0,
45
+ "recall": 1.0,
46
+ "f1": 1.0,
47
+ "tp": 4,
48
+ "fp": 0,
49
+ "fn": 0
50
+ },
51
+ "EMAIL": {
52
+ "precision": 1.0,
53
+ "recall": 1.0,
54
+ "f1": 1.0,
55
+ "tp": 4,
56
+ "fp": 0,
57
+ "fn": 0
58
+ },
59
+ "FIRST_NAME": {
60
+ "precision": 1.0,
61
+ "recall": 1.0,
62
+ "f1": 1.0,
63
+ "tp": 2,
64
+ "fp": 0,
65
+ "fn": 0
66
+ },
67
+ "LAST_NAME": {
68
+ "precision": 1.0,
69
+ "recall": 1.0,
70
+ "f1": 1.0,
71
+ "tp": 2,
72
+ "fp": 0,
73
+ "fn": 0
74
+ },
75
+ "PHONE_NUMBER": {
76
+ "precision": 1.0,
77
+ "recall": 1.0,
78
+ "f1": 1.0,
79
+ "tp": 4,
80
+ "fp": 0,
81
+ "fn": 0
82
+ },
83
+ "POSTCODE": {
84
+ "precision": 1.0,
85
+ "recall": 1.0,
86
+ "f1": 1.0,
87
+ "tp": 8,
88
+ "fp": 0,
89
+ "fn": 0
90
+ },
91
+ "PPSN": {
92
+ "precision": 1.0,
93
+ "recall": 1.0,
94
+ "f1": 1.0,
95
+ "tp": 2,
96
+ "fp": 0,
97
+ "fn": 0
98
+ },
99
+ "STREET_ADDRESS": {
100
+ "precision": 1.0,
101
+ "recall": 1.0,
102
+ "f1": 1.0,
103
+ "tp": 8,
104
+ "fp": 0,
105
+ "fn": 0
106
+ }
107
+ },
108
+ "backend": "onnx_q8"
109
+ }