SqueakyCleanText 0.5.1__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {squeakycleantext-0.5.1/SqueakyCleanText.egg-info → squeakycleantext-0.6.0}/PKG-INFO +241 -102
- squeakycleantext-0.5.1/PKG-INFO → squeakycleantext-0.6.0/README.md +202 -140
- squeakycleantext-0.5.1/README.md → squeakycleantext-0.6.0/SqueakyCleanText.egg-info/PKG-INFO +279 -72
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/SqueakyCleanText.egg-info/SOURCES.txt +4 -0
- squeakycleantext-0.6.0/SqueakyCleanText.egg-info/requires.txt +58 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/pyproject.toml +46 -30
- squeakycleantext-0.6.0/sct/__init__.py +13 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/config.py +171 -26
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/sct.py +119 -27
- squeakycleantext-0.6.0/sct/utils/anonymization_map.py +89 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/contact.py +18 -0
- squeakycleantext-0.6.0/sct/utils/gliclass_adapter.py +114 -0
- squeakycleantext-0.6.0/sct/utils/gliner_adapter.py +191 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/ner.py +113 -15
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/normtext.py +2 -1
- squeakycleantext-0.6.0/sct/utils/process_result.py +67 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/resources.py +45 -10
- squeakycleantext-0.6.0/sct/utils/synthetic.py +125 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/tests/test_sct.py +755 -3
- squeakycleantext-0.5.1/SqueakyCleanText.egg-info/requires.txt +0 -46
- squeakycleantext-0.5.1/sct/__init__.py +0 -7
- squeakycleantext-0.5.1/sct/utils/gliner_adapter.py +0 -110
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/LICENSE +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/SqueakyCleanText.egg-info/dependency_links.txt +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/SqueakyCleanText.egg-info/top_level.txt +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/__init__.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/constants.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/datetime.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/onnx_pipeline.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/special.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/stopwords.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/sct/utils/torch_pipeline.py +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/setup.cfg +0 -0
- {squeakycleantext-0.5.1 → squeakycleantext-0.6.0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: SqueakyCleanText
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Text preprocessing & PII anonymization pipeline for NLP/ML: ONNX NER ensemble, language detection, stopword removal, and configurable token replacement.
|
|
5
5
|
Author: Rehan Fazal
|
|
6
6
|
License: MIT
|
|
@@ -8,6 +8,7 @@ Project-URL: Homepage, https://github.com/rhnfzl/SqueakyCleanText
|
|
|
8
8
|
Project-URL: Repository, https://github.com/rhnfzl/SqueakyCleanText
|
|
9
9
|
Project-URL: Issues, https://github.com/rhnfzl/SqueakyCleanText/issues
|
|
10
10
|
Project-URL: Changelog, https://github.com/rhnfzl/SqueakyCleanText/releases
|
|
11
|
+
Project-URL: llms.txt, https://github.com/rhnfzl/SqueakyCleanText/blob/main/llms.txt
|
|
11
12
|
Keywords: text cleaning,text preprocessing,NLP,natural language processing,named entity recognition,NER,anonymization,PII removal,data cleaning,machine learning,ONNX,language detection
|
|
12
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
13
14
|
Classifier: Intended Audience :: Developers
|
|
@@ -26,44 +27,52 @@ Classifier: Operating System :: OS Independent
|
|
|
26
27
|
Requires-Python: >=3.11
|
|
27
28
|
Description-Content-Type: text/markdown
|
|
28
29
|
License-File: LICENSE
|
|
29
|
-
Requires-Dist: lingua-language-detector>=2.0
|
|
30
|
+
Requires-Dist: lingua-language-detector>=2.1.0
|
|
30
31
|
Requires-Dist: stop-words>=2025.11.4
|
|
31
|
-
Requires-Dist: emoji>=2.
|
|
32
|
-
Requires-Dist: ftfy>=6.
|
|
33
|
-
Requires-Dist: Unidecode>=1.
|
|
34
|
-
Requires-Dist: beautifulsoup4>=4.
|
|
35
|
-
Requires-Dist: onnxruntime>=1.24.
|
|
36
|
-
Requires-Dist: tokenizers>=0.22.
|
|
37
|
-
Requires-Dist: huggingface-hub>=1.
|
|
38
|
-
Requires-Dist: numpy>=2.
|
|
39
|
-
Requires-Dist: presidio_anonymizer>=2.2.
|
|
40
|
-
Requires-Dist: regex>=2024.
|
|
32
|
+
Requires-Dist: emoji>=2.14
|
|
33
|
+
Requires-Dist: ftfy>=6.3
|
|
34
|
+
Requires-Dist: Unidecode>=1.4
|
|
35
|
+
Requires-Dist: beautifulsoup4>=4.14
|
|
36
|
+
Requires-Dist: onnxruntime>=1.24.2
|
|
37
|
+
Requires-Dist: tokenizers>=0.22.2
|
|
38
|
+
Requires-Dist: huggingface-hub>=1.5.0
|
|
39
|
+
Requires-Dist: numpy>=2.2.0
|
|
40
|
+
Requires-Dist: presidio_anonymizer>=2.2.360
|
|
41
|
+
Requires-Dist: regex>=2024.11.6
|
|
41
42
|
Provides-Extra: gpu
|
|
42
|
-
Requires-Dist: onnxruntime-gpu>=1.24.
|
|
43
|
+
Requires-Dist: onnxruntime-gpu>=1.24.2; extra == "gpu"
|
|
43
44
|
Provides-Extra: fuzzy
|
|
44
|
-
Requires-Dist: rapidfuzz>=3.
|
|
45
|
+
Requires-Dist: rapidfuzz>=3.12; extra == "fuzzy"
|
|
45
46
|
Provides-Extra: torch
|
|
46
|
-
Requires-Dist: torch>=2.
|
|
47
|
-
Requires-Dist: transformers>=4.
|
|
47
|
+
Requires-Dist: torch>=2.6.0; extra == "torch"
|
|
48
|
+
Requires-Dist: transformers>=4.48; extra == "torch"
|
|
48
49
|
Provides-Extra: gliner
|
|
49
|
-
Requires-Dist: gliner
|
|
50
|
+
Requires-Dist: gliner<1.0,>=0.2.25; extra == "gliner"
|
|
50
51
|
Provides-Extra: gliner2
|
|
51
|
-
Requires-Dist: gliner2
|
|
52
|
+
Requires-Dist: gliner2<2.0,>=1.0; extra == "gliner2"
|
|
53
|
+
Provides-Extra: synthetic
|
|
54
|
+
Requires-Dist: faker>=33.0; extra == "synthetic"
|
|
55
|
+
Provides-Extra: presidio
|
|
56
|
+
Requires-Dist: presidio-analyzer>=2.2.360; extra == "presidio"
|
|
57
|
+
Provides-Extra: classify
|
|
58
|
+
Requires-Dist: gliclass>=0.1.16; extra == "classify"
|
|
59
|
+
Provides-Extra: classify-onnx
|
|
60
|
+
Requires-Dist: onnxruntime>=1.24.2; extra == "classify-onnx"
|
|
52
61
|
Provides-Extra: all-ner
|
|
53
|
-
Requires-Dist: torch>=2.
|
|
54
|
-
Requires-Dist: transformers>=4.
|
|
55
|
-
Requires-Dist: gliner
|
|
56
|
-
Requires-Dist: gliner2
|
|
62
|
+
Requires-Dist: torch>=2.6.0; extra == "all-ner"
|
|
63
|
+
Requires-Dist: transformers>=4.48; extra == "all-ner"
|
|
64
|
+
Requires-Dist: gliner<1.0,>=0.2.25; extra == "all-ner"
|
|
65
|
+
Requires-Dist: gliner2<2.0,>=1.0; extra == "all-ner"
|
|
57
66
|
Provides-Extra: dev
|
|
58
|
-
Requires-Dist: hypothesis>=6.
|
|
59
|
-
Requires-Dist: faker>=
|
|
60
|
-
Requires-Dist: ruff>=0.
|
|
61
|
-
Requires-Dist: pytest>=8.
|
|
62
|
-
Requires-Dist: pytest-timeout>=2.
|
|
63
|
-
Requires-Dist: rapidfuzz>=3.
|
|
67
|
+
Requires-Dist: hypothesis>=6.130; extra == "dev"
|
|
68
|
+
Requires-Dist: faker>=33.0; extra == "dev"
|
|
69
|
+
Requires-Dist: ruff>=0.11; extra == "dev"
|
|
70
|
+
Requires-Dist: pytest>=8.3; extra == "dev"
|
|
71
|
+
Requires-Dist: pytest-timeout>=2.3; extra == "dev"
|
|
72
|
+
Requires-Dist: rapidfuzz>=3.12; extra == "dev"
|
|
64
73
|
Provides-Extra: test
|
|
65
|
-
Requires-Dist: coverage>=7.
|
|
66
|
-
Requires-Dist: pytest-cov>=
|
|
74
|
+
Requires-Dist: coverage>=7.8; extra == "test"
|
|
75
|
+
Requires-Dist: pytest-cov>=6.0; extra == "test"
|
|
67
76
|
Dynamic: license-file
|
|
68
77
|
|
|
69
78
|
<div align="center">
|
|
@@ -79,11 +88,11 @@ Dynamic: license-file
|
|
|
79
88
|
A comprehensive text cleaning and preprocessing pipeline for machine learning and NLP tasks.
|
|
80
89
|
</div>
|
|
81
90
|
|
|
82
|
-
> **Using an AI coding assistant?** This repo includes an [`llms.txt`](
|
|
91
|
+
> **Using an AI coding assistant?** This repo includes an [`llms.txt`](https://github.com/rhnfzl/SqueakyCleanText/blob/main/llms.txt) with the full API surface, config reference, and Q&A - optimised for Claude, Cursor, Copilot, and ChatGPT.
|
|
83
92
|
|
|
84
93
|
In the world of machine learning and natural language processing, clean and well-structured text data is crucial for building effective downstream models and managing token limits in language models.
|
|
85
94
|
|
|
86
|
-
SqueakyCleanText simplifies the process by automatically addressing common text issues
|
|
95
|
+
SqueakyCleanText simplifies the process by automatically addressing common text issues - removing PII, anonymizing named entities (persons, organisations, locations), and ensuring your data is clean and well-structured for language models and classical ML pipelines with minimal effort on your part.
|
|
87
96
|
|
|
88
97
|
### Key Features
|
|
89
98
|
|
|
@@ -156,7 +165,7 @@ SqueakyCleanText simplifies the process by automatically addressing common text
|
|
|
156
165
|
pip install SqueakyCleanText
|
|
157
166
|
```
|
|
158
167
|
|
|
159
|
-
The base install uses **ONNX Runtime** for NER inference
|
|
168
|
+
The base install uses **ONNX Runtime** for NER inference - no PyTorch or Transformers required.
|
|
160
169
|
|
|
161
170
|
### Optional Extras
|
|
162
171
|
|
|
@@ -167,6 +176,9 @@ The base install uses **ONNX Runtime** for NER inference — no PyTorch or Trans
|
|
|
167
176
|
| PyTorch NER | `pip install SqueakyCleanText[torch]` | PyTorch/Transformers NER backend |
|
|
168
177
|
| GLiNER | `pip install SqueakyCleanText[gliner]` | [GLiNER](https://github.com/urchade/GLiNER) zero-shot NER |
|
|
169
178
|
| GLiNER2 | `pip install SqueakyCleanText[gliner2]` | [GLiNER2](https://github.com/Knowledgator/GLiNER) (knowledgator) backend |
|
|
179
|
+
| Synthetic | `pip install SqueakyCleanText[synthetic]` | Faker-based synthetic replacement (realistic fake values instead of `<TAG>` tokens) |
|
|
180
|
+
| Presidio | `pip install SqueakyCleanText[presidio]` | Presidio-analyzer for `presidio_gliner` backend |
|
|
181
|
+
| Classify | `pip install SqueakyCleanText[classify]` | GLiClass document-level pre-classification |
|
|
170
182
|
| All NER | `pip install SqueakyCleanText[all-ner]` | All NER backends combined |
|
|
171
183
|
| Development | `pip install SqueakyCleanText[dev]` | Testing and linting tools |
|
|
172
184
|
|
|
@@ -211,7 +223,7 @@ cfg = TextCleanerConfig(
|
|
|
211
223
|
replace_with_url="<URL>",
|
|
212
224
|
replace_with_email="<EMAIL>",
|
|
213
225
|
replace_with_phone_numbers="<PHONE>",
|
|
214
|
-
language="
|
|
226
|
+
language="en", # Pin to English (also accepts 'ENGLISH', 'eng')
|
|
215
227
|
)
|
|
216
228
|
|
|
217
229
|
# Initialize with config
|
|
@@ -231,7 +243,7 @@ cfg = TextCleanerConfig(
|
|
|
231
243
|
gliner_labels=('person', 'organization', 'location', 'product', 'event'),
|
|
232
244
|
gliner_label_map={
|
|
233
245
|
'person': 'PER', 'organization': 'ORG', 'location': 'LOC',
|
|
234
|
-
# 'product' and 'event' are unmapped
|
|
246
|
+
# 'product' and 'event' are unmapped - they become <PRODUCT>, <EVENT> tokens
|
|
235
247
|
},
|
|
236
248
|
gliner_threshold=0.4,
|
|
237
249
|
)
|
|
@@ -261,6 +273,144 @@ cleaner = TextCleaner(cfg=cfg)
|
|
|
261
273
|
lm_text, stat_text, lang = cleaner.process("Angela Merkel visited the Bundestag in Berlin.")
|
|
262
274
|
```
|
|
263
275
|
|
|
276
|
+
### PII Detection Mode
|
|
277
|
+
|
|
278
|
+
Automatically configure GLiNER for comprehensive PII detection with 60+ entity types (personal, financial, healthcare, identity, digital):
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
from sct import TextCleaner, TextCleanerConfig
|
|
282
|
+
|
|
283
|
+
cfg = TextCleanerConfig(ner_mode='pii')
|
|
284
|
+
|
|
285
|
+
cleaner = TextCleaner(cfg=cfg)
|
|
286
|
+
lm_text, stat_text, lang = cleaner.process(
|
|
287
|
+
"John Smith's SSN is 123-45-6789, email john@example.com, DOB 1990-01-15"
|
|
288
|
+
)
|
|
289
|
+
# Entities are anonymized: names, SSNs, emails, dates of birth, and 50+ more PII types
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
PII mode auto-configures: `ner_backend='gliner'`, uses [`knowledgator/gliner-pii-base-v1.0`](https://huggingface.co/knowledgator/gliner-pii-base-v1.0), sets threshold to 0.3 (recall-focused), and expands positional tags. User-provided values always take priority.
|
|
293
|
+
|
|
294
|
+
**Alternative PII models** (pass as `gliner_model`):
|
|
295
|
+
|
|
296
|
+
| Model | Type | Size | Labels | F1 |
|
|
297
|
+
|-------|------|------|--------|-----|
|
|
298
|
+
| [`knowledgator/gliner-pii-base-v1.0`](https://huggingface.co/knowledgator/gliner-pii-base-v1.0) | Uni-encoder | 330MB (ONNX FP16) | 60+ | 80.99% |
|
|
299
|
+
| [`nvidia/gliner-PII`](https://huggingface.co/nvidia/gliner-PII) | Bi-encoder | 570MB | 55+ | — |
|
|
300
|
+
| [`gretelai/gretel-gliner-bi-base-v1.0`](https://huggingface.co/gretelai/gretel-gliner-bi-base-v1.0) | Bi-encoder | ~800MB | 40+ | 95% |
|
|
301
|
+
| [`urchade/gliner_multi_pii-v1`](https://huggingface.co/urchade/gliner_multi_pii-v1) | Multilingual | — | — | — |
|
|
302
|
+
|
|
303
|
+
### Synthetic Replacement
|
|
304
|
+
|
|
305
|
+
Replace detected entities with realistic fake values (via [Faker](https://faker.readthedocs.io/)) instead of `<TAG>` placeholder tokens:
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
from sct import TextCleaner, TextCleanerConfig
|
|
309
|
+
|
|
310
|
+
cfg = TextCleanerConfig(
|
|
311
|
+
ner_mode='pii',
|
|
312
|
+
replacement_mode='synthetic', # pip install squeakycleantext[synthetic]
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
cleaner = TextCleaner(cfg=cfg)
|
|
316
|
+
lm_text, stat_text, lang = cleaner.process(
|
|
317
|
+
"Contact John Smith at john.smith@company.com or +1-555-0123"
|
|
318
|
+
)
|
|
319
|
+
# Output: "Contact Jennifer Williams at lisa45@example.net or +1-555-0198"
|
|
320
|
+
# Same entity always maps to same fake value within a document
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
> **Note**: Synthetic replacement preserves data utility for downstream ML tasks but is NOT GDPR-compliant anonymization. Same-document consistency is maintained (same entity text always maps to the same fake value).
|
|
324
|
+
|
|
325
|
+
### Reversible Anonymization
|
|
326
|
+
|
|
327
|
+
Replace entities with indexed placeholders (`<PERSON_0>`, `<LOCATION_1>`) and get a mapping for round-trip deanonymization:
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
from sct import TextCleaner, TextCleanerConfig
|
|
331
|
+
|
|
332
|
+
cfg = TextCleanerConfig(
|
|
333
|
+
ner_mode='pii',
|
|
334
|
+
replacement_mode='reversible',
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
cleaner = TextCleaner(cfg=cfg)
|
|
338
|
+
result = cleaner.process("John Smith works at Google in London.")
|
|
339
|
+
|
|
340
|
+
print(result.lm_text)
|
|
341
|
+
# "<PERSON_0> works at <ORGANISATION_0> in <LOCATION_0>."
|
|
342
|
+
|
|
343
|
+
# Access the anonymization map via metadata
|
|
344
|
+
anon_map = result.metadata['anon_map']
|
|
345
|
+
restored = anon_map.deanonymize(result.lm_text)
|
|
346
|
+
# "John Smith works at Google in London."
|
|
347
|
+
|
|
348
|
+
# Serialize the map for storage
|
|
349
|
+
import json
|
|
350
|
+
json.dumps(anon_map.to_dict())
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
> **Note**: `ProcessResult` from `process()` unpacks as a 3-tuple (`lm_text, stat_text, language`) for backward compatibility, but also exposes `.metadata` for reversible maps and document classification.
|
|
354
|
+
|
|
355
|
+
### Document Classification (GLiClass)
|
|
356
|
+
|
|
357
|
+
Classify documents before processing using zero-shot classification with [GLiClass](https://github.com/Knowledgator/GLiClass):
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
from sct import TextCleaner, TextCleanerConfig
|
|
361
|
+
|
|
362
|
+
cfg = TextCleanerConfig(
|
|
363
|
+
check_classify_document=True,
|
|
364
|
+
gliclass_labels=('email', 'code', 'legal', 'medical'),
|
|
365
|
+
# gliclass_model defaults to 'knowledgator/gliclass-edge-v3.0' (32.7M params)
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
cleaner = TextCleaner(cfg=cfg) # pip install squeakycleantext[classify]
|
|
369
|
+
result = cleaner.process("Dear Sir, please find attached the contract...")
|
|
370
|
+
|
|
371
|
+
# Classification results in metadata
|
|
372
|
+
print(result.metadata['classes'])
|
|
373
|
+
# [{"label": "email", "score": 0.92}, {"label": "legal", "score": 0.78}]
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### Bi-Encoder GLiNER Models
|
|
377
|
+
|
|
378
|
+
Bi-encoder models (ModernBERT, etc.) are auto-detected and leverage pre-computed label embeddings for faster inference with larger context windows:
|
|
379
|
+
|
|
380
|
+
```python
|
|
381
|
+
from sct import TextCleaner, TextCleanerConfig
|
|
382
|
+
|
|
383
|
+
cfg = TextCleanerConfig(
|
|
384
|
+
ner_backend='gliner',
|
|
385
|
+
gliner_model='knowledgator/gliner-bi-base-v2.0',
|
|
386
|
+
gliner_labels=('person', 'organization', 'location'),
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
cleaner = TextCleaner(cfg=cfg)
|
|
390
|
+
# Auto-detects bi-encoder → caches label embeddings → uses 2048+ token context window
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Entity Description Labels (ZERONER-Style)
|
|
394
|
+
|
|
395
|
+
Provide natural-language descriptions for labels to improve zero-shot recognition accuracy:
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
from sct import TextCleaner, TextCleanerConfig
|
|
399
|
+
|
|
400
|
+
cfg = TextCleanerConfig(
|
|
401
|
+
ner_backend='gliner',
|
|
402
|
+
gliner_model='knowledgator/gliner-bi-base-v2.0',
|
|
403
|
+
gliner_label_descriptions={
|
|
404
|
+
'person': "a person's full legal name",
|
|
405
|
+
'location': "a geographical place or address",
|
|
406
|
+
'organization': "a company, institution, or government body",
|
|
407
|
+
},
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
cleaner = TextCleaner(cfg=cfg)
|
|
411
|
+
# Descriptions are used for inference, results are mapped back to original label names
|
|
412
|
+
```
|
|
413
|
+
|
|
264
414
|
### Batch Processing
|
|
265
415
|
|
|
266
416
|
```python
|
|
@@ -317,15 +467,16 @@ cleaner = sct.TextCleaner()
|
|
|
317
467
|
|
|
318
468
|
## NER Backends
|
|
319
469
|
|
|
320
|
-
SqueakyCleanText supports
|
|
470
|
+
SqueakyCleanText supports six NER backends, selectable via the `ner_backend` config field:
|
|
321
471
|
|
|
322
472
|
| Backend | Description | Dependencies | Best for |
|
|
323
473
|
|---------|-------------|-------------|----------|
|
|
324
|
-
| `onnx` (default) | ONNX Runtime inference with quantized XLM-RoBERTa models | Base install | Production
|
|
474
|
+
| `onnx` (default) | ONNX Runtime inference with quantized XLM-RoBERTa models | Base install | Production: fast, torch-free |
|
|
325
475
|
| `torch` | PyTorch/Transformers pipeline with full XLM-RoBERTa models | `[torch]` extra | Compatibility with existing PyTorch workflows |
|
|
326
|
-
| `gliner` | GLiNER zero-shot NER with custom entity labels | `[gliner]` or `[gliner2]` extra | Custom entity types
|
|
476
|
+
| `gliner` | GLiNER zero-shot NER with custom entity labels | `[gliner]` or `[gliner2]` extra | Custom entity types, PII detection, bi-encoder models |
|
|
327
477
|
| `ensemble_onnx` | ONNX + GLiNER ensemble voting | `[gliner]` extra | Maximum recall with custom entities |
|
|
328
478
|
| `ensemble_torch` | Torch + GLiNER ensemble voting | `[torch,gliner]` extra | Maximum recall with PyTorch |
|
|
479
|
+
| `presidio_gliner` | Presidio + GLiNER recognizer (beta) | `presidio-analyzer`, `[gliner]` | Context-aware NER via Presidio's pipeline |
|
|
329
480
|
|
|
330
481
|
### Default NER Models (ONNX)
|
|
331
482
|
|
|
@@ -338,6 +489,17 @@ SqueakyCleanText supports five NER backends, selectable via the `ner_backend` co
|
|
|
338
489
|
| French / Portuguese / Italian | [`rhnfzl/wikineural-multilingual-ner-onnx`](https://huggingface.co/rhnfzl/wikineural-multilingual-ner-onnx) (shared session) |
|
|
339
490
|
| Multilingual (fallback) | [`rhnfzl/wikineural-multilingual-ner-onnx`](https://huggingface.co/rhnfzl/wikineural-multilingual-ner-onnx) |
|
|
340
491
|
|
|
492
|
+
### GLiNER Model Recommendations
|
|
493
|
+
|
|
494
|
+
| Model | Architecture | Context | Languages | Best for |
|
|
495
|
+
|-------|-------------|---------|-----------|----------|
|
|
496
|
+
| `knowledgator/gliner-bi-base-v2.0` | Bi-encoder (ModernBERT) | 2048 | Multi | General NER, long documents |
|
|
497
|
+
| `knowledgator/gliner-pii-base-v1.0` | Bi-encoder | 2048 | Multi | PII detection (60+ entity types) |
|
|
498
|
+
| `urchade/gliner_large-v2.1` | Uni-encoder (DeBERTa) | 512 | Multi | Legacy, high accuracy on short texts |
|
|
499
|
+
| `MatteoFasulo/ModernBERT-base-NER` | ModernBERT | 8192 | English | English-only, very long context |
|
|
500
|
+
|
|
501
|
+
> **GLiNER2 note**: `pip install squeakycleantext[gliner2]` installs [Knowledgator's gliner2 package](https://github.com/Knowledgator/GLiNER), not Fastino AI's GLiNER2 from EMNLP 2025 (different API).
|
|
502
|
+
|
|
341
503
|
### GLiNER Label Mapping
|
|
342
504
|
|
|
343
505
|
GLiNER uses lowercase free-text labels (e.g., `'person'`, `'product'`). To map them to standard NER tags used by the anonymizer, use `gliner_label_map`:
|
|
@@ -448,7 +610,9 @@ new_cfg = dataclasses.replace(cfg, check_ner_process=False)
|
|
|
448
610
|
|
|
449
611
|
| Field | Default | Description |
|
|
450
612
|
|-------|---------|-------------|
|
|
451
|
-
| `ner_backend` | `'onnx'` | Backend: `onnx`, `torch`, `gliner`, `ensemble_onnx`, `ensemble_torch` |
|
|
613
|
+
| `ner_backend` | `'onnx'` | Backend: `onnx`, `torch`, `gliner`, `ensemble_onnx`, `ensemble_torch`, `presidio_gliner` |
|
|
614
|
+
| `ner_mode` | `'standard'` | `'standard'` or `'pii'` (auto-configures GLiNER for PII detection) |
|
|
615
|
+
| `replacement_mode` | `'placeholder'` | `'placeholder'`, `'synthetic'` (Faker), or `'reversible'` (indexed placeholders + deanonymize map) |
|
|
452
616
|
| `positional_tags` | `('PER', 'LOC', 'ORG', 'MISC')` | Entity types to recognize |
|
|
453
617
|
| `ner_confidence_threshold` | `0.85` | Minimum confidence score |
|
|
454
618
|
| `ner_batch_size` | `8` | Inference batch size (must be >= 1) |
|
|
@@ -459,6 +623,7 @@ new_cfg = dataclasses.replace(cfg, check_ner_process=False)
|
|
|
459
623
|
| `gliner_labels` | `('person', 'organization', 'location')` | GLiNER entity labels |
|
|
460
624
|
| `gliner_label_map` | `None` | Maps GLiNER labels to NER tags |
|
|
461
625
|
| `gliner_threshold` | `0.4` | GLiNER confidence threshold |
|
|
626
|
+
| `gliner_label_descriptions` | `None` | ZERONER-style: `{label: "description"}` for improved zero-shot accuracy |
|
|
462
627
|
| `fuzzy_date_score_cutoff` | `85` | Fuzzy matching threshold (0-100) for misspelled months |
|
|
463
628
|
| `custom_pipeline_steps` | `()` | Tuple of `(text: str) -> str` callables appended after all built-in steps |
|
|
464
629
|
|
|
@@ -466,8 +631,8 @@ new_cfg = dataclasses.replace(cfg, check_ner_process=False)
|
|
|
466
631
|
|
|
467
632
|
| Field | Default | Description |
|
|
468
633
|
|-------|---------|-------------|
|
|
469
|
-
| `language` | `None` | Pin language (
|
|
470
|
-
| `extra_languages` | `()` | Additional language names for detection |
|
|
634
|
+
| `language` | `None` | Pin language (`'en'`), restrict detection to a set (`('en','nl')`), or `None` for auto-detect. Accepts Lingua names, ISO 639-1, ISO 639-3 codes. |
|
|
635
|
+
| `extra_languages` | `()` | Additional language names/codes for detection |
|
|
471
636
|
| `custom_stopwords` | `None` | `{LANG: frozenset({...})}` custom stopword sets |
|
|
472
637
|
| `custom_month_names` | `None` | `{LANG: ('Jan', 'Feb', ...)}` for date detection |
|
|
473
638
|
|
|
@@ -506,69 +671,43 @@ Input Text
|
|
|
506
671
|
(lm_text, stat_text, language)
|
|
507
672
|
```
|
|
508
673
|
|
|
509
|
-
Each step is toggled by a `TextCleanerConfig` field. The pipeline is built once at initialization
|
|
510
|
-
|
|
511
|
-
## What's New
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
**
|
|
516
|
-
- `
|
|
517
|
-
- `
|
|
518
|
-
- `
|
|
519
|
-
|
|
520
|
-
**
|
|
521
|
-
-
|
|
522
|
-
-
|
|
523
|
-
|
|
524
|
-
**
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
-
|
|
531
|
-
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
Major release with architectural overhaul since v0.3.0:
|
|
539
|
-
|
|
540
|
-
**Architecture**
|
|
541
|
-
- Frozen `TextCleanerConfig` dataclass replaces global mutable config (thread-safe, per-instance)
|
|
542
|
-
- ONNX-first NER inference — torch-free base install (~400MB models vs ~7GB)
|
|
543
|
-
- Thread-parallel batch processing via `ThreadPoolExecutor` (ONNX releases the GIL)
|
|
544
|
-
|
|
545
|
-
**NER**
|
|
546
|
-
- 5 backends: `onnx`, `torch`, `gliner`, `ensemble_onnx`, `ensemble_torch`
|
|
674
|
+
Each step is toggled by a `TextCleanerConfig` field. The pipeline is built once at initialization; disabled steps are skipped entirely (zero overhead).
|
|
675
|
+
|
|
676
|
+
## What's New
|
|
677
|
+
|
|
678
|
+
**v0.6.0**
|
|
679
|
+
- **PII detection mode** (`ner_mode='pii'`): auto-configures GLiNER with 60+ PII entity labels (personal, financial, healthcare, identity, digital)
|
|
680
|
+
- **Synthetic replacement** (`replacement_mode='synthetic'`): Faker-generated realistic values instead of `<TAG>` placeholders, with per-document consistency
|
|
681
|
+
- **Reversible anonymization** (`replacement_mode='reversible'`): indexed placeholders (`<PERSON_0>`) with `AnonymizationMap` for round-trip deanonymization
|
|
682
|
+
- **Document classification** (`check_classify_document=True`): zero-shot GLiClass pre-classification before text processing
|
|
683
|
+
- **ProcessResult**: `process()` returns `ProcessResult` (backward-compatible 3-tuple) with `.metadata` for anonymization maps and classification results
|
|
684
|
+
- **GLiNER ONNX mode** (`gliner_onnx=True`): load GLiNER with pre-built ONNX weights from HuggingFace Hub (auto-set for PII + ONNX backend)
|
|
685
|
+
- **Bi-encoder support**: auto-detects ModernBERT and other bi-encoder GLiNER models, caches label embeddings, dynamic context windows (2048-8192 tokens)
|
|
686
|
+
- **Entity description labels**: ZERONER-style natural-language descriptions for improved zero-shot accuracy
|
|
687
|
+
- **Presidio GLiNER backend** (beta): opt-in `ner_backend='presidio_gliner'` for Presidio's context-aware recognition pipeline
|
|
688
|
+
- **ModernBERT ONNX export**: updated export script with ModernBERT support (English, 8192 token context)
|
|
689
|
+
- **Dynamic chunk sizing**: GLiNER chunk size adapts to model's actual context window instead of hardcoded 384
|
|
690
|
+
|
|
691
|
+
**v0.5.x**
|
|
692
|
+
- `aprocess_batch()`: async batch processing for FastAPI / aiohttp integrations
|
|
693
|
+
- `warmup(languages)`: pre-load NER models at startup to eliminate first-request latency
|
|
694
|
+
- `custom_pipeline_steps`: attach arbitrary `(text: str) -> str` callables after the built-in pipeline
|
|
695
|
+
- French, Portuguese, and Italian NER support via a shared multilingual ONNX session
|
|
696
|
+
- Improved NER sentence boundary detection with abbreviation guard
|
|
697
|
+
|
|
698
|
+
**v0.4.5**
|
|
699
|
+
- Frozen `TextCleanerConfig` dataclass: immutable, thread-safe, per-instance configuration
|
|
700
|
+
- ONNX-first NER inference: torch-free base install (~400 MB models vs ~7 GB)
|
|
701
|
+
- Thread-parallel batch processing via `ThreadPoolExecutor`
|
|
702
|
+
- Five NER backends: `onnx`, `torch`, `gliner`, `ensemble_onnx`, `ensemble_torch`
|
|
547
703
|
- GLiNER zero-shot NER for custom entity types (PRODUCT, EVENT, SKILL, etc.)
|
|
548
704
|
- Ensemble voting across backends for improved recall
|
|
549
|
-
- Lazy per-language model loading
|
|
550
|
-
-
|
|
551
|
-
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
-
|
|
555
|
-
- Fuzzy date matching for misspelled months (via rapidfuzz, empirically calibrated threshold)
|
|
556
|
-
- Configurable emoji removal
|
|
557
|
-
- Configurable bracket/brace content removal
|
|
558
|
-
- Smart case folding (preserves NER replacement tokens)
|
|
559
|
-
- Custom stopwords and month names per language
|
|
560
|
-
|
|
561
|
-
**Dependencies**
|
|
562
|
-
- `stop-words` package replaces NLTK (50KB bundled vs 30MB download)
|
|
563
|
-
- PyTorch/Transformers moved to optional `[torch]` extra
|
|
564
|
-
- New optional extras: `[gpu]`, `[fuzzy]`, `[gliner]`, `[gliner2]`, `[all-ner]`
|
|
565
|
-
- Migrated from `setup.py` to `pyproject.toml` (PEP 517)
|
|
566
|
-
|
|
567
|
-
**Quality**
|
|
568
|
-
- Python 3.11–3.13 support
|
|
569
|
-
- `ruff` linter (replaces flake8)
|
|
570
|
-
- hypothesis-based property testing with pytest-timeout
|
|
571
|
-
- Collision-safe NER entity keys
|
|
705
|
+
- Lazy per-language model loading
|
|
706
|
+
- Multilingual date detection and fuzzy date matching
|
|
707
|
+
- Configurable emoji removal, bracket/brace content removal, and smart case folding
|
|
708
|
+
- `stop-words` replaces NLTK (50 KB bundled vs 30 MB download)
|
|
709
|
+
- PyTorch and Transformers moved to optional extras
|
|
710
|
+
- Migrated to `pyproject.toml` (PEP 517), Python 3.11-3.13, ruff linter
|
|
572
711
|
|
|
573
712
|
## Contributing
|
|
574
713
|
|