Об этом проекте

pii-mask — локальный шлюз маскировки персональных данных (PII) перед отправкой текста в облачные LLM и обратной подстановки оригиналов в ответ. Русскоцентричный: распознаёт ПД-форматы РФ, использует NER и учитывает морфологию русского языка. Основной сценарий — обработка транскриптов встреч (саммари, action items) без утечки имён, телефонов и компаний провайдеру модели. Облачная модель никогда не видит настоящих данных. Как устроено: 1. Regex + контрольные суммы (форматные ПД РФ): телефон, email, ИНН (10/12, контрольные цифры), ОГРН/ОГРНИП (13/15, контрольный разряд), СНИЛС, карта (Луна), паспорт (только рядом со словом "паспорт"/"серия"), telegram-ник, УИД договора, ФИО капсом и с инициалами. 2. NER (Natasha/slovnet, CPU, офлайн): имена и организации. Ключ консистентности — нормальная форма: "Иван Петров", "Ивана Петрова" и "Иваном Петровым" дают одну метку. Одиночное имя линкуется к единственному подходящему полному ФИО. 3. LLM-аудитор (опционально, --audit, Ollama): второй проход по уже замаскированному тексту — "какие ПД остались?". Ловит косвенное: "моя жена Оля", адреса без формата, ники. Модель только предлагает кандидатов (литеральные подстроки), замену всегда делает код. Принципы: - LLM не переписывает текст. Все замены детерминированные, по спанам. - Stateless. Mapping "метка -> оригинал" возвращается вызывающему (файл рядом с задачей или поле ответа API). Сервис ничего не хранит. - Fail-closed. Это шаг пайплайна: упал — текст никуда не ушёл. Запрошенный --audit при недоступной Ollama — ошибка, а не тихая маскировка без аудита. - Формат-сохраняющие фейки для телефонов (+7 000 ...) и email ([email protected]). При обратной подстановке телефоны матчатся и по цифрам. - Защита от выдумок: метка или фейк, которых не было во входе, при unmask превращается в [неизвестное значение]. - Пропуск дороже лишней маски: golden-тесты проверяют recall, ложные срабатывания не считаются ошибкой. Сознательно не маскируется: города/страны (LOC), даты и деньги. Установка: Python 3.10+, pip install -e . Для --audit нужна Ollama (дефолт qwen3:1.7b). Использование: - CLI: pii-mask mask встреча.md -> встреча.masked.md + встреча.mapping.json (0600); pii-mask unmask summary.md --mapping встреча.mapping.json -o summary.final.md. - Повторный mask с тем же --mapping продолжает нумерацию: одна сущность — одна метка на весь диалог. - Флаги: --audit, --no-ner, --types PERSON,PHONE,..., --org-dict файл. - Именованные наборы: pii-mask presets; pii-mask mask резюме.pdf --preset resume; pii-mask mask счет.xlsx --preset accounting; pii-mask mask файл.md --preset auto. - Микросервис: pii-mask serve --port 8377 (слушает только 127.0.0.1). POST /mask, POST /unmask, GET /health/live. Тела запросов не логируются. Гигиена mapping-файлов: *.mapping.json содержит оригиналы ПД, права 600, паттерн в .gitignore. Файл живёт рядом с задачей и удаляется вместе с ней. Соотношение с 152-ФЗ: шлюз — техническая мера снижения риска, а не "соответствие закону из коробки". Это псевдонимизация, а не обезличивание (п. 9 ст. 3 152-ФЗ). Правовое основание обработки, уведомление и трансграничная передача остаются заботой пользователя. Квазиидентификаторы (должность + город + даты) не ловятся регулярками. Правильная формулировка — "техническая мера минимизации персональных данных, передаваемых внешнему обработчику". Это инженерное описание, не юридическое заключение. Критерии качества: 36 тестов, прогон pytest -q. Проверяются полнота (golden-транскрипт с 9 персданными разных форм), структура цела (5 контрольных строк), обратимость (roundtrip, в т.ч. переформатированный телефон), отсечение ложных (18 тестов распознавателей), идемпотентность, устойчивость к выдуманному, границы LLM-аудитора. Реальные ПД в тестах не используются. Количественного recall на реальных данных нет. Официальные документы: акты, реестры, выгрузки. Важно, как извлечён текст: pdftotext -layout рвёт сущности, поток — целые. Замер на акте 76 страниц: постранично с -layout полных ФИО капсом 55, потоком — 879. ФИО капсом ловятся регулярками с якорем на суффикс отчества. Реквизиты (ОГРН, УИД договора) идентифицируют не хуже имени. УИД рвётся по дефису в PDF-вёрстке, шаблон принимает и обрубок (голова из 12-20 шестнадцатеричных знаков). Номера поручений, реестров и входящих не трогаются. Ограничения: - Метки вместо псевдонимов: в восстановленном тексте имя всегда в именительном падеже ("заявка для Иван Петров"). - NER не всеведущ: экзотические имена и транскрипционные искажения может пропустить — для чувствительных текстов включайте --audit. - Названия организаций маскируются не все: название с организационно-правовой формой берётся правилом, остальное — на совести NER. Название без формального признака закрывается --org-dict или --audit. - Агентные сценарии (модель сама читает файлы) шлюз не покрывает — он для пайплайна "текст туда — текст обратно".