
Inverso del filtro de privacidad de OpenAI. El mismo modelo de 1.5b, devuelve PII como spans estructurados en lugar de enmascararlos.
Encuentra cada fragmento de PII en un montón de texto y recupéralo como spans estructurados.
Construido sobre OpenAI Privacy Filter: mismo modelo de 1.5B, mismas etiquetas, mismos pesos.
Privacy Filter enmascara. Privacy Parser extrae.
Hi Quindle Testwick ([email protected] / +1-415-555-0102),
account 40702810500001234567, 14 Beautiful Ct, Anytown USA,
password Priv4cy-Filt3r-2026.
private_person Quindle Testwick
private_email [email protected]
private_phone +1-415-555-0102
account_number 40702810500001234567
private_address 14 Beautiful Ct, Anytown USA
secret Priv4cy-Filt3r-2026
En lugar de <REDACTED> obtienes qué se encontró, dónde está (start, end) y qué tipo es.
Privacy Filter responde a "haz que este texto sea seguro". A veces necesitas una respuesta diferente: "¿qué hay exactamente aquí?"
| Backend | Requiere pesos | Velocidad | F1 * | Úsalo cuando |
|---|---|---|---|---|
PIIParser | no | µs | 1.000 | sin dependencias, patrones estructurados |
ModelPIIParser | 1.5B | ~500 ms CPU | 0.733 | salida directa del modelo |
HybridPIIParser | 1.5B | ~600 ms CPU | 0.929 | opción por defecto |
* coincidencia exacta de fragmentos en los cinco fixtures de muestra de opf. Un conjunto pequeño: trátalo como una prueba de humo, no como un benchmark.
git clone https://github.com/openai/privacy-filter
git clone https://github.com/chiefautism/privacy-parser
uv venv
uv pip install -e ./privacy-filter # only for the model backends
uv pip install -e ./privacy-parser
La primera ejecución del modelo descarga el checkpoint opf (~3 GB) en ~/.opf/privacy_filter/.
Establece OPF_CHECKPOINT o pasa model= para usar otra ubicación.
from pii_parser.hybrid import HybridPIIParser
parser = HybridPIIParser(device="cpu") # or "cuda"
result = parser.parse("Hi Quindle Testwick, call me at +1-415-555-0102")
for s in result.spans:
print(s.label, s.start, s.end, s.text)
print(result.to_json())
from pii_parser import parse
result = parse("mail [email protected], token ghp_abcdefghijklmnopqrstuvwxyz0123456789")
result.detected_spans # (DetectedSpan(label='private_email', ...), ...)
result.redacted_text # 'mail <REDACTED>, token <REDACTED>'
result.summary # {'span_counts': {...}, 'total_spans': 2}
Backend de regex, sin modelo:
$ echo "Alice paid 40702810500001234567 on 2026-05-17." | pii-parser --mode spans
account_number 11 31 40702810500001234567
private_date 35 45 2026-05-17
$ pii-parser "mail [email protected]" --mode redacted
mail <REDACTED>
| Flag | Valores | Predeterminado |
|---|---|---|
TEXT | texto, o -f FILE, o stdin | |
--mode | json · spans · redacted | json |
--placeholder | cualquier cadena | <REDACTED> |
--indent | int, 0 para JSON compacto | 2 |
Backend del modelo:
python -m pii_parser.cli_model "Alice paid 40702810500001234567 on 2026-05-17."
python -m pii_parser.cli_model -f dump.txt --device cuda --mode spans
taxonomía opf v2, 8 categorías:
| Etiqueta | Ejemplo |
|---|---|
private_person | Quindle Testwick |
private_email | [email protected] |
private_phone | +1-415-555-0102 |
private_address | 14 Beautiful Ct, Anytown USA |
private_url | https://example.com/u/quindle |
private_date | 2026-05-17 |
account_number | 40702810500001234567 |
secret | sk-…, ghp_…, AKIA…, Bearer … |
Cuando los spans se superponen, gana el más largo, y luego la etiqueta de mayor prioridad: email > url > secret > account > phone > date > address > person.
text
│
▼
opf 1.5B ──► BIOES logits ──► Viterbi (tuned biases) ──► char spans
│
▼
span merge glues "Quindle" + "Testwick" into one person
│
▼
regex backstop adds url / secret / account where the model missed them
│
▼
spans[]
Cada etapa se puede desactivar:
HybridPIIParser(
enable_merge=True,
enable_regex_backstop=True,
enable_viterbi_tuning=True,
decode_mode="viterbi", # or "argmax"
)
{
"text": "Hi Quindle Testwick ...",
"spans": [
{ "label": "private_person", "start": 3, "end": 19, "text": "Quindle Testwick" }
]
}
El regex PIIParser refleja opf.RedactionResult (schema_version, summary, detected_spans, redacted_text), por lo que puedes intercambiar backends sin tocar a los consumidores.
Las pruebas esperan que privacy-filter esté clonado junto a este repositorio (leen sus fixtures de ejemplo).
python tests/test_hybrid.py
Fixture F1: 0.929
Scenarios: 8/8 passed
Latency: ~600 ms CPU
Esta es una herramienta de doble uso. Ejecútala sobre datos que poseas o estés autorizado a procesar. Extraer datos personales de fuentes filtradas o robadas es ilegal en la mayoría de las jurisdicciones.