WARNING

Translated, needs to be reviewed

# Usage statistics

# New users

This is the number of new people who have initiated a conversation with the chatbot during the selected time period.

# Active users

This is the total number of different people who have used the chatbot in the selected time period. It is always at least equal to the number of new users.

# Number of messages

This is the number of messages the bot has received in the selected time period.

For example on the image below we have:

  • 307 new users from 16/06/2021 to 22/06/2021
  • 314 active users in the same period
  • 1033 messages received by the chatbot

image

# Contenus

Vous souhaitez savoir quelles ressources sont le plus consultées par vos utilisateurs ? Nous avons rajouté un onglet contenus dans le dashboard qui vous permet de voir la liste des 15 sujets les plus consultés par les utilisateurs.

Nous allons améliorer progressivement cet onglet donc n'hésitez pas à revenir vers nous avec les données que vous souhaiteriez voir dans cet onglet 🤝

# Content

Want to know which resources are most viewed by your users? We have added a content tab in the dashboard that allows you to see the list of the 15 most popular topics brought up by chatbot users.

This tab is a work-in-progress, and we will be updating this tab with new improvements! Don't hesitate to come back to us with other information you would like to see in this tab 🤝

# NLU Stats

Understanding statistics are useful for analyzing the effectiveness of your NLU setup.

This section contains the following statistics:

  • Number of queries processed
  • Number of queries understood
  • Number of queries not understood
  • Number of queries rated positively
  • Number of requests rated negatively
  • A table ranking the intention/entity pairs by decreasing number of requests included

On the top left of your screen you can select a time period. All statistics made available will be calculated over this period.

Below is more information about the above statistics:

# Number of queries processed

This is the number of messages typed by all chatbot users in natural language (by writing in the chat bar).

# Number of queries understood (to be reviewed)

