Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,4 @@ If you have questions, please open an issue on GitHub.

## License

By contributing, you agree that your contributions will be licensed under the MIT License.
By contributing, you agree that your contributions will be licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
10 changes: 5 additions & 5 deletions RAPIDAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,18 @@
- **Flexible Redaction**: Choose between masking (`***`) or placeholders (`<PERSON>`).
- **Entity Filtering**: Select exactly which PII types to redact.
- **Multi-Language**: Optimized for English and Russian.
- **High Performance**: < 20ms response time for typical payloads.
- **Detection Methods**: Regex patterns for email, phone, and card candidates; spaCy NER for person names.

---

## 🛠️ Supported PII Types

| Type | Description | Detection Method |
|------|-------------|------------------|
| `EMAIL` | Email addresses | Regex (100% accuracy) |
| `PHONE` | International phone numbers | Regex (100% accuracy) |
| `CARD` | Credit/debit card numbers | Regex + Luhn check |
| `PERSON` | Person names | AI/NER (spaCy) |
| `EMAIL` | Email addresses | Regex |
| `PHONE` | International phone numbers | Regex |
| `CARD` | Credit/debit card number candidates | Regex |
| `PERSON` | Person names | spaCy NER |

---

Expand Down
5 changes: 2 additions & 3 deletions RAPIDAPI_LISTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ Every time you send customer data to a public LLM, you risk a leak. Names, email

### Why Masker?
* **0% Retention:** We are stateless. Your data is processed in RAM and forgotten instantly.
* **High Velocity:** Built for high-throughput pipelines. <50ms latency P95.
* **Context Aware:** Unlike regex, our NER models understand context, distinguishing between a dollar amount and a credit card number.
* **Detection Methods:** Regex patterns handle email, phone, and card candidates; spaCy NER handles person-name candidates.

### Core Features
* **Smart Redaction:** Replace PII with tokenized placeholders (e.g., `[EMAIL]`, `[PERSON]`) so LLMs can still understand the sentence structure.
Expand All @@ -35,7 +34,7 @@ You may not use the Service to:
The Service is **stateless**. We process your input text solely for the purpose of redaction and do not store, log, or train on your payloads. Once the response is returned, your data is wiped from our memory.

**3. Disclaimer of Warranty**
The Service is provided "AS IS". While we strive for high accuracy (>95% F1-score), no automated PII detection system is perfect. You remain largely responsible for ensuring your data compliance (GDPR, CCPA, HIPAA). We are not liable for any missed PII entities or subsequent data leaks.
The Service is provided "AS IS". No automated PII detection system is perfect. You remain largely responsible for ensuring your data compliance (GDPR, CCPA, HIPAA). We are not liable for any missed PII entities or subsequent data leaks.

**4. Fair Use**
We reserve the right to throttle or terminate API keys that exhibit abusive behavior, consistent errors, or attempts to bypass rate limits.
Expand Down
11 changes: 5 additions & 6 deletions RAPIDAPI_README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Masker - The PII Redaction Firewall

Welcome to Masker. This guide will help you integrate high-performance PII redaction into your applications in minutes.
Welcome to Masker. This guide will help you integrate PII redaction into your applications.

## 🚀 Quick Start
Masker is designed to be dead simple. You send text, we return purged text.
Expand Down Expand Up @@ -98,8 +98,8 @@ Masker isn't just for flat text. You can send complex nested JSON objects, and w
We automatically detect the following entities:
* `EMAIL` - Email addresses
* `PHONE` - International phone numbers
* `CARD` - Credit cards, debit cards (Luhn validated)
* `PERSON` - Person names (using Neural NER models)
* `CARD` - Credit and debit card number candidates detected with regex
* `PERSON` - Person-name candidates detected with spaCy NER

