After reading this series’ first part and applying all the things explained, you are probably wondering what to do with that super fancy, high performing ML-model.
Well, the answer is: We are going to query it using HTTP every time a lead event arrives at the sGTM-container.
To do so, just follow these simple steps:
Import variable template
I created this template based on a solution engineered by Google.
It keeps the data type flexibility of Google’s solution while being customized to return a single float, that either represents your models return value (conversion probability) or a value, that has been multiplied with the before mentioned value (e.g. the lead’s value multiplied with its probability to convert).
const getEventData = require("getEventData");
const getGoogleAuth = require("getGoogleAuth");
const JSON = require("JSON");
const logToConsole = require("logToConsole");
const makeInteger = require("makeInteger");
const makeNumber = require("makeNumber");
const makeString = require("makeString");
const makeTableMap = require("makeTableMap");
const sendHttpRequest = require("sendHttpRequest");
const event_list = data.events;
const event = getEventData("event_name");
// Build the URL for Vertex AI.
const url = "https://" + data.cloudLocation +
"-aiplatform.googleapis.com/v1/projects/" + data.projectNumber +
"/locations/" + data.cloudLocation + "/endpoints/" + data.vertexEndpointID +
":predict";
logToConsole(url);
// Get Google credentials from the service account running the container.
const auth = getGoogleAuth({
scopes: ["https://www.googleapis.com/auth/cloud-platform"]
});
// Helper function for determining if the string starts with a suffix.
const strEndsWith = (str, suffix) => {
return str.indexOf(suffix, str.length - suffix.length) !== -1;
};
// Build an object containing all the global default values configured in the
// variable.
let globalValues = {};
if (data.data) {
let customData = makeTableMap(data.data, 'key', 'value');
for (let key in customData) {
key = makeString(key);
if (strEndsWith(key, '_int')) {
const new_key = key.replace('_int', '');
globalValues[new_key] = makeInteger(customData[key]);
} else if (strEndsWith(key, '_num')) {
const new_key = key.replace('_num', '');
globalValues[new_key] = makeNumber(customData[key]);
} else {
globalValues[key] = customData[key];
}
}
}
let predictionData = [globalValues];
// The payload for VertexAI.
const postBodyData = {
"instances": predictionData,
"parameters": {}
};
const postBody = JSON.stringify(postBodyData);
const postHeaders = {
"Content-Type": "application/json"
};
const requestOptions = {
headers: postHeaders,
method: "POST",
authorization: auth
};
// Make the request to Vertex AI & process the response.
if (event_list.split(',').indexOf(event) > -1) {
return sendHttpRequest(url, requestOptions, postBody)
.then(success_result => {
logToConsole(JSON.stringify(success_result));
if (success_result.statusCode >= 200 && success_result.statusCode < 300) {
let result_object = JSON.parse(success_result.body);
let value = result_object.predictions[0].converted_sale_probs[0];
if (data.multiply_with_value && data.multiplier) {
value = value * data.multiplier;
}
return value;
} else {
return data.defaultValueOnError;
}
})
.catch((error) => {
logToConsole("Error with VertexAI call to " + url + ". Error: ", error);
return data.defaultValueOnError;
}
);
} else {
logToConsole("No Vertex AI API query for this event.");
}
Configure template according to your needs
First configure all of the template’s fields with your Vertex AI model data, like region, id and so on. Now you add all the model parameters to the request data table within the template. You can convert your data to either integer or float by adding an appendix to the corresponding key (either “_int” or “_num”).
You can skip the “event list” field for now, I will get back to this in the next part.
Configure transformation
In my opinion sGTM’s Transformations are the optimal way to set up API-queries, since it gives you all the control as to what Tags get access to what data, while at the same time avoiding one API call for every Tag, that requires that data. But Transformations do have one issue: They are resolved every time the runContainer() API is called, even when its rules do not apply and thus the Transformation itself is not applied on the event data.
To avoid querying Vertex AI for every single incoming event, when actually only want to run the query for one or two, I’ve added the “event list”-field. Just add a comma-seperated list of all the events you want the query to be run at.
Test & Deploy
Testing thoroughly is always important so don’t be lazy!
Last words
There we go! Now you can officially call yourself an Analyst that has built a machine learning model, deployed it and applied it in production.
I hope you enjoyed this read!