This is the number of messages typed by all users of the chatbot in natural language that were redirected to the right resource (where the chatbot answered the expected message, corresponding to the user's request).

# Number of queries not understood  (to be reviewed)

This is the number of messages typed by all chatbot users in natural language that were not understood...

# Number of queries rated positively

This is the number of times the green thumb was used to positively rate a chatbot message.

# Number of requests rated negatively

This is the number of times the red thumb was used to negatively rate a chatbot message.

# List of queries misunderstood by the chatbot

This table lists all the user requests that have been misperceived by the chatbot.

# A table ranking the popularity of intention/entity pairs

Here you will find the intention + entities combinations that the algorithm has found the most.
In front of each combination, we display the possible positive and negative notes given by your users. This allows you to identify possible faulty combinations.

# Custom stats

Custom statistics will allow you to track your chatbot's KPIs by creating custom graphs. These statistics are based on the values stored in the chatbot's memory attributes.

You can choose between three types of graphs:

  • Single value: displays the number of responses stored under an attribute (e.g. number of people who answered the first question)
  • Breakdown: displays the distribution of responses to a given attribute (e.g. which button my users clicked on the most at the introduction)
  • Graph: displays the number of responses recorded under an attribute over time (e.g. evolution of the number of people who answered the first question)

# Add a new statistic

Start by going to the "Dashboard" menu of your chatbot. Then select the "Custom Statistics" tab. You now have the possibility to create statistics by clicking on the "Create a graph" button on the top right of your screen.

The first step is to choose a name and a description for your graph.

Then, you can choose three types of graphs:

  • Simple value : display of a simple calculated value
  • Distribution: display of numerical proportions
  • Graph : display of graphs

# Simple Value

You need to choose the attribute on which the calculation of the final value will be based.

In this case, you can look at how many people clicked or wrote Wifi to the Menu FAQ resource.

Optional: It is possible to display this value based on another attribute. In this case, only the value is displayed value for users who have previously clicked or written FAQ in the intro resource.

You can now admire your new Single Value statistic!

# Distribution (pie chart)

First, you have to choose on which criterion you will group the users. In my case, I want to differentiate users according to their answers to the FAQ Menu resource.

Then, you can choose to add a criterion to filter the data. In my case, I want to understand the distribution of user responses to the FAQ Menu resource only for users who responded "FAQ" to the intro. resource.

Now you can enjoy your distribution graph!

PS: To understand what each part of the pie chart corresponds to, just move your mouse cursor over it.

Be careful, the graph shows the natural language queries AND the button clicks. So there can be many parts to the pie. We are currently working on this issue.

# Graphique

This feature is not yet available, but we are working on it!

Contact us via the chat at the bottom right if you need it right away.

How are the responses counted?

We count one response per process. This means that if a user has responded 3 times to the same action skill (ticket creation for example). We will count 3 responses to the corresponding attribute. (see the example of a process below for more explanation)
If the user modifies one of his answers, we will only count the last answer given.

You can use select dates at the top of the screen to choose the time period you want.

DANGER

Here we show all responses for an attribute that were given in the selected time period.

# Example of a procedure

Exemple: I answer competence action which includes 2 attributes: last name, first name.

What would you like to do?

Me présenter
Create a request

Introduce Myself

What is your last name?

Benoit

Hello, what is your first name?

Benoit

Thank you, please confirm the information you entered below.

Modify last name
Modify first name
Confirm

Confirm

Thank you Benoit Benoit, what would you like to do now ?

Introduce Myself
Create a request

Introduce Myself

What is your last name?

Vizir

What is your first name?

Benoit

Thank you, please confirm the information below.

Modify last name
Modify first name
Confirm

Confirmed

Thank you, Benoit Vizir, what would you like to do now?

Introduce Myself
Create a ticket

TIP

In this case, we have 2 respondents to the attribute "name" and 2 respondents to the attribute "first name".
However, we have only 1 user.

# Scoring statistics

Before setting up scoring statistics, you need to create your scoring system. The following article explains how to do this: See article here:

Finally, go to the "Custom Statistics" menu and you will see the scoring stats your chatbot has received.

Below the statistics of the number of scores you have a table of answers that will allow you to know in detail each of the answers given by the users to your satisfaction questionnaire.

We are currently working on the readability of this table which is currently in JSON format.

If you have any questions about this article, please feel free to use the chat at the bottom right of your screen.

# Export

DANGER

Export data is stored with the date of the respondent's answer, so you may have differentials between a respondent's data (in the conversation tab) and your exports.

DANGER

We store the response payload (buttons, carousel, Burger Menu) all the time.

TIP

We have updated the statistics export file in April 2021. If you are using the old version (available until December 2021), please refer to this page old doc

Vous pouvez exporter les données directement dans Spreadsheet pour ensuite faire votre propre analyse.

Voici le fichier de base: ouvrir (opens new window)

It has 2 tabs:

  • convStatistics: export conversation data
  • attributeStatistics: export attribute and skill data

Here's how to:

  • Duplicate the spreadsheet you need to insert into the file of your choice.
  • Open the script editor >Tools>Script Editor.
  • Paste the script below
  • Replace line 2 with your token that you get in the Vizir dashboard (my account > token)
  • Run initScript to validate the Vizir rights on this file. Run script
  • Complete the table of each tab (you can rename it)
    • ChatbotId: To be retrieved directly from the url of your dashboard as below chatbotId

    • Environment ID: To be retrieved in the Environment settings of your chatbot envID

    • apikey and apisecret: To be retrieved in your account account token

    • URL data: To be retrieved from the dashboard in Export data, copy the link and paste it in the cell export_dashboard

TIP

If you want to use a different pair (apikey, apisecret) after the initialization it is possible. Please fill in the token box like this: apikey:apisecret.

# Script Google Sheet

/* Variables to modify */
var token = undefined;
var apikey = ''
var apisecret = '';
var dataSheets = {
  conversationStatistics: ['convStatistics'],
  attributeData: []
}


/* Fixed variables */
var dataTypes = ['attributeData', 'conversationStatistics']
var baseUrl = 'https://developers.vizir.co'
var functionCell = 'D5';
var cells = {
  conversationStatistics: {
    chatbotIdCell: 'D6',
    envIdCell: 'D7',
    tokenCell: 'D8',
    weekNumberCell: 'D9',
    overwriteCell: 'D10',
    addHeaders: 'D11',
    firstRowData: 13
  },
  attributeData: {
    chatbotIdCell: 'D6',
    envIdCell: 'D6',
    tokenCell: 'D6',
    startingDate: 'D7',
    endingDate: 'D8',
    urlApiCell: 'D9',
    overwriteCell: 'D10',
    addHeaders: 'D11',
    firstRowData: 13
  }
}



/**********************************************************
                        AUTOMATION
/**********************************************************/
function automateGetStatistics () {
  // Goal: Write the week number and new date boundaries in order to launch the script


  let today = new Date();
  let endOfWeek = new Date(new Date().setDate(new Date().getDate() + 7))
  let weekNumber = getWeekNumber(today)
  Logger.log(today)
  Logger.log(weekNumber)
  for (let d = 0; d< dataTypes.length; d++) {
    let type = dataTypes[d]
    for (let i=0; i< dataSheets[type].length; i++) {
      if (type === 'attributeData') {
        writeValuesSheetName(today, cells[type].startingDate, dataSheets[type][i])
        writeValuesSheetName(endOfWeek, cells[type].endingDate, dataSheets[type][i]);
      } else if (type === 'conversationStatistics') {
        writeValuesSheetName(weekNumber[1], cells[type].weekNumberCell, dataSheets[type][i])
      }
      getFunctionsValues(true, dataSheets[type][i]);
    }
  }


}

function getWeekNumber(d) {
    // Copy date so don't modify original
    d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
    // Set to nearest Thursday: current date + 4 - current day number
    // Make Sunday's day number 7
    d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
    // Get first day of year
    var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
    // Calculate full weeks to nearest Thursday
    var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
    // Return array of year and week number
    return [d.getUTCFullYear(), weekNo];
}



/**********************************************************
                        SCRIPT
/**********************************************************/

function getFunctionsValues(forceAddValues = false, sheetName = undefined) {
  if (!sheetName) {
    // Case click on button
    sheetName = SpreadsheetApp.getActiveSheet().getName();
  }
  var func = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(functionCell).getValue();
  var chatbotId = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells[func].chatbotIdCell).getValue();
  var envId = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells[func].envIdCell).getValue();
  var token = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells[func].tokenCell).getValue();
  var overwriteValues = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells[func].overwriteCell).getValue();
  var addHeaders = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells[func].addHeaders).getValue();
  if (forceAddValues) {
    // Add line based on cron job
    overwriteValues = false;
    addHeaders = false;
  }
  var values;
  var headers;
  if (func == 'conversationStatistics') {
    [headers, values] = getConversationStatistics_(sheetName, chatbotId, envId, token)
  } else if (func == 'attributeData') {
    [headers, values] = getAttributeStatistics_(sheetName, token)
  }

  if (!values || values.length == 0) {
    // Set empty values
    values = [['']]
  }

  if (overwriteValues) {
    resetValues(sheetName, cells[func].firstRowData);
  }
  firstRowData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getLastRow();
  if (addHeaders && headers && headers.length>0) {
    writeValues(headers, firstRowData, sheetName);
  }
  firstRowData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getLastRow();
  writeValues(values, firstRowData, sheetName);
}


