cancel
Showing results for 
Search instead for 
Did you mean: 

Flowiseai + Sisense = RAG from a dashboard (all widgets chart data value of a dashboard)

saxoji
7 - Data Storage
7 - Data Storage

In the previous post, I showed how to use the Sisense Rest-API to get the data values of a specific widget and RAG them through the LLM. (ref https://community.sisense.com/t5/help-and-how-to/flowiseai-sisense-rag-from-widget-data-values/m-p/2...)
This time, I will introduce how to get the data values of all contained widget's chart for a dashboard that contains multiple widgets via Rest-API and implement RAG via LLM.

When we implement a dashboard with Sisense, it contains multiple widgets that are needed to analyze one topic or theme, but it takes a lot of learning for customers to get comprehensive insights from various widget charts, and different users sometimes have different interpretations of the same data.

Therefore, this post aims to overcome these problems by using LLM RAG to consolidate data from multiple widget charts in a dashboard to create a comprehensive and consistent insight or report.

The basic code routine is similar to the previous post on RAG via LLM like GPT, where you enter the metadata and data values of one widget chart as the Context.

The difference is that we use the REST-API to get all the widgetID(oid) values that the dashboard has through the dashboard ID, and then get the metadata of the widget chart through the dashboardID/widgetID.
After obtaining the widget's datasource and jaql, run the url( your.sisnese.domian /api/datasources/${parsedJaqlQuery.datasource.title}/jaql) to return the widget chart's data, and repeat the process for all widgetIDs, storing them in memory for building the context for LLM.

The next step is to input the contents of that memory (even if it's in json format) into the LLM as context, but the problem is that the LLM has a limited number of input tokens.
If you have ten widget charts in a dashboard, you will exceed the maximum number of input tokens for gpt-4o and you will not get the desired answer from GPT.
Therefore, we used a method to reduce the number of tokens in the Context that is passed to the final LLM by summarizing the chart data of each widget through LLM in the middle of the code. The prompt we used to summarize each widget's chart data is “const prompt = `Summarize the following widget data qualitatively and quantitatively:\n\n${JSON.stringify(widgetData)}`;”.

In this process, we were able to successfully implement RAG by writing all widgets' chart contents to LLM as Context with only the dashboard id.

 

Our target dashboard

saxoji_0-1717586057751.png

Prompt exemple for LLM RAG : Aggregate and analyze all widget chart data value from Sisense dashboard id :  your-dahsboard-id

 

using Flowiseai Custom tool  for LLM(ex. GPT) function call

saxoji_1-1717586467583.png

node.js fetch api code start------

const fetch = require('node-fetch');

 

const apikey = 'your-sisense-api-key';

const gptApiKey = 'your-gpt-api-key';

const baseUrl = 'https://your-sisense-url';

const gptApiUrl = 'https://api.openai.com/v1/chat/completions';

const gptmodel = 'gpt-4o'

 

const dashboardId = $dashboard_id;

 

const getDashboardWidgets = async () => {

    const url = `${baseUrl}/api/v1/dashboards/${dashboardId}/widgets`;

    const options = {

        method: 'GET',

        headers: {

            'Authorization': `Bearer ${apikey}`,

            'Content-Type': 'application/json'

        }

    };

 

    try {

        const response = await fetch(url, options);

        if (!response.ok) {

            throw new Error(`Error fetching dashboard widgets: ${response.statusText}`);

        }

        const widgets = await response.json();

        return widgets.map(widget => widget.oid);

    } catch (error) {

        console.error(`Error in getDashboardWidgets: ${error.message}`);

        return [];

    }

};

 

const getWidgetMetadata = async (widgetId) => {

    const url = `${baseUrl}/api/v1/dashboards/${dashboardId}/widgets/${widgetId}`;

    const options = {

        method: 'GET',

        headers: {

            'Authorization': `Bearer ${apikey}`,

            'Content-Type': 'application/json'

        }

    };

    

    try {

        const response = await fetch(url, options);

        if (!response.ok) {

            throw new Error(`Error fetching widget metadata: ${response.statusText}`);

        }

        const metadata = await response.json();

        return metadata;

    } catch (error) {

        console.error(`Error in getWidgetMetadata: ${error.message}`);

        return null;

    }

};

 

const getJaql = (widgetStructure) => {

    const result = [];

    for (const panel of widgetStructure.metadata.panels) {

        for (const item of panel.items) {

            if (item && item.jaql) {

                result.push(item.jaql);

            }

        }

    }

    const payload = {

        datasource: widgetStructure.datasource,

        metadata: result

    };

    return JSON.stringify(payload);

};

 

const getWidgetChartData = async (jaqlQuery) => {

    try {

        const parsedJaqlQuery = JSON.parse(jaqlQuery);

        if (!parsedJaqlQuery.datasource || !parsedJaqlQuery.datasource.title) {

            throw new Error('Datasource title is missing in JAQL query');

        }

        const jaqlUrl = `${baseUrl}/api/datasources/${parsedJaqlQuery.datasource.title}/jaql`;

        

        const jaqlOptions = {

            method: 'POST',

            headers: {

                'Authorization': `Bearer ${apikey}`,

                'Content-Type': 'application/json'

            },

            body: jaqlQuery

        };

 

        const response = await fetch(jaqlUrl, jaqlOptions);

        if (!response.ok) {

            throw new Error(`Error fetching widget chart data: ${response.statusText}`);

        }

        const chartData = await response.json();

        return chartData;

    } catch (error) {

        console.error(`Error in getWidgetChartData: ${error.message}`);

        return null;

    }

};

 

const summarizeWidgetData = async (widgetData) => {

    const prompt = `Summarize the following widget data qualitatively and quantitatively:\n\n${JSON.stringify(widgetData)}`;

    

    try {

        const response = await fetch(gptApiUrl, {

            method: 'POST',

            headers: {

                'Authorization': `Bearer ${gptApiKey}`,

                'Content-Type': 'application/json'

            },

            body: JSON.stringify({

                model: gptmodel,

                messages: [{role: "system", content: "You are a best data analyst."}, {role: "user", content: prompt}]

            })

        });

 

        if (!response.ok) {

            throw new Error(`Error summarizing widget data: ${response.statusText}`);

        }

 

        const summary = await response.json();

        return summary.choices[0].message.content.trim();

    } catch (error) {

        console.error(`Error in summarizeWidgetData: ${error.message}`);

        return null;

    }

};

 

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

 

const fetchDashboardWidgetsData = async () => {

    try {

        const widgetIds = await getDashboardWidgets();

        if (widgetIds.length === 0) {

            return `Error in getDashboardWidgets`;

        }

 

        const allSummaries = [];

        for (const widgetId of widgetIds) {

            const widgetDefinition = await getWidgetMetadata(widgetId);

            if (!widgetDefinition) {

                allSummaries.push({ widgetId, error: `Error fetching widget metadata for widget ${widgetId}` });

                continue;

            }

 

            const jaqlQuery = getJaql(widgetDefinition);

 

            const widgetChartData = await getWidgetChartData(jaqlQuery);

            if (!widgetChartData) {

                allSummaries.push({ widgetId, error: `Error fetching chart data for widget ${widgetId}` });

                continue;

            }

 

            const summary = await summarizeWidgetData(widgetChartData);

            if (!summary) {

                allSummaries.push({ widgetId, error: `Error summarizing data for widget ${widgetId}` });

                continue;

            }

 

            allSummaries.push({ widgetId, summary });

 

            // Add delay to avoid hitting rate limits

            await delay(1000);  // Adjust the delay as needed

        }

 

        return JSON.stringify(allSummaries);

    } catch (error) {

        console.error(`Error in fetchDashboardWidgetsData: ${error.message}`);

        return `Error in fetchDashboardWidgetsData: ${error.message}`;

    }

};

 

try {

    return await fetchDashboardWidgetsData();

} catch (error) {

    console.error(`Error in fetchDashboardWidgetsData: ${error.message}`);

    return `Error in fetchDashboardWidgetsData: ${error.message}`;

}

-------node.js fetch api code end

 

RAG RESULT Screenshot

saxoji_2-1717586675042.png

generated raw text :

Sisense Dashboard Widget Data Analysis

Data Summary

  1. Weekly Reviews and Differences
    • Data includes the number of reviews and differences from the previous week spanning from 1970 to 2024.
    • Review counts show significant volatility with extreme increases or decreases in specific weeks.
    • There were notable spikes in review counts in June 2020 and December 2020 (17,932 and 32,442 returns, respectively).
    • The average number of reviews and standard deviations measure the variability in review counts.
  2. Review Star Rating Distribution
    • Data includes 1,921 items categorized by weekly reviews with star ratings from 1 to 5.
    • 5-star reviews are the most common, especially during Black Friday and Christmas seasons.
    • The data consistently shows more positive reviews than negative ones.
  3. Number of Reviews by Keyword
    • "Fast delivery" is the most mentioned keyword with 356,062 reviews.
    • Keywords like "good quality" and "sensitive skin" indicate positive customer experiences.
    • Major keywords emphasize customer loyalty and repeat purchase behavior.
  4. Weekly Reviews by Star Rating
    • Comprising a total of 2,409 rows, with 5-star reviews being the most frequent at 844,372 mentions.
    • The number of reviews increases over time, especially in recent years.
    • Patterns of sudden increases or decreases in review counts in certain weeks and periods are observed.
  5. 2022 Review Statistics
    • In 2022, there are a total of 373,173 reviews, with 254,374 including comments.
    • Data includes reviews written in 53 languages across 46 countries worldwide.
    • There are 10,880 instances of the sales code.
  6. Country-wise 2024 Review Data
    • Comprising columns "country_name," "2024 Reviews," "EVOL(%)," and "Total reviews," indicating the number of reviews expected or recorded in 2024 by country.
    • "EVOL(%)" shows the year-over-year growth rate in the number of reviews.
  7. Reviews by Language
    • Categorizes reviews by "review_language_name" indicating the languages in which reviews were written.
    • Includes the number of text reviews expected in 2024 and the growth rate from the previous year.
  8. Product Review Keywords
    • Includes the number of reviews for keywords such as "acne scars," "bubble wrap," and "combination skin."
    • Provides the number of reviews reflecting major aspects of feedback and related keywords.
  9. Product-wise Review Data
    • Includes the unique number of reviews per product name and the growth rate from the previous year.
    • Review counts are calculated by aggregating the number of unique review IDs.
  10. Mall Review Data
    • Includes mall names and the number of reviews in 2024 and total reviews.
    • "EVOL(%)" indicates the annual growth rate in the number of reviews.
  11. Country-wise User Review Data
    • The total number of unique review IDs is very high, with Indonesia, the United States, Vietnam, Japan, and the Philippines being significant contributors.
    • The lowest contributing countries are Myanmar, Mauritius, Azerbaijan, etc.

 

Summary

  • Review Trend and Volatility: The number of reviews fluctuates sharply during specific weeks, potentially due to marketing campaigns, product launches, or seasonal factors.
  • Star Ratings and Customer Satisfaction: Positive reviews outnumber negative ones, indicating high customer satisfaction.
  • Keywords and Customer Loyalty: Keywords highlight positive feedback on product quality and delivery service, leading to increased repeat purchase behavior.
  • Country and Mall Analysis: The number of reviews in specific countries or malls reflects consumer engagement and market share, useful for strategic marketing planning.
  • Data Completeness: Though some data may lack specific values, the overall structure and metrics are clearly defined.

This analysis helps in understanding customer behavior and product performance, aiding in strategic marketing planning.

 

* You can customize several prompts in the code.

0 REPLIES 0