Categorize the Transaction in The Bank’s E-Statement Using Node JS + Google Vertex AI Studio
We will categorize bank transaction based on the defined categories with Google Vertex AI Studio (Gemini Generative AI).
In the previous article, we tried to extract the transactions from the BCA’s e-statement file (.pdf) into an array of strings.
Google Vertex AI Studio
It is a fully managed, unified AI development platform for building and using Generative AI (Gemini). See the prompt gallery here, we will ask the AI to categorize the transaction
I choose “Classify Text” and open it on Google Console, the sample prompt will be put in the “Context” section.
or you can create it manually in the Vertex AI Studio > Language > Create Prompt
Let’s continue to the prompt structure.
Prompt Structure
There are 3 steps there to help the Generative AI execute the prompt.
- Context
Indicate the category you require and specify the task for the AI. - Examples
Provide an example based on the real text, if there is an inaccurate result, put the text and expected result here. We want to provide some examples for each category. - Test
Put any transaction here and see the result
In the right sidebar, there is a temperature, we need to adjust the value to be low because it controls the result.
Lower temperatures are good for prompts that require a less open-ended or creative response, while higher temperatures can lead to more diverse or creative results. A temperature of
0
means that the highest probability tokens are always selected. In this case, responses for a given prompt are mostly deterministic, but a small amount of variation is still possible.If the model returns a response that’s too generic, too short, or the model gives a fallback response, try increasing the temperature. — Google Generative AI
Here is the prompt that I used with temperature 0.
Define the categories for the text below?
Options:
- groceries
- investment
- transfer IN
- topup e-money
- transaction fee
- withdraw
- transfer OUT
- others
Please only print the one category name without anything else.
This is the sample input and output
Here is the json format
[
{
"inputs": ["CR, Credit, SETORAN TUNAI 28/10/95031/00000"],
"outputs": ["transfer IN"]
},
{
"inputs": [
"TRSF E-BANKING DB 0610/FTFVA/WS95031 80777/TOKOPEDIA,Tokopedia,Shopee,Tiktok,Lazada,harihari,transmart,superindo,matahari,indomaret,alfa"
],
"outputs": ["groceries"]
},
{
"inputs": [
"TRSF E-BANKING DB 0710/FTFVA/WS95031 12208/SHOPEEPAY, TRSF E-BANKING DB 1410/FTFVA/WS95031 39358/OVO, DANA 17/10 TRSF E-BANKING DB, OVO, DANA, GOPAY, SHOPEEPAY"
],
"outputs": ["topup e-money"]
},
{
"inputs": [
"TRSF E-BANKING DB 2910/FTFVA/WS95031 89831/LOGAM MULIA, gold, emas, antam, reksadanam saham, IDX Mobile,MOST ,BNI Sekuritas Mobile,Mirae HOTS,BCA Sekuritas Mobile,BRI Mobile Sekuritas,Stockbit,Motion Trade,Bareksa,IPOTGO,CGS-CIMB iTrade,Trimegah Sekuritas Indonesia,Phillip Sekuritas Indonesia,KoinWorks,Ajaib,Modalku,"
],
"outputs": ["investment"]
},
{
"inputs": ["TARIKAN ATM, WITHDRAWAL"],
"outputs": ["withdraw"]
},
{
"inputs": ["BIAYA TXN, BIAYA W/D, BIAYA ADM, Administrasi"],
"outputs": ["transaction fee"]
},
{
"inputs": ["BI FAST DB BIF TRANSFER KE, Transfer to, RSF E-BANKING DB"],
"outputs": ["transfer OUT"]
},
{
"inputs": ["SALDO AWAL"],
"outputs": ["others"]
}
]
Test and Result
If your test found a mismatch, it means you should add more information in the prompt or add a new sample input and output.
Don’t forget to change the name and save the prompt.
Prompt Code
You can get the sample request with Node JS by clicking the button in the next of save button.
We will run it with different code, Node JS + Fetch + JWT.
Export Prompt
Now you can export the prompt to a JSON if you want to create this prompt by JSON in another project.
Here is the JSON,
{
"title": "Classify the transaction",
"description": "",
"parameters": {
"groundingPromptConfig": {
"disabled": true,
"groundingConfig": {
"sources": [
{
"type": "VERTEX_AI_SEARCH"
}
]
}
},
"stopSequences": [],
"temperature": 0,
"tokenLimits": 256,
"topP": 0.8
},
"type": "structured",
"context": "Define the categories for the text below?\nOptions:\n- groceries\n- investment\n- transfer IN\n- topup e-money\n- transaction fee\n- withdraw\n- transfer OUT\n- others\n\nPlease only print the one category name without anything else.",
"inputPrefixes": [
"Text"
],
"outputPrefixes": [
"Categories"
],
"examples": [
{
"inputs": [
"CR, Credit, SETORAN TUNAI 28/10/95031/00000"
],
"outputs": [
"transfer IN"
]
},
{
"inputs": [
"TRSF E-BANKING DB 0610/FTFVA/WS95031 80000/TOKOPEDIA,Tokopedia,Shopee,Tiktok,Lazada,harihari,transmart,superindo,matahari,indomaret,alfa"
],
"outputs": [
"groceries"
]
},
{
"inputs": [
"TRSF E-BANKING DB 0710/FTFVA/WS95031 00000/SHOPEEPAY, TRSF E-BANKING DB 1410/FTFVA/WS95031 39358/OVO, DANA 17/10 TRSF E-BANKING DB, OVO, DANA, GOPAY, SHOPEEPAY"
],
"outputs": [
"topup e-money"
]
},
{
"inputs": [
"TRSF E-BANKING DB 2910/FTFVA/WS95031 00000/LOGAM MULIA, gold, emas, antam, reksadanam saham, IDX Mobile,MOST ,BNI Sekuritas Mobile,Mirae HOTS,BCA Sekuritas Mobile,BRI Mobile Sekuritas,Stockbit,Motion Trade,Bareksa,IPOTGO,CGS-CIMB iTrade,Trimegah Sekuritas Indonesia,Phillip Sekuritas Indonesia,KoinWorks,Ajaib,Modalku,"
],
"outputs": [
"investment"
]
},
{
"inputs": [
"TARIKAN ATM, WITHDRAWAL"
],
"outputs": [
"withdraw"
]
},
{
"inputs": [
"BIAYA TXN, BIAYA W/D, BIAYA ADM, Administrasi"
],
"outputs": [
"transaction fee"
]
},
{
"inputs": [
"BI FAST DB BIF TRANSFER KE, Transfer to, RSF E-BANKING DB"
],
"outputs": [
"transfer OUT"
]
},
{
"inputs": [
"SALDO AWAL"
],
"outputs": [
"others"
]
}
],
"testData": [
{
"inputs": [
"TRSF E-BANKING DB 0610/FTFVA/WS950000 00000/TOKOPEDIA 63,028.00 DB"
]
}
],
"model": "gemini-1.5-flash-001"
}
API Integration
The API integration is already explained in this article
Preparation
We need 3 things
- Prepare the URL by putting your region and project ID in the URL
https://[REGION]-aiplatform.googleapis.com/v1/projects/[PROJECT_ID]/locations/us-central1/publishers/google/models/[MODEL]:streamGenerateContent?alt=sse
My region is us-central1
My model is gemini-1.5-flash-001 - The JSON file from the prompt’s export
- Access token
cURL
if you are running in the local, you can get the token by gcloud auth print-access-token
in your terminal
curl -X POST \
-H "Authorization: Bearer ACCESS_TOKEN" \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
"https://REGION-aiplatform.googleapis.com/v1/projects/PROJECT_ID/locations/us-central1/publishers/google/models/gemini-1.0-pro:streamGenerateContent?alt=sse"
Node JS with Fetch and JWT
We need to prepare the JWT access token by service account, it already explained here
Create a service account with 2 roles:
1. Service Account Token Creator
2. Vertex AI User
Then open the service account detail > keys > Create new key > JSON.
You would get the JSON like this and put it into the .env as a string JSON (stringify) with the name “VERTEX_AI_SERVICE_ACCOUNT”
{
"type": "service_account",
"project_id": ".....",
"private_key_id": "614ff1.....822d87a...........",
"private_key": "-----BEGIN PRIVATE KEY-----...........",
"client_email": "vertexai@............iam.gserviceaccount.com",
"client_id": "102873..........",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/vertexai%40..........iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}
Use the service account to generate the JWT access token, and then install the google auth library package to run this file.
const { JWT } = require("google-auth-library");
/**
{
type: "service_account",
project_id: "",
private_key_id: "",
private_key: "",
client_email: "",
client_id: "",
auth_uri: "",
token_uri: "",
auth_provider_x509_cert_url: "",
client_x509_cert_url: "",
universe_domain: "",
};
*/
const serviceAccount = JSON.parse(process.env.VERTEX_AI_SERVICE_ACCOUNT)
async function getJWTAccessToken() {
const jwt = new JWT({
email: serviceAccount.client_email,
key: serviceAccount.private_key,
scopes: ["https://www.googleapis.com/auth/cloud-platform"],
});
const as = await jwt.getAccessToken();
return as.token;
}
async function main() {
const accessToken = await getJWTAccessToken();
const model = "gemini-1.5-flash-001";
const text = "17/10 DB OTOMATIS KOR BIAYA W/D 3,500.00 DB 7,554,013.52";
const body = {
contents: [
{
role: "user",
parts: [
{
text: `Define the category for the text below?
Options:
- groceries
- investment
- transfer IN
- topup e-money
- transaction fee
- withdraw
- transfer OUT
- others
Please only print the one category name without anything else.
Text: CR, Credit, SETORAN TUNAI 28/10/95031/00000
Category: transfer IN
Text: TRSF E-BANKING DB 0610/FTFVA/WS95031 00000/TOKOPEDIA,Tokopedia,Shopee,Tiktok,Lazada,harihari,transmart,superindo,matahari,indomaret,alfa
Category: groceries
Text: TRSF E-BANKING DB 0710/FTFVA/WS95031 00000/SHOPEEPAY, TRSF E-BANKING DB 1410/FTFVA/WS95031 39358/OVO, DANA 17/10 TRSF E-BANKING DB, OVO, DANA, GOPAY, SHOPEEPAY
Category: topup e-money
Text: TRSF E-BANKING DB 2910/FTFVA/WS95031 00000/LOGAM MULIA, gold, emas, antam, reksadanam saham, IDX Mobile,MOST ,BNI Sekuritas Mobile,Mirae HOTS,BCA Sekuritas Mobile,BRI Mobile Sekuritas,Stockbit,Motion Trade,Bareksa,IPOTGO,CGS-CIMB iTrade,Trimegah Sekuritas Indonesia,Phillip Sekuritas Indonesia,KoinWorks,Ajaib,Modalku,
Category: investment
Text: TARIKAN ATM, WITHDRAWAL
Category: withdraw
Text: BIAYA TXN, BIAYA W/D, BIAYA ADM, Administrasi
Category: transaction fee
Text: BI FAST DB BIF TRANSFER KE, Transfer to, RSF E-BANKING DB
Category: transfer OUT
Text: SALDO AWAL
Category: others
Text: ${text}
Category:
`,
},
],
},
],
generationConfig: {
maxOutputTokens: 256,
temperature: 0,
topP: 0.8,
},
safetySettings: [
{
category: "HARM_CATEGORY_HATE_SPEECH",
threshold: "BLOCK_MEDIUM_AND_ABOVE",
},
{
category: "HARM_CATEGORY_DANGEROUS_CONTENT",
threshold: "BLOCK_MEDIUM_AND_ABOVE",
},
{
category: "HARM_CATEGORY_SEXUALLY_EXPLICIT",
threshold: "BLOCK_MEDIUM_AND_ABOVE",
},
{
category: "HARM_CATEGORY_HARASSMENT",
threshold: "BLOCK_MEDIUM_AND_ABOVE",
},
],
};
const classifyTextRes = await fetch(
`https://us-central1-aiplatform.googleapis.com/v1/projects/instaroom-photobooth/locations/instaroom-photobooth/publishers/google/models/${model}:streamGenerateContent`,
{
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
}
).then((r) => r.json());
const category = classifyTextRes
.map((c) => c.candidates[0].content.parts[0].text.replace("\n", "").trim())
.join(" ")
.trim();
console.log({ category });
}
main();
module.exports = main;
Result { category: ‘transaction fee’ }
Thank you for reading my article!
Reach me on Linkedin: https://www.linkedin.com/in/didikmulyadi