/*
  G sheet functions
  get and reset Values
*/
function resetValues(sheetName, firstRowData) {
  SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(firstRowData + 1, 1,SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getLastRow(), SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getLastColumn()).clearContent();
}

function writeValues (values, startingLine, sheetName) {
  var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(startingLine+1,1,values.length,values[0].length);
  range.setValues(values);
  return;
}

function writeValuesSheetName (value, cell, sheetName) {
  var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cell);
  range.setValue(value);
  return;
}

/*
  Internal Functions
*/
function ImportJSONAdvanced_(url, fetchOptions, query) {
  if (query) {
    for (let key in query) {
      if (url.indexOf('?' == -1)) {
        url= url + '?'+key+'=' + query[key]
      } else {
        url= url + '&'+key+'=' + query[key]
      }
    }
  }
  var jsondata = UrlFetchApp.fetch(url, fetchOptions);
  var object   = JSON.parse(jsondata.getContentText());
  return object;
}

function ImportJSONBearerAuth_(url, token, query) {
  var header = {headers: {Authorization: "Bearer " + token}};
  return ImportJSONAdvanced_(url, header, query);
}

function ImportJSONApiKeyAuth_(url,token, query) {
  if (apikey == '' || apikey == '') {
    [apikey, apisecret] = token.split(':')
  }
  var header = {headers: {apikey: apikey, apisecret: apisecret}};
  return ImportJSONAdvanced_(url, header, query);
}


