Local privacy protection and model server
Project description
Aegis AI — Privacy-First Chat Interface
Aegis AI is a privacy-first chat application that de-identifies sensitive information before sending prompts to cloud-based LLMs (Gemini / Claude), then reconstructs the original data into the response — ensuring PII never leaves your device.
Architecture
┌──────────────────────────────────────────────────────────────────────┐
│ BROWSER (React + Vite) │
│ │
│ User types prompt ──► ChatInput ──► Index.tsx handleSendMessage │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Privacy Pipeline │ │
│ │ (localhost:3001) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌────────────────────────────┼────────────────────┐ │
│ │ LOCAL PROCESSING ONLY │ │ │
│ │ ▼ │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ deembeder.py │ │ │
│ │ │ │ │ │
│ │ │ PHASE 1: Regex Detection (fast) │ │ │
│ │ │ • Structured PII: emails, phones, │ │ │
│ │ │ IBANs, SSNs, cards, VAT, postcodes │ │ │
│ │ │ • Addresses, PO Boxes, signatures │ │ │
│ │ │ • Company names, passwords, secrets │ │ │
│ │ │ • Names via salutations & labels │ │ │
│ │ │ │ │ │
│ │ │ PHASE 2a: Focused LLM Pass (Ollama) │ │ │
│ │ │ • Names + company names combined │ │ │
│ │ │ │ │ │
│ │ │ PHASE 2b: Broad LLM Pass (Ollama) │ │ │
│ │ │ • All remaining PII categories │ │ │
│ │ │ │ │ │
│ │ │ PHASE 3: Replacement engine │ │ │
│ │ │ • Whitespace-flexible substitution │ │ │
│ │ │ • Cascading root-word replacement │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ sensitive_info map + desensitized_prompt │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ Cloud LLM (Gemini │ │
│ │ or Claude) receives │ SAFE │
│ │ ONLY [NAME_1], │◄── No PII │
│ │ [ADDRESS_1], etc. │ leaves │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ reconstructor.py │ │
│ │ Restores [NAME_1] │ │
│ │ → real values back │ │
│ │ into LLM response │ │
│ └──────────┬───────────┘ │
│ │ │
│ ▼ │
│ Final response shown to user │
│ (with real names, addresses, etc.) │
└──────────────────────────────────────────────────────────────────────┘
Tech Stack
| Layer | Technology |
|---|---|
| Frontend | React 18, TypeScript, Vite |
| UI Components | shadcn/ui, Tailwind CSS, Framer Motion |
| Markdown | react-markdown |
| Auth & Database | Firebase (Auth + Firestore) |
| Privacy Pipeline | Python Flask server (port 3001) |
| Local LLM | Ollama — Gemma3 240M (runs entirely on-device) |
| Cloud LLMs | Google Gemini (gemini-2.5-flash), Anthropic Claude |
Privacy Pipeline — Detection Categories
The deembeder uses a two-layer approach: regex for structured/patterned PII, then Gemma3 240M (via Ollama) for semantic, context-dependent detection that regex cannot catch.
| Layer | What it catches |
|---|---|
| Regex — Identifiers | Emails, phone numbers, IBANs, credit/debit cards, SSNs (incl. masked), VAT numbers, account numbers |
| Regex — Locations | Street addresses, PO Boxes, postcodes (UK/US/IE), country names |
| Regex — Names | Salutation names (Dear X), field labels (Borrowers: X), middle initials, capitalized word heuristic, signature blocks |
| Regex — Credentials | Passwords & alphanumeric tokens, API keys, env vars, secrets |
| Regex — Companies | Legal suffix patterns (Ltd, Inc, LLC), CamelCase brands (MediMatch, PayPal) |
| Gemma3 LLM — Semantic | Person names in natural context, organization names without suffixes, and any remaining PII the regex layer missed — uses a focused prompt for thorough, context-aware extraction |
Getting Started
Prerequisites
- Node.js ≥ 18 and npm — install with nvm
- Ollama — install from ollama.ai with the Gemma3 240M model pulled
- Firebase project with Firestore and Authentication enabled
- API Keys for Gemini and/or Claude
Installation
# Clone the repository
git clone https://github.com/lukasnoelss/chatty-front.git
cd chatty-front
# Install frontend dependencies
npm install
# Install local Python backend package
pip install -e .
# Pull the Ollama model
ollama pull gemma3:270m
Environment Setup
Create a .env file (see .env.example):
VITE_GEMINI_API_KEY=your_gemini_api_key
VITE_CLAUDE_API_KEY=your_claude_api_key
VITE_FIREBASE_API_KEY=your_firebase_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
Running
# Terminal 1: Start the privacy pipeline server
npm run server
# Terminal 2: Start the frontend dev server
npm run dev
The app will be available at http://localhost:8080.
Standalone Executable (Distribution)
If you want to build a single standalone binary that doesn't require a Python/Node environment:
# For macOS:
npm run build:mac
# For Windows:
npm run build:windows
# For Linux:
npm run build:linux
The output will be placed in dist/ and copied to public/downloads/ for web-based distribution.
Project Structure
chatty-front/
├── server.py # Flask server — routes /api/deembed and /api/reconstruct
├── build_mac.sh # Build script for standalone Mac binary
├── build_windows.ps1 # Build script for standalone Windows binary
├── build_linux.sh # Build script for standalone Linux binary
├── src/
│ ├── components/
│ │ └── chat/
│ │ ├── ChatInput.tsx # Message input with privacy status
│ │ ├── ChatMessage.tsx # Message bubble with copy/rerun buttons
│ │ ├── PrivacyDebugPanel.tsx # Expandable pipeline visualization
│ │ ├── Sidebar.tsx # Conversation history sidebar
│ │ ├── TypingIndicator.tsx
│ │ └── WelcomeScreen.tsx
│ ├── gemma/
│ │ ├── deembeder.py # PII detection and replacement (Python)
│ │ └── reconstructor.py # PII restoration (Python)
│ ├── hooks/
│ │ ├── useAuth.ts # Firebase authentication hook
│ │ └── useChat.ts # Firestore chat persistence hook
│ ├── lib/
│ │ ├── gemini.ts # Gemini API client
│ │ ├── claude.ts # Claude API client
│ │ ├── privacyPipeline.ts # Frontend API calls to privacy server
│ │ └── firebase.ts # Firebase configuration
│ ├── pages/
│ │ └── Index.tsx # Main chat page — orchestrates pipeline
│ └── types/
│ └── chat.ts # Message and Conversation types
└── package.json
How It Works
- User types a prompt → saved to Firestore as-is
- Deembeder strips all sensitive data locally (regex + Ollama), producing a sanitized prompt and a
sensitive_infomap - Sanitized prompt is sent to the cloud LLM (Gemini or Claude) — no PII leaves the device
- LLM responds using placeholders like
[NAME_1],[ADDRESS_1] - Reconstructor swaps placeholders back to real values
- Final response is shown to the user with all personal data intact
License
MIT
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 aegis_local-0.1.0.tar.gz.
File metadata
- Download URL: aegis_local-0.1.0.tar.gz
- Upload date:
- Size: 18.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4eeaa031f1506a52cf2df5eb09d0e20b4ec4644109b92351283b8857e711fbc8
|
|
| MD5 |
e881262bb861adbbed68c799022fb178
|
|
| BLAKE2b-256 |
d5da4ea73193197b5f052bb39e55b17573cd29959338649e81c62571aef44567
|
File details
Details for the file aegis_local-0.1.0-py3-none-any.whl.
File metadata
- Download URL: aegis_local-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84ee4bbc7c6bd32d53e6589e404e7c9356005cc0c4855cd7dcdaf8e1e0a58bae
|
|
| MD5 |
c2a1df4f892b2653623414a4e358facf
|
|
| BLAKE2b-256 |
ff88620f6d5bcd850920270e9fdf7e521a897c46b817c256afd7e3be8d28a198
|