Appearance
Extraction Tiers
Waspada AI uses a two-tier extraction system that balances speed, accuracy, and resource usage.
Tier 1: Regex Engine (Deterministic)
Always available. Zero model download required.
The regex engine runs instantly and handles the majority of Malaysian financial document patterns:
| Pattern | Example | Regex |
|---|---|---|
| Malaysian NRIC | 880101-14-5678 | \d{6}-\d{2}-\d{4} |
| Bank Account (8-17 digits) | 1234567890 | \d{8,17} |
| SWIFT/BIC Code | MBBEMYKL | [A-Z]{4}MY[A-Z0-9]{2} |
| Phone (MY format) | +60123456789 | \+?60\d{9,10} |
| URLs | https://scam.com | Standard URL regex |
| Transaction Amount | RM 1,500.00 | RM\s*[\d,]+\.?\d* |
Supported Banks (BIC Resolution)
| Bank | BIC Code |
|---|---|
| Maybank | MBBEMYKL |
| CIMB | CIBBMYKL |
| Public Bank | PBBEMYKL |
| Hong Leong | HLBBMYKL |
| RHB | RHBBMYKL |
| AmBank | AMMBMYKL |
| Bank Islam | BIMBMYKL |
| Bank Rakyat | BKRMMYKL |
| Alliance Bank | AFBQMYKL |
| Affin Bank | ARBKMYKL |
| OCBC | OCBCMYKL |
| UOB | UOBBMYKL |
| HSBC | HBMBMYKL |
| Standard Chartered | SCBLMYKX |
| BSN | BSNAMYK1 |
| Agrobank | AGOBMYKL |
| Bank Muamalat | MBABOREA |
| GXBank | GXSPMYKL |
| Touch 'n Go | TNGDMYNB |
Measured accuracy
Noisy figures are in-sample, post-fix on the corpus that surfaced the bugs — a characterized error inventory + regression floor, not a holdout generalization estimate. See package
EXTRACTION_METRICS.md.
Clean CI gate (regression floor)
Corpus 2026-07-11 — 37 synthetic Malay receipt layouts (Tier-1 regex).
Hard gate: P ≥ 0.90 and R ≥ 0.85 on account + BIC. Clean text near-perfect is expected for this contract — not a claim about production OCR.
| Field | Support | Notes |
|---|---|---|
| mule_account_number | 29 | No errors on clean layouts (gate PASS) |
| mule_bank_bic | 32 | No errors on clean layouts (gate PASS) |
| scammer_alias | 35 | Tracked; not the hard gate |
| malicious_urls | 3 | Tracked; small support |
Noisy / adversarial soft gate (bank conversation surface)
Corpus 2026-07-26-noisy — 21 OCR-mash / adversarial layouts.
Soft gate: P ≥ 0.85 and R ≥ 0.80 on account + BIC.
| Outcome (account) | Count | Meaning |
|---|---|---|
| Correct | 14 | Match |
| Miss (no account) | 2 | Safe failure — costs coverage |
| Wrong account | 1 | Line-wrap truncation (5642… → 23456789) |
Honest register: ~90% of account outputs correct under adversarial text (n=21, wide CI). About 1 in 15 account outputs was the wrong account — which is why nothing we emit is a freeze instruction, and why actionable requires three independent institutions on the same account.
| Field | Support | Honest summary |
|---|---|---|
| mule_bank_bic | 19 | No errors observed on these 19 samples — not “100% across MY banks × OCR” |
| scammer_alias | 21 | ~1 miss (merchant SDN BHD / person-name filter) |
| malicious_urls | 1 | Not meaningfully measured — omit from pitch tables |
Priority gap: line-wrap account join (only failure that emits a different real-looking account). Phone-shaped 6012… miss is a deliberate phone/NRIC-vs-account tradeoff.
CI gate scope
Hard gate = Tier-1 regex on clean labeled text. Soft gate = noisy account/BIC floors. Neither covers DistilBERT NER regressions, image→OCR end-to-end, or a held-out set. Holdout (label once, score once, never tune) is the follow-up before quoting out-of-sample accuracy.
DuitNow QR (no account on the slip)
Many DuitNow QR receipts never show a recipient account number — only a name and sometimes a bank/e-wallet. The eval corpus labels those as mule_account_number: null on purpose. Inventing an account from a DuitNow reference ID is a false positive. Product response: extract alias/BIC when present, keep disposition advisory, and ask the user for a second (account-transfer) slip when possible.
Tier 2: NER Engine (AI-Powered)
Available after background model download or local air-gap cache load (~100MB).
The NER engine uses a quantized BERT-class ONNX model (Xenova/bert-base-NER) to extract entities that regex cannot reliably identify:
| Entity Type | NER Label | Maps To |
|---|---|---|
| Person name | PER | scammer_alias |
| Organization | ORG | mule_bank_bic (via bank name lookup) |
When Tier 2 Activates
Tier 2 only runs when Tier 1 results are incomplete:
Regex extracts account + BIC + alias → REGEX_ONLY (skip NER)
Regex extracts account + BIC only → Run NER for alias → HYBRID
Regex extracts nothing → Run NER for all → NER_ENCODERPerformance Optimization
For 95%+ of digital bank receipts, Tier 1 Regex is sufficient. The NER model is only invoked for ambiguous, informal, or handwritten evidence where regex patterns fail.
Extraction Tier Labels
| Tier | Meaning | Typical Latency |
|---|---|---|
REGEX_ONLY | All indicators extracted by regex | < 10ms |
NER_ENCODER | NER model used for extraction | 100-200ms |
HYBRID | Regex + NER combined | 100-200ms |