v3.2.0: новый LLM-промпт (STEP 1/2, фикс. типы, NOT PII, already_found), убран хардкод НУБЕС
Deploy drhider / validate (push) Waiting to run
Deploy drhider / validate (push) Waiting to run
This commit is contained in:
@@ -81,7 +81,7 @@ class TwoPassObfuscator:
|
||||
if text and not text.startswith("[DOC binary"):
|
||||
scanner.scan_regex(text, self._mapping)
|
||||
|
||||
# LLM-сканирование (медленное, сетевое — только если есть клиент)
|
||||
# LLM-сканирование (получает уже найденное regex'ом чтобы не дублировать)
|
||||
if self._llm_client:
|
||||
scanner.scan_llm_ner(all_texts, self._mapping, self._llm_client)
|
||||
|
||||
|
||||
+27
-12
@@ -66,10 +66,6 @@ def scan_regex(text: str, mapping: Dict[str, str]) -> None:
|
||||
if not original or original in mapping:
|
||||
continue
|
||||
|
||||
# «НУБЕС» — Исполнитель, НЕ заменяем
|
||||
if re.search(r'НУБЕС|NUBES', original, re.IGNORECASE):
|
||||
continue
|
||||
|
||||
mapping[original] = generate_company(original)
|
||||
|
||||
# ── ФИО (Фамилия И.О.) ──
|
||||
@@ -99,20 +95,39 @@ def scan_llm_ner(all_texts: Dict[str, str], mapping: Dict[str, str], llm_client)
|
||||
f"FILE: {fname}\n{t[:3000]}" for fname, t in all_texts.items()
|
||||
)
|
||||
|
||||
# ── Универсальный промпт — без фиксированного списка типов ──
|
||||
# ── Универсальный промпт: STEP 1 (Исполнитель) + STEP 2 (ПДн) ──
|
||||
already_found = "\n".join(f"- {k}" for k in mapping.keys()) if mapping else "(none)"
|
||||
|
||||
prompt = (
|
||||
"You are a PII (Personally Identifiable Information) detector. "
|
||||
"Find ALL sensitive or private information in the text below.\n\n"
|
||||
"You are a PII (Personally Identifiable Information) detector for Russian legal documents.\n\n"
|
||||
|
||||
"STEP 1 — Identify the service provider:\n"
|
||||
"Read the contract and find which company/person is labeled 'Исполнитель' "
|
||||
"(the party providing services). "
|
||||
"This party's own name is NOT PII — do NOT include it in results.\n\n"
|
||||
|
||||
"STEP 2 — Find all PII that is NOT already captured below.\n\n"
|
||||
|
||||
"Already captured by regex (skip these exact strings):\n"
|
||||
f"{already_found}\n\n"
|
||||
|
||||
"Return a JSON array. Each item must have:\n"
|
||||
' - "type": short snake_case label describing the entity\n'
|
||||
' (e.g. person_name, phone, email, address, inn, company, passport,\n'
|
||||
' contract_number, employee_id, bank_account — WHATEVER you see)\n'
|
||||
' - "type": MUST be one of: person_name, company, phone, email, address,\n'
|
||||
' inn, kpp, ogrn, bik, passport, contract_number, bank_account, other_id\n'
|
||||
' Use "other_id" only if nothing else fits. If unsure — do NOT include.\n'
|
||||
' - "value": the EXACT string from the text (copy verbatim)\n\n'
|
||||
|
||||
"NOT PII — do NOT include these (legal roles and terms, not private data):\n"
|
||||
"- Roles: Исполнитель, Заказчик, Стороны, Сторона, Покупатель, Поставщик\n"
|
||||
"- Titles: Генеральный директор, Директор, Президент, действующего на основании\n"
|
||||
"- Legal terms: Услуги, Договор, Приложение, Спецификация, НДС, Устава\n"
|
||||
"- The 'Исполнитель' company name identified in STEP 1\n\n"
|
||||
|
||||
"Rules:\n"
|
||||
"- Copy value VERBATIM — same spaces, punctuation, case as in text\n"
|
||||
"- If same value appears multiple times — include only once\n"
|
||||
"- Invent the type label yourself based on what you see\n"
|
||||
"- Same value → include only once\n"
|
||||
"- Return ONLY the JSON array, no other text, no markdown wrapping\n\n"
|
||||
|
||||
f"Text:\n{combined[:8000]}"
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user