scrub / review_filters.py
solidprivacy-nl
Add review filter helpers
b0fa475
Raw
History Blame
4.38 kB
"""Review filter helpers for the Scrub replacement workflow.
The filters are intentionally presentation-oriented. They help the user focus on
specific rows, but they should not silently remove hidden rows from the export
workflow unless the UI explicitly implements safe merge-back behaviour.
"""
from __future__ import annotations
from typing import Any, Iterable, Mapping
FILTER_SHOW_ALL = "Toon alles"
FILTER_NEEDS_REVIEW = "Alleen controle nodig"
FILTER_LEGAL_REFERENCES = "Alleen juridische referenties"
FILTER_NAMES_ADDRESSES = "Alleen namen/adressen"
FILTER_LOW_CONFIDENCE = "Alleen lage zekerheid"
REVIEW_FILTER_OPTIONS = [
FILTER_SHOW_ALL,
FILTER_NEEDS_REVIEW,
FILTER_LEGAL_REFERENCES,
FILTER_NAMES_ADDRESSES,
FILTER_LOW_CONFIDENCE,
]
LEGAL_REFERENCE_ENTITY_TYPES = {
"NL_LEGAL_CASE_NUMBER",
"NL_ROLNUMMER",
"NL_REKESTNUMMER",
"NL_PARKETNUMMER",
"NL_DOSSIER_NUMBER",
"NL_CLIENT_NUMBER",
"NL_CJIB_NUMBER",
"NL_POLICE_REPORT_NUMBER",
"NL_INSURANCE_CLAIM_NUMBER",
"NL_INCIDENT_NUMBER",
"NL_CLAIM_NUMBER",
"NL_OTHER_REFERENCE",
"NL_CLIENT_REFERENCE",
"NL_CASE_REFERENCE",
"NL_INTERNAL_REFERENCE",
"NL_CONTEXTUAL_REFERENCE",
"NL_INVOICE_NUMBER",
"NL_ORDER_OR_CONTRACT_NUMBER",
"NL_SCHOOL_REFERENCE",
"NL_CHILD_PROTECTION_REFERENCE",
"NL_EMPLOYMENT_REFERENCE",
"NL_INSURANCE_REFERENCE",
"NL_HEALTHCARE_REFERENCE",
"NL_POLICE_REFERENCE",
"NL_IMMIGRATION_REFERENCE",
"NL_MUNICIPAL_REFERENCE",
"NL_REAL_ESTATE_REFERENCE",
"NL_VEHICLE_REFERENCE",
"NL_OBJECT_REFERENCE",
"NL_SUSPICIOUS_REFERENCE_CANDIDATE",
"NL_POSSIBLE_LICENSE_PLATE",
"NL_ECLI",
"NL_KVK_NUMBER",
"NL_VAT_NUMBER",
"NL_BIG_NUMBER",
}
NAME_ADDRESS_ENTITY_TYPES = {
"PERSON",
"NL_LEGAL_PARTY_NAME",
"LOCATION",
"NL_ADDRESS",
"NL_POSTCODE",
"ORGANIZATION",
"NL_COURT_OR_AUTHORITY",
}
def _cell(row: Mapping[str, Any], key: str, default: Any = "") -> Any:
value = row.get(key, default)
return default if value is None else value
def _normalised_entity_type(row: Mapping[str, Any]) -> str:
return str(_cell(row, "entity_type", "")).strip().upper()
def _normalised_status(row: Mapping[str, Any]) -> str:
status = str(_cell(row, "review_status", "")).strip().lower()
label = str(_cell(row, "review_status_label", "")).strip().lower()
if status:
return status
if label == "controle nodig":
return "needs_review"
if label == "automatisch vervangen":
return "auto_detected"
if label == "handmatig toegevoegd":
return "manual"
if label == "onthouden vervanging":
return "remembered"
return ""
def _score(row: Mapping[str, Any]) -> float | None:
raw = _cell(row, "score", None)
if raw in (None, ""):
return None
try:
return float(raw)
except Exception:
return None
def row_matches_review_filter(row: Mapping[str, Any], filter_label: str) -> bool:
if filter_label == FILTER_SHOW_ALL:
return True
if filter_label == FILTER_NEEDS_REVIEW:
return _normalised_status(row) == "needs_review"
entity_type = _normalised_entity_type(row)
if filter_label == FILTER_LEGAL_REFERENCES:
return entity_type in LEGAL_REFERENCE_ENTITY_TYPES
if filter_label == FILTER_NAMES_ADDRESSES:
return entity_type in NAME_ADDRESS_ENTITY_TYPES
if filter_label == FILTER_LOW_CONFIDENCE:
confidence = str(_cell(row, "confidence", "")).strip().lower()
score = _score(row)
return confidence == "laag" or (score is not None and score < 0.60)
return True
def filter_review_records(records: Iterable[Mapping[str, Any]], filter_label: str) -> list[Mapping[str, Any]]:
return [row for row in records if row_matches_review_filter(row, filter_label)]
def filter_review_dataframe(df, filter_label: str):
"""Filter a pandas-like DataFrame without importing pandas at module import.
Tests use the record-level function. The Streamlit app can use this helper
with a pandas DataFrame.
"""
if filter_label == FILTER_SHOW_ALL:
return df
if df is None or len(df) == 0:
return df
mask = [row_matches_review_filter(row, filter_label) for _, row in df.iterrows()]
return df.loc[mask].reset_index(drop=True)