Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions Telerik.Examples.Mvc/NuGet.config

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Telerik.Examples.Mvc.Controllers.Chat
{
public class AiService
{
private readonly HttpClient _http;
private readonly string _apiKey;
private readonly string _endpoint;
private readonly string _deployment;

public AiService(IConfiguration config)
{
_http = new HttpClient();
_apiKey = config["OpenAI:ApiKey"];
_endpoint = config["OpenAI:Endpoint"];
_deployment = config["OpenAI:DeploymentName"];
}

public async Task<string> ProcessAsync(string prompt)
{
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
var payload = new
{
messages = new[]
{
new { role = "system", content = "You are a helpful assistant." },
new { role = "user", content = prompt }
},
temperature = 0.3,
max_tokens = 1500
};

_http.DefaultRequestHeaders.Clear();
_http.DefaultRequestHeaders.Add("api-key", _apiKey);

var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
var response = await _http.PostAsync(url, content);
var text = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
return $"Azure OpenAI API error: {response.StatusCode}";

var json = JObject.Parse(text);
return json["choices"]?[0]?["message"]?["content"]?.ToString()?.Trim() ?? "";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Kendo.Mvc.UI;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;
using Telerik.Examples.Mvc.Models;

namespace Telerik.Examples.Mvc.Controllers.Chat
{
public class ChatAiIntegrationController : Controller
{
public IActionResult ChatAiIntegration()
{
return View();
}

private readonly AiService _ai;
public ChatAiIntegrationController(AiService ai) { _ai = ai; }

[HttpPost]
public async Task<IActionResult> Ask([FromBody] AiPrompt req)
{
try
{
var result = await _ai.ProcessAsync(req.Prompt);
return Json(new { answer = result });
}
catch (Exception ex)
{
return StatusCode(500, ex.ToString());
}
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Telerik.Examples.Mvc.Models
{
public class AiPrompt
{
public string Prompt { get; set; }
}
}
32 changes: 17 additions & 15 deletions Telerik.Examples.Mvc/Telerik.Examples.Mvc/Program.cs
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
using AutoMapper;
using AutoMapper.Internal;
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System.Text.Json;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.OData;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json.Serialization;
using Telerik.Examples.Mvc.Hubs;
using AutoMapper;
using AutoMapper.Internal;
using Telerik.Examples.Mvc.Models;
using Microsoft.AspNetCore.OData;
using Microsoft.OData.Edm;
using Microsoft.OData.ModelBuilder;
using Telerik.Examples.Mvc.Database;
using Telerik.Examples.Mvc.Seeders;
using Kendo.Mvc.UI;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json.Serialization;
using System;
using Kendo.Mvc.Extensions;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Telerik.Examples.Mvc.Controllers.Chat;
using Telerik.Examples.Mvc.Database;
using Telerik.Examples.Mvc.Hubs;
using Telerik.Examples.Mvc.Models;
using Telerik.Examples.Mvc.Seeders;
using Telerik.SvgIcons;


Expand Down Expand Up @@ -54,6 +55,7 @@
builder.Services.AddSingleton(mapper);

builder.Services.AddTransient<CarsService>();
builder.Services.AddTransient<AiService>();

builder.Services.AddMvc()
.AddNewtonsoftJson(options =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="Telerik.Core.Export" Version="2025.3.812" />
<PackageReference Include="Telerik.UI.for.AspNet.Core" Version="2025.3.825" />
<PackageReference Include="Telerik.UI.for.AspNet.Core" Version="2025.4.1111" />
<PackageReference Include="Telerik.Web.Captcha" Version="2.0.3" />
<PackageReference Include="Telerik.Web.Spreadsheet" Version="2025.3.812" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<div class="k-d-flex k-justify-content-center main-container">
@(Html.Kendo().Chat()
.Name("aiChat")
.SkipSanitization(true)
.Width("400px")
.Height("600px")
.MessageWidthMode(MessageWidthMode.Full)
.Messages(m => m.Placeholder("Ask the AI..."))
.Events(e => e.SendMessage("onSendMessage"))
)
</div>

<script>
async function onSendMessage(e) {
e.message.authorName = "John Smith";
const chat = $("#aiChat").data("kendoChat");

try {
const response = await fetch('/ChatAiIntegration/Ask', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: e.message.text })
});

if (!response.ok) {
chat.postMessage({
authorId: 'ai-assistant',
authorName: 'AI Assistant',
text: "Please add your Azure OpenAI keys in the AiService.cs file.",
id: kendo.guid(),
timestamp: new Date()
});
return;
}

const data = await response.json();

chat.postMessage({
authorId: 'ai-assistant',
authorName: 'AI Assistant',
text: data.answer,
id: kendo.guid(),
timestamp: new Date()
});

} catch (error) {
chat.postMessage({
authorId: 'ai-assistant',
authorName: 'AI Assistant',
text: "The AI Service is currently unavailable. Please check your configuration.",
id: kendo.guid(),
timestamp: new Date()
});
}
}
</script>


Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - Telerik.Examples.Mvc</title>
@{
var kendoVersion = "2025.3.825";
var themeVersion = "12.0.0";
var kendoVersion = "2025.4.1111";
var themeVersion = "12.2.3";
}
<link href="https://kendo.cdn.telerik.com/themes/@themeVersion/default/default-ocean-blue.css" rel="stylesheet" type="text/css" />

Expand Down
6 changes: 6 additions & 0 deletions Telerik.Examples.Mvc/Telerik.Examples.Mvc/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,11 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"OpenAI": {
"UseAzure": true,
"ApiKey": "",
"Endpoint": "",
"DeploymentName": ""
},
"AllowedHosts": "*"
}
Original file line number Diff line number Diff line change
@@ -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"}]
[{"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"}]