import React, { useState, useCallback } from 'react'; import { apiCall } from '../utils/api'; import { FALLBACK_TRIGGER_REVIEW, FALLBACK_TRIGGER_PRODUCT, FALLBACK_TRIGGER_TRANSACTION } from '../constants/fallbacks'; const ENTITIES = [ { id: 'review', label: 'Customer Review' }, { id: 'product', label: 'Product' }, { id: 'transaction', label: 'Transaction' }, ]; const ENTITY_STEPS = { review: [ { label: 'BEGIN TRANSACTION', sub: 'INSERT INTO reviews (text, customer_id) executing...', color: 'var(--text)' }, { label: 'TRIGGER: ai_sentiment_analyzer FIRES', sub: 'DistilBERT sentiment analysis (confidence, label)', color: 'var(--amber)' }, { label: 'TRIGGER: ai_embedder FIRES', sub: 'text-embedding-3-small generating 1536-dim vector', color: 'var(--purple-l)' }, { label: 'TRIGGER: fulltext_indexer FIRES', sub: 'tsvector lexeme array updated for hybrid search', color: 'var(--teal)' }, { label: 'COMMIT', sub: 'ACID transaction finalized successfully ✓', color: 'var(--green)' }, ], product: [ { label: 'BEGIN TRANSACTION', sub: 'INSERT INTO products (name, description) executing...', color: 'var(--text)' }, { label: 'TRIGGER: ai_product_classifier FIRES', sub: 'LLM classification for categories, subcategories, tags', color: 'var(--amber)' }, { label: 'TRIGGER: ai_embedder FIRES', sub: 'Generating product vector representation', color: 'var(--purple-l)' }, { label: 'COMMIT', sub: 'Product catalog entry committed successfully ✓', color: 'var(--green)' }, ], transaction: [ { label: 'BEGIN TRANSACTION', sub: 'INSERT INTO transactions (amount, customer_id, merchant, location) executing...', color: 'var(--text)' }, { label: 'TRIGGER: xgboost_fraud_scorer FIRES', sub: 'Running live XGBoost Classifier inference on server...', color: 'var(--purple-l)' }, { label: 'TRIGGER: shap_tree_explainer FIRES', sub: 'SHAP TreeExplainer calculating local feature attribution...', color: 'var(--amber)' }, { label: 'COMMIT', sub: 'Transaction authorized or flagged, details logged ✓', color: 'var(--green)' }, ], }; export default function TriggerSim() { const [entity, setEntity] = useState('review'); const [reviewText, setReviewText] = useState('The battery on this product died completely after 11 days. Customer support never responded to my emails.'); const [productName, setProductName] = useState('WirelessPro X5 Headphones'); const [productDesc, setProductDesc] = useState('Premium over-ear headphones with 40hr battery, active noise cancellation, and multi-device connectivity.'); const [txAmount, setTxAmount] = useState('4821.50'); const [txCustomer, setTxCustomer] = useState('cust_0044 (avg spend $89)'); const [txMerchant, setTxMerchant] = useState('Electronics Store'); const [txLocation, setTxLocation] = useState('Lagos, NG'); const [loading, setLoading] = useState(false); const [currentStep, setCurrentStep] = useState(-1); const [result, setResult] = useState(null); const [usedFallback, setUsedFallback] = useState(false); const [showRawRow, setShowRawRow] = useState(false); const [retraining, setRetraining] = useState(false); const [retrainSuccess, setRetrainSuccess] = useState(false); const handleRetrain = useCallback(async () => { setRetraining(true); setRetrainSuccess(false); try { const res = await apiCall('/api/demo/retrain', {}, { timeout: 30000 }); if (res.success) { setRetrainSuccess(true); setResult(prev => { if (!prev) return null; return { ...prev, model_version: res.new_version || "XGBoost-v1.1-SelfHealed", drift_result: { drift_detected: false, ks_p_value: 1.0, message: "Statistical distribution has been recalibrated. System status: STABLE" } }; }); } } catch (err) { console.error("Retraining failed", err); } finally { setRetraining(false); } }, []); const handleInsert = useCallback(async () => { setLoading(true); setCurrentStep(0); setResult(null); setUsedFallback(false); setShowRawRow(false); setRetrainSuccess(false); // Animate steps const steps = ENTITY_STEPS[entity]; for (let i = 0; i < steps.length; i++) { await new Promise((r) => setTimeout(r, 600)); setCurrentStep(i); } try { let payload = { entity_type: entity }; if (entity === 'review') payload.text = reviewText; else if (entity === 'product') { payload.product_name = productName; payload.product_description = productDesc; } else { payload.amount = parseFloat(txAmount) || 0; payload.customer_id = txCustomer; payload.merchant = txMerchant; payload.location = txLocation; } const res = await apiCall('/api/demo/trigger', payload, { timeout: 30000 }); if (res.ok && res.data) { setResult(res.data); } else { throw new Error(res.error || 'Failed'); } } catch { setUsedFallback(true); if (entity === 'review') setResult(FALLBACK_TRIGGER_REVIEW); else if (entity === 'product') setResult(FALLBACK_TRIGGER_PRODUCT); else setResult(FALLBACK_TRIGGER_TRANSACTION); } finally { setLoading(false); } }, [entity, reviewText, productName, productDesc, txAmount, txCustomer, txMerchant, txLocation]); return (
Simulate a database INSERT and watch three AI models fire automatically inside PostgreSQL trigger functions — in a single ACID transaction.
{/* Entity selector */}
{`review_id: ${crypto.randomUUID ? crypto.randomUUID().substring(0,8) : 'a1b2c3d4'}...
customer_id: cust_8821
text: ${reviewText.substring(0, 60)}...
sentiment_score: ${result.score}
sentiment_label: ${result.label}
sentiment_conf: ${result.confidence}
key_phrases: ${JSON.stringify(result.key_phrases || [])}
embedding: [0.231, -0.445, 0.882 ... vector(1536)]
embedding_model: text-embedding-3-small
tsvector: 'batteri':1 'complet':3 'die':4 'email':9
fraud_score: 0.14
flagged: false
ai_metadata: {"trigger_version": "1.0", "processed_ms": 0.48}
created_at: ${new Date().toISOString()}`}
)}
{entity === 'product' && (
{`product_id: ${Math.random().toString(36).substring(2, 10)}...
name: ${productName}
category: ${result.category}
subcategory: ${result.subcategory}
tags: ${JSON.stringify(result.tags || [])}
quality_score: ${result.quality_score}
similar_cats: ${JSON.stringify(result.similar_categories || [])}
embedding: [0.112, -0.332, 0.751 ... vector(1536)]
created_at: ${new Date().toISOString()}`}
)}
{entity === 'transaction' && (
{`transaction_id: ${Math.random().toString(36).substring(2, 10)}...
customer_id: ${txCustomer}
amount: $${txAmount}
fraud_score: ${result.fraud_score}
risk_level: ${result.risk_level}
risk_factors: ${JSON.stringify(result.risk_factors || [])}
recommendation: ${result.recommended_action}
confidence: ${result.confidence}
flagged: ${(result.fraud_score || 0) > 0.7}
created_at: ${new Date().toISOString()}`}
)}