77
88from typing import Any
99
10- from fastapi import Body , FastAPI
10+ from fastapi import FastAPI
1111from presidio_analyzer import AnalyzerEngine , Pattern , PatternRecognizer , RecognizerResult
1212from presidio_analyzer .nlp_engine import NlpEngineProvider
1313from presidio_analyzer .predefined_recognizers import (
3535)
3636from presidio_anonymizer import AnonymizerEngine
3737from presidio_anonymizer .entities import OperatorConfig
38+ from pydantic import BaseModel
3839
3940# Languages served. Each needs its spaCy model installed in the image; the
4041# es/it/pl/fi predefined recognizers (ES_NIF, IT_FISCAL_CODE, PL_PESEL, ...)
@@ -112,14 +113,18 @@ def validate_result(self, pattern_text: str):
112113def build_analyzer () -> AnalyzerEngine :
113114 nlp_engine = NlpEngineProvider (nlp_configuration = NLP_CONFIGURATION ).create_engine ()
114115 analyzer = AnalyzerEngine (nlp_engine = nlp_engine , supported_languages = SUPPORTED_LANGUAGES )
116+ # VIN is language-agnostic, so register it under every served language —
117+ # a recognizer only fires for the language the caller routes to.
115118 vin_pattern = Pattern (name = "vin" , regex = r"\b[A-HJ-NPR-Z0-9]{17}\b" , score = 0.7 )
116- analyzer .registry .add_recognizer (
117- VinRecognizer (
118- supported_entity = "VIN" ,
119- patterns = [vin_pattern ],
120- context = ["vin" , "vehicle" , "chassis" ],
119+ for language in SUPPORTED_LANGUAGES :
120+ analyzer .registry .add_recognizer (
121+ VinRecognizer (
122+ supported_entity = "VIN" ,
123+ patterns = [vin_pattern ],
124+ context = ["vin" , "vehicle" , "chassis" ],
125+ supported_language = language ,
126+ )
121127 )
122- )
123128 for recognizer_cls in EXTRA_RECOGNIZERS :
124129 analyzer .registry .add_recognizer (recognizer_cls ())
125130 return analyzer
@@ -131,6 +136,21 @@ def build_analyzer() -> AnalyzerEngine:
131136app = FastAPI (title = "Sim Presidio" , docs_url = None , redoc_url = None )
132137
133138
139+ class AnalyzeRequest (BaseModel ):
140+ text : str
141+ language : str = "en"
142+ entities : list [str ] | None = None
143+ score_threshold : float | None = None
144+ return_decision_process : bool = False
145+
146+
147+ class AnonymizeRequest (BaseModel ):
148+ text : str
149+ analyzer_results : list [dict [str , Any ]] = []
150+ anonymizers : dict [str , dict [str , Any ]] | None = None
151+ operators : dict [str , dict [str , Any ]] | None = None
152+
153+
134154@app .get ("/health" )
135155def health () -> dict [str , str ]:
136156 return {"status" : "ok" }
@@ -142,38 +162,38 @@ def supported_entities(language: str = "en") -> list[str]:
142162
143163
144164@app .post ("/analyze" )
145- def analyze (payload : dict [str , Any ] = Body (...)) -> list [dict [str , Any ]]:
146- entities = payload .get ("entities" ) or None
165+ def analyze (req : AnalyzeRequest ) -> list [dict [str , Any ]]:
147166 results = analyzer .analyze (
148- text = payload [ " text" ] ,
149- language = payload . get ( " language" , "en" ) ,
150- entities = entities ,
151- score_threshold = payload . get ( " score_threshold" ) ,
152- return_decision_process = payload . get ( " return_decision_process" , False ) ,
167+ text = req . text ,
168+ language = req . language ,
169+ entities = req . entities or None ,
170+ score_threshold = req . score_threshold ,
171+ return_decision_process = req . return_decision_process ,
153172 )
154173 return [r .to_dict () for r in results ]
155174
156175
157176@app .post ("/anonymize" )
158- def anonymize (payload : dict [ str , Any ] = Body (...) ) -> dict [str , Any ]:
177+ def anonymize (req : AnonymizeRequest ) -> dict [str , Any ]:
159178 analyzer_results = [
160179 RecognizerResult (
161180 entity_type = r ["entity_type" ],
162181 start = r ["start" ],
163182 end = r ["end" ],
164183 score = r .get ("score" , 1.0 ),
165184 )
166- for r in payload . get ( " analyzer_results" , [])
185+ for r in req . analyzer_results
167186 ]
168- raw_operators = payload . get ( " anonymizers" ) or payload . get ( " operators" )
187+ raw_operators = req . anonymizers or req . operators
169188 operators = None
170189 if raw_operators :
171190 operators = {}
172- for entity , cfg in raw_operators .items ():
173- cfg = dict (cfg )
174- operators [entity ] = OperatorConfig (cfg .pop ("type" ), cfg )
191+ for entity , raw_cfg in raw_operators .items ():
192+ op_cfg = dict (raw_cfg )
193+ op_type = op_cfg .pop ("type" , "replace" )
194+ operators [entity ] = OperatorConfig (op_type , op_cfg )
175195 result = anonymizer .anonymize (
176- text = payload [ " text" ] ,
196+ text = req . text ,
177197 analyzer_results = analyzer_results ,
178198 operators = operators ,
179199 )
0 commit comments