GDPR-compliant LLM routing with real-time PII detection. Detects personal data in prompts and forces EU-only routing automatically.
Project description
GDPR-compliant LLM routing with real-time PII detection
Your AI calls cross the Atlantic. Your users' data shouldn't.
Quick Start • How It Works • Features • SDKs • Examples • API Reference • Contributing
If your LLM prompt contains a name, email, or IBAN — and it hits a US server — that's a GDPR violation. Max fine: 4% of global revenue or 20M EUR.
This gateway fixes that in 3 lines of code.
The Problem
Every time you call openai.chat.completions.create() with a European user's name in the prompt, you're potentially violating GDPR Article 44 (international data transfers).
Your EU User --> Your App --> OpenAI API (Virginia, US) --> GDPR VIOLATION
| |
| Name, email, IBAN |
| in the prompt |
+------------------------------------+
Personal data left the EU
Most teams either:
- A) Ignore it and hope for the best
- B) Route everything to EU (expensive)
- C) Anonymize all data (breaks context)
We built option D:
Your EU User --> Your App --> Sovereign Gateway --> PII detected?
| |
| YES: EU provider only
| NO: cheapest provider
|
100% GDPR compliant
30-40% cheaper than option B
Quick Start
Install
pip install mh-gdpr-ai
3 Lines — PII Detection + Routing Decision
from sovereign_gateway import SovereignGateway
gateway = SovereignGateway()
result = gateway.route([{"role": "user", "content": "Analyze the account of jean.dupont@company.fr"}])
print(result.pii_detected) # True
print(result.pii_types) # ['EMAIL_ADDRESS']
print(result.forced_eu_routing) # True
print(result.gdpr_compliant) # True
End-to-End — PII Detection + Routing + LLM Call
Add your provider API key and the gateway calls the LLM for you:
from sovereign_gateway import SovereignGateway
# Configure with your provider(s)
gateway = SovereignGateway(providers={
"scaleway": {"api_key": "scw-your-key"}, # EU provider (Paris)
"together_ai": {"api_key": "tok-your-key"}, # Non-EU fallback
})
# PII detected -> automatically calls Scaleway (EU only)
result = gateway.complete([
{"role": "user", "content": "Analyze the account of jean.dupont@company.fr"}
])
print(result.content) # Actual LLM response
print(result.provider_used) # "scaleway" (EU, because PII detected)
print(result.forced_eu_routing) # True
print(result.gdpr_compliant) # True
print(result.tokens_used) # 42
# No PII -> automatically calls cheapest provider
result = gateway.complete([
{"role": "user", "content": "Summarize this quarterly report"}
])
print(result.provider_used) # cheapest available provider
print(result.forced_eu_routing) # False
Works with any OpenAI-compatible provider: Scaleway, OVHcloud, Together AI, OpenAI, Mistral, DeepSeek, Groq, Fireworks.
See It In Action
How It Works
The gateway runs a 3-filter pipeline on every request in under 50ms:
┌─────────────────────────────────────┐
│ INCOMING REQUEST │
│ "Analyze jean.dupont@company.fr" │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ FILTER 1: PII DETECTION │
│ │
│ Layer 1: Presidio NLP │
│ -> PERSON, EMAIL, PHONE, IBAN... │
│ │
│ Layer 2: Regex (defense in depth) │
│ -> EMAIL, CREDIT_CARD, SSN... │
│ │
│ Result: EMAIL_ADDRESS detected │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ FILTER 2: ROUTING DECISION │
│ │
│ PII found? │
│ ├─ YES -> EU providers ONLY │
│ │ (Scaleway, OVHCloud) │
│ │ Cannot be bypassed. │
│ │ │
│ └─ NO -> Cheapest provider │
│ (any region) │
└──────────────┬──────────────────────┘
│
┌──────────────▼──────────────────────┐
│ FILTER 3: COMPLIANCE METADATA │
│ │
│ { │
│ "gdpr_compliant": true, │
│ "pii_types": ["EMAIL_ADDRESS"], │
│ "forced_eu_routing": true, │
│ "provider": "scaleway" │
│ } │
│ │
│ Ready for your DPO's audit report. │
└─────────────────────────────────────┘
Dual-Layer PII Detection
| Layer | Engine | Speed | Entities | Purpose |
|---|---|---|---|---|
| Primary | Microsoft Presidio (NLP) | ~30ms | 15+ types | High accuracy, context-aware |
| Fallback | Regex patterns | <5ms | 7 types | Guaranteed detection, always runs |
Both layers run on every request. If Presidio misses something, regex catches it. If Presidio isn't installed, regex handles everything.
Features
PII Detection (15+ Entity Types)
| Entity Type | Example | Detection |
|---|---|---|
PERSON |
Jean Dupont | Presidio |
EMAIL_ADDRESS |
jean@company.fr | Presidio + Regex |
PHONE_NUMBER |
+33 6 12 34 56 78 | Presidio + Regex |
IBAN_CODE |
FR76 3000 6000 0112... | Presidio + Regex |
CREDIT_CARD |
4111 1111 1111 1111 | Presidio + Regex |
US_SSN |
123-45-6789 | Presidio + Regex |
FR_NIR |
1 85 05 78 006 084 36 | Regex |
IP_ADDRESS |
192.168.1.1 | Presidio + Regex |
LOCATION |
14 Rue de Rivoli, Paris | Presidio |
DATE_TIME |
Born on 15/03/1985 | Presidio |
MEDICAL_LICENSE |
DEA: AB1234567 | Presidio |
CRYPTO |
1A1zP1eP5QGefi2... | Presidio |
NRP |
French nationality | Presidio |
UK_NHS |
943 476 5919 | Presidio |
US_PASSPORT |
123456789 | Presidio |
Sovereign Routing
| Condition | Routing | Providers | Model |
|---|---|---|---|
| PII detected | EU ONLY | Scaleway, OVHCloud | EU-safe (Mistral, Llama, Gemma) |
| No PII | CHEAPEST | Any provider | Any model |
PII Masking
from sovereign_gateway import PIIMasker
masker = PIIMasker()
masked, types = masker.mask("Email jean@company.fr, IBAN FR76 3000 6000 0112 3456 7890 189")
print(masked) # "Email [EMAIL_REDACTED], IBAN [IBAN_REDACTED]"
print(types) # ["EMAIL_ADDRESS", "IBAN_CODE"]
Compliance-Ready Audit Logs
result = gateway.route([{"role": "user", "content": "Patient Jean Dupont..."}])
# Ready for your DPO
print(result.compliance_summary)
# {
# "gdpr_compliant": True,
# "pii_detected": True,
# "pii_types": ["PERSON"],
# "routing_decision": "eu_only",
# "provider_region": "EU",
# "provider": "scaleway",
# "model": "mistral-7b"
# }
SDKs
Full-featured SDKs with OpenAI-compatible interface, circuit breaker, retry logic, and real-time cost tracking.
| SDK | Install | Docs |
|---|---|---|
| Python | pip install ai-infra |
sdk/python/README.md |
| TypeScript | npm install ai-infra |
sdk/typescript/README.md |
Migration from OpenAI (2 lines)
# Before
from openai import OpenAI
client = OpenAI(api_key="sk-...")
# After — same API, GDPR-compliant routing
from ai_infra import Client
client = Client(api_key="sk-...")
# Zero changes to your existing code
response = client.chat.completions.create(
model="auto", # intelligent routing
messages=[{"role": "user", "content": "Hello"}],
)
print(response.savings.cost_saved_usd) # see your savings
See sdk/python/examples/ for more examples (streaming, cost tracking, sovereign routing, migration).
Examples
Basic Routing
from sovereign_gateway import SovereignGateway
gateway = SovereignGateway()
# PII detected -> EU forced
result = gateway.route([
{"role": "user", "content": "Analyze the account of jean.dupont@company.fr"}
])
assert result.forced_eu_routing == True
assert result.gdpr_compliant == True
# No PII -> cheapest
result = gateway.route([
{"role": "user", "content": "Summarize this quarterly report"}
])
assert result.forced_eu_routing == False
FastAPI Integration
from fastapi import FastAPI
from sovereign_gateway import SovereignGateway
app = FastAPI()
gateway = SovereignGateway(providers={
"scaleway": {"api_key": "scw-your-key"},
"together_ai": {"api_key": "tok-your-key"},
})
@app.post("/v1/chat")
async def chat(messages: list[dict]):
# One call — PII detection + routing + LLM call
result = gateway.complete(messages)
return {
"content": result.content,
"compliance": result.compliance_summary,
}
PII Detection Only
from sovereign_gateway import PIIDetector
detector = PIIDetector()
# Full entity detection
entities = detector.detect("Call Jean at +33 6 12 34 56 78")
for entity in entities:
print(f" {entity.entity_type} (confidence: {entity.score})")
# Quick check
if detector.has_pii(user_input):
print("WARNING: PII detected in user input")
Run Examples
python examples/basic_routing.py
python examples/pii_detection.py
Installation Options
| Installation | Command | Use Case |
|---|---|---|
| Core (regex-only) | pip install mh-gdpr-ai |
Quick start, minimal deps |
| With Presidio (recommended) | pip install mh-gdpr-ai[presidio] |
Production, NLP detection |
| With FastAPI | pip install mh-gdpr-ai[api] |
API server |
| Everything | pip install mh-gdpr-ai[all] |
Full installation |
With Presidio (Recommended)
Presidio adds NLP-based detection for entities that regex can't catch (person names, locations, dates). Install it for production use:
pip install mh-gdpr-ai[presidio]
python -m spacy download en_core_web_lg
# Presidio is automatically used when installed
gateway = SovereignGateway() # uses Presidio + regex
# Force regex-only (faster, fewer dependencies)
gateway = SovereignGateway(use_presidio=False)
API Reference
SovereignGateway
The main entry point.
| Method | Description | Returns |
|---|---|---|
complete(messages, model?, max_tokens?, temperature?) |
End-to-end: PII scan + routing + LLM call | CompletionResult |
route(messages, model?, request_id?) |
PII scan + routing decision (no LLM call) | RouteResult |
detect_pii(text) |
Detect PII types | list[str] |
has_pii(text) |
Quick PII check | bool |
mask(text) |
Mask PII in text | str |
mask_messages(messages) |
Mask PII in messages | list[dict] |
Constructor accepts providers= dict to configure LLM providers:
gateway = SovereignGateway(providers={
"scaleway": {"api_key": "scw-xxx"}, # EU (Paris)
"ovhcloud": {"api_key": "ovh-xxx"}, # EU (Gravelines)
"together_ai": {"api_key": "tok-xxx"}, # Non-EU fallback
"openai": {"api_key": "sk-xxx"}, # Non-EU
"scaleway": {"api_key": "scw-xxx", "base_url": "https://custom.url/v1"}, # Custom URL
})
Or set environment variables: SCALEWAY_API_KEY, TOGETHER_AI_API_KEY, OPENAI_API_KEY, etc.
CompletionResult
Returned by gateway.complete() — includes the LLM response and compliance metadata.
| Field | Type | Description |
|---|---|---|
content |
str |
The model's response text |
model_used |
str |
Model that generated the response |
provider_used |
str |
Provider that served the request |
forced_eu_routing |
bool |
Whether EU was forced due to PII |
gdpr_compliant |
bool |
Whether the request is GDPR compliant |
pii_detected |
bool |
Whether PII was found |
pii_types |
list[str] |
Types of PII detected |
latency_ms |
float |
Total time (PII scan + routing + LLM call) |
tokens_used |
int |
Total tokens consumed |
compliance_summary |
dict |
Audit-ready summary for DPO |
RouteResult
| Field | Type | Description |
|---|---|---|
decision |
RoutingDecision |
eu_only, cheapest, or cache_hit |
pii_detected |
bool |
Whether PII was found |
pii_types |
list[str] |
Types of PII detected |
forced_eu_routing |
bool |
Whether EU was forced |
gdpr_compliant |
bool |
Whether the result is GDPR compliant |
model_used |
str |
Selected model |
provider_used |
str |
Selected provider |
latency_ms |
float |
Processing time in ms |
compliance_summary |
dict |
Audit-ready summary |
PIIDetector
| Method | Description | Returns |
|---|---|---|
detect(text) |
Full entity detection | list[PIIEntity] |
detect_types(text) |
Type names only | list[str] |
has_pii(text) |
Quick boolean check | bool |
PIIMasker
| Method | Description | Returns |
|---|---|---|
mask(text) |
Mask PII in text | (str, list[str]) |
detect(text) |
Detect types (no mask) | list[str] |
mask_messages(messages) |
Mask across messages | (list[dict], list[str]) |
Supported Models
EU-Safe Models (used when PII detected)
| Model | Family | Use Case |
|---|---|---|
mistral-7b |
Mistral | Fast, cheap, general |
mixtral-8x7b |
Mistral | Reasoning, long context |
codestral |
Mistral | Code generation |
mistral-large |
Mistral | Complex analysis |
llama-3-70b |
Meta | High quality |
llama-3-8b |
Meta | Fast, efficient |
gemma-7b |
Lightweight |
The gateway supports 20+ models across 9 families: Mistral, OpenAI, Anthropic, Meta, Google, Cohere, Microsoft, DeepSeek, and Alibaba.
Architecture
mh-gdpr-ai.eu/
├── sovereign_gateway/ # Main package
│ ├── gateway.py # SovereignGateway (route + complete)
│ ├── pii/
│ │ ├── detector.py # Dual-layer PII detection
│ │ └── masker.py # PII masking
│ ├── router/
│ │ └── sovereign.py # Sovereign routing engine
│ ├── providers/
│ │ └── openai_compat.py # OpenAI-compatible provider client
│ └── models/
│ └── schemas.py # Pydantic models
├── examples/ # Working examples
│ ├── basic_routing.py
│ ├── pii_detection.py
│ └── fastapi_integration.py
├── tests/ # Full test suite
│ ├── test_pii_detector.py
│ ├── test_masker.py
│ └── test_sovereign_router.py
├── pyproject.toml # Package config
├── Dockerfile # Production container
└── Makefile # Dev commands
Development
Prerequisites
| Tool | Version | Check |
|---|---|---|
| Python | >= 3.10 | python --version |
| pip | latest | pip --version |
| Git | any | git --version |
Setup
git clone https://github.com/mahadillahm4di-cyber/mh-gdpr-ai.eu.git
cd mh-gdpr-ai.eu
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -e ".[dev]"
# Run tests
make test
# Run linter
make lint
# Run examples
make examples
Why This Exists
GDPR Article 44 requires that personal data of EU residents stays within the EEA unless adequate safeguards exist. Most LLM API calls go to US servers. If your prompt contains a user's name, email, or IBAN — you're transferring personal data outside the EU.
The fine is up to 4% of global annual revenue or 20 million EUR, whichever is higher.
This gateway ensures that never happens, automatically.
Roadmap
- Regex-based PII detection (7 entity types)
- Presidio NLP integration (15+ entity types)
- Sovereign routing engine
- PII masking
- Compliance audit summaries
- PyPI package published
- CI/CD with automated PyPI publish
- End-to-end LLM calls (
gateway.complete()) with automatic EU routing - Multi-provider support (Scaleway, OVHcloud, Together AI, OpenAI, etc.)
- Semantic cache integration
- Real-time dashboard
- GDPR compliance report generation (PDF)
Platform Architecture
This open-source library is the core of a fully managed AI infrastructure platform. The managed service adds enterprise features on top of the library.
┌──────────────────────────────────┐
│ Your Application │
│ (2 lines to integrate SDK) │
└──────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ API Gateway (Go) │
│ Auth · Rate Limiting · DDoS Protection · Request Routing │
└────────────────────────────┬────────────────────────────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Auth Service │ │Router Engine │ │ Billing │
│ (Go) │ │ (Python) │ │ Service │
│ │ │ │ │ (Go) │
│ JWT · API │ │ PII Detect │ │ Usage Track │
│ Keys · RBAC │ │ EU Routing │ │ Stripe │
│ Multi-tenant │ │ Model Select │ │ Invoices │
└──────────────┘ │ Cache Layer │ └──────────────┘
└──────┬───────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Scaleway │ │ OVHCloud │ │ RunPod / │
│ Paris (EU) │ │ FR (EU) │ │ Together / │
│ │ │ │ │ Lambda │
│ Priority 1 │ │ Priority 2 │ │ Fallback │
└──────────────┘ └──────────────┘ └──────────────┘
Open Source (this repo)
| Component | What it does |
|---|---|
| PII Detection | Dual-layer: Presidio NLP + regex fallback, 15+ entity types |
| Sovereign Routing | PII detected → EU only, no PII → cheapest provider |
| PII Masking | Type-specific placeholders (email, phone, IBAN, SSN...) |
| Python SDK | OpenAI-compatible client, circuit breaker, retry, cost tracking |
| TypeScript SDK | Same features, same API, for Node.js/Deno/Bun |
Managed Service (coming soon)
| Component | What it does | Why it matters |
|---|---|---|
| API Gateway | Auth, rate limiting, DDoS protection | Zero infrastructure for clients |
| Auth Service | JWT, API keys, multi-tenant isolation | Each client is sandboxed |
| Router Engine | Semantic cache, model selection, fallback chain | 30-70% cost savings |
| Billing Service | Usage tracking, Stripe integration, invoices | Pay-per-use, no subscription |
| Real-Time Dashboard | Cost savings, RGPD compliance score, latency | Clients see savings grow daily |
| GDPR Compliance Reports | Auto-generated PDF for DPO/regulators | Unblocks sales in regulated sectors |
| Monitoring | Prometheus, Grafana, Loki | Full observability, zero PII in logs |
| Deployment | Helm charts, Terraform, Kubernetes | Production-ready, auto-scaling |
Supported Models (24 models, 9 families)
| Family | Models | EU Safe |
|---|---|---|
| Mistral | mistral-7b, mixtral-8x7b, codestral, mistral-large, mistral-embed | Yes |
| Meta/Llama | llama-3-70b, llama-3-8b, codellama-34b | Yes |
| gemma-7b, gemini-pro | Partial | |
| OpenAI | gpt-4o, gpt-4-turbo, gpt-3.5-turbo | No |
| Anthropic | claude-3-opus, claude-3-sonnet, claude-3-haiku | No |
| Cohere | command-r-plus, command-r | No |
| DeepSeek | deepseek-v2, deepseek-coder | No |
| Alibaba | qwen2-72b, qwen2-7b | No |
| Microsoft | phi-3-medium, phi-3-mini | No |
Interested in the managed service? Join the waitlist or reach out at mahadillah@mh-gdpr-ai.eu
License
Apache License 2.0 — see LICENSE for details.
Contributing
Contributions are welcome! See CONTRIBUTING.md for guidelines.
Security
Found a vulnerability? See SECURITY.md for responsible disclosure.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mh_gdpr_ai-0.2.0.tar.gz.
File metadata
- Download URL: mh_gdpr_ai-0.2.0.tar.gz
- Upload date:
- Size: 134.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bea4ecf9dd3c64179bfe167a82e8d13e3ef90608a119e9f96293ecba79d571c5
|
|
| MD5 |
f5b0271806547cf3bba549cfa466a199
|
|
| BLAKE2b-256 |
a2a8ad3b9fb1df0dd4bd75875033ec9a2ff2f05e5b2cc84e9a01bb216bcd457c
|
File details
Details for the file mh_gdpr_ai-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mh_gdpr_ai-0.2.0-py3-none-any.whl
- Upload date:
- Size: 30.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
899fd6a1f2363fccb8457d2d40cc95887de48244923a52d494d4fb9aef937f54
|
|
| MD5 |
fd93ae6cd7b10594fc255714415e8b9f
|
|
| BLAKE2b-256 |
03a623c29b070d875660173caf8e30b88ee0d9bca04aa09c4151f01a3100b5a2
|