You can restrict detection to specific types using the `entities` array:
```json
Expand All @@ -111,9 +111,8 @@ You can restrict detection to specific types using the `entities` array:

---

## ⚡ Performance & Limits
* **Latency:** P95 < 50ms for typical inputs.
* **Batch Size:** Ensure payloads are < 5MB.
## ⚡ Limits
* **Payload Size:** Requests are validated against the service's configured text and payload limits.
* **Concurrency:** Stateless architecture scales horozontally. Contact us for custom enterprise limits.

## 🔒 Security
Expand Down
8 changes: 4 additions & 4 deletions app/api/v1/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@

## Detected Entity Types

- **EMAIL**: Email addresses (regex, 100% accuracy)
- **PHONE**: Phone numbers (international formats, 100% accuracy)
- **CARD**: Credit card numbers (regex + Luhn validation, 100% accuracy)
- **PERSON**: Person names (spaCy NER, ~85% accuracy)
- **EMAIL**: Email addresses (regex)
- **PHONE**: Phone numbers (international formats, regex)
- **CARD**: Credit card number candidates (regex)
- **PERSON**: Person names (spaCy NER)

## Example Response

Expand Down
36 changes: 19 additions & 17 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Masker API | Privacy for LLMs</title>
<meta name="description" content="Preview client-side regex masking for email addresses, phone numbers, and card-like numbers before sharing text with AI tools.">
<link rel="canonical" href="https://kikuai-lab.github.io/masker/">
<title>Masker | Client-side PII masking preview</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;800&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
Expand All @@ -20,18 +22,18 @@
<div class="nav-links">
<a href="#features">Features</a>
<a href="#demo">Live Demo</a>
<a href="#docs">Docs</a>
<a href="https://rapidapi.com" class="btn-primary">Get API Key</a>
<a href="https://github.com/KikuAI-Lab/masker#documentation">Docs</a>
<a href="https://github.com/KikuAI-Lab/masker#quick-start" class="btn-primary">Run locally</a>
</div>
</nav>

<header class="hero">
<div class="hero-content">
<h1 class="glitch-text" data-text="Protect Your Data">Protect Your Data</h1>
<h1 class="sub-glitch">Before It Reaches AI</h1>
<p class="sub-glitch">Before It Reaches AI</p>
<p class="hero-desc">
The ultimate PII redaction layer for LLMs.
Stateless. Fast. Secure.
Preview local regex masking for common identifiers before sharing text with AI tools.
This browser demo is not the full Masker API.
</p>
<div class="hero-btns">
<a href="#demo" class="btn-primary">Try Live Demo</a>
Expand All @@ -58,27 +60,27 @@ <h1 class="sub-glitch">Before It Reaches AI</h1>
</div>
</div>
<div class="status-badge">
<span class="indicator"></span> SYSTEM ACTIVE
<span class="indicator"></span> CLIENT-SIDE PREVIEW
</div>
</div>
</header>

<section id="demo" class="interactive-demo">
<div class="container">
<h2>Interactive Console</h2>
<p>Type anything. We'll find the secrets.</p>
<p>Paste text to preview regex masking for emails, phone numbers, and card-like numbers. Review the result before use.</p>

<div class="terminal-window">
<div class="terminal-header">
<div class="dots">
<span></span><span></span><span></span>
</div>
<div class="title">masker_cli — v1.0.0</div>
<div class="title">masker_regex_preview</div>
</div>
<div class="terminal-body">
<div class="input-area">
<span class="prompt">></span>
<textarea id="demo-input" placeholder="Paste text with emails, phones, or names here..."></textarea>
<textarea id="demo-input" placeholder="Paste text with emails, phone numbers, or card-like numbers here..."></textarea>
</div>
<div class="output-area">
<div class="processing-line hidden">Scanning...</div>
Expand All @@ -95,18 +97,18 @@ <h2>Interactive Console</h2>
<div class="feature-grid">
<div class="feature-card">
<div class="icon">🔒</div>
<h3>Privacy First</h3>
<p>Stateless processing. No database. No logs. Your data never touches a disk.</p>
<h3>Local Preview</h3>
<p>Pasted text is processed by this page's client-side JavaScript and is not sent to the Masker API.</p>
</div>
<div class="feature-card">
<div class="icon">⚡</div>
<h3>Ultra Fast</h3>
<p>Optimized regex & lightweight NLP. Sub-20ms latency for real-time streams.</p>
<h3>Three Regex Patterns</h3>
<p>The preview highlights email addresses, phone numbers, and card-like 16-digit strings.</p>
</div>
<div class="feature-card">
<div class="icon">🌍</div>
<h3>Multi-Language</h3>
<p>Native support for English and Russian entity recognition out of the box.</p>
<h3>Full API Source</h3>
<p>Use the documentation to run the Python API locally and review its supported entities and deployment boundaries.</p>
</div>
</div>
</div>
Expand All @@ -116,7 +118,7 @@ <h3>Multi-Language</h3>
<div class="container">
<div class="footer-content">
<div class="footer-logo">MASKER</div>
<p>Built by KikuAI. Open Source.</p>
<p>Built by KikuAI. AGPL-3.0 source.</p>
</div>
</div>
</footer>
Expand Down
75 changes: 59 additions & 16 deletions demo/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ gsap.from('.feature-card', {
stagger: 0.2
});

// Interactive Demo Logic (Client-side emulation for speed/demo purposes)
// Interactive Demo Logic (client-side regex preview, not the full Masker API)
const demoInput = document.getElementById('demo-input');
const demoOutput = document.getElementById('demo-output');
const demoStats = document.getElementById('demo-stats');
const processingLine = document.querySelector('.processing-line');

// Simple regex for demo purposes (Backend is much more powerful)
// This preview intentionally covers only these three regex patterns.
const PATTERNS = {
email: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g,
phone: /(\+\d{1,3}[-.\s]?)?(\(\d{1,4}\)[-.\s]?)?\d{3,4}[-.\s]?\d{3,4}/g,
Expand All @@ -66,32 +66,29 @@ demoInput.addEventListener('input', () => {

function processText(text) {
if (!text) {
demoOutput.innerHTML = '';
demoStats.innerHTML = '';
demoOutput.replaceChildren();
demoStats.replaceChildren();
processingLine.classList.add('hidden');
return;
}

const startTime = performance.now();
let maskedText = text;
let count = 0;

// Apply masking
maskedText = maskedText.replace(PATTERNS.email, () => { count++; return '<span class="highlight-masked">***</span>'; });
maskedText = maskedText.replace(PATTERNS.phone, () => { count++; return '<span class="highlight-masked">***</span>'; });
maskedText = maskedText.replace(PATTERNS.card, () => { count++; return '<span class="highlight-masked">***</span>'; });
const ranges = findMaskRanges(text);

const endTime = performance.now();
const duration = (endTime - startTime).toFixed(2);

demoOutput.innerHTML = maskedText;
renderMaskedText(text, ranges);
demoOutput.style.opacity = '1';
processingLine.classList.add('hidden');

demoStats.innerHTML = `
<span>⚡ Processed in ${duration}ms</span>
<span>🛡️ ${count} PII entities masked</span>
`;
const durationStat = document.createElement('span');
durationStat.textContent = `⚡ Regex pass in ${duration}ms`;

const matchStat = document.createElement('span');
matchStat.textContent = `🛡️ ${ranges.length} regex matches masked`;

demoStats.replaceChildren(durationStat, matchStat);

// Animate result
gsap.from(demoOutput, {
Expand All @@ -101,6 +98,52 @@ function processText(text) {
});
}

function findMaskRanges(text) {
const matches = [];

Object.values(PATTERNS).forEach((pattern) => {
for (const match of text.matchAll(pattern)) {
matches.push({
start: match.index,
end: match.index + match[0].length
});
}
});

matches.sort((left, right) => left.start - right.start || right.end - left.end);

return matches.reduce((ranges, match) => {
const previous = ranges[ranges.length - 1];

if (!previous || match.start >= previous.end) {
ranges.push(match);
} else if (match.end > previous.end) {
previous.end = match.end;
}

return ranges;
}, []);
}

function renderMaskedText(text, ranges) {
const fragment = document.createDocumentFragment();
let position = 0;

ranges.forEach((range) => {
fragment.append(document.createTextNode(text.slice(position, range.start)));

const highlight = document.createElement('span');
highlight.className = 'highlight-masked';
highlight.textContent = '***';
fragment.append(highlight);

position = range.end;
});

fragment.append(document.createTextNode(text.slice(position)));
demoOutput.replaceChildren(fragment);
}

// Glitch Effect for Title
const glitchText = document.querySelector('.glitch-text');
setInterval(() => {
Expand Down
2 changes: 1 addition & 1 deletion openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@
"PII Detection"
],
"summary": "\ud83d\udd0d Detect PII without modifying content",
"description": "**Scan text or JSON for PII entities without modifying the content.**\n\nUse this endpoint when you only need to identify PII without redacting it.\n\n## Input Modes\n\n### Text Mode\n```json\n{\n \"text\": \"Contact John Doe at john@example.com\"\n}\n```\n\n### JSON Mode\n```json\n{\n \"json\": {\n \"user\": {\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n }\n}\n```\n\n## Detected Entity Types\n\n- **EMAIL**: Email addresses (regex, 100% accuracy)\n- **PHONE**: Phone numbers (international formats, 100% accuracy)\n- **CARD**: Credit card numbers (regex + Luhn validation, 100% accuracy)\n- **PERSON**: Person names (spaCy NER, ~85% accuracy)\n\n## Example Response\n\n```json\n{\n \"entities\": [\n {\n \"type\": \"PERSON\",\n \"value\": \"John Doe\",\n \"start\": 8,\n \"end\": 16\n },\n {\n \"type\": \"EMAIL\",\n \"value\": \"john@example.com\",\n \"start\": 20,\n \"end\": 36\n }\n ]\n}\n```\n\nFor JSON mode, each entity includes a `path` field showing its location (e.g., `\"user.name\"`).",
"description": "**Scan text or JSON for PII entities without modifying the content.**\n\nUse this endpoint when you only need to identify PII without redacting it.\n\n## Input Modes\n\n### Text Mode\n```json\n{\n \"text\": \"Contact John Doe at john@example.com\"\n}\n```\n\n### JSON Mode\n```json\n{\n \"json\": {\n \"user\": {\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n }\n }\n}\n```\n\n## Detected Entity Types\n\n- **EMAIL**: Email addresses (regex)\n- **PHONE**: Phone numbers (international formats, regex)\n- **CARD**: Credit card number candidates (regex)\n- **PERSON**: Person names (spaCy NER)\n\n## Example Response\n\n```json\n{\n \"entities\": [\n {\n \"type\": \"PERSON\",\n \"value\": \"John Doe\",\n \"start\": 8,\n \"end\": 16\n },\n {\n \"type\": \"EMAIL\",\n \"value\": \"john@example.com\",\n \"start\": 20,\n \"end\": 36\n }\n ]\n}\n```\n\nFor JSON mode, each entity includes a `path` field showing its location (e.g., `\"user.name\"`).",
"operationId": "detect_pii_api_v1_detect_post",
"requestBody": {
"content": {
Expand Down
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ name = "masker"
version = "1.0.0"
description = "PII Redaction & Text Anonymization API for LLMs"
readme = "README.md"
license = {text = "MIT"}
license = {text = "AGPL-3.0-only"}
requires-python = ">=3.11"
authors = [
{name = "KikuAI"}
]
keywords = ["pii", "redaction", "anonymization", "privacy", "llm", "fastapi"]
classifiers = [
"Development Status :: 5 - Production/Stable",
"Framework :: FastAPI",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"License :: OSI Approved :: GNU Affero General Public License v3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Security",
Expand Down