privaro 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- privaro-0.1.0/PKG-INFO +232 -0
- privaro-0.1.0/README.md +200 -0
- privaro-0.1.0/privaro/__init__.py +122 -0
- privaro-0.1.0/privaro/async_client.py +110 -0
- privaro-0.1.0/privaro/client.py +204 -0
- privaro-0.1.0/privaro/exceptions.py +35 -0
- privaro-0.1.0/privaro/models.py +77 -0
- privaro-0.1.0/privaro.egg-info/PKG-INFO +232 -0
- privaro-0.1.0/privaro.egg-info/SOURCES.txt +13 -0
- privaro-0.1.0/privaro.egg-info/dependency_links.txt +1 -0
- privaro-0.1.0/privaro.egg-info/requires.txt +10 -0
- privaro-0.1.0/privaro.egg-info/top_level.txt +1 -0
- privaro-0.1.0/pyproject.toml +48 -0
- privaro-0.1.0/setup.cfg +4 -0
- privaro-0.1.0/tests/test_sdk.py +160 -0
privaro-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: privaro
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Privacy Infrastructure for Enterprise AI — Official Python SDK
|
|
5
|
+
Author-email: iCommunity Labs <hello@icommunity.io>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://privaro.io
|
|
8
|
+
Project-URL: Documentation, https://privaro.io/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/icommunity-labs/privaro-python-sdk
|
|
10
|
+
Project-URL: Bug Tracker, https://github.com/icommunity-labs/privaro-python-sdk/issues
|
|
11
|
+
Keywords: privacy,pii,gdpr,ai,llm,compliance,blockchain
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Security
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Provides-Extra: async
|
|
25
|
+
Requires-Dist: aiohttp>=3.9; extra == "async"
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
29
|
+
Requires-Dist: aiohttp>=3.9; extra == "dev"
|
|
30
|
+
Requires-Dist: black; extra == "dev"
|
|
31
|
+
Requires-Dist: ruff; extra == "dev"
|
|
32
|
+
|
|
33
|
+
# Privaro Python SDK
|
|
34
|
+
|
|
35
|
+
**Privacy Infrastructure for Enterprise AI** — Official Python SDK by [iCommunity Labs](https://privaro.io)
|
|
36
|
+
|
|
37
|
+
Protect PII in AI prompts with one line of code. Every interaction is tokenized, audited, and blockchain-certified.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install privaro
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
No required dependencies — uses Python stdlib only.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Optional: async support
|
|
51
|
+
pip install privaro[async]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
import privaro
|
|
60
|
+
|
|
61
|
+
# Initialize once (e.g., at app startup)
|
|
62
|
+
privaro.init(
|
|
63
|
+
api_key="prvr_your_api_key",
|
|
64
|
+
pipeline_id="your-pipeline-uuid",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Protect a prompt before sending to any LLM
|
|
68
|
+
result = privaro.protect("Patient: María García, DNI 34521789X, IBAN ES91 2100...")
|
|
69
|
+
|
|
70
|
+
print(result.protected) # "Patient: [NM-0001], DNI [ID-0001], IBAN [BK-0001]..."
|
|
71
|
+
print(result.risk_score) # 0.847
|
|
72
|
+
print(result.risk_level) # "high"
|
|
73
|
+
print(result.gdpr_compliant) # True
|
|
74
|
+
|
|
75
|
+
# Send protected prompt to your LLM — no PII ever reaches the model
|
|
76
|
+
response = openai.chat.completions.create(
|
|
77
|
+
model="gpt-4o",
|
|
78
|
+
messages=[{"role": "user", "content": result.protected}]
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Usage Patterns
|
|
85
|
+
|
|
86
|
+
### Protect + LLM (full pipeline)
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import privaro
|
|
90
|
+
import openai
|
|
91
|
+
|
|
92
|
+
privaro.init(api_key="prvr_xxx", pipeline_id="uuid")
|
|
93
|
+
|
|
94
|
+
def ask_ai(user_input: str) -> str:
|
|
95
|
+
# 1. Protect PII
|
|
96
|
+
protected = privaro.protect(user_input)
|
|
97
|
+
|
|
98
|
+
if not protected.is_safe:
|
|
99
|
+
raise ValueError(f"PII leak detected: {protected.leaked} entities exposed")
|
|
100
|
+
|
|
101
|
+
# 2. Call LLM with protected prompt
|
|
102
|
+
response = openai.chat.completions.create(
|
|
103
|
+
model="gpt-4o",
|
|
104
|
+
messages=[{"role": "user", "content": protected.protected}]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return response.choices[0].message.content
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Detect only (analysis mode)
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
result = privaro.detect("Call me at 612 345 678, email: user@company.es")
|
|
114
|
+
|
|
115
|
+
for detection in result.detections:
|
|
116
|
+
print(f"{detection.type}: {detection.severity} ({detection.detector})")
|
|
117
|
+
# phone: high (regex)
|
|
118
|
+
# email: high (regex)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Agent mode (stricter policies)
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
result = privaro.protect(
|
|
125
|
+
prompt=agent_input,
|
|
126
|
+
agent_mode=True, # Applies stricter policy preset
|
|
127
|
+
)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Multiple clients (multiple pipelines)
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from privaro import PrivaroClient
|
|
134
|
+
|
|
135
|
+
legal_client = PrivaroClient(api_key="prvr_xxx", pipeline_id="legal-pipeline-uuid")
|
|
136
|
+
hr_client = PrivaroClient(api_key="prvr_xxx", pipeline_id="hr-pipeline-uuid")
|
|
137
|
+
|
|
138
|
+
legal_result = legal_client.protect(contract_text)
|
|
139
|
+
hr_result = hr_client.protect(employee_record)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Async support
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from privaro.async_client import AsyncPrivaroClient
|
|
146
|
+
|
|
147
|
+
client = AsyncPrivaroClient(api_key="prvr_xxx", pipeline_id="uuid")
|
|
148
|
+
|
|
149
|
+
async def process(prompt: str):
|
|
150
|
+
result = await client.protect(prompt)
|
|
151
|
+
return result.protected
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Error handling
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from privaro.exceptions import AuthError, PolicyBlockError, ProxyUnavailableError
|
|
158
|
+
|
|
159
|
+
try:
|
|
160
|
+
result = privaro.protect(prompt)
|
|
161
|
+
except PolicyBlockError as e:
|
|
162
|
+
# Request blocked by policy (e.g., health data on non-approved provider)
|
|
163
|
+
logger.warning(f"Request blocked: {e}")
|
|
164
|
+
return "Request cannot be processed — sensitive data detected."
|
|
165
|
+
except ProxyUnavailableError:
|
|
166
|
+
# Fallback: log and fail safely
|
|
167
|
+
logger.error("Privaro proxy unavailable")
|
|
168
|
+
raise
|
|
169
|
+
except AuthError:
|
|
170
|
+
logger.error("Invalid Privaro API key")
|
|
171
|
+
raise
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## ProtectResult Reference
|
|
177
|
+
|
|
178
|
+
| Property | Type | Description |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `result.protected` | str | Prompt with PII replaced by tokens |
|
|
181
|
+
| `result.original` | str | Original prompt (local only) |
|
|
182
|
+
| `result.risk_score` | float | 0.0–1.0 composite risk score |
|
|
183
|
+
| `result.risk_level` | str | "high" / "medium" / "low" |
|
|
184
|
+
| `result.gdpr_compliant` | bool | True if no PII leaked |
|
|
185
|
+
| `result.is_safe` | bool | True if all PII masked |
|
|
186
|
+
| `result.has_pii` | bool | True if any entities detected |
|
|
187
|
+
| `result.total_detected` | int | Total PII entities found |
|
|
188
|
+
| `result.total_masked` | int | Entities successfully masked |
|
|
189
|
+
| `result.leaked` | int | Entities that passed through |
|
|
190
|
+
| `result.detections` | list[Detection] | Per-entity details |
|
|
191
|
+
| `result.audit_log_id` | str | Supabase audit log UUID |
|
|
192
|
+
| `result.processing_ms` | int | Proxy latency in ms |
|
|
193
|
+
| `result.summary()` | str | One-line log summary |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Detection Reference
|
|
198
|
+
|
|
199
|
+
| Property | Values |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `detection.type` | `dni` `iban` `email` `full_name` `phone` `health_record` `credit_card` `ip_address` `date_of_birth` |
|
|
202
|
+
| `detection.severity` | `critical` `high` `medium` `low` |
|
|
203
|
+
| `detection.action` | `tokenised` `anonymised` `blocked` |
|
|
204
|
+
| `detection.detector` | `regex` `presidio` |
|
|
205
|
+
| `detection.confidence` | 0.0–1.0 |
|
|
206
|
+
| `detection.is_high_risk` | bool |
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Blockchain Verification
|
|
211
|
+
|
|
212
|
+
Every `protect()` call creates an immutable audit entry certified on **Fantom Opera Mainnet** via iBS. Verify any event at:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
https://checker.icommunitylabs.com/check/fantom_opera_mainnet/{tx_hash}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Access the TX hash from your Privaro dashboard → Audit Logs → ⛓️ badge.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Requirements
|
|
223
|
+
|
|
224
|
+
- Python 3.9+
|
|
225
|
+
- Zero required dependencies (uses `urllib` from stdlib)
|
|
226
|
+
- Optional: `aiohttp>=3.9` for async support
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## License
|
|
231
|
+
|
|
232
|
+
MIT — © 2026 iCommunity Labs · [privaro.io](https://privaro.io)
|
privaro-0.1.0/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Privaro Python SDK
|
|
2
|
+
|
|
3
|
+
**Privacy Infrastructure for Enterprise AI** — Official Python SDK by [iCommunity Labs](https://privaro.io)
|
|
4
|
+
|
|
5
|
+
Protect PII in AI prompts with one line of code. Every interaction is tokenized, audited, and blockchain-certified.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install privaro
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
No required dependencies — uses Python stdlib only.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Optional: async support
|
|
19
|
+
pip install privaro[async]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import privaro
|
|
28
|
+
|
|
29
|
+
# Initialize once (e.g., at app startup)
|
|
30
|
+
privaro.init(
|
|
31
|
+
api_key="prvr_your_api_key",
|
|
32
|
+
pipeline_id="your-pipeline-uuid",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Protect a prompt before sending to any LLM
|
|
36
|
+
result = privaro.protect("Patient: María García, DNI 34521789X, IBAN ES91 2100...")
|
|
37
|
+
|
|
38
|
+
print(result.protected) # "Patient: [NM-0001], DNI [ID-0001], IBAN [BK-0001]..."
|
|
39
|
+
print(result.risk_score) # 0.847
|
|
40
|
+
print(result.risk_level) # "high"
|
|
41
|
+
print(result.gdpr_compliant) # True
|
|
42
|
+
|
|
43
|
+
# Send protected prompt to your LLM — no PII ever reaches the model
|
|
44
|
+
response = openai.chat.completions.create(
|
|
45
|
+
model="gpt-4o",
|
|
46
|
+
messages=[{"role": "user", "content": result.protected}]
|
|
47
|
+
)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Usage Patterns
|
|
53
|
+
|
|
54
|
+
### Protect + LLM (full pipeline)
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
import privaro
|
|
58
|
+
import openai
|
|
59
|
+
|
|
60
|
+
privaro.init(api_key="prvr_xxx", pipeline_id="uuid")
|
|
61
|
+
|
|
62
|
+
def ask_ai(user_input: str) -> str:
|
|
63
|
+
# 1. Protect PII
|
|
64
|
+
protected = privaro.protect(user_input)
|
|
65
|
+
|
|
66
|
+
if not protected.is_safe:
|
|
67
|
+
raise ValueError(f"PII leak detected: {protected.leaked} entities exposed")
|
|
68
|
+
|
|
69
|
+
# 2. Call LLM with protected prompt
|
|
70
|
+
response = openai.chat.completions.create(
|
|
71
|
+
model="gpt-4o",
|
|
72
|
+
messages=[{"role": "user", "content": protected.protected}]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
return response.choices[0].message.content
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Detect only (analysis mode)
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
result = privaro.detect("Call me at 612 345 678, email: user@company.es")
|
|
82
|
+
|
|
83
|
+
for detection in result.detections:
|
|
84
|
+
print(f"{detection.type}: {detection.severity} ({detection.detector})")
|
|
85
|
+
# phone: high (regex)
|
|
86
|
+
# email: high (regex)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Agent mode (stricter policies)
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
result = privaro.protect(
|
|
93
|
+
prompt=agent_input,
|
|
94
|
+
agent_mode=True, # Applies stricter policy preset
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Multiple clients (multiple pipelines)
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from privaro import PrivaroClient
|
|
102
|
+
|
|
103
|
+
legal_client = PrivaroClient(api_key="prvr_xxx", pipeline_id="legal-pipeline-uuid")
|
|
104
|
+
hr_client = PrivaroClient(api_key="prvr_xxx", pipeline_id="hr-pipeline-uuid")
|
|
105
|
+
|
|
106
|
+
legal_result = legal_client.protect(contract_text)
|
|
107
|
+
hr_result = hr_client.protect(employee_record)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Async support
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from privaro.async_client import AsyncPrivaroClient
|
|
114
|
+
|
|
115
|
+
client = AsyncPrivaroClient(api_key="prvr_xxx", pipeline_id="uuid")
|
|
116
|
+
|
|
117
|
+
async def process(prompt: str):
|
|
118
|
+
result = await client.protect(prompt)
|
|
119
|
+
return result.protected
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Error handling
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from privaro.exceptions import AuthError, PolicyBlockError, ProxyUnavailableError
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
result = privaro.protect(prompt)
|
|
129
|
+
except PolicyBlockError as e:
|
|
130
|
+
# Request blocked by policy (e.g., health data on non-approved provider)
|
|
131
|
+
logger.warning(f"Request blocked: {e}")
|
|
132
|
+
return "Request cannot be processed — sensitive data detected."
|
|
133
|
+
except ProxyUnavailableError:
|
|
134
|
+
# Fallback: log and fail safely
|
|
135
|
+
logger.error("Privaro proxy unavailable")
|
|
136
|
+
raise
|
|
137
|
+
except AuthError:
|
|
138
|
+
logger.error("Invalid Privaro API key")
|
|
139
|
+
raise
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## ProtectResult Reference
|
|
145
|
+
|
|
146
|
+
| Property | Type | Description |
|
|
147
|
+
|---|---|---|
|
|
148
|
+
| `result.protected` | str | Prompt with PII replaced by tokens |
|
|
149
|
+
| `result.original` | str | Original prompt (local only) |
|
|
150
|
+
| `result.risk_score` | float | 0.0–1.0 composite risk score |
|
|
151
|
+
| `result.risk_level` | str | "high" / "medium" / "low" |
|
|
152
|
+
| `result.gdpr_compliant` | bool | True if no PII leaked |
|
|
153
|
+
| `result.is_safe` | bool | True if all PII masked |
|
|
154
|
+
| `result.has_pii` | bool | True if any entities detected |
|
|
155
|
+
| `result.total_detected` | int | Total PII entities found |
|
|
156
|
+
| `result.total_masked` | int | Entities successfully masked |
|
|
157
|
+
| `result.leaked` | int | Entities that passed through |
|
|
158
|
+
| `result.detections` | list[Detection] | Per-entity details |
|
|
159
|
+
| `result.audit_log_id` | str | Supabase audit log UUID |
|
|
160
|
+
| `result.processing_ms` | int | Proxy latency in ms |
|
|
161
|
+
| `result.summary()` | str | One-line log summary |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Detection Reference
|
|
166
|
+
|
|
167
|
+
| Property | Values |
|
|
168
|
+
|---|---|
|
|
169
|
+
| `detection.type` | `dni` `iban` `email` `full_name` `phone` `health_record` `credit_card` `ip_address` `date_of_birth` |
|
|
170
|
+
| `detection.severity` | `critical` `high` `medium` `low` |
|
|
171
|
+
| `detection.action` | `tokenised` `anonymised` `blocked` |
|
|
172
|
+
| `detection.detector` | `regex` `presidio` |
|
|
173
|
+
| `detection.confidence` | 0.0–1.0 |
|
|
174
|
+
| `detection.is_high_risk` | bool |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Blockchain Verification
|
|
179
|
+
|
|
180
|
+
Every `protect()` call creates an immutable audit entry certified on **Fantom Opera Mainnet** via iBS. Verify any event at:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
https://checker.icommunitylabs.com/check/fantom_opera_mainnet/{tx_hash}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Access the TX hash from your Privaro dashboard → Audit Logs → ⛓️ badge.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Requirements
|
|
191
|
+
|
|
192
|
+
- Python 3.9+
|
|
193
|
+
- Zero required dependencies (uses `urllib` from stdlib)
|
|
194
|
+
- Optional: `aiohttp>=3.9` for async support
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT — © 2026 iCommunity Labs · [privaro.io](https://privaro.io)
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Privaro Python SDK
|
|
3
|
+
Privacy Infrastructure for Enterprise AI — iCommunity Labs
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
import privaro
|
|
7
|
+
|
|
8
|
+
privaro.init(api_key="prvr_xxx", pipeline_id="uuid")
|
|
9
|
+
result = privaro.protect("Patient: María García, DNI 34521789X")
|
|
10
|
+
|
|
11
|
+
print(result.protected) # "Patient: [NM-0001], DNI [ID-0001]"
|
|
12
|
+
print(result.risk_score) # 0.847
|
|
13
|
+
print(result.gdpr_compliant) # True
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from .client import PrivaroClient
|
|
17
|
+
from .models import ProtectResult, Detection
|
|
18
|
+
from .exceptions import PrivaroError, AuthError, PipelineNotFoundError
|
|
19
|
+
|
|
20
|
+
__version__ = "0.1.0"
|
|
21
|
+
__all__ = [
|
|
22
|
+
"PrivaroClient",
|
|
23
|
+
"ProtectResult",
|
|
24
|
+
"Detection",
|
|
25
|
+
"PrivaroError",
|
|
26
|
+
"AuthError",
|
|
27
|
+
"PipelineNotFoundError",
|
|
28
|
+
"init",
|
|
29
|
+
"protect",
|
|
30
|
+
"detect",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# ── Module-level default client ───────────────────────────────────────────────
|
|
34
|
+
_default_client: "PrivaroClient | None" = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def init(
|
|
38
|
+
api_key: str,
|
|
39
|
+
pipeline_id: str,
|
|
40
|
+
base_url: str = "https://privaro-proxy-production.up.railway.app/v1",
|
|
41
|
+
timeout: float = 10.0,
|
|
42
|
+
) -> PrivaroClient:
|
|
43
|
+
"""
|
|
44
|
+
Initialize the default Privaro client.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
api_key: Your Privaro API key (starts with prvr_)
|
|
48
|
+
pipeline_id: UUID of your active pipeline
|
|
49
|
+
base_url: Proxy URL (default: production)
|
|
50
|
+
timeout: Request timeout in seconds
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
PrivaroClient instance (also set as module default)
|
|
54
|
+
|
|
55
|
+
Example:
|
|
56
|
+
privaro.init(
|
|
57
|
+
api_key="prvr_abc123",
|
|
58
|
+
pipeline_id="c93aed87-b440-4de0-bb21-54a938e475f2"
|
|
59
|
+
)
|
|
60
|
+
"""
|
|
61
|
+
global _default_client
|
|
62
|
+
_default_client = PrivaroClient(
|
|
63
|
+
api_key=api_key,
|
|
64
|
+
pipeline_id=pipeline_id,
|
|
65
|
+
base_url=base_url,
|
|
66
|
+
timeout=timeout,
|
|
67
|
+
)
|
|
68
|
+
return _default_client
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _require_client() -> "PrivaroClient":
|
|
72
|
+
if _default_client is None:
|
|
73
|
+
raise PrivaroError(
|
|
74
|
+
"Privaro not initialized. Call privaro.init(api_key=..., pipeline_id=...) first."
|
|
75
|
+
)
|
|
76
|
+
return _default_client
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def protect(
|
|
80
|
+
prompt: str,
|
|
81
|
+
mode: str = "tokenise",
|
|
82
|
+
reversible: bool = True,
|
|
83
|
+
agent_mode: bool = False,
|
|
84
|
+
include_detections: bool = True,
|
|
85
|
+
) -> "ProtectResult":
|
|
86
|
+
"""
|
|
87
|
+
Detect and tokenize PII in a prompt.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
prompt: Text to protect
|
|
91
|
+
mode: tokenise | anonymise | block
|
|
92
|
+
reversible: Store reversible tokens in vault
|
|
93
|
+
agent_mode: Apply stricter policies for agent pipelines
|
|
94
|
+
include_detections: Include detection details in response
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
ProtectResult with .protected, .risk_score, .detections, etc.
|
|
98
|
+
|
|
99
|
+
Example:
|
|
100
|
+
result = privaro.protect("Patient: María García, DNI 34521789X")
|
|
101
|
+
llm_response = your_llm.complete(result.protected)
|
|
102
|
+
"""
|
|
103
|
+
return _require_client().protect(
|
|
104
|
+
prompt=prompt,
|
|
105
|
+
mode=mode,
|
|
106
|
+
reversible=reversible,
|
|
107
|
+
agent_mode=agent_mode,
|
|
108
|
+
include_detections=include_detections,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def detect(prompt: str) -> "ProtectResult":
|
|
113
|
+
"""
|
|
114
|
+
Detect PII without masking (analysis mode).
|
|
115
|
+
Does not store audit logs or tokens.
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
result = privaro.detect("Call me at 612 345 678")
|
|
119
|
+
for d in result.detections:
|
|
120
|
+
print(d.type, d.confidence)
|
|
121
|
+
"""
|
|
122
|
+
return _require_client().detect(prompt=prompt)
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Privaro SDK — Async Client (optional, requires Python 3.11+)
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
from privaro.async_client import AsyncPrivaroClient
|
|
6
|
+
|
|
7
|
+
client = AsyncPrivaroClient(api_key="prvr_xxx", pipeline_id="uuid")
|
|
8
|
+
|
|
9
|
+
async with client:
|
|
10
|
+
result = await client.protect("María García, DNI 34521789X")
|
|
11
|
+
"""
|
|
12
|
+
import json
|
|
13
|
+
from typing import Optional
|
|
14
|
+
from .client import PrivaroClient
|
|
15
|
+
from .models import ProtectResult
|
|
16
|
+
from .exceptions import (
|
|
17
|
+
AuthError, PipelineNotFoundError, PolicyBlockError,
|
|
18
|
+
RateLimitError, ProxyUnavailableError, PrivaroError,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AsyncPrivaroClient(PrivaroClient):
|
|
23
|
+
"""
|
|
24
|
+
Async version of PrivaroClient using aiohttp (optional dependency).
|
|
25
|
+
|
|
26
|
+
Install with: pip install privaro[async]
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
async def _request_async(self, method: str, path: str, payload: dict) -> dict:
|
|
30
|
+
try:
|
|
31
|
+
import aiohttp
|
|
32
|
+
except ImportError:
|
|
33
|
+
raise PrivaroError(
|
|
34
|
+
"aiohttp is required for async support. "
|
|
35
|
+
"Install with: pip install privaro[async]"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
url = f"{self.base_url}{path}"
|
|
39
|
+
|
|
40
|
+
async with aiohttp.ClientSession() as session:
|
|
41
|
+
try:
|
|
42
|
+
async with session.request(
|
|
43
|
+
method, url,
|
|
44
|
+
json=payload,
|
|
45
|
+
headers=self._headers(),
|
|
46
|
+
timeout=aiohttp.ClientTimeout(total=self.timeout),
|
|
47
|
+
) as resp:
|
|
48
|
+
body = await resp.json()
|
|
49
|
+
|
|
50
|
+
if resp.status == 401:
|
|
51
|
+
raise AuthError("Invalid API key.")
|
|
52
|
+
if resp.status == 404:
|
|
53
|
+
raise PipelineNotFoundError(f"Pipeline '{self.pipeline_id}' not found.")
|
|
54
|
+
if resp.status == 429:
|
|
55
|
+
raise RateLimitError("Rate limit exceeded.")
|
|
56
|
+
if resp.status >= 400:
|
|
57
|
+
raise PrivaroError(f"HTTP {resp.status}: {body}")
|
|
58
|
+
|
|
59
|
+
return body
|
|
60
|
+
|
|
61
|
+
except aiohttp.ClientConnectorError as e:
|
|
62
|
+
raise ProxyUnavailableError(f"Cannot reach proxy: {e}")
|
|
63
|
+
|
|
64
|
+
async def protect(
|
|
65
|
+
self,
|
|
66
|
+
prompt: str,
|
|
67
|
+
mode: str = "tokenise",
|
|
68
|
+
reversible: bool = True,
|
|
69
|
+
agent_mode: bool = False,
|
|
70
|
+
include_detections: bool = True,
|
|
71
|
+
) -> ProtectResult:
|
|
72
|
+
"""Async version of protect()."""
|
|
73
|
+
if not prompt or not prompt.strip():
|
|
74
|
+
return ProtectResult(protected="", original="", request_id="",
|
|
75
|
+
audit_log_id=None, gdpr_compliant=True)
|
|
76
|
+
|
|
77
|
+
raw = await self._request_async("POST", "/proxy/protect", {
|
|
78
|
+
"pipeline_id": self.pipeline_id,
|
|
79
|
+
"prompt": prompt,
|
|
80
|
+
"options": {
|
|
81
|
+
"mode": mode,
|
|
82
|
+
"reversible": reversible,
|
|
83
|
+
"agent_mode": agent_mode,
|
|
84
|
+
"include_detections": include_detections,
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
return self._parse_result(raw, original=prompt)
|
|
88
|
+
|
|
89
|
+
async def detect(self, prompt: str) -> ProtectResult:
|
|
90
|
+
"""Async version of detect()."""
|
|
91
|
+
if not prompt or not prompt.strip():
|
|
92
|
+
return ProtectResult(protected=prompt, original=prompt, request_id="",
|
|
93
|
+
audit_log_id=None, gdpr_compliant=True)
|
|
94
|
+
|
|
95
|
+
raw = await self._request_async("POST", "/proxy/detect", {
|
|
96
|
+
"pipeline_id": self.pipeline_id,
|
|
97
|
+
"prompt": prompt,
|
|
98
|
+
})
|
|
99
|
+
result = self._parse_result(
|
|
100
|
+
{**raw, "protected_prompt": prompt, "gdpr_compliant": True},
|
|
101
|
+
original=prompt,
|
|
102
|
+
)
|
|
103
|
+
result.protected = prompt
|
|
104
|
+
return result
|
|
105
|
+
|
|
106
|
+
async def __aenter__(self):
|
|
107
|
+
return self
|
|
108
|
+
|
|
109
|
+
async def __aexit__(self, *args):
|
|
110
|
+
pass
|