@@ -30,21 +30,229 @@ To enable a custom AI client implementation, follow these steps:
3030
3131 The following example demonstrates an Azure OpenAI integration for illustration purposes, though you can use any LLM provider:
3232
33- >caption .NET
34- {{source=CodeSnippets\Blazor\Docs\CustomAiClient.cs region=Enabling_Custom_AI_Client}}
35- >caption .NET Framework
36- {{source=CodeSnippets\CS\API\Telerik\Reporting\AI\CustomAIClient.cs region=custom_client_integration_ai_insights_Snippet}}
33+ ```C# .NET
34+ using Azure.AI.OpenAI;
35+ using Microsoft.Extensions.AI;
36+ using System.ClientModel;
37+ using Telerik.Reporting.AI;
38+
39+ namespace WebApplication1.AI;
40+
41+ public class CustomAIClient : IClient
42+ {
43+ public string Model { get; } = "gpt-4o-mini";
44+
45+ public bool SupportsSystemPrompts => false;
46+
47+ private readonly IChatClient chatClient;
48+
49+ public CustomAIClient()
50+ {
51+ string endpoint = "https://ai-explorations.openai.azure.com/";
52+ string credential = "YOUR_API_KEY";
53+ string model = "gpt-4o-mini";
54+
55+ chatClient = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(credential))
56+ .GetChatClient(model)
57+ .AsIChatClient();
58+ }
59+
60+ public async Task<IReadOnlyCollection<IMessage>> GetResponseAsync(IReadOnlyCollection<IMessage> query, CancellationToken cancellationToken)
61+ {
62+ // Convert Telerik.Reporting.AI IMessage to Microsoft.Extensions.AI ChatMessage
63+ var chatMessages = new List<ChatMessage>();
64+ foreach (var message in query)
65+ {
66+ ChatRole chatRole = message.Role switch
67+ {
68+ MessageRole.System => ChatRole.System,
69+ MessageRole.Assistant => ChatRole.Assistant,
70+ MessageRole.User => ChatRole.User,
71+ _ => throw new ArgumentException($"Invalid MessageRole: {message.Role}")
72+ };
73+
74+ // Convert text contents from Telerik.Reporting.AI TO Microsoft.Extensions.AI
75+ var textContents = message.Contents
76+ .OfType<Telerik.Reporting.AI.TextContent>()
77+ .Select(textContent => new Microsoft.Extensions.AI.TextContent(textContent.Text))
78+ .Cast<AIContent>()
79+ .ToList();
80+
81+ chatMessages.Add(new ChatMessage(chatRole, textContents));
82+ }
83+
84+ // Call Azure OpenAI
85+ var response = await chatClient.GetResponseAsync(chatMessages, new ChatOptions(), cancellationToken);
86+
87+ // Convert response back to Telerik.Reporting.AI IMessage
88+ var resultMessages = new List<IMessage>();
89+ foreach (var responseMessage in response.Messages)
90+ {
91+ MessageRole messageRole = responseMessage.Role.Value switch
92+ {
93+ "system" => MessageRole.System,
94+ "assistant" => MessageRole.Assistant,
95+ "user" => MessageRole.User,
96+ _ => throw new ArgumentException($"Invalid ChatRole: {responseMessage.Role}")
97+ };
98+
99+ // Convert back to Telerik.Reporting.AI content
100+ var contents = responseMessage.Contents
101+ .OfType<Microsoft.Extensions.AI.TextContent>()
102+ .Select(tc => new Telerik.Reporting.AI.TextContent(tc.Text))
103+ .Cast<IContent>()
104+ .ToList();
105+
106+ resultMessages.Add(new Message(messageRole, contents));
107+ }
108+
109+ return resultMessages;
110+ }
111+
112+ public static IClient GetCustomAIClient()
113+ {
114+ return new CustomAIClient();
115+ }
116+ }
117+ ```
118+ ```C# .NET Framework
119+ using Azure.AI.OpenAI;
120+ using Microsoft.Extensions.AI;
121+ using System;
122+ using System.ClientModel;
123+ using System.Collections.Generic;
124+ using System.Linq;
125+ using System.Threading;
126+ using System.Threading.Tasks;
127+ using Telerik.Reporting.AI;
128+
129+ namespace WebApplication1.AI
130+ {
131+ public class CustomAIClient : IClient
132+ {
133+ public string Model { get; } = "gpt-4o-mini";
134+
135+ public bool SupportsSystemPrompts => false;
136+
137+ private readonly IChatClient chatClient;
138+
139+ public CustomAIClient()
140+ {
141+ string endpoint = "https://ai-explorations.openai.azure.com/";
142+ string credential = "YOUR_API_KEY";
143+ string model = "gpt-4o-mini";
144+
145+ chatClient = new AzureOpenAIClient(new Uri(endpoint), new ApiKeyCredential(credential))
146+ .GetChatClient(model)
147+ .AsIChatClient();
148+ }
149+
150+ public async Task<IReadOnlyCollection<Telerik.Reporting.AI.IMessage>> GetResponseAsync(IReadOnlyCollection<Telerik.Reporting.AI.IMessage> query, CancellationToken cancellationToken)
151+ {
152+ // Convert Telerik.Reporting.AI IMessage to Microsoft.Extensions.AI ChatMessage
153+ var chatMessages = new List<ChatMessage>();
154+ foreach (var message in query)
155+ {
156+ ChatRole chatRole;
157+ switch (message.Role)
158+ {
159+ case MessageRole.System:
160+ chatRole = ChatRole.System;
161+ break;
162+ case MessageRole.Assistant:
163+ chatRole = ChatRole.Assistant;
164+ break;
165+ case MessageRole.User:
166+ chatRole = ChatRole.User;
167+ break;
168+ default:
169+ throw new ArgumentException($"Invalid MessageRole: {message.Role}");
170+ }
171+
172+ // Convert text contents from Telerik.Reporting.AI TO Microsoft.Extensions.AI
173+ var textContents = message.Contents
174+ .OfType<Telerik.Reporting.AI.TextContent>()
175+ .Select(textContent => new Microsoft.Extensions.AI.TextContent(textContent.Text))
176+ .Cast<AIContent>()
177+ .ToList();
178+
179+ chatMessages.Add(new ChatMessage(chatRole, textContents));
180+ }
181+
182+ // Call Azure OpenAI
183+ var response = await chatClient.GetResponseAsync(chatMessages, new ChatOptions(), cancellationToken);
184+
185+ // Convert response back to Telerik.Reporting.AI IMessage
186+ var resultMessages = new List<Telerik.Reporting.AI.IMessage>();
187+ foreach (var responseMessage in response.Messages)
188+ {
189+ MessageRole messageRole;
190+ switch (responseMessage.Role.Value)
191+ {
192+ case "system":
193+ messageRole = MessageRole.System;
194+ break;
195+ case "assistant":
196+ messageRole = MessageRole.Assistant;
197+ break;
198+ case "user":
199+ messageRole = MessageRole.User;
200+ break;
201+ default:
202+ throw new ArgumentException($"Invalid ChatRole: {responseMessage.Role}");
203+ }
204+
205+ // Convert back to Telerik.Reporting.AI content
206+ var contents = responseMessage.Contents
207+ .OfType<Microsoft.Extensions.AI.TextContent>()
208+ .Select(tc => new Telerik.Reporting.AI.TextContent(tc.Text))
209+ .Cast<IContent>()
210+ .ToList();
211+
212+ resultMessages.Add(new Telerik.Reporting.AI.Message(messageRole, contents));
213+ }
214+
215+ return resultMessages;
216+ }
217+
218+ public static IClient GetCustomAIClient()
219+ {
220+ return new CustomAIClient();
221+ }
222+ }
223+ }
224+ ```
37225
38226 > This Azure OpenAI example uses `Azure.AI.OpenAI` version `2.2.0-beta.4` and `Microsoft.Extensions.AI.OpenAI` version `9.4.3-preview.1.25230.7` for demonstration purposes.
39227 >
40228 > For your implementation, you will typically use different packages specific to your LLM provider. Focus on the implementation structure, which is further detailed in the [Understanding the IClient Interface](#understanding-the-iclient-interface) section.
41229
422301 . Register the custom client in your ` ReportServiceConfiguration ` :
43231
44- >caption .NET
45- {{source=CodeSnippets\Blazor\Docs\ProgramWithRestConfig.cs region=custom_client_integration_ai_insights_Snippet_2}}
46- >caption .NET Framework
47- {{source=CodeSnippets\MvcCS\Controllers\CustomResolverReportsController.cs region=custom_client_integration_ai_insights_Snippet_3}}
232+ ```C# .NET
233+ builder.Services.TryAddSingleton<IReportServiceConfiguration>(sp => new ReportServiceConfiguration
234+ {
235+ HostAppId = "MyApp",
236+ AIClientFactory = WebApplication1.AI.CustomAIClient.GetCustomAIClient,
237+ // ...
238+ });
239+ ```
240+ ```C# .NET Framework
241+ public class CustomResolverReportsController : ReportsControllerBase
242+ {
243+ static ReportServiceConfiguration configurationInstance;
244+
245+ static CustomResolverReportsController()
246+ {
247+ configurationInstance = new ReportServiceConfiguration
248+ {
249+ HostAppId = "MyApp",
250+ AIClientFactory = WebApplication1.AI.CustomAIClient.GetCustomAIClient,
251+ // ...
252+ };
253+ }
254+ }
255+ ```
48256
49257You can further customize the AI client to enable additional features like RAG optimization, predefined prompts, and user consent settings.
50258
0 commit comments