Multi Model Chatbot

Multi Model Chatbot

In the second project phase of Resolve's chatbot we needed the ability to determine what model to query as the user asks a question. I spoke vaguely about this in the last article I wrote about Resolve, or in the article where I spoke about callbacks to select model to be specifically - But the problem condensed is that Resolve have multiple products, and therefor needed no less than 3 machine learning models, while all these had one support interface.

This implies we'll need somehow the ability for the user to select which model to query as he is given support.In the screenshot below you can see how we solved the UI parts.

Multi model chatbot

The basic idea is that we've got a select drop-down list allowing the user to select what product he or she needs support for. This changes the actual model we're using as we're sending queries to the backend.

The code

The code relies upon the callback I wrote about in the multi model article I linked in before, which basically is a dynamically injected IoC type of JavaScript function, that returns what model to use as the chatbot invokes the backend. Below is the whole of the JavaScript code needed to include on your page to make this work.

(function() {

// Active type/model.
let ainiro_active_type = null;

/*
 * All types and names of types.
 *
 * Notice, the "type" needs to corelate to a machine learning type/model you've got
 * in your backend cloudlet. While the "name" is the friendly display name that is
 * shown to the user in the option element.
 */
const ainiro_all_types = [
  {
    name: 'Resolve',
    type: 'resolve'
  },
  {
    name: 'Actions Express',
    type: 'actions-express-saas'
  },
  {
    name: 'Actions Express SaaS',
    type: 'actions-express-saas'
  },
  {
    name: 'Actions Pro',
    type: 'actions-pro'
  }
];

/*
 * Callback invoked by chatbot when it is initialized.
 *
 * This is where we "inject" our custom model/type selector.
 */
window.ainiroInitializeChatWindow = function() {

  // Checking session to see if user has already selected a type/model.
  ainiro_active_type = sessionStorage.getItem('ainiro_active_type');

  /*
   * Notice, if ainiro_active_type is null, it means we're starting a new session,
   * which implies we need to create the HTML for our selector, and "inject" it into
   * the chatbot's main surface.
   * 
   * If ainiro_active_type is NOT null, it means we've already got a session, and
   * all the markup for our select drop-down list is already existing, and we only
   * need to wire up its event listener and make sure we select the model/type the
   * user has already selected that is stored in the session object.
   * 
   * Notice also that the HTML for the chatbot isn't persisted into session before user
   * actually submits a question, so we'll have to check if the select HTML element exists
   * in addition to that the "ainiro_active_type" value has been set before we can be sure
   * of that we've got an actual select list in our HTML chatbot surface.
   */
  if (!ainiro_active_type || window.document.getElementsByClassName('ainiro-select-list').length === 0) {

    /*
     * We need to create our "select model drop down", defaulting selected value
     * to first value from our list of models.
     */
    ainiro_active_type = ainiro_all_types[0].type;

    // Storing selected value to session.
    sessionStorage.setItem('ainiro_active_type', ainiro_active_type);

    // This is the DOM element where we inject our select drop-down list.
    const msgs = window.document.getElementsByClassName('aista-chat-msg-container')[0];

    // Creating instructions informing user to select model before querying.
    const info = window.document.createElement('div');
    info.className = 'aista-chat-answer cached';
    info.innerHTML = 'Please select the correct product before asking me questions';
    msgs.appendChild(info);

    // Creating our select drop-down list.
    const sel = window.document.createElement('select');
    sel.className = 'ainiro-select-list';

    // Creating our options, one for each type/model declared above in "ainiro_all_types".
    for (let idx = 0; idx < ainiro_all_types.length; idx++) {

      // Creating option element for currently iterated type/model.
      const opt = window.document.createElement('option');
      opt.value = ainiro_all_types[idx].type;
      opt.innerHTML = ainiro_all_types[idx].name;

      // Checking if this is the currently selected option.
      if (ainiro_all_types[idx].type === ainiro_active_type) {
        opt.selected = true;
      }

      // Appending option element to select drop down list.
      sel.appendChild(opt);
    }

    // Making sure we listen to change events on select element.
    sel.addEventListener('change', () => {

      // Storing the selected type/model.
      ainiro_active_type = sel.value;

      // Changing session value to persist across page loads.
      sessionStorage.setItem('ainiro_active_type', ainiro_active_type);
    });

    // Appending select element to chat output element.
    msgs.appendChild(sel);

  } else {

    // Already created "select model drop down"
    const sel = window.document.getElementsByClassName('ainiro-select-list')[0];

    // Finding the correct model/type and making sure it's selected.
    window.document.querySelector('option[value=' + ainiro_active_type + ']').selected = true;

    // Listen to our change events on select element.
    sel.addEventListener('change', () => {

      // Storing the selected type/model.
      ainiro_active_type = sel.value;
      sessionStorage.setItem('ainiro_active_type', ainiro_active_type);
    });
  }
}

// Callback invoked by chatbot when it needs the type/model.
window.getAiniroChatbotType = function() {

  // Returning the currently activated type/model to chatbot.
  return ainiro_active_type;
}

const bot = window.document.createElement('script');
bot.src = 'https://your-cloudlet.us.ainiro.io/magic/system/openai/include-javascript?markdown=true&speech=false&rtl=false&submit_button=true&stream=true&search=true&chat=true&css=scandinavian-chocolate&file=default&type=ainiro_io&header=Ask%20about%20our%20services%20or%20products&button=&v=16.10.1';
window.document.getElementsByTagName('head')[0].appendChild(bot);
})();

Notice, the above script is the only script needed to include, since it dynamically injects the chatbot script itself, without needing to explicitly link in this. You also need to change the your-cloudlet parts.

If you're creating similar types of chatbots yourself, you'll need to modify the URL, in addition to modifying the ainiro_all_types values. If you put the above code into a JavaScript file on your cloudlet named for instance "/etc/www/chatbot.js", you will need to include it using something resembling the following.

<script src="https://your-cloudlet.us.ainiro.io/chatbot.js?v=16.10.1" async></script>

How it works

When created initially the chatbot's JavaScript file will check if a global ainiroInitializeChatWindow function exists on the window object, and if it does, it will invoke this function as it's being created.

This function will then dynamically insert a select drop-down list into the chatbot's primary container element, containing one option element for each value in the above ainiro_all_types list. The active model is tracked both in the session object and in the ainiro_active_type variable. this might be redundant, and arguably a violation of the "single source of truth" principle, but I'll leave it an exercise to you to simplify it if you wish.

As the user changes the selected value of the select element, the active model is changed, which again the chatbot's internals will query using the getAiniroChatbotType function - Which is another global "sink" the chatbot will invoke if it exists every time it needs to determine the model in the backend to use.

All in all a pretty OK solution I would say for scenarios where you have one chatbot UI, but needs to dynamically determine which model to query on the backend parts of your solution.

Thomas Hansen

Thomas Hansen I am the CTO of AINIRO.IO AS and the CEO of AINIRO.IO, Ltd. I am a software developer with more than 25 years of experience. I write about Machine Learning, AI, and how to help organizations adopt said technologies. You can follow me on LinkedIn if you want to read more of what I write.

Published 17. Oct 2023

Free 7-Day Trial

Create your own Free 7-Day Trial Custom ChatGPT Chatbot
Or contact us if you want us to discuss your particular needs

Call to Action icon to create a ChatGPT demo website chatbot