Quick Start Guide

Summary
A developer guide to implement AHI's Web MultiScan SDK for FaceScan.

This tutorial shows you how to implement AHI's MultiScan SDK for Web. The example will include a full FaceScan process.

GitHub example code

SDK Reference Docs

Environment

Before you start building your web form, you will need to set up your development environment.

You will need:

  • an IDE/text editor,
  • a web server
  • a web browser

Prepare

To get started we will create several files in the development folder.

For health details input form, SDK Setup, and initializing the SDK:
  • index.html - Not included in guide (create your own form UI)
  • indexscript.js - Instructions provided below

Note: Refer to FaceScan Schemas to view the user input requirements for the form page.

For handling and displaying results from the SDK output:
  • results.html - Not included in guide (create your own results UI)
  • resultsScript.js - Instructions provided below

For styling:

  • styles.css - Not included in guide (create your own styles)

There are three parts to implementing MultiScan Web SDK:

  1. Setting up the system
  2. Initializing the service and integrating ScanControl API
  3. Handling the results

The form input and results display pages are not a part of this SDK. We recommend that developers build these pages according to their use case and include a scan guide for users to achieve best results.

1. Setup MultiScan SDK

In the first instance we will configure our code to call the AHI service and set-up MultiScan. This is done by adding the following code to index.html before the closing BODY tag

  	 
<script type="text/javascript" src="https://sdk.advancedhumanimaging.io/js/22.0/ahi.js"></script>
 		
  
Copied!

With the javascipt now being loaded we need to turn our attention to indexscript.js

The following code needs to be added to the file:

  	 
/**
 * Initializes the AHIMultiScan object and authorizes the user.
 * @returns {Promise} A Promise that resolves when the setup and authorization are successful, and rejects if there's an error.
 */
let multi = null;
function initScan() {
  multi = new AHIMultiScan();
  multi
    .setup(
      JSON.stringify({
        TOKEN:
          "<token>",
      })
    )
    .then(() => {
      console.log("[Setup] Completed successfully.");
      multi
        .userAuthorize("<user_id>", "<salt>", JSON.stringify(["<claim_1>", "<claim_2>", ...]))
        .then(() => {
          console.log("[Auth] Completed successfully.");
        })
        .catch((err) => {
          console.log("[Auth] Failed.");
        });
    })
    .catch((error) => {
      console.error("[Setup] FAILED: An error occurred:", error);
    });
}
 		
  
Copied!

The above code requires that you add a <TOKEN> to the MultiScan set up.

Please ensure that you have a valid MultiScan token prior to continuing. If you do not have a token please contact AHI via your primary contact to arrange.

It also requires that you supply: <userID>, <salt>, and <claims>. More information on this can be found here: Authorization vs. Authentication

An example may look like:

  	 
.userAuthorize("USER1234", "Company12345", JSON.stringify(["13101978",]))
 		
  
Copied!

Where USER1234 is the user's id, Company12345 represents your company (generally this should always be the same), and 13101978 (D/M/Y) represents the user's join date (helps to harden the security, and should be a value unique to the user but not changeable).

Note to Developer: User Claims

An array of user claims is needed for user authorization in order to provide additional information about the user beyond their username and identifier. These claims can be used to verify that the user is who they claim to be.

Here are a few examples of user claims that do not change and can be used for user authorization:

  1. dateCreated: The date an account was created can not change.
  2. dateOfBirth: A user's birthday can not change.

It is recommended to use claims that do not change over time such as an email address, as it can result in authorization issues if the user updates their information.

Now that the script for MultiScan setup has been added, proceed to add onload event to your body tag in index.html:

  	 
<body onload="initScan()"> 		

  
Copied!

2. Initialize the Scan

One you have a MultiScan Object and your user is authorized you are ready to initialize a FaceScan.

FaceScan has a set of requirements that need to be adhered to in order for a successful Scan session. The following schema specifies the expected parameters that the web form must pass to MultiScan initiateScan() method:

See FaceScan Schemas - Input

Validation

It is important to note that the schema gives the type and validation rules required for each field.

Implementing the validation for these requirements is left to the developer for a production system.

For our example we will use HTML5's built in validation. We recommend you do not solely rely on this method and implement additional validation as per your preferred framework.

Submitting Form

To initalize the scan an onSubmit action will need to be added to the opening tag of the input form in index.html.

  	 
<form onsubmit="return postValidateForm(event)">
  <h2>Advanced Health Intelligence</h2>
  <h3>New FaceScan</h3>
  
  <div>
    <label
      for="age"
      title="Web Scan is not intended for children under 13 years old."
    >
      Age:
    </label>

    <input
      type="number"
      id="age"
      name="age"
      required
      min="13"
      max="120"
      pattern="\d*"
      placeholder="Enter your current age in years"
    />
  </div>
  <!-- ... remaining form code ... -->
</form>

  
Copied!

