import { useState } from 'react'; import { Download, Zap, RefreshCw, FileText, Layers, AlertTriangle, Terminal, CheckCircle2, Play, AlertCircle } from 'lucide-react'; import { Slider } from '../components/Slider'; import { BackButton } from '../components/BackButton'; import { cn } from '../lib/utils'; import { saveAs } from 'file-saver'; import { jsPDF } from 'jspdf'; import { Document, Packer, Paragraph, TextRun } from 'docx'; import { endpoints, getAuthHeaders } from '../lib/api'; const LEVEL_DESCRIPTIONS = [ { title: "Level 0: Pass-Through", desc: "No redaction applied. Useful for formatting or conversion testing.", badge: "Neutral", color: "text-slate-400" }, { title: "Level 1: Ultra-Fast Regex Rules", desc: "Instantly masks structured PII: Emails, Phone numbers, Dates, Credit Cards, Aadhaar & PAN numbers.", badge: "Regex Fast", color: "text-blue-400" }, { title: "Level 2: Lightweight AI NER", desc: "Uses spaCy statistical NER model to identify names, locations, and organizations with low latency.", badge: "spaCy Small", color: "text-indigo-400" }, { title: "Level 3: Enhanced AI NER", desc: "High-precision multi-word entity detection using spaCy medium statistical NLP pipeline.", badge: "spaCy Medium", color: "text-blue-400" }, { title: "Level 4: Advanced Domain NER", desc: "Broad semantic masking using best-in-class spaCy domain-specific pipeline.", badge: "spaCy Best", color: "text-purple-400" }, { title: "Level 5: Deep Learning Transformer", desc: "State-of-the-art neural network (BERT / RoBERTa) fine-tuned on complex Indian & Global PII datasets.", badge: "BERT / RoBERTa AI", color: "text-red-400 font-bold" }, ]; export function TextRedaction() { const [inputText, setInputText] = useState(''); const [outputText, setOutputText] = useState(''); const [redactionLevel, setRedactionLevel] = useState([2]); const [mode, setMode] = useState<'mask' | 'synthetic'>('mask'); const [isLoading, setIsLoading] = useState(false); const [showDownloadOptions, setShowDownloadOptions] = useState(false); const [showFeedbackModal, setShowFeedbackModal] = useState(false); const [feedbackMode, setFeedbackMode] = useState<'initial' | 'correction'>('initial'); const [missedInput, setMissedInput] = useState(''); const [isSubmittingFeedback, setIsSubmittingFeedback] = useState(false); const [isRetraining, setIsRetraining] = useState(false); const currentLevel = redactionLevel[0]; const levelInfo = LEVEL_DESCRIPTIONS[currentLevel] || LEVEL_DESCRIPTIONS[0]; const handleFeedback = async (satisfaction: string) => { if (satisfaction === 'yes') { try { await fetch(endpoints.feedback, { method: 'POST', headers: getAuthHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ text: inputText, redacted_text: outputText, satisfaction: 'yes', redaction_level: currentLevel, }), }); } catch (e) { console.error(e); } alert('Thank you! Your positive feedback reinforces our model accuracy.'); setShowFeedbackModal(false); } else { setFeedbackMode('correction'); } }; const handleCorrectionSubmit = async () => { if (isSubmittingFeedback) return; setIsSubmittingFeedback(true); try { const missedList = missedInput.split(',').map((s) => s.trim()).filter(Boolean); await fetch(endpoints.feedback, { method: 'POST', headers: getAuthHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ text: inputText, redacted_text: outputText, satisfaction: 'no', missed_entities: missedList, corrected_text: missedInput, redaction_level: currentLevel, }), }); alert('🎯 Correction ingested into Active Learning loop! Our AI training dataset has been automatically updated.'); } catch (e) { console.error(e); alert('Error submitting feedback to server.'); } finally { setIsSubmittingFeedback(false); setShowFeedbackModal(false); setFeedbackMode('initial'); setMissedInput(''); } }; const handleRetrain = async () => { if (isRetraining) return; setIsRetraining(true); try { const res = await fetch(endpoints.triggerRetrain, { method: 'POST', headers: getAuthHeaders(), }); const data = await res.json(); alert(`🤖 Active Learning Retrain Triggered:\n${data.message}`); } catch (e) { console.error(e); alert('Failed to connect to retrain endpoint.'); } finally { setIsRetraining(false); } }; const handleRedact = async () => { if (isLoading) return; if (!inputText.trim()) { alert('Please enter some text to redact first.'); return; } setIsLoading(true); try { const response = await fetch(endpoints.redactText, { method: 'POST', headers: getAuthHeaders({ 'Content-Type': 'application/json' }), body: JSON.stringify({ text: inputText, redaction_level: currentLevel, mode: mode, }), }); if (!response.ok) { throw new Error('Failed to redact text from server.'); } const data = await response.json(); setOutputText(data.redacted_text || 'Error: No redacted text returned'); } catch (error) { console.error(error); setOutputText('An error occurred while communicating with the RE-DACT AI Engine. Please check that backend server is running.'); } finally { setIsLoading(false); } }; const handleClear = () => { setInputText(''); setOutputText(''); setRedactionLevel([2]); setShowDownloadOptions(false); setShowFeedbackModal(false); }; const handleDownload = (format: string) => { if (format === 'txt') { const blob = new Blob([outputText], { type: 'text/plain;charset=utf-8' }); saveAs(blob, `redactx_sanitized_text.txt`); } else if (format === 'pdf') { const doc = new jsPDF(); const splitText = doc.splitTextToSize(outputText, 180); doc.text(splitText, 15, 15); doc.save(`redactx_sanitized_text.pdf`); } else if (format === 'docx') { const docx = new Document({ sections: [ { properties: {}, children: outputText.split('\n').map((line) => new Paragraph({ children: [new TextRun(line)] })), }, ], }); Packer.toBlob(docx).then((blob) => { saveAs(blob, `redactx_sanitized_text.docx`); }); } setShowDownloadOptions(false); }; return (
{/* Top SOC Critical Alert Banner */}
TEXT SANITIZATION MODULE
Escalation: Level {currentLevel}

Text PII & Financial Sanitizer

Obfuscate sensitive identifiers, Indian & Global names, organizations, bill prices, orders, and confidential markers.

{/* Main Studio Container */}
{/* Mode Selection and Sample Loaders */}
Mode:
{/* Redaction Slider Section */}
Redaction Scale {levelInfo.badge}
Level {currentLevel} of 5

{levelInfo.title}

{levelInfo.desc}

{/* Input and Output Split Grid */}
{inputText.length} chars