Alienseeker commited on
Commit
31938c7
Β·
verified Β·
1 Parent(s): e411ea2

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +339 -0
app.py ADDED
@@ -0,0 +1,339 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ TSZ (Thyris Safe Zone) - Interactive Demo
3
+ ==========================================
4
+ This demo showcases how TSZ detects and redacts sensitive information
5
+ before it reaches LLMs or third-party APIs.
6
+
7
+ GitHub: https://github.com/thyrisAI/safe-zone
8
+ Website: https://thyris.ai
9
+ """
10
+
11
+ import gradio as gr
12
+ import re
13
+ from dataclasses import dataclass
14
+ from typing import List, Tuple
15
+
16
+ # ============================================================================
17
+ # PII Detection Patterns (Simplified version of TSZ's detection engine)
18
+ # ============================================================================
19
+
20
+ @dataclass
21
+ class Detection:
22
+ """Represents a detected PII entity"""
23
+ type: str
24
+ value: str
25
+ start: int
26
+ end: int
27
+ confidence: str
28
+
29
+ class TSZDetector:
30
+ """
31
+ Simplified PII detector that mimics TSZ's detection capabilities.
32
+ The real TSZ uses more sophisticated pattern matching and validators.
33
+ """
34
+
35
+ PATTERNS = {
36
+ "EMAIL": {
37
+ "pattern": r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
38
+ "placeholder": "[EMAIL]",
39
+ "description": "Email addresses"
40
+ },
41
+ "PHONE": {
42
+ "pattern": r'\b(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}\b',
43
+ "placeholder": "[PHONE]",
44
+ "description": "Phone numbers (US format)"
45
+ },
46
+ "PHONE_TR": {
47
+ "pattern": r'\b(?:\+90|0)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{3}[-.\s]?[0-9]{2}[-.\s]?[0-9]{2}\b',
48
+ "placeholder": "[PHONE]",
49
+ "description": "Phone numbers (Turkey format)"
50
+ },
51
+ "CREDIT_CARD": {
52
+ "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',
53
+ "placeholder": "[CREDIT_CARD]",
54
+ "description": "Credit card numbers"
55
+ },
56
+ "SSN": {
57
+ "pattern": r'\b[0-9]{3}-[0-9]{2}-[0-9]{4}\b',
58
+ "placeholder": "[SSN]",
59
+ "description": "Social Security Numbers (US)"
60
+ },
61
+ "TC_KIMLIK": {
62
+ "pattern": r'\b[1-9][0-9]{10}\b',
63
+ "placeholder": "[TC_KIMLIK]",
64
+ "description": "Turkish National ID (TC Kimlik)"
65
+ },
66
+ "IBAN": {
67
+ "pattern": r'\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\b',
68
+ "placeholder": "[IBAN]",
69
+ "description": "International Bank Account Numbers"
70
+ },
71
+ "IP_ADDRESS": {
72
+ "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',
73
+ "placeholder": "[IP_ADDRESS]",
74
+ "description": "IPv4 addresses"
75
+ },
76
+ "API_KEY": {
77
+ "pattern": r'\b(?:sk-[a-zA-Z0-9]{32,}|api[_-]?key[_-]?[=:]\s*["\']?[a-zA-Z0-9]{16,}["\']?)\b',
78
+ "placeholder": "[API_KEY]",
79
+ "description": "API keys and secrets"
80
+ },
81
+ "AWS_KEY": {
82
+ "pattern": r'\b(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}\b',
83
+ "placeholder": "[AWS_ACCESS_KEY]",
84
+ "description": "AWS Access Keys"
85
+ },
86
+ "PASSWORD": {
87
+ "pattern": r'(?:password|passwd|pwd)[_\s]*[=:]\s*["\']?[^\s"\']{4,}["\']?',
88
+ "placeholder": "[PASSWORD]",
89
+ "description": "Passwords in config/code"
90
+ },
91
+ "JWT_TOKEN": {
92
+ "pattern": r'\beyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\b',
93
+ "placeholder": "[JWT_TOKEN]",
94
+ "description": "JSON Web Tokens"
95
+ },
96
+ "DATE_OF_BIRTH": {
97
+ "pattern": r'\b(?:0[1-9]|[12][0-9]|3[01])[/-](?:0[1-9]|1[0-2])[/-](?:19|20)[0-9]{2}\b',
98
+ "placeholder": "[DOB]",
99
+ "description": "Dates of birth"
100
+ }
101
+ }
102
+
103
+ def detect(self, text: str) -> Tuple[List[Detection], str]:
104
+ """
105
+ Detect PII in text and return detections + redacted text.
106
+
107
+ Returns:
108
+ Tuple of (list of detections, redacted text)
109
+ """
110
+ detections = []
111
+ redacted_text = text
112
+
113
+ for pii_type, config in self.PATTERNS.items():
114
+ pattern = config["pattern"]
115
+ placeholder = config["placeholder"]
116
+
117
+ for match in re.finditer(pattern, text, re.IGNORECASE):
118
+ # Avoid duplicate detections for overlapping patterns
119
+ value = match.group()
120
+
121
+ # Skip if this looks like a false positive
122
+ if pii_type == "TC_KIMLIK" and len(value) != 11:
123
+ continue
124
+
125
+ detections.append(Detection(
126
+ type=pii_type,
127
+ value=value,
128
+ start=match.start(),
129
+ end=match.end(),
130
+ confidence="HIGH" if len(value) > 8 else "MEDIUM"
131
+ ))
132
+
133
+ # Sort by position (reverse) for correct replacement
134
+ detections.sort(key=lambda x: x.start, reverse=True)
135
+
136
+ # Redact in reverse order to maintain positions
137
+ for det in detections:
138
+ placeholder = self.PATTERNS[det.type]["placeholder"]
139
+ redacted_text = redacted_text[:det.start] + placeholder + redacted_text[det.end:]
140
+
141
+ # Re-sort for display (by position, ascending)
142
+ detections.sort(key=lambda x: x.start)
143
+
144
+ return detections, redacted_text
145
+
146
+ # ============================================================================
147
+ # Gradio Interface
148
+ # ============================================================================
149
+
150
+ detector = TSZDetector()
151
+
152
+ def analyze_text(text: str) -> Tuple[str, str, str]:
153
+ """
154
+ Main analysis function for Gradio interface.
155
+
156
+ Returns:
157
+ Tuple of (redacted_text, detection_report, stats)
158
+ """
159
+ if not text.strip():
160
+ return "", "⚠️ Please enter some text to analyze.", ""
161
+
162
+ detections, redacted_text = detector.detect(text)
163
+
164
+ if not detections:
165
+ return text, "βœ… No sensitive information detected.", "**0** PII entities found"
166
+
167
+ # Build detection report
168
+ report_lines = ["### πŸ” Detected Entities\n"]
169
+
170
+ # Group by type
171
+ by_type = {}
172
+ for det in detections:
173
+ if det.type not in by_type:
174
+ by_type[det.type] = []
175
+ by_type[det.type].append(det)
176
+
177
+ for pii_type, items in by_type.items():
178
+ desc = detector.PATTERNS[pii_type]["description"]
179
+ report_lines.append(f"\n**{pii_type}** ({desc})")
180
+ for item in items:
181
+ masked_value = item.value[:3] + "***" + item.value[-2:] if len(item.value) > 5 else "***"
182
+ report_lines.append(f"- `{masked_value}` (confidence: {item.confidence})")
183
+
184
+ report = "\n".join(report_lines)
185
+
186
+ # Stats
187
+ stats = f"**{len(detections)}** PII entities found across **{len(by_type)}** categories"
188
+
189
+ return redacted_text, report, stats
190
+
191
+ # Example texts for users to try
192
+ EXAMPLES = [
193
+ ["""Hi, my name is John Smith and my email is john.smith@company.com.
194
+ You can reach me at +1-555-123-4567. My SSN is 123-45-6789."""],
195
+
196
+ ["""Customer Order #12345
197
+ Name: Jane Doe
198
+ Email: jane.doe@example.org
199
+ Phone: (555) 987-6543
200
+ Credit Card: 4532015112830366
201
+ Shipping Address: 123 Main St, New York, NY 10001"""],
202
+
203
+ ["""API Configuration:
204
+ api_key = "sk-1234567890abcdefghijklmnopqrstuvwxyz"
205
+ AWS_ACCESS_KEY: AKIAIOSFODNN7EXAMPLE
206
+ password: "super_secret_123"
207
+ database_url: postgres://user:pass@192.168.1.100:5432/db"""],
208
+
209
+ ["""Merhaba, ben Ahmet YΔ±lmaz. TC Kimlik numaram 12345678901.
210
+ Telefon: 0532 123 45 67
211
+ IBAN: TR330006100519786457841326
212
+ Email: ahmet.yilmaz@sirket.com.tr"""],
213
+ ]
214
+
215
+ # Custom CSS
216
+ custom_css = """
217
+ .gradio-container {
218
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
219
+ }
220
+ .detection-box {
221
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
222
+ border-radius: 12px;
223
+ padding: 20px;
224
+ }
225
+ footer {
226
+ visibility: hidden;
227
+ }
228
+ """
229
+
230
+ # Build the interface
231
+ with gr.Blocks(css=custom_css, title="TSZ - Thyris Safe Zone Demo") as demo:
232
+
233
+ # Header
234
+ gr.Markdown("""
235
+ # πŸ›‘οΈ TSZ (Thyris Safe Zone) - Interactive Demo
236
+
237
+ **TSZ** is an open-source PII detection and guardrails engine that prevents sensitive data
238
+ from leaking to LLMs and third-party APIs. This demo showcases its core detection capabilities.
239
+
240
+ <div style="display: flex; gap: 10px; margin: 10px 0;">
241
+ <a href="https://github.com/thyrisAI/safe-zone" target="_blank">
242
+ <img src="https://img.shields.io/badge/GitHub-Repository-black?logo=github" alt="GitHub">
243
+ </a>
244
+ <a href="https://thyris.ai" target="_blank">
245
+ <img src="https://img.shields.io/badge/Website-thyris.ai-blue" alt="Website">
246
+ </a>
247
+ <a href="https://github.com/thyrisAI/safe-zone/blob/main/LICENSE" target="_blank">
248
+ <img src="https://img.shields.io/badge/License-Apache%202.0-green" alt="License">
249
+ </a>
250
+ </div>
251
+ """)
252
+
253
+ with gr.Row():
254
+ with gr.Column(scale=1):
255
+ # Input
256
+ input_text = gr.Textbox(
257
+ label="πŸ“ Input Text",
258
+ placeholder="Paste text containing emails, phone numbers, credit cards, API keys, passwords, etc...",
259
+ lines=10,
260
+ max_lines=20
261
+ )
262
+
263
+ analyze_btn = gr.Button("πŸ” Analyze & Redact", variant="primary", size="lg")
264
+
265
+ gr.Markdown("### πŸ“‹ Try These Examples")
266
+ gr.Examples(
267
+ examples=EXAMPLES,
268
+ inputs=input_text,
269
+ label=""
270
+ )
271
+
272
+ with gr.Column(scale=1):
273
+ # Outputs
274
+ stats_output = gr.Markdown(label="Statistics")
275
+
276
+ redacted_output = gr.Textbox(
277
+ label="πŸ”’ Redacted Output (Safe to send to LLMs)",
278
+ lines=10,
279
+ max_lines=20,
280
+ interactive=False
281
+ )
282
+
283
+ detection_report = gr.Markdown(label="Detection Report")
284
+
285
+ # Supported types info
286
+ gr.Markdown("""
287
+ ---
288
+ ### 🎯 Supported Detection Types
289
+
290
+ | Category | Types |
291
+ |----------|-------|
292
+ | **Personal Info** | Email, Phone (US/TR), SSN, TC Kimlik, Date of Birth |
293
+ | **Financial** | Credit Cards, IBAN |
294
+ | **Technical** | IP Addresses, API Keys, AWS Keys, Passwords, JWT Tokens |
295
+
296
+ ---
297
+
298
+ ### πŸš€ Get the Full Version
299
+
300
+ This demo uses a simplified detection engine. The full **TSZ** includes:
301
+
302
+ - βœ… More comprehensive pattern matching with validators
303
+ - βœ… Configurable guardrails and policies
304
+ - βœ… Allowlist/blocklist management
305
+ - βœ… REST API with hot-reloadable rules
306
+ - βœ… High-performance Go implementation with Redis caching
307
+ - βœ… Docker deployment ready
308
+
309
+ **Install TSZ:**
310
+ ```bash
311
+ git clone https://github.com/thyrisAI/safe-zone.git
312
+ cd safe-zone
313
+ docker-compose up -d
314
+ ```
315
+
316
+ ---
317
+
318
+ <p style="text-align: center; color: #666;">
319
+ Built with ❀️ by <a href="https://thyris.ai" target="_blank">Thyris.AI</a> |
320
+ Licensed under Apache 2.0
321
+ </p>
322
+ """)
323
+
324
+ # Event handlers
325
+ analyze_btn.click(
326
+ fn=analyze_text,
327
+ inputs=[input_text],
328
+ outputs=[redacted_output, detection_report, stats_output]
329
+ )
330
+
331
+ input_text.submit(
332
+ fn=analyze_text,
333
+ inputs=[input_text],
334
+ outputs=[redacted_output, detection_report, stats_output]
335
+ )
336
+
337
+ # Launch
338
+ if __name__ == "__main__":
339
+ demo.launch()