한국어 PII 인식기 경계 추가

This commit is contained in:
Yun Chan 2026-06-28 23:52:37 +09:00
parent 2bb052f624
commit 84599bbaa2
3 changed files with 156 additions and 9 deletions

View file

@ -54,7 +54,9 @@ class PiiMaskingEvalTests(unittest.TestCase):
return_value=(None, None),
)
self.presidio_patch.start()
guardrail.set_ko_pii_recognizer(None)
self.addCleanup(self.presidio_patch.stop)
self.addCleanup(guardrail.set_ko_pii_recognizer, None)
def test_fixture_cases_are_valid_json_list(self) -> None:
cases = load_cases(FIXTURE_PATH)
@ -110,6 +112,50 @@ class PiiMaskingEvalTests(unittest.TestCase):
result = guardrail.mask_pii(raw)
self.assertEqual(result.text_masked, expected)
def test_optional_ko_recognizer_masks_adapter_spans_before_regex_fallback(self) -> None:
class FakeKoRecognizer:
def analyze(self, text: str):
spans = []
for entity_type, value in (
("NAME", "보라별"),
("ORG", "미래학교상담연구랩"),
):
start = text.index(value)
spans.append(guardrail.PiiEntitySpan(entity_type, start, start + len(value)))
return spans
guardrail.set_ko_pii_recognizer(FakeKoRecognizer())
result = guardrail.mask_pii(
"별명은 보라별이고 기관은 미래학교상담연구랩입니다. 전화는 010-1234-5678입니다."
)
self.assertTrue(result.used_ko_recognizer)
self.assertFalse(result.used_presidio)
self.assertIn("NAME", result.entities)
self.assertIn("ORG", result.entities)
self.assertIn("PHONE", result.entities)
self.assertNotIn("보라별", result.text_masked)
self.assertNotIn("미래학교상담연구랩", result.text_masked)
self.assertNotIn("010-1234-5678", result.text_masked)
self.assertIn("[NAME]", result.text_masked)
self.assertIn("[ORG]", result.text_masked)
self.assertIn("[PHONE]", result.text_masked)
def test_optional_ko_recognizer_failure_keeps_regex_fallback(self) -> None:
class BrokenKoRecognizer:
def analyze(self, text: str):
raise RuntimeError("adapter down")
guardrail.set_ko_pii_recognizer(BrokenKoRecognizer())
result = guardrail.mask_pii("전화는 010-1234-5678입니다.")
self.assertFalse(result.used_ko_recognizer)
self.assertFalse(result.used_presidio)
self.assertIn("PHONE", result.entities)
self.assertIn("[PHONE]", result.text_masked)
def test_cli_reports_json_and_nonzero_gate_shape(self) -> None:
completed = subprocess.run(
[