TSZ / app.py
Alienseeker's picture
Update app.py
7c262d4 verified
Raw
History Blame Contribute Delete
14.6 kB
"""
TSZ (Thyris Safe Zone) - Interactive Demo
==========================================
GitHub: https://github.com/thyrisAI/safe-zone
Website: https://thyris.ai
"""
import gradio as gr
import re
import uuid
import hashlib
from dataclasses import dataclass
from typing import List, Tuple
@dataclass
class Detection:
type: str
value: str
placeholder: str
start: int
end: int
confidence: str
mask_id: str
class TSZDetector:
PATTERNS = {
"EMAIL": {
"pattern": r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
"description": "Email addresses"
},
"PHONE": {
"pattern": r'\b(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}\b',
"description": "Phone numbers (US format)"
},
"PHONE_TR": {
"pattern": r'\b(?:\+90|0)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{3}[-.\s]?[0-9]{2}[-.\s]?[0-9]{2}\b',
"description": "Phone numbers (Turkey format)"
},
"CREDIT_CARD": {
"pattern": r'\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})\b',
"description": "Credit card numbers"
},
"SSN": {
"pattern": r'\b[0-9]{3}-[0-9]{2}-[0-9]{4}\b',
"description": "Social Security Numbers (US)"
},
"TC_KIMLIK": {
"pattern": r'\b[1-9][0-9]{10}\b',
"description": "Turkish National ID"
},
"IBAN": {
"pattern": r'\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\b',
"description": "International Bank Account Numbers"
},
"IP_ADDRESS": {
"pattern": r'\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b',
"description": "IPv4 addresses"
},
"API_KEY": {
"pattern": r'\b(?:sk-[a-zA-Z0-9]{32,}|api[_-]?key[_-]?[=:]\s*["\']?[a-zA-Z0-9]{16,}["\']?)\b',
"description": "API keys and secrets"
},
"AWS_KEY": {
"pattern": r'\b(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}\b',
"description": "AWS Access Keys"
},
"PASSWORD": {
"pattern": r'(?:password|passwd|pwd)[_\s]*[=:]\s*["\']?[^\s"\']{4,}["\']?',
"description": "Passwords in config/code"
},
"JWT_TOKEN": {
"pattern": r'\beyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\b',
"description": "JSON Web Tokens"
}
}
def _generate_mask_id(self, value: str) -> str:
"""Generate a short unique mask ID based on value hash"""
hash_val = hashlib.md5(value.encode()).hexdigest()[:6]
return hash_val
def detect(self, text: str, rid: str = "NO-RID") -> Tuple[List[Detection], str]:
detections = []
redacted_text = text
type_counters = {}
for pii_type, config in self.PATTERNS.items():
pattern = config["pattern"]
for match in re.finditer(pattern, text, re.IGNORECASE):
value = match.group()
if pii_type == "TC_KIMLIK" and len(value) != 11:
continue
if pii_type not in type_counters:
type_counters[pii_type] = 0
type_counters[pii_type] += 1
mask_id = self._generate_mask_id(value)
placeholder = f"[{rid}_{pii_type}_{mask_id}]"
detections.append(Detection(
type=pii_type,
value=value,
placeholder=placeholder,
start=match.start(),
end=match.end(),
confidence="HIGH" if len(value) > 8 else "MEDIUM",
mask_id=mask_id
))
detections.sort(key=lambda x: x.start, reverse=True)
for det in detections:
redacted_text = redacted_text[:det.start] + det.placeholder + redacted_text[det.end:]
detections.sort(key=lambda x: x.start)
return detections, redacted_text
detector = TSZDetector()
def analyze_text(text: str, rid: str) -> Tuple[str, str, str, str]:
if not text.strip():
return "", "Please enter some text to analyze.", "", ""
if not rid.strip():
rid = f"TSZ-{uuid.uuid4().hex[:8].upper()}"
detections, redacted_text = detector.detect(text, rid)
if not detections:
return text, "No sensitive information detected.", "**0** PII entities found", f"Request ID: `{rid}`"
report_lines = ["### Detected Entities\n"]
by_type = {}
for det in detections:
if det.type not in by_type:
by_type[det.type] = []
by_type[det.type].append(det)
for pii_type, items in by_type.items():
desc = detector.PATTERNS[pii_type]["description"]
report_lines.append(f"\n**{pii_type}** ({desc})")
for item in items:
masked_value = item.value[:3] + "***" + item.value[-2:] if len(item.value) > 5 else "***"
report_lines.append(f"- `{masked_value}` β†’ `{item.placeholder}`")
report_lines.append(f" - Mask ID: `{item.mask_id}` | Confidence: {item.confidence}")
report = "\n".join(report_lines)
stats = f"**{len(detections)}** PII entities found across **{len(by_type)}** categories"
rid_display = f"Request ID: `{rid}`"
return redacted_text, report, stats, rid_display
EXAMPLES = [
["Hi, my name is John Smith and my email is john.smith@company.com. You can reach me at +1-555-123-4567. My SSN is 123-45-6789.", "REQ-001"],
["Customer Order #12345\nName: Jane Doe\nEmail: jane.doe@example.org\nPhone: (555) 987-6543\nCredit Card: 4532015112830366", "ORDER-12345"],
["API Configuration:\napi_key = \"sk-1234567890abcdefghijklmnopqrstuvwxyz\"\nAWS_ACCESS_KEY: AKIAIOSFODNN7EXAMPLE\npassword: \"super_secret_123\"", "CONFIG-SCAN"],
["Merhaba, ben Ahmet Yilmaz. TC Kimlik numaram 12345678901.\nTelefon: 0532 123 45 67\nIBAN: TR330006100519786457841326", "TR-REQ-001"],
]
with gr.Blocks(title="TSZ - Thyris Safe Zone Demo", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# πŸ›‘οΈ TSZ (Thyris Safe Zone)
**Enterprise-grade PII detection and guardrails gateway** that prevents sensitive data from leaking to LLMs and third-party APIs.
[![GitHub](https://img.shields.io/badge/GitHub-Repository-black?logo=github)](https://github.com/thyrisAI/safe-zone)
[![Website](https://img.shields.io/badge/Website-thyris.ai-blue)](https://thyris.ai)
[![License](https://img.shields.io/badge/License-Apache%202.0-green)](https://github.com/thyrisAI/safe-zone/blob/main/LICENSE)
""")
with gr.Tabs():
with gr.TabItem("πŸ” Interactive Demo"):
with gr.Row():
with gr.Column():
rid_input = gr.Textbox(
label="Request ID (RID)",
placeholder="e.g., REQ-001 (auto-generated if empty)",
lines=1
)
input_text = gr.Textbox(
label="Input Text",
placeholder="Paste text containing emails, phone numbers, credit cards, API keys...",
lines=8
)
analyze_btn = gr.Button("Analyze & Redact", variant="primary")
gr.Markdown("### Try These Examples")
gr.Examples(examples=EXAMPLES, inputs=[input_text, rid_input])
with gr.Column():
rid_display = gr.Markdown(label="Request ID")
stats_output = gr.Markdown(label="Statistics")
redacted_output = gr.Textbox(
label="Redacted Output (Safe to send to LLMs)",
lines=8,
interactive=False
)
detection_report = gr.Markdown(label="Detection Report")
gr.Markdown("""
---
### Placeholder Format
TSZ uses the format `[RID_TYPE_maskId]` for placeholders:
- **RID**: Request ID for audit correlation
- **TYPE**: Detection type (EMAIL, PHONE, etc.)
- **maskId**: Unique identifier derived from the original value
Example: `[REQ-001_EMAIL_a1b2c3]`
This allows you to:
- Track which request generated the redaction
- Identify the type of sensitive data
- Correlate with audit logs for compliance
""")
analyze_btn.click(fn=analyze_text, inputs=[input_text, rid_input], outputs=[redacted_output, detection_report, stats_output, rid_display])
input_text.submit(fn=analyze_text, inputs=[input_text, rid_input], outputs=[redacted_output, detection_report, stats_output, rid_display])
with gr.TabItem("πŸ“š API Reference"):
gr.Markdown("""
## TSZ API Reference
TSZ is an enterprise-grade PII detection and guardrails gateway. It acts as a zero-trust middleware between your applications and external systems.
---
### Confidence & Guardrails Model
| Confidence | Action |
|------------|--------|
| < 0.30 | ALLOW (ignored) |
| 0.30 – 0.85 | MASK (redact) |
| β‰₯ 0.85 | AUTO-BLOCK |
---
### POST /detect
**Request:**
```json
{
"text": "My email is user@company.com",
"rid": "REQ-001",
"guardrails": ["TOXIC_LANGUAGE"]
}
```
**Response:**
```json
{
"redacted_text": "My email is [REQ-001_EMAIL_a1b2c3]",
"detections": [
{
"type": "EMAIL",
"value": "user@company.com",
"placeholder": "[REQ-001_EMAIL_a1b2c3]",
"start": 12,
"end": 28,
"confidence_score": "0.78",
"confidence_explanation": {
"source": "HYBRID",
"regex_score": "0.55",
"ai_score": "0.90",
"final_score": "0.78"
}
}
],
"blocked": false,
"contains_pii": true,
"overall_confidence": "0.78"
}
```
---
### Placeholder Format
TSZ generates unique placeholders in the format:
```
[{RID}_{TYPE}_{maskId}]
```
- **RID**: Request ID for audit log correlation
- **TYPE**: Detection type (EMAIL, CREDIT_CARD, etc.)
- **maskId**: Hash-based unique identifier
Example: `[RID-GW-001_EMAIL_a1b2c3]`
---
### POST /v1/chat/completions
OpenAI-compatible LLM Gateway with built-in guardrails.
**Headers:**
- `X-TSZ-RID`: Request ID for audit logs
- `X-TSZ-Guardrails`: Comma-separated validators
- `X-TSZ-Guardrails-Mode`: `final-only` | `stream-sync` | `stream-async`
**Response with tsz_meta:**
```json
{
"id": "chatcmpl-58",
"choices": [...],
"tsz_meta": {
"rid": "RID-GW-001",
"guardrails": ["TOXIC_LANGUAGE"],
"input": [
{
"redacted_text": "My email is [RID-GW-001_EMAIL_a1b2c3]",
"detections": [...],
"blocked": false
}
],
"output": [...]
}
}
```
---
### Pattern Management
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/patterns` | Create pattern |
| `GET` | `/patterns` | List patterns |
| `DELETE` | `/patterns/{id}` | Delete pattern |
---
### Validators & Guardrails
```json
{
"name": "TOXIC_LANGUAGE",
"type": "AI_PROMPT",
"rule": "Is this text toxic? Answer YES or NO.",
"expected_response": "NO"
}
```
---
### Health & Admin
| Endpoint | Description |
|----------|-------------|
| `GET /healthz` | Liveness probe |
| `GET /ready` | Readiness probe |
| `POST /admin/reload` | Clear caches |
---
πŸ“– **Full Documentation:** [API_REFERENCE.md](https://github.com/thyrisAI/safe-zone/blob/main/docs/API_REFERENCE.md)
""")
with gr.TabItem("πŸš€ Quick Start"):
gr.Markdown("""
## Get Started with TSZ
### Docker (Recommended)
```bash
git clone https://github.com/thyrisAI/safe-zone.git
cd safe-zone
docker-compose up -d
```
TSZ will be available at `http://localhost:8080`
---
### Environment Variables
```bash
# LLM Gateway Configuration
THYRIS_AI_MODEL_URL=https://api.openai.com/v1
THYRIS_AI_API_KEY=sk-your-key
# Confidence Thresholds
CONFIDENCE_ALLOW_THRESHOLD=0.30
CONFIDENCE_BLOCK_THRESHOLD=0.85
# PII Mode
PII_MODE=MASK # or BLOCK
GATEWAY_BLOCK_MODE=BLOCK # BLOCK, MASK, or WARN
```
---
### Test with Request ID
```bash
curl -X POST http://localhost:8080/detect \\
-H "Content-Type: application/json" \\
-d '{
"text": "Email: test@example.com",
"rid": "MY-REQ-001"
}'
```
**Response:**
```json
{
"redacted_text": "Email: [MY-REQ-001_EMAIL_abc123]",
"detections": [...],
"contains_pii": true
}
```
---
### Architecture
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Your App │────▢│ TSZ │────▢│ LLM API β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”
β”‚ β”‚ Audit Log β”‚
β”‚ β”‚ (with RID)β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
---
πŸ“– **Documentation:** [github.com/thyrisAI/safe-zone/docs](https://github.com/thyrisAI/safe-zone/tree/main/docs)
""")
with gr.TabItem("ℹ️ About"):
gr.Markdown("""
## About TSZ (Thyris Safe Zone)
Developed by **Thyris.AI** as an open-source enterprise AI security solution.
### Key Features
| Feature | Description |
|---------|-------------|
| **Hybrid Detection** | Regex + AI-powered confidence scoring |
| **Traceable Redaction** | `[RID_TYPE_maskId]` format for audit |
| **LLM Gateway** | OpenAI-compatible proxy |
| **Streaming Support** | sync/async modes for SSE |
| **Guardrails** | AI validators (toxic, schema, custom) |
---
### Placeholder System
Each redacted value gets a unique, traceable placeholder:
```
[RID-GW-001_EMAIL_a1b2c3]
β”‚ β”‚ β”‚
β”‚ β”‚ └── Unique mask ID (hash of value)
β”‚ └── Detection type
└── Request ID for correlation
```
Benefits:
- Full audit trail
- SIEM integration
- Compliance reporting
- Debug & investigation
---
### Compliance Ready
- βœ… GDPR (EU)
- βœ… KVKK (Turkey)
- βœ… CCPA (California)
- βœ… HIPAA (Healthcare)
- βœ… PCI-DSS (Payment)
---
Built with ❀️ by [Thyris.AI](https://thyris.ai)
""")
if __name__ == "__main__":
demo.launch()