HELP!

How do I embed the Viabl.ai Platform Rules Engine in my webpage (to use my own user interface)?

Integrating the Deployment Engine with other Browser Applications

Browser deployed applications can be integrated with other applications running in the Web Browser to either display an embedded UI or act as an engine with no additional UI.

In the UI mode, the user interface of the deployed engine is displayed in the normal way. In engine mode, the rules are executed and any user interface is performed by the host application and exchanged with the underlying JavaScript.

Example#1: UI mode

The following code can be used in a wrapper page which contains the deployed application in an iframe ie. <iframe src="deploy/main.html"></iframe>

<script>
// called from xpertrule.pause command. Function name matches that in the Knowledge Base Initialize procedure (shown below)
function OnPause(xpertrule, param) {
    switch (param) {
    case "INIT":
        xpertrule.val("Case_Id", 12345);
        break;
    }
 }
 
// called at end of inference. Function name matches that in the Knowledge Base Initialize procedure (shown below)
function OnEnd(xpertrule) {
   alert(xpertrule.val("Case_Result"));
}
</script>

The Knowledge Base Initialize procedure (mentioned in the script above) defines and uses the callbacks.

// Setup the pause callback to call the PauseCallback() function on the wrapper page
wrapperOptions.pauseCallback = parent.OnPause;
wrapperOptions.endCallback = parent.OnEnd;
// do initial pause to tell wrapper that it can set values
xpertrule.pause("INIT");

Example#2: Engine mode

The following code can be used to replace 'main.html' from the root folder of a deployment.

<script type="text/javascript" src="xrkb/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="xrkb/bootstrap.js"></script>
<script>
 
function OnStart(xpertrule) {
    /* Called at the START of inference, use this to setup initial values */
    xpertrule.val("Grade", "Senior_Manager"); // e.g. Set the Grade object to Senior_Manager
    xpertrule.val("Department", "Accounts");
    xpertrule.val("Cost", 75);
    xpertrule.val("In_London", true);
    xpertrule.val("Services", ["Room","Meals"]);
}
 
function OnPause(xpertrule, param) {
    /* Called in response to xpertrule.pause command or an empty attribute or a dialog */
    alert("Pause : " + param);
    return true; // synchronous call, continue inference on return
    // return false; // asynchronous call. You must call xpertrule.continue to continue inference
}
 
function OnDebug(xpertrule, aText) {
    /* Called in response to an xpertrule.message call */
    alert("Debug : " + aText);
}
 
function OnEnd(xpertrule, complete) {
    /* Called at END of inference, use this to retrieve any decisions from the knowledge base */
    var aVal = xpertrule.val("Expenses"); // Get the contents of the Expenses object
    var aVal2 = xpertrule.val("Claims"); // Get the contents of the Claims object
    document.getElementById("res").innerHTML = "Result : " + aVal + " / " + aVal2; 
}
 
function OnError(xpertrule, aDescription) {
    /* Called in response to an engine error */
    alert("Error : " + aDescription);
}
 
$(function(){
    /* This is how inference is started, in this example, called from page load */
    xpertrule.startup({
        xrengine: true,         /* Required */
        startCallback: OnStart, /* Optional (see comments in OnStart function above) */
        pauseCallback: OnPause, /* Optional */
        debugCallback: OnDebug, /* Optional */
        endCallback:   OnEnd,   /* Optional */
        errorCallback: OnError  /* Optional */
    });
});
 
</script>

Integration (Cross-Domain Messaging with postMessage)

Initially browsers were only able to send messages between windows if those windows used the same protocol, port, and host. The postMessage() method in more recent browsers avoids this limitation by providing a way to securely pass messages across domains. Browsers that support this are indicated in the following table.

Chrome IE Firefox Safari
1+ 8+ 3+ 4+

Knowledge base modifications

The following 3 sections of code should be used in the knowledge base. The first section should be included as a static resource.

//static resource in knowledge base
var PARENT_WINDOW_DOMAIN = "**YOUR DOMAIN**";
 
var setDataCallback = null; // function to call when a setdata is received from the parent
 
// utility function to post a message to the parent window
function postMessageToParent(status, data) {
    var data = {
      status: status,
      message: data
    };
    parent.postMessage(data, PARENT_WINDOW_DOMAIN);
}
 
// start a message listener for events passed in by the parent
window.addEventListener("message", function(event) {
    if (event.origin != PARENT_WINDOW_DOMAIN) {
        return; // manual check to only accept data from the valid parent
    }
    if ($.isFunction(setDataCallback)) {
        setDataCallback(event.data);
    }
});

Create a Javascript file containing the code and upload via the 'Knowledge Base Resources...' option on the editor's pull down menu.

Then mark it to be used from the 'Custom Javascript' part of the 'Knowledge Base Settings' dialog.

The second section is the contents of a procedure which should be placed in the logic flow of the application so that it is executed first.

// startup procedure in knowledge base
setDataCallback = null;
replayStack.CriticalSection(
  function(rs){
    setDataCallback = function(parentData) {
      rs.CriticalDone(parentData);
    };
    postMessageToParent("startup", null);
  }, function(data){
    xpertrule.setValuesWithObject(data);
  }
);

The third section is the contents of a procedure which should be placed at the end of the logic flow and modified to return the data of interest, in this case #captured_data.val().

// finalize procedure in knowledge base
xpertrule.once(function() {
  postMessageToParent("end", #captured_data.val());
});

Container page

The following template code can be used to construct a container page that has embedded a Decision Author application in an iframe.


<html>
  <head>
    <script>
      window.addEventListener("message", function(event) {
      if (event.origin != "https://cloud.xpertrule.com") {
        return; // manual check to only accept data from the valid sub page
      }
      switch (event.data.status) {
        case "startup":
          console.log("Inference started, pre-supply some data");
          var data = {'Grade': 'Director','Cost': 75};
          document.getElementById("sub_page").contentWindow.postMessage(data, "https://cloud.xpertrule.com");
          break;
        case "end":
          console.log("Inference complete");
          console.log(event.data.message);
          break;
        }
      });
    </script>
  </head>
  <body>
    Container page<br /><br />
    <iframe id="sub_page" style="border: none; width:100%; height:100%" src="https://cloud.xpertrule.com:443/run.php?s=SAMPLE" frameborder="0" scrolling="auto" ></iframe>
  </body>
</html>

In the container page there are two events the listener is waiting for, 'startup' and 'end'. On 'startup' the message data should be prepared with the object name: value pairs that are to be set before inference is executed, for example...

var data = {
  'Grade': 'Director',
  'Cost': 75
};

On 'end' the message data is posted back from the knowledge base as it has reached the end of inference and in this sample is written to the console.log.

console.log(event.data.message);

On This Page