Coverage for presidio_analyzer / predefined_recognizers / third_party / azure_openai_langextract_recognizer.py: 100%
34 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-29 09:03 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-29 09:03 +0000
1"""Azure OpenAI LangExtract Recognizer for PII/PHI detection."""
3import logging
4import os
5from pathlib import Path
6from typing import Optional
8try:
9 import langextract as lx
10 LANGEXTRACT_AVAILABLE = True
11except ImportError: # pragma: no cover
12 LANGEXTRACT_AVAILABLE = False
13 lx = None
15from presidio_analyzer.predefined_recognizers.third_party import (
16 langextract_recognizer,
17)
19# Import provider module to trigger registration with LangExtract
20# This must happen at module import time for the @register decorator to execute
21try:
22 from presidio_analyzer.predefined_recognizers.third_party import (
23 azure_openai_provider, # noqa: F401 - imported for side effects (registration)
24 )
25except ImportError: # pragma: no cover
26 pass
28logger = logging.getLogger("presidio-analyzer")
30LangExtractRecognizer = langextract_recognizer.LangExtractRecognizer
32AZURE_OPENAI_DOCS_URL = "https://learn.microsoft.com/en-us/azure/ai-services/openai/"
35class AzureOpenAILangExtractRecognizer(LangExtractRecognizer):
36 """
37 Concrete implementation of LangExtract recognizer using Azure OpenAI backend.
39 Provides Azure OpenAI-specific functionality including:
40 - Azure OpenAI endpoint and API key configuration
41 - Deployment name management
42 - API version control
43 - Integration with custom Azure OpenAI provider via LangExtract registry
44 """
46 DEFAULT_API_VERSION = "2024-02-15-preview"
48 DEFAULT_CONFIG_PATH = (
49 Path(__file__).parent.parent.parent
50 / "conf"
51 / "langextract_config_azureopenai.yaml"
52 )
54 def __init__(
55 self,
56 model_id: Optional[str] = None,
57 config_path: Optional[str] = None,
58 azure_endpoint: Optional[str] = None,
59 api_key: Optional[str] = None,
60 api_version: Optional[str] = None,
61 supported_language: str = "en",
62 name: str = "Azure OpenAI LangExtract PII",
63 ):
64 """
65 Initialize Azure OpenAI LangExtract recognizer for PII/PHI detection.
67 Note: Azure OpenAI endpoint and API configuration are not validated
68 during initialization. Any connectivity or authentication issues will
69 be reported when analyze() is first called.
71 Configuration priority for authentication (highest to lowest):
72 1. Direct parameters (azure_endpoint, api_key, api_version)
73 2. Environment variables (AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_KEY,
74 AZURE_OPENAI_API_VERSION)
76 Configuration priority for model_id (deployment name):
77 1. Direct parameter (model_id)
78 2. Config file (langextract.model.model_id)
80 :param model_id: Azure OpenAI deployment name (e.g., "gpt-4",
81 "gpt-4o"). Overrides config file.
82 :param config_path: Path to YAML configuration file. If not provided,
83 uses default config.
84 :param azure_endpoint: Azure OpenAI endpoint URL (overrides env var).
85 :param api_key: Azure OpenAI API key (overrides env var). If not
86 provided, uses managed identity.
87 :param api_version: Azure OpenAI API version (optional, defaults to
88 "2024-02-15-preview").
89 :param supported_language: Language this recognizer supports
90 (optional, default: "en").
91 :raises ImportError: If langextract is not installed.
92 :raises ValueError: If Azure OpenAI endpoint is not provided via
93 parameter or env var.
94 """
96 # Determine actual config path
97 actual_config_path = (
98 config_path if config_path else str(self.DEFAULT_CONFIG_PATH)
99 )
101 # Get Azure-specific settings with priority: parameter > env var
102 self.azure_endpoint = azure_endpoint or os.environ.get("AZURE_OPENAI_ENDPOINT")
103 self._validate_azure_endpoint(self.azure_endpoint)
105 self.api_key = api_key or os.environ.get("AZURE_OPENAI_API_KEY")
106 self.api_version = (
107 api_version
108 or os.environ.get("AZURE_OPENAI_API_VERSION")
109 or self.DEFAULT_API_VERSION
110 )
112 # Initialize parent class (loads config, sets self.model_id from config)
113 super().__init__(
114 config_path=actual_config_path,
115 name=name,
116 supported_language=supported_language,
117 extract_params={
118 "extract": {
119 "fence_output": True,
120 "use_schema_constraints": False,
121 },
122 },
123 )
125 # Override model_id if provided as parameter (deployment name)
126 if model_id:
127 self.model_id = model_id
129 def _validate_azure_endpoint(self, azure_endpoint: Optional[str]) -> None:
130 """
131 Validate that Azure OpenAI endpoint is provided.
133 :param azure_endpoint: Azure OpenAI endpoint URL.
134 :raises ValueError: If endpoint is not provided.
135 """
136 if not azure_endpoint:
137 raise ValueError(
138 "Azure OpenAI endpoint is required. Provide 'azure_endpoint' parameter "
139 f"or set AZURE_OPENAI_ENDPOINT environment variable.\n"
140 f"See {AZURE_OPENAI_DOCS_URL} for details."
141 )
143 def _get_provider_params(self):
144 """Return Azure OpenAI-specific params."""
145 model_id_with_prefix = f"azure:{self.model_id}"
147 language_model_params = {
148 "azure_endpoint": self.azure_endpoint,
149 "api_version": self.api_version,
150 "azure_deployment": self.model_id,
151 }
153 if self.api_key:
154 language_model_params["api_key"] = self.api_key
156 return {
157 "model_id": model_id_with_prefix,
158 "language_model_params": language_model_params,
159 }