Unlock a world of possibilities! Login now and discover the exclusive benefits awaiting you.
We all know and love using Insight Advisor right within the Qlik Sense hub or inside Analytics apps, helping us analyze data, create visualizations or build data models.
In this post, we will tap into the Insight Advisor API to leverage its power within a separate web application.
We will create a simple web app that allows to ask natural language questions against our Qlik Sense app and get a recommended visualization as a response that we will then render using nebula.js
Pre-requisites:
You will need to grab the following before starting:
Installation
Run npm install to install the content of package.json
Folder structure:
The following sections discuss the main parts of building the web app and calling the API, they are not in any particular order. I will provide the complete code for the project at the end of the post so you can see where everything fits.
1. Connecting to Qlik Cloud
First things first, we need to handle the authentication to Qlik Cloud.
Interactive login process:
async function getQCSHeaders() {
await qlikLogin(); // enforce tenant login
const response = await fetch(`${tenantUrl}/api/v1/csrf-token`, {
mode: 'cors',
credentials: 'include',
headers: {
'qlik-web-integration-id': webIntegrationId,
},
});
const csrfToken = new Map(response.headers).get('qlik-csrf-token');
return {
'qlik-web-integration-id': webIntegrationId,
'qlik-csrf-token': csrfToken,
};
}
async function qlikLogin() {
const loggedIn = await fetch(`${tenantUrl}/api/v1/users/me`, {
mode: 'cors',
credentials: 'include',
headers: {
'qlik-web-integration-id': webIntegrationId,
},
});
if (loggedIn.status !== 200) {
if (sessionStorage.getItem('tryQlikAuth') === null) {
sessionStorage.setItem('tryQlikAuth', 1);
window.location = `${tenantUrl}/login?qlik-web-integration-id=${webIntegrationId}&returnto=${location.href}`;
return await new Promise((resolve) => setTimeout(resolve, 10000)); // prevents further code execution
} else {
sessionStorage.removeItem('tryQlikAuth');
const message = 'Third-party cookies are not enabled in your browser settings and/or browser mode.';
alert(message);
throw new Error(message);
}
}
sessionStorage.removeItem('tryQlikAuth');
console.log('Logged in!');
return true;
}
2. Communicating with the Qlik Cloud Engine
(content of the cloud.engine.js file)
We need to open a session using enigma.js to communicate with the Qlik QIX engine.
import enigma from "enigma.js";
const schema = require("enigma.js/schemas/12.1306.0.json");
export default class EngineService {
constructor(engineUri) {
this.engineUri = engineUri;
}
openEngineSession(headers) {
const params = Object.keys(headers)
.map((key) => `${key}=${headers[key]}`)
.join("&");
const session = enigma.create({
schema,
url: `${this.engineUri}?${params}`,
});
session.on("traffic:sent", (data) => console.log("sent:", data));
session.on("traffic:received", (data) => console.log("received:", data));
return session;
}
async closeEngineSession(session) {
if (session) {
await session.close();
console.log("session closed");
}
}
async getOpenDoc(appId, headers) {
let session = this.openEngineSession(headers);
let global = await session.open();
let doc = await global.openDoc(appId);
return doc;
}
}
3. Including the Nebula Charts needed and rendering the recommended viz from Insight Advisor
When we eventually get back a recommendation from Insight Advisor, we will use a nebula object to embed it in our web app.
For a full list of available Nebula objects, visit: https://qlik.dev/embed/foundational-knowledge/visualizations/
We need to install “stardust” that contains the main embed function and all the nebula objects we need:
npm install @nebula.js/stardust
then install all objects needed
npm install @nebula/sn-scatter-plot
npm install @nebula/sn-bar-chart
etc...
import { embed } from '@nebula.js/stardust';
import scatterplot from '@nebula/sn-scatter-plot';
etc...
Inside the rendering function, we will use stardust’s embed method to render the recommended chart type we get from Insight Advisor.
async function fetchRecommendationAndRenderChart(requestPayload) {
// fetch recommendations for text or metadata
const recommendations = await getRecommendation(requestPayload);
const engineUrl = `${tenantUrl.replace('https', 'wss')}/app/${appId}`;
// fetch rec options which has hypercubeDef
const recommendation = recommendations.data.recAnalyses[0];
// get csrf token
const qcsHeaders = await getQCSHeaders();
const engineService = new EngineService(engineUrl);
// get openDoc handle
const app = await engineService.getOpenDoc(appId, qcsHeaders);
await renderHypercubeDef(app, recommendation);
}
async function renderHypercubeDef(app, recommendation) {
const type = recommendation.chartType;
const nebbie = embed(app, {
types: [
{
name: type,
load: async () => charts[type],
},
],
});
document.querySelector('.curr-selections').innerHTML = '';
(await nebbie.selections()).mount(document.querySelector('.curr-selections'));
await nebbie.render({
type: type,
element: document.getElementById('chart'),
properties: { ...recommendation.options }
});
4. Calling the Insight Advisor API for recommendations
You can either call the API with a natural language question or a set of fields and master items with an optional target analysis.
Insight Advisor API endpoints that can be called:
api/v1/apps/{appId}/insight-analyses
api/v1/apps/{appId}/insight-analyses/model
api/v1/apps/{appId}/insight-analyses/actions/recommend
// Getting the recommendation
async function getRecommendation(requestPayload) {
await qlikLogin(); // make sure you are logged in to your tenant
// build url to execute recommendation call
const endpointUrl = `${tenantUrl}/api/v1/apps/${appId}/insight-analyses/actions/recommend`;
let data = {};
// generate request payload
if (requestPayload.text) {
data = JSON.stringify({
text: requestPayload.text,
});
} else if (requestPayload.fields || requestPayload.libItems) {
data = JSON.stringify({
fields: requestPayload.fields,
libItems: requestPayload.libItems,
targetAnalysis: { id: requestPayload.id },
});
}
const response = await fetch(endpointUrl, {
credentials: "include",
mode: "cors",
method: 'POST',
headers,
body: data,
});
const recommendationResponse = await response.json();
return recommendationResponse;
}
Results:
For the complete example that includes calling the API with fields, master items, and a target analysis type, visit qlik.dev post: https://qlik.dev/embed/gen-ai/build-insight-advisor-web-app/
The full code for this post can be found here:
https://github.com/ouadie-limouni/insight-advisor-api
Make sure to change the variables in index.js.
I hope you find this post helpful, please let me know if you have any question in the comment section below!
Ouadie
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.