New to Telerik UI for ASP.NET MVCStart a free 30-day trial

Custom AI Column

The Telerik UI Grid can be enhanced with a custom AI-powered column that provides personalized insights, summaries, and explanations for individual rows. By integrating the InlineAIPrompt component into a custom column, users can interact with AI directly from each row, asking questions and receiving contextual responses.

The example in this article uses a Telerik-hosted AI service for demonstration purposes only. For production applications, implement your own AI service tailored to your domain, data, and business requirements.

1. Set Up the Grid

Start by defining your Grid and its columns, including a column for AI assistance and a column to display the AI-generated info.

Razor
@(Html.Kendo().Grid<PatientRecord>()
    .Name("grid")
    .Columns(columns =>
    {
        columns.Template(
            Html.Kendo().Template()
                .AddHtml("<div class='ai-tool-cell'>")
                .AddComponent(btn => btn.Button()
                    .Name("ai-btn_${data.Id}")
                    .Icon("sparkles")
                    .FillMode(ButtonFillMode.Flat)
                    .Rounded(Rounded.Medium)
                    .Size(ComponentSize.Small)
                    .Events(ev => ev.Click("onAiClick"))
                )
                .AddComponent(ai => ai.InlineAIPrompt()
                    .Name("inlineAi_${data.Id}")
                    .Placeholder("Type your prompt here...")
                    .SpeechToText(true)
                    .Readonly(false)
                    .Popup(p => p.Width(462))
                    .Service(s => s.Url("https://demos.telerik.com/service/v2/ai/completion"))
                    .SystemPrompt("systemPromptHandler")
                    .Commands(commands =>
                    {
                        commands.Add().Id("summarize")
                            .Text("Summarize")
                            .Prompt("summarizeHandler");

                        commands.Add().Id("recommendations")
                            .Text("Recommendations")
                            .Prompt("recommendationsHandler");

                        commands.Add().Id("analyse-condition")
                            .Text("Analyse Condition")
                            .Prompt("analyseHandler");
                    })
                    .OutputActions(actions =>
                    {
                        actions.Copy();
                        actions.Custom()
                            .Text("Insert")
                            .Command("insert")
                            .Icon("insert-bottom")
                            .ThemeColor(ThemeColor.Primary)
                            .Title("Insert content");
                        actions.Discard();
                    })
                    .Events(ev => ev.OutputAction("onOutputAction"))
                )
                .AddHtml("</div>")
        )
        .Title("AI")
        .Width(60);

        columns.Bound(p => p.AiAssistedInfo)
            .Title("AI Assisted Info")
            .ClientTemplate("#= AiAssistedInfo ? AiAssistedInfo : '<em>No AI assistance yet</em>' #")
            .Width(250);

        columns.Bound(p => p.PatientName).Title("Patient Name").Width(150);
        columns.Bound(p => p.Diagnosis).Title("Diagnosis").Width(180);
        columns.Bound(p => p.TreatmentPlanStatus)
            .Title("Treatment Plan Status")
            .ClientTemplate("<span class='treatment-chip'></span>")
            .Width(180);
        columns.Bound(p => p.Medications).Title("Medication Count").Width(120);
        columns.Bound(p => p.RiskIndicators).Title("Risk Indicators").Width(160);
        columns.Bound(p => p.RecentLabResults)
            .Title("Recent Lab Results")
            .ClientTemplate("#= formatLabResults(RecentLabResults) #")
            .Width(220);
    })
    .Pageable()
    .Scrollable()
    .HtmlAttributes(new { style = "height:550px;" })
    .DataSource(ds => ds.Ajax()
        .Read(r => r.Action("Patients_Read", "Grid"))
        .PageSize(15)
        .Model(m =>
        {
            m.Id(x => x.Id);
            m.Field("AiAssistedInfo", typeof(string));
        })
    )
    .Events(e => e.DataBound("onGridDataBound"))
)

2. Add the AI Button and InlineAIPrompt to Each Row

Use a custom template for the AI column to render a button. When the button is clicked, initialize and display an InlineAIPrompt for that row.

javascript
        function onGridDataBound(e) {
            var grid = this;
            grid.table.find("tr").each(function () {
                var dataItem = grid.dataItem(this);
                if (!dataItem) return;

                var themeColor = "base";
                var icon = "user";
                if (dataItem.TreatmentPlanStatus) {
                    if (dataItem.TreatmentPlanStatus === "Active") {
                        icon = "pills-solid"; themeColor = "info";
                    } else if (dataItem.TreatmentPlanStatus === "Under Evaluation") {
                        icon = "calculator"; themeColor = "base";
                    } else if (dataItem.TreatmentPlanStatus === "Adjusting") {
                        icon = "chart-line-stacked100"; themeColor = "base";
                    } else if (dataItem.TreatmentPlanStatus === "Stable") {
                        icon = "arrows-no-change"; themeColor = "success";
                    } else {
                        icon = "wallet-solid"; themeColor = "error";
                    }
                    $(this).find(".treatment-chip").kendoChip({
                        label: dataItem.TreatmentPlanStatus,
                        icon: icon,
                        themeColor: themeColor,
                        size: "large"
                    });
                }
            });
        }

3. Handle AI Output Actions

Configure output actions so users can copy, insert, or discard the AI-generated content.

In the example, Insert is a custom action. When the Insert action is triggered, you can update the corresponding row's "AI Assisted Info" field and refresh the Grid.

Razor
        function onOutputAction(e) {
            if (e.action === "insert") {
                var row = e.sender.element.closest("tr");
                var grid = $("#grid").data("kendoGrid");
                var dataItem = grid.dataItem(row);

                dataItem.set("AiAssistedInfo", e.content);
                grid.refresh();
            }
        }

4. Customize the InlineAIPrompt

You can further customize the InlineAIPrompt with additional commands, output actions, popup settings, and speech-to-text support as needed for your scenario.

Razor
                .AddComponent(ai => ai.InlineAIPrompt()
                    .Name("inlineAi_${data.Id}")
                    .Placeholder("Type your prompt here...")
                    .SpeechToText(true)
                    .Readonly(false)
                    .Popup(p => p.Width(462))
                    .Service(s => s.Url("https://demos.telerik.com/service/v2/ai/completion"))
                    .SystemPrompt("systemPromptHandler")
                    .Commands(commands =>
                    {
                        commands.Add().Id("summarize")
                            .Text("Summarize")
                            .Prompt("summarizeHandler");

                        commands.Add().Id("recommendations")
                            .Text("Recommendations")
                            .Prompt("recommendationsHandler");

                        commands.Add().Id("analyse-condition")
                            .Text("Analyse Condition")
                            .Prompt("analyseHandler");
                    })
                    .OutputActions(actions =>
                    {
                        actions.Copy();
                        actions.Custom()
                            .Text("Insert")
                            .Command("insert")
                            .Icon("insert-bottom")
                            .ThemeColor(ThemeColor.Primary)
                            .Title("Insert content");
                        actions.Discard();
                    })
                    .Events(ev => ev.OutputAction("onOutputAction"))
                )