@angloqq03/gpv
v1.1.4
Published
OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.
Maintainers
Readme
@angloqq03/gpv
GPV is a GCash proof validator toolkit for Node.js.
It gives you two main paths:
- OCR-only mode if you just want to extract text, reference, amount, and date
- OCR + risk scoring mode if you also want Brain.js-based fraud signals
Under the hood, GPV uses:
tesseract.jsfor OCRbrain.jsfor risk scoring
It also ships with an interactive Express demo so developers can test everything in a browser before integrating it into a real app.
Why GPV? 💸
Payment proof screenshots are useful, but they can also be:
- edited
- cropped
- reused
- partially hidden
- taken from different bank apps and passed off as something else
GPV helps you:
- read proof screenshots
- extract likely proof fields
- compare them against expected transaction data
- optionally score how suspicious the proof looks
Pick your mode ✨
1. OCR-only mode
Use this when you only want extraction and parsing.
Main functions:
extractTextFromImage()parseProofText()extractProofDetails()isReferenceDetected()isAmountDetected()isDateDetected()
2. Default built-in model mode
Use this when you want OCR plus the package's built-in Brain.js JSON model.
Main functions:
validateProof()fullAnalysis()validateUploadedProof()analyzeUploadedProof()createExpressProofValidator()
3. Custom model mode
Use this when you want to train your own Brain.js model from real proof samples.
Main functions:
npm run train:modelloadFraudModelFromFile()setFraudModel()resetFraudModel()
Once you call setFraudModel(customModel), GPV uses your custom model for scoring.
Install 📦
npm install @angloqq03/gpvThe required dependencies are installed automatically through npm.
Super quick start 🚀
import { isRefValid, fullAnalysis } from "@angloqq03/gpv";
console.log(isRefValid("123456789012"));
const result = await fullAnalysis("./proof.png", {
reference: "123456789012",
amount: 499.99,
date: "2026-04-03"
});
console.log(result.ok);
console.log(result.extracted);
console.log(result.risk);Interactive demo server 🧪
If you want a browser playground for the package:
npm run demoThen open:
http://localhost:3210/demo/What you can do in the demo:
- upload a proof image
- switch between
OCR only,Validate with model, andFull analysis - set expected reference, amount, date, bank, source bank, and destination
- tweak OCR settings like
pageSegMode - enable a custom OCR crop rectangle
- inspect the live JSON result
You can also start the demo server in code:
import { startInteractiveDemoServer } from "@angloqq03/gpv";
startInteractiveDemoServer({
port: 3210
});OCR-only usage 🔎
Extract raw OCR text
import { extractTextFromImage } from "@angloqq03/gpv";
const ocr = await extractTextFromImage("./proof.png");
console.log(ocr.confidence);
console.log(ocr.text);Extract likely proof fields
import { extractProofDetails } from "@angloqq03/gpv";
const details = await extractProofDetails("./proof.png");
console.log(details.extracted.reference);
console.log(details.extracted.amount);
console.log(details.extracted.date);Parse OCR text manually
Useful if OCR happens elsewhere.
import { parseProofText } from "@angloqq03/gpv";
const parsed = parseProofText(`
Amount Paid PHP 3,000.00
Ref. No. 5695 5992 5
12 April 2022 01:46:01 PM
`);
console.log(parsed.extracted);GPV now uses context-aware parsing, so it is better at:
- preferring
Ref. No.overAccount Number - preferring
Amount PaidoverFee - recognizing full month-name dates like
12 April 2022
Default model usage 🧠
Validate with the built-in model
import { validateProof } from "@angloqq03/gpv";
const result = await validateProof("./proof.png", {
reference: "123456789012",
amount: 250,
date: "2026-04-03"
});
console.log(result.ok);
console.log(result.checks);
console.log(result.risk.level);Full analysis with summary
import { fullAnalysis } from "@angloqq03/gpv";
const analysis = await fullAnalysis("./proof.png", {
reference: "123456789012",
amount: 250,
date: "2026-04-03"
});
console.log(analysis.summary);
console.log(analysis.rawText);
console.log(analysis.candidates);Express usage ⚡
Manual route style
npm install express multerimport express from "express";
import multer from "multer";
import { analyzeUploadedProof } from "@angloqq03/gpv";
const app = express();
const upload = multer({ dest: "uploads/" });
app.post("/upload-proof", upload.single("proof"), async (req, res, next) => {
try {
const expected = {
reference: req.body.reference,
amount: Number(req.body.amount),
date: req.body.date
};
const result = await analyzeUploadedProof(req.file, expected, {
amountTolerance: 0
});
res.json({
success: true,
validation: result
});
} catch (error) {
next(error);
}
});Middleware style
import express from "express";
import multer from "multer";
import { createExpressProofValidator } from "@angloqq03/gpv";
const app = express();
const upload = multer({ dest: "uploads/" });
app.post(
"/upload-proof",
upload.single("proof"),
createExpressProofValidator({
attachToRequestAs: "proofAnalysis",
run: "fullAnalysis",
getExpected: async (req) => ({
reference: req.body.reference,
amount: Number(req.body.amount),
date: req.body.date
})
}),
(req, res) => {
res.json({
success: true,
validation: req.proofAnalysis
});
}
);Custom model workflow 🛠️
If you have real proof samples from:
- GCash
- CIMB to GCash
- MariBank to GCash
- other bank-to-GCash transfer flows
then you can train your own Brain.js JSON model.
Step 1: Add labeled samples
Put screenshots in proofsamples/ and describe them in proofsamples/labels.json.
Example:
{
"language": "eng",
"amountTolerance": 0,
"logOcrProgress": false,
"trainingOptions": {
"iterations": 4000,
"log": false
},
"samples": [
{
"name": "gcash-real-001",
"image": "proofsamples/gcash-real-001.png",
"bank": "gcash",
"sourceBank": "gcash",
"destination": "gcash",
"route": "wallet_to_wallet",
"legitimate": 1,
"isEdited": false,
"isSynthetic": false,
"fraudType": "none",
"tags": ["real", "wallet-to-wallet"],
"notes": "Confirmed against real payment records.",
"expected": {
"reference": "123456789012",
"amount": 250,
"date": "2026-04-03"
}
}
]
}Step 2: Train the model
npm run train:modelThis generates:
models/custom-risk-model.jsonmodels/last-training-dataset.json
Step 3: Load and use your model
import {
loadFraudModelFromFile,
setFraudModel,
validateUploadedProof
} from "@angloqq03/gpv";
const customModel = await loadFraudModelFromFile("./models/custom-risk-model.json");
setFraudModel(customModel);
const result = await validateUploadedProof("./proofsamples/gcash-real-001.png", {
reference: "123456789012",
amount: 250,
date: "2026-04-03"
});
console.log(result.risk);Switch back to default model
import { resetFraudModel } from "@angloqq03/gpv";
resetFraudModel();Helpful functions 🧩
OCR and parsing
extractTextFromImage(image, options?)parseProofText(text, options?)extractProofDetails(image, options?)
Validation and analysis
validateProof(image, expected?, options?)fullAnalysis(image, expected?, options?)validateUploadedProof(upload, expected?, options?)analyzeUploadedProof(upload, expected?, options?)createInteractiveDemoServer(config?)startInteractiveDemoServer(config?)
Model helpers
createFraudDetectionModel()trainFraudModelFromDataset()buildDatasetFromProofSamples()loadFraudModelFromFile()saveFraudModelToFile()setFraudModel()resetFraudModel()
Comparison and detection
compareReference(reference, expectedReference)compareAmount(amount, expectedAmount, tolerance?)compareDate(date, expectedDate)isReferenceDetected(image)isAmountDetected(image)isDateDetected(image)
Format and utility helpers
isRefValid(reference)isValidReference(reference)isReferenceFormatValid(reference)isAmountFormatValid(amount)isDateFormatValid(date)normalizeReference(reference)normalizeAmount(amount)normalizeDate(date)parseNumericAmount(amount)toCleanText(text)safeDate(date)isDateRecent(date, maxAgeDays?)
Options 🎛️
const options = {
language: "eng",
amountTolerance: 0,
pageSegMode: 6,
rectangle: { top: 0, left: 0, width: 1080, height: 1920 },
logger: (message) => console.log(message)
};Notes:
pageSegMode: 6is a solid default for proof screenshots and receipts- OCR text is rebuilt in top-to-bottom order from Tesseract block data
validateProof()andfullAnalysis()use the active model automatically
Testing with proof.png 🧪
If proof.png exists in the package root, npm test will print:
- OCR confidence
- extracted OCR text
- parser helper output
Important note ❤️
GPV helps a lot, but it should not be your only fraud defense.
For best results, always compare against your own server-side order data:
- expected amount
- expected reference
- expected payment date
- order ownership
- payment status in your own database