In this instance we call postValidateForm as we want to satisfy the MIN / MAX requirements for BMI in the schema. As we can't easily achieve this using the HTML5 validation we call our own custom code.

Add the custom code for postValidateForm function to indexscript.js. This is for example purposes and we recommend that the developer implement validation according to their own use case and error messaging system as required.

  	 
/**
* Validates form input values and calculates BMI if input is valid.
* This is a requirement for the Web Measurement Service.
* @param {Event} event - The form submit event object
*/
function postValidateForm(event) {
  const weight = parseFloat(document.querySelector("#weight").value);
  const height = parseFloat(document.querySelector("#height").value);

  const submitButton = document.querySelector("#submit-button");
  submitButton.disabled = true;

  if (!isBMIValid(weight, height)) {
    alert(
      "BMI is not valid. Must be between 10 and 60.\nPlease check and try again."
    );
    submitButton.disabled = false;
    return;
  }
  // Start the Web Measurment Service
  callScan(event);
}

/**
* Validates if BMI is within acceptable range.
* @param {number} weight - The weight of the person in kg.
* @param {number} height - The height of the person in cm.
* @returns {boolean} - Returns true if BMI is between 10 and 6, otherwise false.
*/
function isBMIValid(weight, height) {
  const bmi = weight / Math.pow(height / 100, 2);
  return bmi >= 10 && bmi <= 65;
}

  
Copied!

postValidateForm pulls validated height and weight values from the form to calculate BMI. If this is not within range it will alert the user.

This is for example purposes and we recommend that the developer implement validation according to their own use case and error messaging system as required.

If the form passes all validation tests then callScan(event) is actioned.

Calling FaceScan

Add the code for callScan() into indexscript.js. It should include all the params listed in the FaceScan schema.

  	 
const callback_url = "results.html";
const callback_domain = "http://127.0.01:5500/"; // Used for local test

/**
 * Initiates a face scan with the parameters gathered from the form.
 */
function callScan(event) {
  event.preventDefault(); // Prevents page from refreshing on form submission
 
// FaceScan Schema :
    const params = {
      cb: callback_domain + callback_url,
      kg_ent_weight: parseInt(weightInput.value),
      cm_ent_height: parseInt(heightInput.value),
      enum_ent_sex: sexInput.value,
      yr_ent_age: parseInt(ageInput.value),
      bool_ent_smoker: smokerInput.value === "yes",
      bool_ent_hypertension: hypertensionInput.value === "yes",
      bool_ent_bloodPressureMedication:
        bloodPressureMedicationInput.value === "yes",
      enum_ent_diabetic: diabeticInput.value,
    };
    try {
      const stringifyParams = JSON.stringify(params);
      // Call the FaceScan
      multi.initiateScan("face", stringifyParams);
    } catch (error) {
      console.error("[Scan] An Error occurred:", error);
      throw new Error(error.message);
    }
  }

  
Copied!

It is important to note that params contains a callback url key cb in addition to the metrics required for the scan.

This is the URL that you wish results to be returned to. Once returned, it is the developer's responsibility to decode and interpret these results.

At this point we submit the form and hand control over to the MultiScan SDK and allow the user to complete their scan.

Assuming the scan process is successful we will expect a callback from the service.

Integrating ScanControl API

The ScanControl API is required for initializing scans. This API helps to track and manage the usage of scans.

This stage can be completed after pricing and subscription schemes have been contractually agreed. There will be a handover of the API KEY and a list of relevant PRODUCT ID for calling the API.

See Using ScanControl System to learn how to implement this service.

3. Handling Results

See FaceScan Schemas - Output for definitions of the results output.

Scan results are returned as a Base64 queryString within the URL.

The developer has to extrapolate and intepret these raw outputs according to their needs.

The sample code below is added to resultsScript.js. It simply iterates through the returned results and outputs them to the page.

  	 
/**
* Decodes the base64-encoded `result` parameter value from the URL and parsing its content to JSON, then storing it in `scanResult`.
* @type {string}
*/
const scanResult = atob(
  new URLSearchParams(window.location.search).get("result")
);

/**
* Creating a document fragment to be used as a temporary container.
* @type {DocumentFragment}
*/
const resultList = document.createDocumentFragment();

/**
* Looping through each property from the parsed JSON object in `scanResult`, creating a list item element for each one and appending text content that represents the key-value pair to it.
*/
for (const [property, value] of Object.entries(JSON.parse(scanResult))) {
  const listItem = document.createElement("li");
  listItem.textContent = `${property}: ${value}`;
  resultList.appendChild(listItem);
}

/**
* Selecting the element with ID `JSONResults` and appending the list items to it.
*/
document.querySelector("#JSONResults").appendChild(resultList);

  
Copied!

Demo

View the AHI styled demo for an example of the full FaceScan Web process.

Live Demo

Note: You may need to request access to the demo. Also the form input, scan guide and results pages are only examples. The developer has to build the these pages according to their use case.