Skip to content

Commit fc2187a

Browse files
Merge pull request #104 from telerik/add-chat-ai-integration-example
add ai integration examples for scheduler, grid, editor, and chart te…
2 parents ad7b885 + 18ae6ec commit fc2187a

File tree

14 files changed

+1065
-57
lines changed

14 files changed

+1065
-57
lines changed
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
using Microsoft.Extensions.Configuration;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
using System;
5+
using System.Net.Http;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace Telerik.Examples.Mvc.Controllers
10+
{
11+
public class AiService
12+
{
13+
private readonly HttpClient _http;
14+
private readonly string _apiKey;
15+
private readonly string _endpoint;
16+
private readonly string _deployment;
17+
18+
public AiService(IConfiguration config)
19+
{
20+
_http = new HttpClient();
21+
_apiKey = config["OpenAI:ApiKey"];
22+
_endpoint = config["OpenAI:Endpoint"];
23+
_deployment = config["OpenAI:DeploymentName"];
24+
}
25+
26+
private async Task<string> SendAsync(string url, object payload)
27+
{
28+
_http.DefaultRequestHeaders.Clear();
29+
_http.DefaultRequestHeaders.Add("api-key", _apiKey);
30+
31+
var content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json");
32+
var response = await _http.PostAsync(url, content);
33+
var text = await response.Content.ReadAsStringAsync();
34+
35+
if (!response.IsSuccessStatusCode)
36+
return $"Azure OpenAI API error: {response.StatusCode}";
37+
38+
var json = JObject.Parse(text);
39+
return json["choices"]?[0]?["message"]?["content"]?.ToString()?.Trim() ?? "";
40+
}
41+
42+
public async Task<string> ProcessAsync(string prompt)
43+
{
44+
try
45+
{
46+
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
47+
var payload = new
48+
{
49+
messages = new[]
50+
{
51+
new { role = "system", content = "You are a helpful assistant." },
52+
new { role = "user", content = prompt }
53+
},
54+
temperature = 0.3,
55+
max_tokens = 1500
56+
};
57+
58+
return await SendAsync(url, payload);
59+
}
60+
catch
61+
{
62+
return "AI configuration missing";
63+
}
64+
}
65+
66+
public async Task<string> AnalyzeGridDataAsync(string instructions, string gridDataJson)
67+
{
68+
var systemPrompt = @"
69+
You are an AI assistant analyzing Kendo UI Grid data.
70+
71+
You ALWAYS receive:
72+
1) The full raw data (JSON array)
73+
2) A user question
74+
75+
RULES:
76+
1. If the user explicitly asks for filtering or sorting:
77+
Return ONLY a JSON object such as:
78+
{ ""action"": ""filter"", ""field"": ""Month"", ""operator"": ""eq"", ""value"": ""July"" }
79+
80+
or:
81+
82+
{ ""action"": ""sort"", ""field"": ""Total"", ""dir"": ""desc"" }
83+
84+
2. For ALL OTHER QUESTIONS:
85+
Return a short natural language answer using ONLY the supplied data.
86+
87+
No code, no markdown, no explanations.
88+
";
89+
90+
try
91+
{
92+
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
93+
var payload = new
94+
{
95+
messages = new[]
96+
{
97+
new { role = "system", content = systemPrompt },
98+
new { role = "user", content = $"Grid Data:\n{gridDataJson}" },
99+
new { role = "user", content = $"Question:\n{instructions}" }
100+
},
101+
temperature = 0.3,
102+
max_tokens = 1500
103+
};
104+
105+
return await SendAsync(url, payload);
106+
}
107+
catch
108+
{
109+
return "AI configuration missing";
110+
}
111+
}
112+
113+
public async Task<string> EditTextAsync(string text, string instruction)
114+
{
115+
try
116+
{
117+
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
118+
var payload = new
119+
{
120+
messages = new[]
121+
{
122+
new
123+
{
124+
role = "system",
125+
content =
126+
"You are an AI text editor. Modify the text ONLY according to the user's instruction while preserving existing formatting. " +
127+
"If the user requests color, bold, or styles, return the text wrapped in proper HTML inline styles (e.g., <span style='color: green;'>text</span>). " +
128+
"Do not apply additional formatting unless explicitly requested."
129+
},
130+
new
131+
{
132+
role = "user",
133+
content =
134+
$"Modify this text:\n\n{text}\n\nInstruction: {instruction}\n\nReturn the modified text as valid HTML with inline styles only if formatting changes are required."
135+
}
136+
},
137+
temperature = 0.3,
138+
max_tokens = 500
139+
};
140+
141+
return await SendAsync(url, payload);
142+
}
143+
catch
144+
{
145+
return "AI configuration missing";
146+
}
147+
}
148+
149+
public async Task<string> GenerateChartConfigAsync(string instructions)
150+
{
151+
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
152+
153+
var payload = new
154+
{
155+
messages = new[]
156+
{
157+
new { role = "system", content = "Return ONLY valid JSON for a Kendo UI Chart." },
158+
new { role = "user", content = $"Generate a Kendo UI Chart JSON configuration. Instructions: {instructions}" }
159+
},
160+
temperature = 0.2,
161+
max_tokens = 600
162+
};
163+
164+
var raw = await SendAsync(url, payload);
165+
if (string.IsNullOrWhiteSpace(raw)) return "{}";
166+
167+
string config = raw.Trim();
168+
169+
int start = config.IndexOf('{');
170+
int end = config.LastIndexOf('}');
171+
if (start >= 0 && end > start)
172+
config = config.Substring(start, end - start + 1);
173+
174+
try
175+
{
176+
JObject.Parse(config);
177+
return config;
178+
}
179+
catch
180+
{
181+
config = config.Replace(",]", "]").Replace(",}", "}");
182+
try
183+
{
184+
JObject.Parse(config);
185+
return config;
186+
}
187+
catch
188+
{
189+
return "{}";
190+
}
191+
}
192+
}
193+
194+
public async Task<string> GenerateSchedulerConfigAsync(string instructions)
195+
{
196+
var url = $"{_endpoint}openai/deployments/{_deployment}/chat/completions?api-version=2024-02-15-preview";
197+
198+
var systemPrompt = @"
199+
Return ONLY valid JSON for a Kendo UI Scheduler.
200+
201+
The JSON object MUST contain:
202+
{
203+
""date"": ""2025-01-10T00:00:00Z"",
204+
""events"": [
205+
{
206+
""id"": 1,
207+
""title"": ""Design Review"",
208+
""start"": ""2025-01-10T10:00:00Z"",
209+
""end"": ""2025-01-10T11:00:00Z""
210+
}
211+
]
212+
}
213+
214+
RULES:
215+
- Convert all dates into ISO UTC strings.
216+
- The 'events' array must contain the tasks created or modified.
217+
- Do NOT include Kendo configuration like views or transport.
218+
";
219+
220+
var payload = new
221+
{
222+
messages = new[]
223+
{
224+
new { role = "system", content = systemPrompt },
225+
new { role = "user", content = instructions }
226+
},
227+
temperature = 0.2,
228+
max_tokens = 600
229+
};
230+
231+
var raw = await SendAsync(url, payload);
232+
if (string.IsNullOrWhiteSpace(raw)) return "{}";
233+
234+
string config = raw.Trim();
235+
236+
int start = config.IndexOf("{");
237+
int end = config.LastIndexOf("}");
238+
if (start >= 0 && end > start)
239+
config = config.Substring(start, end - start + 1);
240+
241+
try
242+
{
243+
JObject.Parse(config);
244+
return config;
245+
}
246+
catch
247+
{
248+
config = config.Replace(",]", "]").Replace(",}", "}");
249+
try
250+
{
251+
JObject.Parse(config);
252+
return config;
253+
}
254+
catch
255+
{
256+
return "{}";
257+
}
258+
}
259+
}
260+
}
261+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.Extensions.Logging;
3+
using System;
4+
using System.Threading.Tasks;
5+
6+
namespace Telerik.Examples.Mvc.Controllers.Chart
7+
{
8+
public class SmartChartController : Controller
9+
{
10+
private readonly AiService _chartService;
11+
private readonly ILogger<SmartChartController> _logger;
12+
13+
public SmartChartController(AiService chartService, ILogger<SmartChartController> logger)
14+
{
15+
_chartService = chartService;
16+
_logger = logger;
17+
}
18+
19+
[HttpPost]
20+
[Route("SmartChart/GenerateChart")]
21+
public async Task<IActionResult> GenerateChart([FromBody] ChartRequest request)
22+
{
23+
if (string.IsNullOrWhiteSpace(request.Instructions))
24+
return BadRequest("Instructions cannot be empty.");
25+
26+
try
27+
{
28+
var chartConfig = await _chartService.GenerateChartConfigAsync(request.Instructions);
29+
return Json(new { config = chartConfig });
30+
}
31+
catch (Exception ex)
32+
{
33+
_logger.LogError(ex, "Error generating chart");
34+
return StatusCode(500, new { error = ex.Message });
35+
}
36+
}
37+
38+
[HttpGet]
39+
public IActionResult SmartChart()
40+
{
41+
return View();
42+
}
43+
}
44+
45+
public class ChartRequest
46+
{
47+
public string Instructions { get; set; }
48+
}
49+
}

Telerik.Examples.Mvc/Telerik.Examples.Mvc/Controllers/Chat/AiService.cs

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)