Skip to content

Commit 9dd4ecb

Browse files
Merge pull request #100 from telerik/add-chat-ai-integration-example
add chat ai integration demo telerik/kendo#23850
2 parents 6d44cf4 + d6284df commit 9dd4ecb

File tree

10 files changed

+179
-28
lines changed

10 files changed

+179
-28
lines changed

Telerik.Examples.Mvc/NuGet.config

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
using System.Net.Http;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
8+
namespace Telerik.Examples.Mvc.Controllers.Chat
9+
{
10+
public class AiService
11+
{
12+
private readonly HttpClient _http;
13+
private readonly string _apiKey;
14+
private readonly string _endpoint;
15+
private readonly string _deployment;
16+
17+
public AiService(IConfiguration config)
18+
{
19+
_http = new HttpClient();
20+
_apiKey = config["OpenAI:ApiKey"];
21+
_endpoint = config["OpenAI:Endpoint"];
22+
_deployment = config["OpenAI:DeploymentName"];
23+
}
24+
25+
public async Task<string> ProcessAsync(string prompt)
26+
{
27+
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
28+
var payload = new
29+
{
30+
messages = new[]
31+
{
32+
new { role = "system", content = "You are a helpful assistant." },
33+
new { role = "user", content = prompt }
34+
},
35+
temperature = 0.3,
36+
max_tokens = 1500
37+
};
38+
39+
_http.DefaultRequestHeaders.Clear();
40+
_http.DefaultRequestHeaders.Add("api-key", _apiKey);
41+
42+
var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
43+
var response = await _http.PostAsync(url, content);
44+
var text = await response.Content.ReadAsStringAsync();
45+
46+
if (!response.IsSuccessStatusCode)
47+
return $"Azure OpenAI API error: {response.StatusCode}";
48+
49+
var json = JObject.Parse(text);
50+
return json["choices"]?[0]?["message"]?["content"]?.ToString()?.Trim() ?? "";
51+
}
52+
}
53+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using Kendo.Mvc.UI;
2+
using Microsoft.AspNetCore.Mvc;
3+
using System;
4+
using System.Threading.Tasks;
5+
using Telerik.Examples.Mvc.Models;
6+
7+
namespace Telerik.Examples.Mvc.Controllers.Chat
8+
{
9+
public class ChatAiIntegrationController : Controller
10+
{
11+
public IActionResult ChatAiIntegration()
12+
{
13+
return View();
14+
}
15+
16+
private readonly AiService _ai;
17+
public ChatAiIntegrationController(AiService ai) { _ai = ai; }
18+
19+
[HttpPost]
20+
public async Task<IActionResult> Ask([FromBody] AiPrompt req)
21+
{
22+
try
23+
{
24+
var result = await _ai.ProcessAsync(req.Prompt);
25+
return Json(new { answer = result });
26+
}
27+
catch (Exception ex)
28+
{
29+
return StatusCode(500, ex.ToString());
30+
}
31+
}
32+
33+
}
34+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Telerik.Examples.Mvc.Models
2+
{
3+
public class AiPrompt
4+
{
5+
public string Prompt { get; set; }
6+
}
7+
}

Telerik.Examples.Mvc/Telerik.Examples.Mvc/Program.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
1+
using AutoMapper;
2+
using AutoMapper.Internal;
3+
using Kendo.Mvc.Extensions;
4+
using Kendo.Mvc.UI;
15
using Microsoft.AspNetCore.Builder;
26
using Microsoft.AspNetCore.Hosting;
3-
using System.Text.Json;
7+
using Microsoft.AspNetCore.Http;
48
using Microsoft.AspNetCore.Identity;
9+
using Microsoft.AspNetCore.Mvc;
510
using Microsoft.AspNetCore.Mvc.Razor;
11+
using Microsoft.AspNetCore.OData;
612
using Microsoft.EntityFrameworkCore;
713
using Microsoft.Extensions.Configuration;
814
using Microsoft.Extensions.DependencyInjection;
915
using Microsoft.Extensions.Hosting;
10-
using Newtonsoft.Json.Serialization;
11-
using Telerik.Examples.Mvc.Hubs;
12-
using AutoMapper;
13-
using AutoMapper.Internal;
14-
using Telerik.Examples.Mvc.Models;
15-
using Microsoft.AspNetCore.OData;
1616
using Microsoft.OData.Edm;
1717
using Microsoft.OData.ModelBuilder;
18-
using Telerik.Examples.Mvc.Database;
19-
using Telerik.Examples.Mvc.Seeders;
20-
using Kendo.Mvc.UI;
21-
using Microsoft.AspNetCore.Http;
22-
using Microsoft.AspNetCore.Mvc;
23-
using System.Linq;
24-
using System.Threading.Tasks;
18+
using Newtonsoft.Json.Serialization;
2519
using System;
26-
using Kendo.Mvc.Extensions;
2720
using System.Collections.Generic;
21+
using System.Linq;
22+
using System.Text.Json;
2823
using System.Threading;
24+
using System.Threading.Tasks;
25+
using Telerik.Examples.Mvc.Controllers.Chat;
26+
using Telerik.Examples.Mvc.Database;
27+
using Telerik.Examples.Mvc.Hubs;
28+
using Telerik.Examples.Mvc.Models;
29+
using Telerik.Examples.Mvc.Seeders;
2930
using Telerik.SvgIcons;
3031

3132

@@ -54,6 +55,7 @@
5455
builder.Services.AddSingleton(mapper);
5556

5657
builder.Services.AddTransient<CarsService>();
58+
builder.Services.AddTransient<AiService>();
5759

5860
builder.Services.AddMvc()
5961
.AddNewtonsoftJson(options =>

Telerik.Examples.Mvc/Telerik.Examples.Mvc/Telerik.Examples.Mvc.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<PackageReference Include="System.Net.Http" Version="4.3.4" />
2525
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
2626
<PackageReference Include="Telerik.Core.Export" Version="2025.3.812" />
27-
<PackageReference Include="Telerik.UI.for.AspNet.Core" Version="2025.3.825" />
27+
<PackageReference Include="Telerik.UI.for.AspNet.Core" Version="2025.4.1111" />
2828
<PackageReference Include="Telerik.Web.Captcha" Version="2.0.3" />
2929
<PackageReference Include="Telerik.Web.Spreadsheet" Version="2025.3.812" />
3030
</ItemGroup>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<div class="k-d-flex k-justify-content-center main-container">
2+
@(Html.Kendo().Chat()
3+
.Name("aiChat")
4+
.SkipSanitization(true)
5+
.Width("400px")
6+
.Height("600px")
7+
.MessageWidthMode(MessageWidthMode.Full)
8+
.Messages(m => m.Placeholder("Ask the AI..."))
9+
.Events(e => e.SendMessage("onSendMessage"))
10+
)
11+
</div>
12+
13+
<script>
14+
async function onSendMessage(e) {
15+
e.message.authorName = "John Smith";
16+
const chat = $("#aiChat").data("kendoChat");
17+
18+
try {
19+
const response = await fetch('/ChatAiIntegration/Ask', {
20+
method: 'POST',
21+
headers: { 'Content-Type': 'application/json' },
22+
body: JSON.stringify({ prompt: e.message.text })
23+
});
24+
25+
if (!response.ok) {
26+
chat.postMessage({
27+
authorId: 'ai-assistant',
28+
authorName: 'AI Assistant',
29+
text: "Please add your Azure OpenAI keys in the AiService.cs file.",
30+
id: kendo.guid(),
31+
timestamp: new Date()
32+
});
33+
return;
34+
}
35+
36+
const data = await response.json();
37+
38+
chat.postMessage({
39+
authorId: 'ai-assistant',
40+
authorName: 'AI Assistant',
41+
text: data.answer,
42+
id: kendo.guid(),
43+
timestamp: new Date()
44+
});
45+
46+
} catch (error) {
47+
chat.postMessage({
48+
authorId: 'ai-assistant',
49+
authorName: 'AI Assistant',
50+
text: "The AI Service is currently unavailable. Please check your configuration.",
51+
id: kendo.guid(),
52+
timestamp: new Date()
53+
});
54+
}
55+
}
56+
</script>
57+
58+

Telerik.Examples.Mvc/Telerik.Examples.Mvc/Views/Shared/_Layout.cshtml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
88
<title>@ViewData["Title"] - Telerik.Examples.Mvc</title>
99
@{
10-
var kendoVersion = "2025.3.825";
11-
var themeVersion = "12.0.0";
10+
var kendoVersion = "2025.4.1111";
11+
var themeVersion = "12.2.3";
1212
}
1313
<link href="https://kendo.cdn.telerik.com/themes/@themeVersion/default/default-ocean-blue.css" rel="stylesheet" type="text/css" />
1414

Telerik.Examples.Mvc/Telerik.Examples.Mvc/appsettings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@
99
"Microsoft.Hosting.Lifetime": "Information"
1010
}
1111
},
12+
"OpenAI": {
13+
"UseAzure": true,
14+
"ApiKey": "",
15+
"Endpoint": "",
16+
"DeploymentName": ""
17+
},
1218
"AllowedHosts": "*"
1319
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"ComponentName":"TreeList","ActionName":"TreeListODataBinding","ControllerName":"TreeListODataBinding"},{"ComponentName":"StylesAndLayout","ActionName":"ClientThemeChange","ControllerName":"ClientThemeChange"},{"ComponentName":"Spreadsheet","ActionName":"Spreadsheet_Load_Xlsx_From_Server","ControllerName":"Spreadsheet_Load_Xlsx_From_Server"},{"ComponentName":"Scheduler","ActionName":"SchedulerCustomEdit","ControllerName":"SchedulerCustomEdit"},{"ComponentName":"Scheduler","ActionName":"SchedulerGoogleCalendar","ControllerName":"SchedulerGoogleCalendar"},{"ComponentName":"Scheduler","ActionName":"SchedulerServerFiltering","ControllerName":"SchedulerServerFiltering"},{"ComponentName":"Scheduler","ActionName":"SchedulerSignalR","ControllerName":"SchedulerSignalR"},{"ComponentName":"Scheduler","ActionName":"SchedulerSqlServerBinding","ControllerName":"SchedulerSqlServerBinding"},{"ComponentName":"MultiSelect","ActionName":"Cascading_MultiSelect","ControllerName":"Cascading_MultiSelect"},{"ComponentName":"MultiSelect","ActionName":"MultiSelectPost","ControllerName":"MultiSelectPost"},{"ComponentName":"MultiSelect","ActionName":"MultiSelectPost","ControllerName":"MultiSelectPost"},{"ComponentName":"Menu","ActionName":"SecurityTrimming","ControllerName":"SecurityTrimming"},{"ComponentName":"ListBox","ActionName":"RemoteBinding","ControllerName":"RemoteBinding"},{"ComponentName":"ImageEditor","ActionName":"ImageEditorSave","ControllerName":"ImageEditorSave"},{"ComponentName":"ImageEditor","ActionName":"ImageEditorSave","ControllerName":"ImageEditorSave"},{"ComponentName":"Grid","ActionName":"AjaxBinding","ControllerName":"AjaxBinding"},{"ComponentName":"Grid","ActionName":"AjaxEditing","ControllerName":"AjaxEditing"},{"ComponentName":"Grid","ActionName":"AlternatingRows","ControllerName":"AlternatingRows"},{"ComponentName":"Grid","ActionName":"AsynchronousBindingWithCancellationToken","ControllerName":"AsynchronousBindingWithCancellationToken"},{"ComponentName":"Grid","ActionName":"AudioColumn","ControllerName":"AudioColumn"},{"ComponentName":"Grid","ActionName":"AutocompleteEditorAllowSettingNewValues","ControllerName":"AutocompleteEditorAllowSettingNewValues"},{"ComponentName":"Grid","ActionName":"CustomDataSource","ControllerName":"CustomDataSource"},{"ComponentName":"Grid","ActionName":"CustomPopUpEditor","ControllerName":"CustomPopUpEditor"},{"ComponentName":"Grid","ActionName":"CustomPopUpEditorTagHelper","ControllerName":"CustomPopUpEditorTagHelper"},{"ComponentName":"Grid","ActionName":"DefiningColumnFormat","ControllerName":"DefiningColumnFormat"},{"ComponentName":"Grid","ActionName":"DragAndDropBetweenGrids","ControllerName":"DragAndDropBetweenGrids"},{"ComponentName":"Grid","ActionName":"DynamicBatchEditing","ControllerName":"DynamicBatchEditing"},{"ComponentName":"Grid","ActionName":"Dynamic","ControllerName":"Dynamic"},{"ComponentName":"Grid","ActionName":"DynamicPopupEditing","ControllerName":"DynamicPopupEditing"},{"ComponentName":"Grid","ActionName":"EditingWithCascadingDropDownLists","ControllerName":"EditingWithCascadingDropDownLists"},{"ComponentName":"Grid","ActionName":"EnableOperationsForObjectColumn","ControllerName":"EnableOperationsForObjectColumn"},{"ComponentName":"Grid","ActionName":"EncodedForeignKeyValues","ControllerName":"EncodedForeignKeyValues"},{"ComponentName":"Grid","ActionName":"GridInlineEditingWithNullableBoolean","ControllerName":"GridInlineEditingWithNullableBoolean"},{"ComponentName":"Grid","ActionName":"GridODataBinding","ControllerName":"GridODataBinding"},{"ComponentName":"Grid","ActionName":"Grid_SignalR","ControllerName":"Grid_SignalR"},{"ComponentName":"Grid","ActionName":"HierarchyCrud","ControllerName":"HierarchyCrud"},{"ComponentName":"Grid","ActionName":"HierarchySignalR","ControllerName":"HierarchySignalR"},{"ComponentName":"Grid","ActionName":"Hierarchy_Persist_Expanded_Children","ControllerName":"Hierarchy_Persist_Expanded_Children"},{"ComponentName":"Grid","ActionName":"ListBoxAsEditor","ControllerName":"ListBoxAsEditor"},{"ComponentName":"Grid","ActionName":"MinimalAPI","ControllerName":"MinimalAPI"},{"ComponentName":"Grid","ActionName":"MultiSelectAsEditor","ControllerName":"MultiSelectAsEditor"},{"ComponentName":"Grid","ActionName":"ToggleEditMode","ControllerName":"ToggleEditMode"},{"ComponentName":"Grid","ActionName":"ViewComponent","ControllerName":"ViewComponent"},{"ComponentName":"FormIndex","ActionName":"FormIndex","ControllerName":"FormIndex"},{"ComponentName":"Editor","ActionName":"EditorContent","ControllerName":"EditorContent"},{"ComponentName":"Editor","ActionName":"Editor_Header_And_Footer_Simulation","ControllerName":"Editor_Header_And_Footer_Simulation"},{"ComponentName":"DropDownList","ActionName":"AddItem","ControllerName":"AddItem"},{"ComponentName":"DateTimeOffset","ActionName":"DateTimeOffset","ControllerName":"DateTimeOffset"},{"ComponentName":"Chat","ActionName":"ChatPeerToPeer","ControllerName":"ChatPeerToPeer"},{"ComponentName":"Captcha","ActionName":"CaptchaOverview","ControllerName":"CaptchaOverview"}]
1+
[{"ComponentName":"TreeList","ActionName":"TreeListODataBinding","ControllerName":"TreeListODataBinding"},{"ComponentName":"StylesAndLayout","ActionName":"ClientThemeChange","ControllerName":"ClientThemeChange"},{"ComponentName":"Spreadsheet","ActionName":"Spreadsheet_Load_Xlsx_From_Server","ControllerName":"Spreadsheet_Load_Xlsx_From_Server"},{"ComponentName":"Scheduler","ActionName":"SchedulerCustomEdit","ControllerName":"SchedulerCustomEdit"},{"ComponentName":"Scheduler","ActionName":"SchedulerGoogleCalendar","ControllerName":"SchedulerGoogleCalendar"},{"ComponentName":"Scheduler","ActionName":"SchedulerServerFiltering","ControllerName":"SchedulerServerFiltering"},{"ComponentName":"Scheduler","ActionName":"SchedulerSignalR","ControllerName":"SchedulerSignalR"},{"ComponentName":"Scheduler","ActionName":"SchedulerSqlServerBinding","ControllerName":"SchedulerSqlServerBinding"},{"ComponentName":"MultiSelect","ActionName":"Cascading_MultiSelect","ControllerName":"Cascading_MultiSelect"},{"ComponentName":"MultiSelect","ActionName":"MultiSelectPost","ControllerName":"MultiSelectPost"},{"ComponentName":"MultiSelect","ActionName":"MultiSelectPost","ControllerName":"MultiSelectPost"},{"ComponentName":"Menu","ActionName":"SecurityTrimming","ControllerName":"SecurityTrimming"},{"ComponentName":"ListBox","ActionName":"RemoteBinding","ControllerName":"RemoteBinding"},{"ComponentName":"ImageEditor","ActionName":"ImageEditorSave","ControllerName":"ImageEditorSave"},{"ComponentName":"ImageEditor","ActionName":"ImageEditorSave","ControllerName":"ImageEditorSave"},{"ComponentName":"Grid","ActionName":"AjaxBinding","ControllerName":"AjaxBinding"},{"ComponentName":"Grid","ActionName":"AjaxEditing","ControllerName":"AjaxEditing"},{"ComponentName":"Grid","ActionName":"AlternatingRows","ControllerName":"AlternatingRows"},{"ComponentName":"Grid","ActionName":"AsynchronousBindingWithCancellationToken","ControllerName":"AsynchronousBindingWithCancellationToken"},{"ComponentName":"Grid","ActionName":"AudioColumn","ControllerName":"AudioColumn"},{"ComponentName":"Grid","ActionName":"AutocompleteEditorAllowSettingNewValues","ControllerName":"AutocompleteEditorAllowSettingNewValues"},{"ComponentName":"Grid","ActionName":"CustomDataSource","ControllerName":"CustomDataSource"},{"ComponentName":"Grid","ActionName":"CustomPopUpEditor","ControllerName":"CustomPopUpEditor"},{"ComponentName":"Grid","ActionName":"CustomPopUpEditorTagHelper","ControllerName":"CustomPopUpEditorTagHelper"},{"ComponentName":"Grid","ActionName":"DefiningColumnFormat","ControllerName":"DefiningColumnFormat"},{"ComponentName":"Grid","ActionName":"DragAndDropBetweenGrids","ControllerName":"DragAndDropBetweenGrids"},{"ComponentName":"Grid","ActionName":"DynamicBatchEditing","ControllerName":"DynamicBatchEditing"},{"ComponentName":"Grid","ActionName":"Dynamic","ControllerName":"Dynamic"},{"ComponentName":"Grid","ActionName":"DynamicPopupEditing","ControllerName":"DynamicPopupEditing"},{"ComponentName":"Grid","ActionName":"EditingWithCascadingDropDownLists","ControllerName":"EditingWithCascadingDropDownLists"},{"ComponentName":"Grid","ActionName":"EnableOperationsForObjectColumn","ControllerName":"EnableOperationsForObjectColumn"},{"ComponentName":"Grid","ActionName":"EncodedForeignKeyValues","ControllerName":"EncodedForeignKeyValues"},{"ComponentName":"Grid","ActionName":"GridInlineEditingWithNullableBoolean","ControllerName":"GridInlineEditingWithNullableBoolean"},{"ComponentName":"Grid","ActionName":"GridODataBinding","ControllerName":"GridODataBinding"},{"ComponentName":"Grid","ActionName":"Grid_SignalR","ControllerName":"Grid_SignalR"},{"ComponentName":"Grid","ActionName":"HierarchyCrud","ControllerName":"HierarchyCrud"},{"ComponentName":"Grid","ActionName":"HierarchySignalR","ControllerName":"HierarchySignalR"},{"ComponentName":"Grid","ActionName":"Hierarchy_Persist_Expanded_Children","ControllerName":"Hierarchy_Persist_Expanded_Children"},{"ComponentName":"Grid","ActionName":"ListBoxAsEditor","ControllerName":"ListBoxAsEditor"},{"ComponentName":"Grid","ActionName":"MinimalAPI","ControllerName":"MinimalAPI"},{"ComponentName":"Grid","ActionName":"MultiSelectAsEditor","ControllerName":"MultiSelectAsEditor"},{"ComponentName":"Grid","ActionName":"ToggleEditMode","ControllerName":"ToggleEditMode"},{"ComponentName":"Grid","ActionName":"ViewComponent","ControllerName":"ViewComponent"},{"ComponentName":"FormIndex","ActionName":"FormIndex","ControllerName":"FormIndex"},{"ComponentName":"Editor","ActionName":"EditorContent","ControllerName":"EditorContent"},{"ComponentName":"Editor","ActionName":"Editor_Header_And_Footer_Simulation","ControllerName":"Editor_Header_And_Footer_Simulation"},{"ComponentName":"DropDownList","ActionName":"AddItem","ControllerName":"AddItem"},{"ComponentName":"DateTimeOffset","ActionName":"DateTimeOffset","ControllerName":"DateTimeOffset"},{"ComponentName":"Chat","ActionName":"ChatAiIntegration","ControllerName":"ChatAiIntegration"},{"ComponentName":"Chat","ActionName":"ChatPeerToPeer","ControllerName":"ChatPeerToPeer"},{"ComponentName":"Captcha","ActionName":"CaptchaOverview","ControllerName":"CaptchaOverview"}]

0 commit comments

Comments
 (0)