Data Grids / Data Management ▸ AI Assistant

The AI Assistant for the DevExtreme DataGrid allows you to interact with the component using natural language.

You can use/configure the following DataGrid features via AI Assistant Chat prompts:

This AI Assistant feature is also available in the DevExtreme TreeList component.

In this demo, the AI Assistant is enabled for a DataGrid that displays mock sales data with over 1500 records.

[note]

AI services used for this demo have been rate and data limited. As such, you may experience performance-related delays when exploring the capabilities of the DataGrid AI Assistant.

When connected to your own AI model/service without rate and data limits, the AI Assistant will perform seamlessly, without artificial delays. Note that DevExtreme does not offer an AI REST API and does not ship any built-in LLMs/SLMs.

[/note]

To enable the AI Assistant, configure the aiIntegration or aiAssistant.aiIntegration object and set the aiAssistant.enabled property to true. Once activated, the DataGrid adds a predefined item ("aiAssistantButton") to the toolbar. This button opens our AI Assistant Chat in a draggable pop-up window.

Our Chat implementation supports speech-to-text input, ideal for hands-free interaction or entering longer prompts.

This demo also configures suggestions for the AI Assistant Chat. These buttons allow you to interact with the assistant in one click using predefined prompts. For additional information about suggestions, refer to the following demo: DevExtreme Chat - Prompt Suggestions.

@using DevExtreme.MVC.Demos.Models
@model IEnumerable<DataGridSale>

@section ExternalDependencies {
    <script type="module">
        import { AzureOpenAI } from "https://esm.sh/openai@4.73.1";
        window.AzureOpenAI = AzureOpenAI;
    </script>
}

@(Html.DevExtreme().DataGrid<DataGridSale>()
    .ID("gridContainer")
    .DataSource(Model, "Id")
    .ShowBorders(true)
    .AllowColumnResizing(true)
    .AllowColumnReordering(true)
    .FocusedRowEnabled(true)
    .Selection(s => s.Mode(SelectionMode.Multiple))
    .Sorting(s => s.Mode(GridSortingMode.Multiple))
    .AiIntegration(new JS("aiIntegration"))
    .SearchPanel(s => s
        .Visible(true)
        .Width(240)
        .Placeholder("Search...")
    )
    .GroupPanel(g => g.Visible(true))
    .HeaderFilter(h => h.Visible(true))
    .FilterRow(f => f.Visible(true))
    .FilterSyncEnabled(true)
    .Paging(p => p.PageSize(10))
    .Pager(p => p
        .Visible(true)
        .AllowedPageSizes(new[] { 10, 25, 50, 100 })
        .ShowPageSizeSelector(true)
    )
    .AIAssistant(a => a
        .Enabled(true)
        .AiIntegration(new JS("aiIntegration"))
        .Chat(chat => chat
            .OnInitialized("onChatInitialized")
            .User(u => u.Id("user"))
            .Option("suggestions", new JS("suggestions"))
        )
    )
    .Columns(columns => {
        columns.AddFor(m => m.Product);

        columns.AddFor(m => m.Amount)
            .Caption("Sale Amount")
            .DataType(GridColumnDataType.Number)
            .Format(Format.Currency);

        columns.AddFor(m => m.Region)
            .DataType(GridColumnDataType.String);

        columns.AddFor(m => m.Sector)
            .DataType(GridColumnDataType.String);

        columns.AddFor(m => m.SaleDate)
            .DataType(GridColumnDataType.Date);

        columns.AddFor(m => m.Customer)
            .DataType(GridColumnDataType.String);
    })
)

<script>
  let chatService;
  let chatInstance;
  const deployment = "demo-mini";
  const apiVersion = "2024-02-01";
  const endpoint = "https://public-api.devexpress.com/demo-openai";
  const apiKey = "DEMO";

  const suggestionItems = [
    {
      text: '💡 Help',
      prompt: `💡 The DataGrid AI Assistant allows you to control the component using natural language. You can execute commands such as the following:
• Sort records
• Apply a filter
• Search for a specific value
• Group records by a field
• Focus and select rows
• Modify paging settings
• Pin, resize, and reorder columns
• Configure data summaries
• Pick a suggestion or enter a custom request to get started.`,
    },
    {
      text: '🔍 Filter Sector by Health',
      prompt: 'Filter Sector by Health',
    },
    {
      text: '↕️ Sort by Region',
      prompt: 'Sort by Region',
    },
    {
      text: '🧩 Group by Product',
      prompt: 'Group by Product',
      width: 170,
    },
  ];

  var suggestions = {
    items: suggestionItems,
    onItemClick(e) {
      const { prompt, text } = e.itemData;
      const userId = text === "💡 Help" ? "help" : "user";

      const message = {
        id: Date.now(),
        timestamp: new Date(),
        author: { id: userId },
        text: prompt,
      };

      chatInstance.getDataSource().store().push([{
        type: "insert",
        data: message,
      }]);
    },
  };

  function onChatInitialized({ component }) {
    chatInstance = component;
  }

  async function getAIResponse(messages, signal, responseSchema) {
    const params = {
      messages,
      model: deployment,
      max_completion_tokens: 1000,
      temperature: 0.7,
    };

    params.response_format = {
      type: 'json_schema',
      json_schema: {
        name: 'grid_assistant_response',
        strict: false,
        schema: responseSchema,
      },
    };

    const response = await chatService.chat.completions
      .create(params, { signal });
    const result = response.choices[0].message?.content;

    return result;
  }

  async function getAIResponseRecursive(messages, signal, responseSchema) {
    return getAIResponse(messages, signal, responseSchema)
      .catch(async (error) => {
        if (!error.message.includes("Connection error")) {
          return Promise.reject(error);
        }

        DevExpress.ui.notify({
          message: "Our demo AI service reached a temporary request limit. Retrying in 30 seconds.",
          width: "auto",
          type: "error",
          displayTime: 5000,
        });

        await new Promise((resolve) => setTimeout(resolve, 30000));

        return getAIResponseRecursive(messages, signal, responseSchema);
      });
  }

  const aiIntegration = new DevExpress.aiIntegration.AIIntegration({
    sendRequest({ prompt, data }) {
      const isValidRequest = JSON.stringify(prompt.user).length < 5000;
      if (!isValidRequest) {
        return {
          promise: Promise.reject(new Error("Request is too long. Specify a shorter prompt.")),
          abort: () => {},
        };
      }
      const controller = new AbortController();
      const signal = controller.signal;

      const aiPrompt = [
        { role: "system", content: prompt.system },
        { role: "user", content: prompt.user },
      ];
      const promise = getAIResponseRecursive(aiPrompt, signal, data?.responseSchema);

      const result = {
        promise,
        abort: () => {
          controller.abort();
        },
      };

      return result;
    },
  });

  $(() => {
    chatService = new AzureOpenAI({
      dangerouslyAllowBrowser: true,
      deployment,
      endpoint,
      apiVersion,
      apiKey,
    });
  });
</script>
using DevExtreme.MVC.Demos.Models;
using DevExtreme.MVC.Demos.Models.DataGrid;
using DevExtreme.MVC.Demos.Models.SampleData;
using System;
using System.Linq;
using System.Web.Mvc;

namespace DevExtreme.MVC.Demos.Controllers {
    public class DataGridController : Controller {

        public ActionResult AIAssistant() {
            return View(SampleData.DataGridSales);
        }

    }
}
#gridContainer {
    max-height: 800px;
}