@privateid/small-age-sdk-alpha
Version:
716 lines (627 loc) • 23.9 kB
JavaScript
/* eslint-disable no-eval */
/* eslint-disable default-param-last */
/* eslint-disable no-undef */
/* eslint-disable no-underscore-dangle */
// importScripts('https://unpkg.com/comlink/dist/umd/comlink.js');
importScripts('./unpkg.js');
let debugType;
let wasmPrivGoogModule;
let wasmGoogSession = null;
let privid_wasm_result = null;
let checkWasmLoaded = null;
let isSimd;
let currentVersion;
let inputPtr;
let barCodePtr;
/**
* @brief A closure to create an output 32bits pointer closure.
* This is usefull for allocating a native address and pass it to the
* 'wasmPrivModule' so it can return in the address of a buffer (or an object like session)
* that was allocated inside the wasm. This typically, correspond to
* an argument of type void** (marked output argument) to pass to a native wasm
* call.
* @usage var myoutput_ptr = output_ptr();
* when passing the output pointer to the 'wasmPrivModule' module use
* wasmPrivModule.nativecall(myoutput_ptr.outer_ptr());
* Then pull out the the allocated buffer by the wasm call this way:
* @code
* my_buffer_or_structure = myoutput_ptr.inner_ptr();
* @note It is the responsability of the caller to free the pointer returned by this inner_ptr()
*/
const m_output_ptr = function (module) {
let out_ptr = null;
let in_ptr = null;
const priv_module = module;
const free_ptr = (ptr) => {
if (ptr) {
priv_module._free(ptr);
// eslint-disable-next-line no-param-reassign
ptr = null;
}
};
return {
/**
* @brief Allocates a pointer to contain the result and return it,
* if the container is already created it will be returned
*/
outer_ptr: () => {
// TODO: may be used SharedArrayBuffer() instead
// allocate memory the expected pointer (outer pointer or container)
if (!out_ptr) out_ptr = priv_module._malloc(Int32Array.BYTES_PER_ELEMENT);
return out_ptr;
},
/**
* @brief Creates a javascript Uint32Array pointer to contain the result pointed by outer_ptr and return it,
* It is the responsability of the caller to free the pointer returned by this function
*/
inner_ptr: () => {
// If we did not allocate yet the output buffer return null
if (!out_ptr) return null;
// if we already have our inner pointer for this closure return it
if (in_ptr) return in_ptr;
// Access the outer pointer as an arry of uint32 which conatin a single cell
// whose value is the pointer allocated in the wasm module (inner pointer of the output param)
// and return it
[in_ptr] = new Uint32Array(priv_module.HEAPU8.buffer, out_ptr, 1);
return in_ptr;
},
};
};
/**
* @brief A closure to create a string buffer arguments that can be used with wasm calls
* for a given javascript value.
* This is suitable for native calls that have string input arguments represented with contigious
* string_buffer,sizeofbuffer arguments.
* If the 'text' argument is null or undefined or NaN then the arguments generated are [null,0]
* @usage
*
var url_args= buffer_args(url);
var key_args= buffer_args(key);
var session_out_ptr = output_ptr();
const s_result = wasmPrivModule._privid_initialize_session(
...key_args.args(),
...url_args.args(),
debug_type,
session_out_ptr.outer_ptr(),
);
url_args.free();
key_args.free();
//get
var session = session_out_ptr.inner_ptr();
*
* when .free() is called the closure can be reused to create a buffer for the same string with which, it was created with
* over and over again.
*/
const stringToBufferArgs = function (module, text) {
const priv_module = module;
let strInputtPtr = null;
let strInputSize = 0;
let argsv = [];
return {
args: () => {
do {
if (argsv.length > 0) break;
argsv = [null, 0];
if (text === null) break;
if (text === undefined) break;
// eslint-disable-next-line use-isnan
if (text === NaN) break;
const str = `${text}`;
const encoder = new TextEncoder();
const bytes = encoder.encode(str);
strInputSize = bytes.length * bytes.BYTES_PER_ELEMENT;
strInputtPtr = priv_module._malloc(strInputSize);
priv_module.HEAP8.set(bytes, strInputtPtr / bytes.BYTES_PER_ELEMENT);
argsv = [strInputtPtr, strInputSize];
} while (false);
return argsv;
},
free: () => {
if (strInputtPtr) {
priv_module._free(strInputtPtr);
strInputtPtr = null;
strInputSize = 0;
argsv = [];
}
},
};
};
const load_module = async (wasm_js_path, wasm_bin_path, moduleType, saveCache, version) => {
console.log('start load', { wasm_js_path, wasm_bin_path, moduleType, saveCache, version });
const wasm = await fetch(wasm_bin_path);
const script = await fetch(wasm_js_path);
console.log('Wasm, script', { wasm, script });
const scriptBuffer = await script.text();
const buffer = await wasm.arrayBuffer();
eval(scriptBuffer);
const loadedModule = await createTFLiteModule({ wasmBinary: buffer });
if (saveCache) {
await putKey(moduleType, buffer, scriptBuffer, version);
}
return loadedModule;
};
const isLoad = (a_simd, a_debug_type) =>
new Promise(async (resolve, reject) => {
if (a_debug_type === undefined) {
debugType = 0;
} else {
debugType = parseInt(a_debug_type, 10);
}
isSimd = a_simd;
const cachedModule = await readKey('gage');
const modulePath = a_simd ? 'simd' : 'noSimd';
const fetchdWasmVersion = await fetch(`../wasm/${modulePath}/version.json`);
const fetchdVersion = await fetchdWasmVersion.json();
currentVersion = fetchdVersion.version;
console.log('Versioning:', {
cacheVersion: cachedModule?.version.toString() || '',
currentVersion: fetchdVersion?.version.toString(),
});
if (cachedModule?.version && cachedModule?.version.toString() === fetchdVersion?.version.toString()) {
if (debugType >= 1) {
console.log(`loading from cache.`);
}
if (!wasmPrivGoogModule) {
const { cachedWasm, cachedScript } = cachedModule;
eval(cachedScript);
wasmPrivGoogModule = await createTFLiteModule({ wasmBinary: cachedWasm });
checkWasmLoaded = true;
}
console.log('gage modules:', { wasmPrivGoogModule });
await initializeGoogWasmSession(debugType);
resolve('Cache Loaded');
} else {
const wasm_path = {
simd: {
bin: '../wasm/simd/privid_fhe_goog.wasm',
js: '../wasm/simd/privid_fhe_goog.js',
},
noSimd: {
bin: '../wasm/noSimd/privid_fhe_goog_no_simd.wasm',
js: '../wasm/noSimd/privid_fhe_goog_no_simd.js',
},
};
try {
// loading wasm modules
if (!wasmPrivGoogModule) {
wasmPrivGoogModule = await load_module(
isSimd ? wasm_path.simd.js : wasm_path.noSimd.js,
isSimd ? wasm_path.simd.bin : wasm_path.noSimd.bin,
'gage',
true,
currentVersion.toString(),
);
console.log({ wasmPrivGoogModule });
await initializeGoogWasmSession(debugType);
checkWasmLoaded = true;
}
resolve(true);
} catch (e) {
console.log(e);
}
}
});
function readKey(key) {
if (!indexedDB) return Promise.reject(new Error('IndexedDB not available'));
return new Promise((resolve, reject) => {
const open = indexedDB.open('/privid-wasm', 21);
open.onerror = function () {
resolve(false);
// console.log('Private Browser. ');
};
open.onupgradeneeded = function () {
open.result.createObjectStore('/privid-wasm');
};
open.onsuccess = function () {
const db = open.result;
const tx = db.transaction('/privid-wasm', 'readwrite');
const store = tx.objectStore('/privid-wasm');
const getKey = store.get(key);
getKey.onsuccess = function () {
resolve(getKey.result);
};
tx.onerror = function () {
reject(tx.error);
};
tx.oncomplete = function () {
try {
db.close();
} catch (e) {
//
}
};
};
});
}
function putKey(key, cachedWasm, cachedScript, version) {
if (!indexedDB) return Promise.reject(new Error('IndexedDB not available'));
return new Promise((resolve, reject) => {
const open = indexedDB.open('/privid-wasm', 21);
open.onerror = function () {
resolve(false);
// console.log('Private Browser.');
};
open.onupgradeneeded = function () {
open.result.createObjectStore('/privid-wasm');
};
open.onsuccess = function () {
const db = open.result;
const tx = db.transaction('/privid-wasm', 'readwrite');
const store = tx.objectStore('/privid-wasm');
const getKey = store.put({ cachedWasm, cachedScript, version }, key);
getKey.onsuccess = function () {
resolve('saved');
};
tx.onerror = function () {
reject(tx.error);
};
tx.oncomplete = function () {
try {
db.close();
} catch (e) {
//
}
};
};
});
}
async function initializeGoogWasmSession(debug_type) {
console.log('INITIALIZE SESSION GOOGLE:');
if (!wasmGoogSession) {
console.log('initializing session');
const session_out_ptr = m_output_ptr(wasmPrivGoogModule);
const debug = debug_type || 0;
const initializationArgs = {
debug_level: debug,
};
const configArgs = stringToBufferArgs(wasmPrivGoogModule, JSON.stringify(initializationArgs));
console.log('Config Args:', configArgs);
// console.log('debug type in session?>??', debug);
console.log('module:', wasmPrivGoogModule);
const s_result = wasmPrivGoogModule._privid_initialize_session(...configArgs.args(), session_out_ptr.outer_ptr());
// console.log("Initialize session result:", s_result);
if (s_result) {
if (debug_type >= 1) {
console.log('[WASM_RESULT] : goog session initialized successfully');
}
} else {
if (debug_type >= 1) {
console.log('[WASM_RESULT] : goog session initialized failed');
}
return;
}
// get our inner session created by wasm and free the outer container ptr
wasmGoogSession = session_out_ptr.inner_ptr();
configArgs.free();
// console.log('WASM MODULES', wasmPrivGoogModule);
// await wasmPrivGoogModule._privid_set_default_configuration(wasmGoogSession, 1);
await wasmPrivGoogModule._privid_set_configuration(wasmGoogSession, 1);
if (debug_type >= 1) {
// console.log('Session Created');
}
} else {
// eslint-disable-next-line no-lonely-if
if (debug_type >= 1) {
// console.log('wasm goog Session', wasmGoogSession);
// console.log('Wasm goog session is available. Skipping creating session');
}
}
}
const multiframeLivenessAndAgePredict = async (data, width, height, config, cb) => {
privid_wasm_result = cb;
console.log("Config in Worker:", config);
const imageSize = data.length * data.BYTES_PER_ELEMENT;
const imagePtr = wasmPrivGoogModule._malloc(imageSize);
wasmPrivGoogModule.HEAP8.set(data, imagePtr / data.BYTES_PER_ELEMENT);
const encoder = new TextEncoder();
const config_bytes = encoder.encode(`${config}`);
const configInputSize = config.length;
const configInputPtr = wasmPrivGoogModule._malloc(configInputSize);
wasmPrivGoogModule.HEAP8.set(config_bytes, configInputPtr / config_bytes.BYTES_PER_ELEMENT);
const resultFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
// create a pointer to interger to hold the length of the output buffer
const resultLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
console.log({
wasmGoogSession /* session pointer */,
imagePtr,
width,
height,
configInputPtr,
configInputSize,
resultFirstPtr,
resultLenPtr,
});
try {
// return false if failure, true if operation ran without problem. The livness code is returned by the JS call back
await wasmPrivGoogModule._privid_estimate_age(
wasmGoogSession /* session pointer */,
imagePtr,
width,
height,
configInputPtr,
configInputSize,
resultFirstPtr,
resultLenPtr,
);
} catch (e) {
console.error('_estimate_age', e);
}
wasmPrivGoogModule._free(configInputPtr);
wasmPrivGoogModule._free(resultFirstPtr);
wasmPrivGoogModule._free(resultLenPtr);
wasmPrivGoogModule._free(imagePtr);
};
const prividDocumentMugshotFaceCompare = (imageInputA, imageInputB, simd, debug_type = 0, cb, config = {}) =>
new Promise(async (resolve) => {
privid_wasm_result = cb;
// First Image A
const { data: imageDataA } = imageInputA;
const imageInputSizeA = imageDataA.length * imageDataA.BYTES_PER_ELEMENT;
const imageInputPtrA = wasmPrivGoogModule._malloc(imageInputSizeA);
wasmPrivGoogModule.HEAP8.set(imageDataA, imageInputPtrA / imageDataA.BYTES_PER_ELEMENT);
// Second Image B
const { data: imageDataB } = imageInputB;
const imageInputSizeB = imageDataB.length * imageDataB.BYTES_PER_ELEMENT;
const imageInputPtrB = wasmPrivGoogModule._malloc(imageInputSizeB);
wasmPrivGoogModule.HEAP8.set(imageDataB, imageInputPtrB / imageDataB.BYTES_PER_ELEMENT);
const encoder = new TextEncoder();
const config_bytes = encoder.encode(`${config}`);
const configInputSize = config.length;
const configInputPtr = wasmPrivGoogModule._malloc(configInputSize);
wasmPrivGoogModule.HEAP8.set(config_bytes, configInputPtr / config_bytes.BYTES_PER_ELEMENT);
const resultFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
// create a pointer to interger to hold the length of the output buffer
const resultLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
// Initialize Session
// await initializeWasmSession(apiUrl, apiKey);
let result = null;
try {
result = wasmPrivGoogModule._privid_compare_face_and_mugshot(
wasmGoogSession,
configInputPtr,
configInputSize,
imageInputPtrA,
// imageInputA.data.length,
imageInputA.width,
imageInputA.height,
imageInputPtrB,
// imageInputB.data.length,
imageInputB.width,
imageInputB.height,
resultFirstPtr,
resultLenPtr,
);
} catch (e) {
console.error('________ Doc mugshot face compare _______', e);
}
wasmPrivGoogModule._privid_free_char_buffer(configInputPtr);
wasmPrivGoogModule._free(imageInputPtrA);
wasmPrivGoogModule._free(imageInputPtrB);
wasmPrivGoogModule._free(resultFirstPtr);
wasmPrivGoogModule._free(resultLenPtr);
resolve({ result });
});
const scanDocument = async (imageInput, simd, cb, doPredict, config, debug_type = 0) => {
privid_wasm_result = cb;
configGlobal = config;
// const version = wasmPrivModule._get_version();
const encoder = new TextEncoder();
const config_bytes = encoder.encode(`${config}`);
const configInputSize = config.length;
const configInputPtr = wasmPrivGoogModule._malloc(configInputSize);
wasmPrivGoogModule.HEAP8.set(config_bytes, configInputPtr / config_bytes.BYTES_PER_ELEMENT);
const { data: imageData } = imageInput;
const imageInputSize = imageData.length * imageData.BYTES_PER_ELEMENT;
if (!inputPtr) {
inputPtr = wasmPrivGoogModule._malloc(imageInputSize);
}
wasmPrivGoogModule.HEAP8.set(imageData, inputPtr / imageData.BYTES_PER_ELEMENT);
// Cropped Document malloc
const croppedDocumentBufferFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const croppedDocumentBufferLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
// Cropped Mugshot malloc
const croppedMugshotBufferFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const croppedMugshotBufferLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
let result = null;
console.log('data before front scan:', {
wasmGoogSession,
configInputPtr,
configInputSize,
inputPtr,
width: imageInput.width,
height: imageInput.height,
croppedDocumentBufferFirstPtr,
croppedDocumentBufferLenPtr,
croppedMugshotBufferFirstPtr,
croppedMugshotBufferLenPtr,
});
try {
result = wasmPrivGoogModule._privid_doc_scan_face(
wasmGoogSession,
configInputPtr,
configInputSize,
inputPtr,
imageInput.width,
imageInput.height,
croppedDocumentBufferFirstPtr,
croppedDocumentBufferLenPtr,
croppedMugshotBufferFirstPtr,
croppedMugshotBufferLenPtr,
null,
0,
);
} catch (err) {
console.error('-----------------ERROR---------------', err);
return;
}
// Document
const { outputBufferData: croppedDocument } = getBufferFromPtr(
croppedDocumentBufferFirstPtr,
croppedDocumentBufferLenPtr,
);
// Mugshot
const { outputBufferData: croppedMugshot } = getBufferFromPtr(
croppedMugshotBufferFirstPtr,
croppedMugshotBufferLenPtr,
);
const imageBuffer = getBufferFromPtrImage(inputPtr, imageInputSize);
wasmPrivGoogModule._free(croppedDocumentBufferFirstPtr);
wasmPrivGoogModule._free(croppedDocumentBufferLenPtr);
wasmPrivGoogModule._free(croppedMugshotBufferFirstPtr);
wasmPrivGoogModule._free(croppedMugshotBufferLenPtr);
wasmPrivGoogModule._free(configInputPtr);
wasmPrivGoogModule._free(inputPtr);
inputPtr = null;
// eslint-disable-next-line consistent-return, no-param-reassign
return {
result,
croppedDocument,
croppedMugshot,
imageData: imageInput,
};
};
const isValidBarCode = async (imageInput, simd, cb, config, debug_type = 0) => {
privid_wasm_result = cb;
configGlobal = config;
const { data: imageData } = imageInput;
const imageInputSize = imageData.length * imageData.BYTES_PER_ELEMENT;
if (!barCodePtr) {
barCodePtr = wasmPrivGoogModule._malloc(imageInputSize);
}
wasmPrivGoogModule.HEAP8.set(imageData, barCodePtr / imageData.BYTES_PER_ELEMENT);
// Cropped Document malloc
const croppedDocumentBufferFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const croppedDocumentBufferLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
// Cropped Barcode malloc
const croppedBarcodeBufferFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const croppedBarcodeBufferLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const encoder = new TextEncoder();
const config_bytes = encoder.encode(`${config}`);
const configInputSize = config.length;
const configInputPtr = wasmPrivGoogModule._malloc(configInputSize);
wasmPrivGoogModule.HEAP8.set(config_bytes, configInputPtr / config_bytes.BYTES_PER_ELEMENT);
let result = null;
try {
result = wasmPrivGoogModule._privid_doc_scan_barcode_for_age(
wasmGoogSession,
configInputPtr,
configInputSize,
barCodePtr,
imageInput.width,
imageInput.height,
null,
0,
);
} catch (err) {
console.error('-----------_E_-----------', err);
}
// Document
// const { outputBufferData: croppedDocument, outputBufferSize: croppedDocumentSize } = getBufferFromPtr(
// croppedDocumentBufferFirstPtr,
// croppedDocumentBufferLenPtr,
// );
//
// // Mugshot
// const { outputBufferData: croppedBarcode, outputBufferSize: croppedBarcodeSize } = getBufferFromPtr(
// croppedBarcodeBufferFirstPtr,
// croppedBarcodeBufferLenPtr,
// );
// let imageBuffer = null;
// if (croppedBarcodeSize && croppedDocumentSize) {
// imageBuffer = getBufferFromPtrImage(barCodePtr, imageInputSize);
// }
wasmPrivGoogModule._free(barCodePtr);
barCodePtr = null;
wasmPrivGoogModule._free(croppedDocumentBufferFirstPtr);
wasmPrivGoogModule._free(croppedDocumentBufferLenPtr);
wasmPrivGoogModule._free(croppedBarcodeBufferFirstPtr);
wasmPrivGoogModule._free(croppedBarcodeBufferLenPtr);
wasmPrivGoogModule._free(configInputPtr);
// return { result, croppedDocument, croppedBarcode, imageData: imageBuffer };
};
const getBufferFromPtr = (bufferPtr, bufferSize) => {
const [outputBufferSize] = new Uint32Array(wasmPrivGoogModule.HEAPU8.buffer, bufferSize, 1);
let outputBufferSecPtr = null;
if (outputBufferSize > 0) {
[outputBufferSecPtr] = new Uint32Array(wasmPrivGoogModule.HEAPU8.buffer, bufferPtr, 1);
}
const outputBufferPtr = new Uint8Array(wasmPrivGoogModule.HEAPU8.buffer, outputBufferSecPtr, outputBufferSize);
const outputBuffer = Uint8ClampedArray.from(outputBufferPtr);
wasmPrivGoogModule._privid_free_char_buffer(outputBufferSecPtr);
const outputBufferData = outputBufferSize > 0 ? outputBuffer : null;
return { outputBufferData, outputBufferSize };
};
const getBufferFromPtrImage = (bufferPtr, outputBufferSize) => {
const outputBufferPtr = new Uint8Array(wasmPrivGoogModule.HEAPU8.buffer, bufferPtr, outputBufferSize);
const outputBuffer = Uint8ClampedArray.from(outputBufferPtr);
return outputBufferSize > 0 ? outputBuffer : null;
};
const frontDocumentOcr = (imageInput, simd, cb, config, debug_type = 0) => {
console.log('params', { imageInput, simd, cb, config, debug_type });
privid_wasm_result = cb;
configGlobal = config;
const { data: imageData } = imageInput;
const imageInputSize = imageData.length * imageData.BYTES_PER_ELEMENT;
if (!barCodePtr) {
barCodePtr = wasmPrivGoogModule._malloc(imageInputSize);
}
wasmPrivGoogModule.HEAP8.set(imageData, barCodePtr / imageData.BYTES_PER_ELEMENT);
// Cropped Document malloc
const croppedDocumentBufferFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const croppedDocumentBufferLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
// Cropped Barcode malloc
const croppedBarcodeBufferFirstPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const croppedBarcodeBufferLenPtr = wasmPrivGoogModule._malloc(Int32Array.BYTES_PER_ELEMENT);
const encoder = new TextEncoder();
const config_bytes = encoder.encode(`${config}`);
const configInputSize = config.length;
const configInputPtr = wasmPrivGoogModule._malloc(configInputSize);
wasmPrivGoogModule.HEAP8.set(config_bytes, configInputPtr / config_bytes.BYTES_PER_ELEMENT);
let result = null;
try {
result = wasmPrivGoogModule._privid_doc_scan_face_for_age(
wasmGoogSession,
configInputPtr,
configInputSize,
barCodePtr,
imageInput.width,
imageInput.height,
null,
0,
);
} catch (err) {
console.error('-----------_E_-----------', err);
}
// Document
// const { outputBufferData: croppedDocument, outputBufferSize: croppedDocumentSize } = getBufferFromPtr(
// croppedDocumentBufferFirstPtr,
// croppedDocumentBufferLenPtr,
// );
//
// // Mugshot
// const { outputBufferData: croppedBarcode, outputBufferSize: croppedBarcodeSize } = getBufferFromPtr(
// croppedBarcodeBufferFirstPtr,
// croppedBarcodeBufferLenPtr,
// );
// let imageBuffer = null;
// if (croppedBarcodeSize && croppedDocumentSize) {
// imageBuffer = getBufferFromPtrImage(barCodePtr, imageInputSize);
// }
console.log('OCR RESULT: ', result);
wasmPrivGoogModule._free(barCodePtr);
barCodePtr = null;
wasmPrivGoogModule._free(croppedDocumentBufferFirstPtr);
wasmPrivGoogModule._free(croppedDocumentBufferLenPtr);
wasmPrivGoogModule._free(croppedBarcodeBufferFirstPtr);
wasmPrivGoogModule._free(croppedBarcodeBufferLenPtr);
wasmPrivGoogModule._free(configInputPtr);
// return { imageInput };
};
Comlink.expose({
isLoad,
multiframeLivenessAndAgePredict,
prividDocumentMugshotFaceCompare,
scanDocument,
isValidBarCode,
frontDocumentOcr,
});