Spaces:
Running
Running
| """Pure Scrub Key import/reload helpers for SolidPrivacy Scrub. | |
| This module prepares v13.2 import/reload without touching the Streamlit UI. It | |
| parses a previously downloaded Scrub Key JSON string, validates it with the v13.0 | |
| model, and normalises the mappings into review-table-like rows for later UI and | |
| reinsert work. | |
| The helpers deliberately avoid file-system writes, server-side storage, cloud | |
| processing and UI side effects. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from collections.abc import Mapping | |
| from typing import Any | |
| from scrub_key import scrub_key_from_json, validate_scrub_key | |
| IMPORT_PRIVACY_WARNING = ( | |
| "Een Scrub Key maakt vervangen waarden lokaal herleidbaar. " | |
| "Gebruik dit bestand alleen lokaal en deel het niet met AI-diensten of derden " | |
| "tenzij dat bewust en toegestaan is." | |
| ) | |
| def _text(value: Any) -> str: | |
| return str(value or "").strip() | |
| def _validation_errors_for_text(json_text: Any) -> tuple[dict[str, Any] | None, list[str]]: | |
| """Parse and validate Scrub Key JSON text with safe user-facing errors.""" | |
| if not isinstance(json_text, str) or _text(json_text) == "": | |
| return None, ["Scrub Key JSON ontbreekt of is leeg."] | |
| try: | |
| scrub_key = scrub_key_from_json(json_text) | |
| except json.JSONDecodeError: | |
| return None, ["Scrub Key JSON is geen geldige JSON."] | |
| except ValueError as exc: | |
| return None, [f"Scrub Key JSON heeft een ongeldig hoofdformaat: {exc}"] | |
| validation_issues = validate_scrub_key(scrub_key) | |
| if validation_issues: | |
| return scrub_key, [f"Scrub Key is niet geldig: {issue}" for issue in validation_issues] | |
| return scrub_key, [] | |
| def validate_scrub_key_import_text(json_text: Any) -> list[str]: | |
| """Return safe validation errors for a candidate Scrub Key JSON string.""" | |
| _scrub_key, errors = _validation_errors_for_text(json_text) | |
| return errors | |
| def normalise_scrub_key_items(scrub_key: Mapping[str, Any]) -> list[dict[str, Any]]: | |
| """Convert Scrub Key items to review-table-like mapping rows. | |
| The normalised rows are intentionally simple and deterministic. They can be | |
| reused later by UI import/reload and deterministic reinsert helpers. | |
| """ | |
| items = scrub_key.get("items") | |
| if not isinstance(items, list): | |
| return [] | |
| rows: list[dict[str, Any]] = [] | |
| for item in items: | |
| if not isinstance(item, Mapping): | |
| continue | |
| rows.append( | |
| { | |
| "find": _text(item.get("original_value")), | |
| "replace_with": _text(item.get("placeholder")), | |
| "original_value": _text(item.get("original_value")), | |
| "placeholder": _text(item.get("placeholder")), | |
| "entity_type": _text(item.get("entity_type")), | |
| "type_label": _text(item.get("type_label")), | |
| "source": _text(item.get("source")), | |
| "review_status": _text(item.get("review_status")), | |
| "include": item.get("include_state") == "included", | |
| "include_state": _text(item.get("include_state")), | |
| "timestamp": _text(item.get("timestamp")), | |
| "document_label": _text(item.get("document_label")) | |
| or _text(scrub_key.get("document_label")), | |
| } | |
| ) | |
| return rows | |
| def build_scrub_key_import_result(json_text: Any) -> dict[str, Any]: | |
| """Parse, validate and normalise a Scrub Key JSON string. | |
| The return shape is deliberately UI-friendly while staying pure and | |
| side-effect free. `ok=True` means the Scrub Key is structurally valid and the | |
| `mapping_rows` can be used by later import/reload or reinsert work. | |
| """ | |
| scrub_key, errors = _validation_errors_for_text(json_text) | |
| if errors: | |
| return { | |
| "ok": False, | |
| "errors": errors, | |
| "warnings": [IMPORT_PRIVACY_WARNING], | |
| "scrub_key": scrub_key, | |
| "mapping_rows": [], | |
| "item_count": 0, | |
| "reversible": False, | |
| } | |
| assert scrub_key is not None | |
| mapping_rows = normalise_scrub_key_items(scrub_key) | |
| return { | |
| "ok": True, | |
| "errors": [], | |
| "warnings": [IMPORT_PRIVACY_WARNING], | |
| "scrub_key": scrub_key, | |
| "mapping_rows": mapping_rows, | |
| "item_count": len(mapping_rows), | |
| "reversible": scrub_key.get("reversible") is True, | |
| "privacy_model": scrub_key.get("privacy_model"), | |
| "document_label": scrub_key.get("document_label"), | |
| } | |