Metadata-Version: 2.4
Name: presidio-ru-recognizers
Version: 0.1.0
Summary: Russian PII recognizers for Microsoft Presidio (ИНН, СНИЛС, ОГРН, ОГРНИП, паспорт РФ, телефон РФ, расчётный счёт)
Project-URL: Homepage, https://github.com/brikkoAI/presidio-ru-recognizers
Project-URL: Documentation, https://github.com/brikkoAI/presidio-ru-recognizers#readme
Project-URL: Repository, https://github.com/brikkoAI/presidio-ru-recognizers
Project-URL: Issues, https://github.com/brikkoAI/presidio-ru-recognizers/issues
Project-URL: Changelog, https://github.com/brikkoAI/presidio-ru-recognizers/blob/main/CHANGELOG.md
Project-URL: Sponsored by, https://brikko.ru
Author-email: Brikko <hello@brikko.ru>
License: MIT
License-File: LICENSE
Keywords: 152-fz,anonymization,data-privacy,gdpr,inn,ogrn,passport,pii,presidio,rus,russia,russian,snils
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: Russian
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Text Processing :: Linguistic
Requires-Python: >=3.10
Requires-Dist: presidio-analyzer>=2.2
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Description-Content-Type: text/markdown

# presidio-ru-recognizers

[![PyPI](https://img.shields.io/pypi/v/presidio-ru-recognizers.svg)](https://pypi.org/project/presidio-ru-recognizers/)
[![Python](https://img.shields.io/pypi/pyversions/presidio-ru-recognizers.svg)](https://pypi.org/project/presidio-ru-recognizers/)
[![License](https://img.shields.io/pypi/l/presidio-ru-recognizers.svg)](LICENSE)
[![CI](https://github.com/brikkoAI/presidio-ru-recognizers/actions/workflows/ci.yml/badge.svg)](https://github.com/brikkoAI/presidio-ru-recognizers/actions/workflows/ci.yml)

> Russian PII recognizers for [Microsoft Presidio](https://github.com/microsoft/presidio).
> Распознаватели российских персональных данных для Microsoft Presidio.

Drop-in `PatternRecognizer` subclasses with **strict checksum validation** for
seven Russian identifier types:

| Entity            | What                                       | Checksum?            |
|-------------------|--------------------------------------------|----------------------|
| `INN_RU`          | ИНН — 10 (юрлицо) или 12 (физлицо/ИП)      | да (per-length)      |
| `SNILS`           | СНИЛС — `XXX-XXX-XXX YY` или `XXXXXXXXXXX` | да                   |
| `OGRN`            | ОГРН — 13 цифр (юрлицо)                    | да                   |
| `OGRNIP`          | ОГРНИП — 15 цифр (ИП)                      | да                   |
| `PASSPORT_RF`     | Паспорт РФ — 4 (серия) + 6 (номер)         | нет (нет в спеке)    |
| `PHONE_RF`        | Российский телефон `+7` / `8`              | формат + ровно 11 цифр |
| `BANK_ACCOUNT_RF` | Расчётный счёт юрлица — 20 цифр            | regex-only*          |

\* Полная БИК-зависимая КС счёта требует справочника ЦБ РФ — за scope
этого пакета.

---

## Why a separate package?

Microsoft Presidio's default recognizers cover English-locale PII (US SSN,
US passport, UK NHS, etc.) — там нет ничего про РФ. Делать regex для
ИНН/ОГРН без контрольной суммы — почти бесполезно: на любом log'е с
длинными цифровыми ID получите false-positive rate под 90%. Этот пакет
закрывает gap для compliance-задач (152-ФЗ, GDPR в части data-subject
identifiers, audit-логи).

Англ.: Presidio ships English-locale recognizers only. Russian
identifiers without their checksums produce 90%+ false positive rates on
any log containing long numeric IDs (timestamps, hashes, internal PKs).
This package wires the official Federal Tax Service / Pension Fund /
state-registration checksums into Presidio recognizers so detections
arrive validated.

---

## Installation

```bash
pip install presidio-ru-recognizers
```

Requires `presidio-analyzer >= 2.2`. Pure stdlib for the checksums — no
extra runtime dependencies.

---

## Quick start / Быстрый старт

```python
from presidio_analyzer import AnalyzerEngine, RecognizerRegistry
from presidio_analyzer.nlp_engine import NlpEngineProvider

from presidio_ru_recognizers import register_all_ru_recognizers

# Configure NLP — Presidio needs *some* spaCy model loaded even if our
# recognizers are pattern-based. Map 'ru' to the English small model
# as a stub if you don't have a Russian spaCy model set up.
nlp = NlpEngineProvider(nlp_configuration={
    "nlp_engine_name": "spacy",
    "models": [
        {"lang_code": "en", "model_name": "en_core_web_sm"},
        {"lang_code": "ru", "model_name": "en_core_web_sm"},
    ],
}).create_engine()

registry = RecognizerRegistry(supported_languages=["en", "ru"])
register_all_ru_recognizers(registry)

analyzer = AnalyzerEngine(
    registry=registry,
    nlp_engine=nlp,
    supported_languages=["en", "ru"],
)

text = (
    "ООО Сбербанк, ИНН 7707083893, ОГРН 1027700132195. "
    "Тел +7 (495) 500-55-50. Паспорт 4505 678901."
)

for r in analyzer.analyze(text=text, language="ru"):
    print(f"{r.entity_type:20s} score={r.score:.2f}  '{text[r.start:r.end]}'")
```

Output:

```
INN_RU               score=1.00  '7707083893'
OGRN                 score=1.00  '1027700132195'
PHONE_RF             score=0.60  '+7 (495) 500-55-50'
PASSPORT_RF          score=0.40  '4505 678901'
```

`score=1.0` означает «прошло КС-валидацию». Паспорт без КС идёт с
базовым `0.4` — поднимайте контекстными словами через
`ContextAwareEnhancer`.

### Регистрация одного recognizer'а

```python
from presidio_ru_recognizers import InnRecognizer

analyzer.registry.add_recognizer(InnRecognizer())
```

### Overlapping spans

Presidio runs every recognizer independently and returns all matches.
Это значит, что 10-цифровой ИНН в тексте *also* совпадёт с
`PASSPORT_RF` (поскольку 4+6 без сепаратора — те же 10 цифр). Сравнение
очков снимает неоднозначность: КС-валидированный ИНН будет иметь
`score=1.0`, паспорт — `0.4`. Берите highest-score-wins:

```python
from collections import defaultdict

results = analyzer.analyze(text=text, language="ru")
by_span: dict[tuple[int, int], list] = defaultdict(list)
for r in results:
    by_span[(r.start, r.end)].append(r)
final = [max(group, key=lambda r: r.score) for group in by_span.values()]
```

Или используйте `decision_process=True` и
`presidio-anonymizer` — он применяет тот же tie-break автоматически.

### Использование чистых КС-функций без Presidio

```python
from presidio_ru_recognizers import inn10, snils, ogrn

inn10("7707083893")        # True (Sberbank)
inn10("7707083892")        # False (wrong checksum)
snils("112-233-445 95")    # True
ogrn("1027700132195")      # True
```

---

## Entity reference

### `INN_RU` — ИНН

* 10 цифр (юрлицо): веса `[2,4,10,3,5,9,4,6,8]`, КС = `Σ % 11 % 10`.
* 12 цифр (физлицо/ИП): два каскадных КС.

```python
from presidio_ru_recognizers import InnRecognizer
analyzer.registry.add_recognizer(InnRecognizer())
```

### `SNILS`

* `XXX-XXX-XXX YY` — каноничный формат.
* `XXXXXXXXXXX` — bare 11 цифр (нижний score, чтобы не ловить телефоны).
* Special-case для ранних выпусков (≤ 001-001-998): КС всегда `00`.

### `OGRN` / `OGRNIP`

* ОГРН (13): `int(first_12) % 11 % 10 == digit[12]`.
* ОГРНИП (15): `int(first_14) % 13 % 10 == digit[14]`.

### `PASSPORT_RF`

`\d{4}[\s\-]?\d{6}` со word-boundary. КС не существует, поэтому базовый
score 0.4 — повышайте через context.

### `PHONE_RF`

`+7` или `8` + 10 цифр; разделители ` -().` допускаются. После strip —
ровно 11 цифр.

### `BANK_ACCOUNT_RF`

20 цифр. КС зависит от БИК (справочник ЦБ РФ — out of scope здесь);
держите низкий score и опирайтесь на контекстные слова (`р/с`,
`расчётный счёт`).

---

## Sponsored by Brikko

This package was extracted from the [Brikko Gateway](https://brikko.ru) —
the legal Russian gateway to OpenAI, Anthropic, Google, DeepSeek,
YandexGPT and GigaChat from a single rouble account, with smart routing,
failover, and full closing documents (договор, акт, чек).

If you build LLM apps for Russian companies, Brikko is the legal entry
point. Try it at **[brikko.ru](https://brikko.ru)** or follow development
at [github.com/brikkoAI](https://github.com/brikkoAI).

This recognizer package will stay community-maintained and brand-neutral
under MIT — Brikko sponsors it because we eat our own dog food (every
LLM request through Brikko Gateway runs through these checksums before
hitting a provider).

---

## Development

```bash
git clone https://github.com/brikkoAI/presidio-ru-recognizers
cd presidio-ru-recognizers
pip install -e ".[dev]"
python -m spacy download en_core_web_sm
pytest                       # 61 tests
ruff check .
mypy presidio_ru_recognizers
```

### Adding a new recognizer

1. Add the algorithm to `presidio_ru_recognizers/checksums.py` (pure stdlib).
2. Subclass `PatternRecognizer` in a new module — see `inn.py` as the canonical example.
3. Register the class in `_RECOGNIZER_CLASSES` in `__init__.py`.
4. Add fixtures + tests in `tests/`.
5. PR welcome.

---

## License

MIT. See [LICENSE](LICENSE).

The checksum algorithms themselves are public mathematical procedures
defined by Russian federal regulators (ФНС, ПФР, ЦБ РФ) — not subject to
copyright. The Python implementations here are released under MIT for
maximum compatibility with the upstream Microsoft Presidio license.
