API Reference¶
This page is automatically generated from source code using mkdocstrings.
It reflects the current public surface of pdf-anonymizer-core. The hand-written usage guide is in SDK & API Usage. For practical examples see Recipes & Common Workflows.
Info
The CLI (pdf-anonymizer-cli) is a thin wrapper built with Typer. Most logic lives in the core package.
Core Functions¶
pdf_anonymizer_core.core.anonymize_file(file_path: str, characters_to_anonymize: int, prompt_template: str, model_name: str, anonymized_entities: Optional[List[str]] = None, chunk_overlap: int = DEFAULT_CHUNK_OVERLAP, regex_patterns: Optional[Dict[str, str]] = None, max_retries: int = 3, base_retry_delay: float = 1.0, max_retry_delay: float = 10.0) -> Tuple[Optional[str], Optional[Dict[str, str]]]
¶
Anonymize a file by processing its text content.
Performs a two-stage entity detection (fast regex first pass followed by LLM-based semantic detection), deduplicates, consolidates base forms for coreference (e.g. "Dr. Smith" / "Smith"), generates typed placeholders (PERSON_1, ORGANIZATION_3.v_1, ...), and performs length-descending safe replacement to produce reversible anonymized output.
The function streams large inputs via chunking (Markdown-aware for PDF/MD) so that very large files (hundreds of MB) can be processed without exhausting context windows or memory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
str
|
Path to the file to anonymize (.pdf, .md, or .txt). |
required |
characters_to_anonymize
|
int
|
Target character size of each chunk sent to the LLM. |
required |
prompt_template
|
str
|
The full prompt template string (use one from pdf_anonymizer_core.prompts or supply your own). |
required |
model_name
|
str
|
Model identifier or "provider/model" string (e.g. "gemini-2.5-flash", "ollama/phi4-mini", "google/gemini-2.0-flash-exp"). |
required |
anonymized_entities
|
Optional[List[str]]
|
Optional whitelist of entity types (e.g. ["PERSON", "ORGANIZATION"]). When provided, only matching entities are replaced. |
None
|
chunk_overlap
|
int
|
Number of characters of overlap between consecutive chunks. |
DEFAULT_CHUNK_OVERLAP
|
regex_patterns
|
Optional[Dict[str, str]]
|
Custom first-stage regex map. Defaults to the large built-in collection in DEFAULT_REGEX_PATTERNS (see conf.py). The collection covers universal PII (email, URLs, credit cards, crypto wallets, IBANs, VIN, MAC, IPv4/IPv6, dates) plus country-partitioned national IDs, tax IDs, driver licenses, VAT/business numbers, passports etc. for 30+ countries (mandatory: US, CA, GB, ES, IT, FR, IN, CN plus DE, JP, BR, AU, NL, ...). Keys become entity TYPEs (IPV4_ADDRESS, SSN_US, IBAN, CRYPTO_ETH, ...). All patterns are RE2 (google-re2) safe. |
None
|
max_retries
|
int
|
Maximum LLM call attempts per chunk (with exponential backoff). |
3
|
base_retry_delay
|
float
|
Base delay in seconds for retry backoff. |
1.0
|
max_retry_delay
|
float
|
Maximum delay cap for retry backoff. |
10.0
|
Returns:
| Type | Description |
|---|---|
Tuple[Optional[str], Optional[Dict[str, str]]]
|
A tuple (anonymized_text, mapping) where: - anonymized_text is the masked document (or None on failure) - mapping is a dict of original_value -> placeholder (or None on failure) |
Note
The returned mapping is in original -> placeholder direction. The CLI later converts it to placeholder -> original for deanonymization.
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/core.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | |
pdf_anonymizer_core.utils.deanonymize_file(anonymized_file_path: str, mapping_file_path: str) -> tuple[str, str]
¶
Deanonymize a file using a mapping file.
Restores original PII values from placeholders. Supports both current (placeholder -> original) and legacy (original -> placeholder) mapping directions via auto-detection.
The implementation correctly handles variation placeholders (PERSON_1.v_2 etc.) by falling back to the base placeholder's original value.
After processing it also produces an audit statistics JSON file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anonymized_file_path
|
str
|
Path to the previously anonymized document. |
required |
mapping_file_path
|
str
|
Path to the JSON mapping file. |
required |
Returns:
| Type | Description |
|---|---|
str
|
A tuple (deanonymized_file_path, stats_file_path). |
str
|
The stats file contains: - unused_mappings: placeholders in the map that did not appear in text - not_found_mappings: placeholders seen in text but missing from the map |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/utils.py
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
pdf_anonymizer_core.utils.consolidate_mapping(anonymized_text: str, mapping: Dict[str, str]) -> Tuple[str, Dict[str, str]]
¶
Consolidates the mapping to ensure one-to-one correspondence and updates the text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
anonymized_text
|
str
|
The text with anonymized placeholders. |
required |
mapping
|
Dict[str, str]
|
The dictionary mapping placeholders to original PII. |
required |
Returns:
| Type | Description |
|---|---|
Tuple[str, Dict[str, str]]
|
A tuple containing the updated anonymized text and the consolidated mapping. |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/utils.py
pdf_anonymizer_core.utils.save_results(full_anonymized_text: str, final_mapping: dict[str, str], file_path: str) -> tuple[str, str]
¶
Save the anonymized text and the mapping to files.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
full_anonymized_text
|
str
|
The anonymized text. |
required |
final_mapping
|
dict[str, str]
|
Mapping of original text -> placeholder. |
required |
file_path
|
str
|
The path to the original file. |
required |
Returns:
| Type | Description |
|---|---|
tuple[str, str]
|
tuple[str, str]: The paths to the anonymized text file and the mapping file. |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/utils.py
Configuration & Models¶
pdf_anonymizer_core.conf
¶
Central configuration, defaults, profiles, and model/provider enums.
This module defines: - Default constants and directories used by the anonymizer. - Three built-in ConfigProfiles (best-quality, best-speed, best-cost) that bundle sensible combinations of model, prompt, chunk size, retries, etc. - The AppConfig Pydantic model. - get_config_for_profile() helper (used heavily by the CLI). - Legacy enums (PromptEnum, ModelName, etc.) for compatibility and dynamic provider/model resolution.
get_config_for_profile(profile: ConfigProfile, model_name: Optional[str] = None, prompt_name: Optional[str] = None, chunk_size: Optional[int] = None, chunk_overlap: Optional[int] = None) -> AppConfig
¶
Return an AppConfig populated from one of the built-in profiles.
Profiles provide convenient quality/speed/cost presets. Any of the scalar overrides (model_name, prompt_name, chunk_size, chunk_overlap) take precedence over the profile defaults.
The other fields (retries, delays, cache settings, directories) always come from the chosen profile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
profile
|
ConfigProfile
|
One of ConfigProfile.BEST_QUALITY, BEST_SPEED or BEST_COST. |
required |
model_name
|
Optional[str]
|
Optional override for the model (string or provider/model). |
None
|
prompt_name
|
Optional[str]
|
Optional override ("simple" or "detailed"). |
None
|
chunk_size
|
Optional[int]
|
Optional override for characters_to_anonymize / chunk_size. |
None
|
chunk_overlap
|
Optional[int]
|
Optional override for chunk overlap. |
None
|
Returns:
| Type | Description |
|---|---|
AppConfig
|
A fully populated AppConfig instance ready to drive anonymize_file |
AppConfig
|
(or to be passed through configure_cache, etc.). |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/conf.py
Prompts¶
The package ships two ready-to-use prompt templates.
pdf_anonymizer_core.prompts.detailed
¶
Detailed (higher-quality) PII identification prompt.
This prompt instructs the LLM to: - Use deep contextual understanding - Return base_form for coreference handling - Identify a rich set of entity types including JOB_TITLE, ID, and DATE (birthdates only) - Explicitly handle variations and possessives
Use this prompt (via pdf_anonymizer_core.prompts.detailed.prompt_template) when you want maximum accuracy (pairs well with BEST_QUALITY profile).
pdf_anonymizer_core.prompts.simple
¶
Simple (faster/cheaper) PII identification prompt.
This prompt is a lightweight version that asks the model only for basic "text" + "type" entities. It is faster and cheaper but does not request base_form or the full entity type list.
Use this prompt (via pdf_anonymizer_core.prompts.simple.prompt_template) for speed/cost sensitive workloads (pairs well with BEST_SPEED or BEST_COST).
Low-Level Components (for advanced use / extension)¶
pdf_anonymizer_core.llm_provider
¶
LLM provider adapters + response caching layer.
This module contains: - LocalLLMCache: thread-safe on-disk caching of LLM responses (keyed by model + prompt hash) to avoid repeated calls during development or re-processing. - LLMProvider abstract base + concrete implementations for Google, Ollama, Hugging Face, OpenRouter, OpenAI, and Anthropic. - configure_cache() and get_provider() factory.
All providers implement a uniform .call(prompt, model_name) that goes
through the cache when enabled.
LLMProvider
¶
Bases: ABC
Abstract base class for LLM providers.
Subclasses must implement _call_raw. The public .call() method (inherited) adds transparent caching when the global cache is enabled.
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/llm_provider.py
call(prompt: str, model_name: str, max_output_tokens: Optional[int] = None) -> str
¶
Public entry point used by the anonymizer.
Checks the cache (if enabled) before delegating to the concrete provider.
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/llm_provider.py
configure_cache(enabled: bool, cache_dir: str = 'data/cache', cache_file: str = 'llm_responses.json')
¶
Enable or disable (and optionally relocate) the global LLM response cache.
Called automatically by the CLI according to the active AppConfig. You can also call it directly when using the core SDK.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
enabled
|
bool
|
Whether caching should be active. |
required |
cache_dir
|
str
|
Directory in which llm_responses.json will be stored. |
'data/cache'
|
cache_file
|
str
|
Filename for the JSON cache. |
'llm_responses.json'
|
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/llm_provider.py
get_provider(provider_name: str) -> LLMProvider
¶
Factory function to get a provider instance.
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/llm_provider.py
pdf_anonymizer_core.call_llm
¶
LLM calling logic with structured parsing and resilient retries.
Contains: - Pydantic models used to validate LLM JSON responses (EntityModel, IdentificationResult). - classify_error(): decides which exceptions are worth retrying. - identify_entities_with_llm(): the main retrying wrapper that talks to providers.
classify_error(exception: Exception) -> tuple[bool, str]
¶
Classify an exception to determine if it is retryable and get a descriptive label.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exception
|
Exception
|
The exception object. |
required |
Returns:
| Type | Description |
|---|---|
tuple[bool, str]
|
A tuple of (is_retryable, error_category). |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/call_llm.py
identify_entities_with_llm(text: str, prompt_template: str, model_name: str, max_retries: int = 3, base_retry_delay: float = 1.0, max_retry_delay: float = 10.0) -> List[dict]
¶
Call an LLM (via the configured provider) to extract PII entities from one chunk.
The call is wrapped with retry logic: - Transient errors (rate limits, 5xx, connection, parsing) are retried. - Auth errors are not retried. - Uses exponential backoff + jitter.
The response is cleaned of markdown fences and validated with Pydantic before returning a list of plain dicts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The chunk of text to analyze. |
required |
prompt_template
|
str
|
Prompt containing a {text} placeholder. |
required |
model_name
|
str
|
Model string (passed through get_provider_and_model_name). |
required |
max_retries
|
int
|
Maximum number of attempts. |
3
|
base_retry_delay
|
float
|
Starting backoff delay (seconds). |
1.0
|
max_retry_delay
|
float
|
Upper bound on backoff delay (seconds). |
10.0
|
Returns:
| Type | Description |
|---|---|
List[dict]
|
List of entity dicts (each with "text", "type", and optionally "base_form"). |
List[dict]
|
Returns [] on unrecoverable failure after retries. |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/call_llm.py
pdf_anonymizer_core.load_and_extract
¶
Text extraction and semantic chunking for PDF, Markdown, and plain text.
Uses pymupdf4llm for high-quality PDF → Markdown conversion (preserves structure useful for LLMs) and langchain text splitters: - MarkdownTextSplitter for .pdf and .md (respects headers/code blocks) - RecursiveCharacterTextSplitter for .txt / fallback
Chunk size and overlap are the primary controls for memory usage and LLM context consumption.
load_and_extract_text_from_file(file_path: str, characters_to_anonymize: int = 100000, chunk_overlap: int = 0) -> Tuple[str, List[str]]
¶
Loads a file and extracts text, returning the full text and chunked text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
str
|
The path to the file. |
required |
characters_to_anonymize
|
int
|
Number of characters to process in each chunk. |
100000
|
chunk_overlap
|
int
|
Overlap size between chunks. |
0
|
Returns:
| Type | Description |
|---|---|
Tuple[str, List[str]]
|
Tuple[str, List[str]]: The full text as a string, and a list of chunk strings. |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/load_and_extract.py
load_and_extract_text_from_pdf(file_path: str, characters_to_anonymize: int = 100000, chunk_overlap: int = 0) -> Tuple[str, List[str]]
¶
Loads a PDF file and extracts text from each page, returning the full text and chunked text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file_path
|
str
|
The path to the PDF file. |
required |
characters_to_anonymize
|
int
|
Number of characters to anonymize in one go (chunk size). |
100000
|
chunk_overlap
|
int
|
Overlap size between chunks. |
0
|
Returns:
| Type | Description |
|---|---|
Tuple[str, List[str]]
|
Tuple[str, List[str]]: The full text as a string, and a list of chunk strings. |
Source code in packages/pdf-anonymizer-core/src/pdf_anonymizer_core/load_and_extract.py
pdf_anonymizer_core.regex_ner
¶
Fast first-stage Named Entity Recognition using regular expressions (RE2 engine).
The hybrid pipeline (core.anonymize_file) ALWAYS runs this regex NER pass before the (more expensive) LLM stage. Matches are later merged/deduped with LLM results via a priority system in core.py (EMAIL, CREDIT_CARD, IBAN, crypto, SSN_* etc. receive elevated priority).
ENGINE¶
This module uses the RE2 engine (package "google-re2") instead of Python's stdlib
re. Benefits:
* Linear-time matching (O(length) worst-case). Immune to catastrophic backtracking
(ReDoS) even with complex patterns or adversarial input.
* Predictable performance on large PDFs / logs / code dumps.
* Same fundamental API surface: compile / finditer / match.group(0) / error.
RE2 LIMITATIONS (patterns here are written to be compliant)¶
- No look-ahead / look-behind assertions ((?=...), (?!...), (?<=...)).
- Limited support for some advanced Python re features (no recursive patterns, limited backreferences). All DEFAULT patterns and documented examples stay within the safe subset.
- word boundaries are supported and used for many PII tokens.
COUNTRY PARTITIONING & EXTENSIVE PII COVERAGE¶
Patterns are defined in pdf_anonymizer_core.conf.DEFAULT_REGEX_PATTERNS and are partitioned by country using ISO-2 suffixes (SSN_US, NINO_GB, INSEE_FR, AADHAAR_IN, RESIDENT_ID_CN, DNI_ES, CODICE_FISCALE_IT, ...).
Mandatory countries covered: USA, Canada, UK, Spain, Italy, France, India, China. 30+ total countries supported via dedicated national/tax/driver/VAT/business ID patterns + universal patterns (IBAN covers most EU+ countries, credit cards, crypto, VIN, MAC, etc. are global).
Supported categories (non-exhaustive): EMAIL, PHONE, URL, IPV4/IPV6, MAC, CREDIT_CARD, CURRENCY_AMOUNT, CRYPTO_BTC / CRYPTO_ETH, IBAN, BIC_SWIFT, VIN, DATE_ISO, SSN / SSN_US / SIN_CA / NINO_GB / INSEE_FR / AADHAAR_IN / RESIDENT_ID_CN, EIN_US, VAT_, PASSPORT_, DRIVERS_LICENSE_, MEDICAL_ , business regs, CURP_MX, CPF_BR, TFN_AU, NRIC_SG, HKID_HK, PESEL_PL, etc.
CUSTOMISATION¶
You can supply a completely custom regex_patterns: Dict[str, str] (type -> pattern)
when calling anonymize_file(). Keys become the emitted entity TYPE (upper-cased)
and are used for placeholder generation (EMAIL_1, IBAN_7, DRIVERS_LICENSE_CA_2, ...).
Only the keys you provide are used; there is no automatic merging with defaults
unless you build your dict from DEFAULT_REGEX_PATTERNS.
The function is intentionally tiny. It only does structural scanning. Semantic disambiguation, name coreference, and hard-to-regex PII remain the responsibility of the LLM stage that always follows.
extract_entities_via_regex(text: str, patterns: Dict[str, str]) -> List[EntityDict]
¶
Scans the text for PII using pre-configured regular expressions (RE2 engine).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Input text to analyze. |
required |
patterns
|
Dict[str, str]
|
Dictionary mapping entity type strings (e.g. "IBAN", "SSN_US", "CRYPTO_ETH") to RE2-compatible regex pattern strings. |
required |
Returns:
| Type | Description |
|---|---|
List[EntityDict]
|
A list of EntityDict representing identified PII. "type" is always |
List[EntityDict]
|
upper-cased. "base_form" currently equals the matched text (core |
List[EntityDict]
|
consolidation may later promote variations to a longer base form). |