/*
  Vizir Functions
*/
function getConversationStatistics_(sheetName, chatbotId, envId, token) {
  var weeknumber = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells.conversationStatistics.weekNumberCell).getValue();
  var url = baseUrl + '/chatbots/'+chatbotId+ '/environments/'+ envId +'/statistics/sheets';
  var query = {
    week_number: weeknumber
  }
  let columns = ['Week Number','from', 'nb_users', 'new_users', 'nb_messages', 'nb_live_messages', 'total_request', 'understood', 'notunderstood']
  var data;
  if (token && token.indexOf('ey') > -1 ) {
    data = ImportJSONBearerAuth_(url, token, query)
  } else {
    data = ImportJSONApiKeyAuth_(url, token, query)
  }
  if (data && data.arrayPerso) {
    for (let d=0; d< data.arrayPerso.length; d++) {
      columns.push(data.arrayPerso[d]);
    }
  }
  let returnData = [weeknumber]
  for (let i=1; i< columns.length; i++) {
    returnData.push(data[columns[i]])
  }
  return [[columns], [returnData]];
}

function getAttributeStatistics_(sheetName, token) {
  var url = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells.attributeData.urlApiCell).getValue();
  var startingDate = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells.attributeData.startingDate).getValue();
  var endingDate = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).getRange(cells.attributeData.endingDate).getValue();
  url = url + '&from='+ startingDate.getTime() + '&to=' + endingDate.getTime()  
  var data;
  if (token && token.indexOf('ey') > -1 ) {
    data = ImportJSONBearerAuth_(url, token, {})
  } else {
    data = ImportJSONApiKeyAuth_(url, token, {})
  }
  if (Array.isArray(data.data[0])) {
    // Old function that return arrays
    headers = data.data[0];
    result = data.data.splice(0,1)
  } else {
    // New function that return json
    [headers, emptyLine] = getHeaders(data.data)
    result = getValues(data.data, headers, emptyLine)
  }
  return [[headers], result];
}

function getHeaders (data) {
  var headers = [];
  var emptyLine = [];
  data.map(line => {
    for (key in line) {
      if (headers.indexOf(key) === -1) {
        headers.push(key);
        emptyLine.push('')
      }
    }
  })
  return [headers, emptyLine];
}
function getValues (data, headers, emptyLine) {
  var values = [];
  data.map(line => {
    var lineValues = JSON.parse(JSON.stringify(emptyLine));
    for (key in line) {
      var index = headers.indexOf(key);
      lineValues[index] = line[key];
    }
    values.push(lineValues);
  })
  return values;
}
/*
  Initiation Script
*/
function initScript () {
  var url = baseUrl + '/chatbots';
  var data;
  var query = {};
  if (token && token.indexOf('ey') > -1 ) {
    data = ImportJSONBearerAuth_(url, token, query)
  } else {
    data = ImportJSONApiKeyAuth_(url, token, query)
  }
  return data.data;
}

/*
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  ui.createMenu('Vizir')
    .addSubMenu(ui.createMenu('Data')
          .addItem('Conversation Statistics Template', 'importConversationStatisticsTemplate')
          .addItem('Attribute Data Template', 'importGetAttributeStatisticsTemplate'))
    .addToUi();
}
*/

# Bonus automatiser la récupération des statistiques

Avec cette nouvelle version disponible depuis le 15 avril 2021, vous pouvez facilement automatiser la récupération des statistiques à intervals réguliers.

Voici comment le faire:

# Déclarer les Feuilles de calcul

Dans le script que vous avez collez dans google Script vous pouvez voir en ligne 3 la déclaration suivante:

var dataSheets = {
  conversationStatistics: ['convStatistics'],
  attributeData: []
}

Le script que nous allons lancer de manière automatique tous les lundi (ou tout autre jour de la semaine), va récupérer la liste de toutes les feuilles de calculs présentes dans cette liste.

Ajouter le nom de vos feuilles de calcul dans la liste qui correspond.

DANGER

Il est indispensable de bien respecter le type de données qu'on récupère. Indiquez bien dans conversationStatistics la liste des feuilles de calculs qui récupèrent des données de conversation et dans attributeData la liste des feuilles de calculs qui récupèrent les données d'attributs.

# Automatiser le lancement du script

  • Cliquez sur la gauche de l'écran sur Déclencheurs (comme ci dessous)
  • En bas à droite, cliquez sur ajouter un déclencheur
  • Choisissez la fonction automateGetStatistics et Choisissez les paramètres comme vous le souhaitez

Et voilà ✨✨✨!!

Tous les lundi entre 7h et 8h vous aurez vos statistiques qui seront remontées dans votre Excel.