Skip to content

Commit 2e39aa3

Browse files
authored
update example
update example
2 parents 97c1ce8 + 9ee8da2 commit 2e39aa3

File tree

5 files changed

+66
-41
lines changed

5 files changed

+66
-41
lines changed

CS/ReportingApp/ReportingApp.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
<PackageReference Include="Azure.AI.OpenAI.Assistants" Version="1.0.0-beta.4" />
5252
<PackageReference Include="DevExpress.AIIntegration.OpenAI" Version="25.1.*-*" />
5353
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.11" />
54-
<PackageReference Include="Microsoft.Extensions.AI" Version="9.4.3-preview.1.25230.7" />
55-
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.4.3-preview.1.25230.7" />
54+
<PackageReference Include="Microsoft.Extensions.AI" Version="9.5.0" />
55+
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.5.0-preview.1.25265.7" />
5656
<PackageReference Include="System.Data.SQLite" Version="1.0.117" />
5757
<PackageReference Include="DevExpress.AspNetCore.Reporting" Version="25.1.*-*" />
5858
<PackageReference Include="DevExpress.AIIntegration.Web" Version="25.1.*-*" />

CS/ReportingApp/Services/AIAssistantCreator.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,29 +20,26 @@ public AIAssistantCreator(OpenAIClient client, string deployment) {
2020
this.deployment = deployment;
2121
}
2222

23-
public async Task<(string assistantId, string threadId)> CreateAssistantAsync(Stream data, string fileName, string instructions, bool useFileSearchTool = true, CancellationToken ct = default) {
23+
public async Task<(string assistantId, string threadId)> CreateAssistantAndThreadAsync(Stream data, string fileName, string instructions, CancellationToken ct = default) {
2424
data.Position = 0;
2525

2626
ClientResult<OpenAIFile> fileResponse = await fileClient.UploadFileAsync(data, fileName, FileUploadPurpose.Assistants, ct);
2727
OpenAIFile file = fileResponse.Value;
2828

2929
var resources = new ToolResources() {
3030
CodeInterpreter = new CodeInterpreterToolResources(),
31-
FileSearch = useFileSearchTool ? new FileSearchToolResources() : null
31+
FileSearch = new FileSearchToolResources()
3232
};
3333
resources.FileSearch?.NewVectorStores.Add(new VectorStoreCreationHelper([file.Id]));
3434
resources.CodeInterpreter.FileIds.Add(file.Id);
3535

3636
AssistantCreationOptions assistantCreationOptions = new AssistantCreationOptions() {
3737
Name = Guid.NewGuid().ToString(),
3838
Instructions = instructions,
39-
ToolResources = resources
39+
ToolResources = resources,
40+
Tools = { new CodeInterpreterToolDefinition(),
41+
new FileSearchToolDefinition() }
4042
};
41-
assistantCreationOptions.Tools.Add(new CodeInterpreterToolDefinition());
42-
if (useFileSearchTool) {
43-
assistantCreationOptions.Tools.Add(new FileSearchToolDefinition());
44-
}
45-
4643
ClientResult<Assistant> assistantResponse = await assistantClient.CreateAssistantAsync(deployment, assistantCreationOptions, ct);
4744
ClientResult<AssistantThread> threadResponse = await assistantClient.CreateThreadAsync(cancellationToken: ct);
4845

CS/ReportingApp/Services/AIAssistantProvider.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
using System;
1+
using DevExpress.AIIntegration.Services.Assistant;
2+
using Microsoft.AspNetCore.Hosting;
3+
using System;
24
using System.Collections.Concurrent;
35
using System.IO;
46
using System.Threading.Tasks;
5-
using Microsoft.AspNetCore.Hosting;
6-
using DevExpress.AIIntegration.Services.Assistant;
77

88
namespace ReportingApp.Services {
99
public class AIAssistantProvider : IAIAssistantProvider {
@@ -19,7 +19,7 @@ public class AIAssistantProvider : IAIAssistantProvider {
1919
private ConcurrentDictionary<string, IAIAssistant> Assistants { get; set; } = new ();
2020

2121
private async Task<string> CreateAssistant(Stream data, string fileName, string prompt) {
22-
(string assistantId, string threadId) = await assistantCreator.CreateAssistantAsync(data, fileName, prompt);
22+
(string assistantId, string threadId) = await assistantCreator.CreateAssistantAndThreadAsync(data, fileName, prompt);
2323

2424
IAIAssistant assistant = await assistantFactory.GetAssistant(assistantId, threadId);
2525
await assistant.InitializeAsync();
@@ -35,9 +35,15 @@ public AIAssistantProvider(IAIAssistantFactory assistantFactory, IWebHostEnviron
3535
this.environment = environment;
3636
this.assistantCreator = assistantCreator;
3737
}
38+
39+
// Creates a Data Analysis Assistant for Web Document Viewer.
40+
// This assistant analyzes report content and answers questions related to information within the report.
3841
public async Task<string> CreateDocumentAssistant(Stream data) {
3942
return await CreateAssistant(data, Guid.NewGuid().ToString() + ".pdf", DOCUMENT_ASSISTANT_PROMPT);
4043
}
44+
45+
// Creates a UI Asisstant for Web Report Designer.
46+
// This assistant explains how to use the Designer UI to accomplish various tasks.
4147
public async Task<string> CreateUserAssistant() {
4248
string dirPath = Path.Combine(environment.ContentRootPath, "Data");
4349
string filePath = Path.Combine(dirPath, DOCUMENTATION_FILE_NAME);

CS/ReportingApp/wwwroot/js/aiIntegration.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const createAssistantTab = (function() {
1+
const createAssistantTab = (function() {
22

33
let lastUserQuery;
44
let errorList = [];
@@ -34,11 +34,16 @@ const createAssistantTab = (function() {
3434
}
3535

3636
function normalizeAIResponse(text) {
37-
text = text.replace(/\d+:\d+[^\】]+/g, "");
38-
let html = marked.parse(text);
39-
if(/<p>\.\s*<\/p>\s*$/.test(html))
40-
html = html.replace(/<p>\.\s*<\/p>\s*$/, "")
41-
return html;
37+
if (text) {
38+
text = text.replace(/\d+:\d+[^\】]+/g, "");
39+
let html = marked.parse(text);
40+
if (/<p>\.\s*<\/p>\s*$/.test(html))
41+
html = html.replace(/<p>\.\s*<\/p>\s*$/, "")
42+
return html;
43+
}
44+
else {
45+
return "Please try again later."
46+
}
4247
}
4348

4449
function copyText(text) {

README.md

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
<!-- default badges list -->
2-
![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/853003889/25.1.3%2B)
32
[![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T1252182)
43
[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183)
54
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
@@ -18,7 +17,9 @@ The AI assistant's role depends on the associated DevExpress Reports component:
1817
> [!Note]
1918
> We use the following versions of the `Microsoft.Extensions.AI.*` libraries in our source code:
2019
>
21-
> v25.1.2+ | **9.4.3-preview.1.25230.7**
20+
> - Microsoft.Extensions.AI.Abstractions: **9.5.0**
21+
> - Microsoft.Extensions.AI: **9.5.0**
22+
> - Microsoft.Extensions.AI.OpenAI: **9.5.0-preview.1.25265.7**
2223
>
2324
> We do not guarantee compatibility or correct operation with higher versions.
2425
@@ -76,20 +77,28 @@ Files to Review:
7677

7778
#### AI Assistant Provider
7879

79-
On the server side, the `AIAssistantProvider` service manages assistants. An `IAIAssistantFactory` instance creates assistants with keys specified in previous steps.
80+
On the server side, the `AIAssistantProvider` service manages assistants.
8081

8182
```cs
8283
public interface IAIAssistantProvider {
8384
IAIAssistant GetAssistant(string assistantName);
84-
Task<string> CreateAssistant(AssistantType assistantType, Stream data);
85-
Task<string> CreateAssistant(AssistantType assistantType);
85+
Task<string> CreateDocumentAssistant(Stream data);
86+
Task<string> CreateUserAssistant();
8687
void DisposeAssistant(string assistantName);
8788
}
8889
```
8990

91+
The `AIAssistantCreator.CreateAssistantAsync` method uploads a file to OpenAI, configures tool resources, creates an assistant with specified instructions and tools, initializes a new thread, and returns the assistant and thread IDs. The generated assistant and thread IDs are then passed to the `IAIAssistantFactory.GetAssistant` method, which returns an `IAIAssistant` instance. The created instance is added to the application's assistant collection and is referenced by its unique name.
92+
93+
For information on OpenAI Assistants, refer to the following documents:
94+
- [OpenAI Assistants API overview](https://platform.openai.com/docs/assistants/overview)
95+
- [Azure OpenAI: OpenAI Assistants client library for .NET](https://learn.microsoft.com/en-us/dotnet/api/overview/azure/ai.openai.assistants-readme?view=azure-dotnet-preview)
96+
- [OpenAI .NET API library](https://github.com/openai/openai-dotnet)
97+
9098
Files to Review:
9199
- [AIAssistantProvider.cs](./CS/ReportingApp/Services/AIAssistantProvider.cs)
92100
- [IAIAssistantProvider.cs](./CS/ReportingApp/Services/IAIAssistantProvider.cs)
101+
- [AIAssistantCreator.cs](./CS/ReportingApp/Services/AIAssistantCreator.cs)
93102

94103

95104
### Web Document Viewer (Data Analysis Assistant)
@@ -132,7 +141,7 @@ On the `BeforeRender` event, add a new tab (a container for the assistant interf
132141

133142
#### Access the Assistant
134143

135-
Once the document is ready, the `DocumentReady` event handler sends a request to the server and obtains the assistant's ID:
144+
Once the document is ready, the `DocumentReady` event handler sends a request to the server and obtains the assistant name:
136145

137146
```js
138147
async function DocumentReady(sender, args) {
@@ -144,7 +153,27 @@ async function DocumentReady(sender, args) {
144153
}
145154
```
146155
147-
The [`PerformCustomDocumentOperation`](https://docs.devexpress.com/XtraReports/js-ASPxClientWebDocumentViewer?p=netframework#js_aspxclientwebdocumentviewer_performcustomdocumentoperation) method exports the report to PDF and creates an assistant based on the exported document. See [AIDocumentOperationService.cs](./CS/ReportingApp/Services/AIDocumentOperationService.cs) for implementation details.
156+
The [`PerformCustomDocumentOperation`](https://docs.devexpress.com/XtraReports/js-ASPxClientWebDocumentViewer?p=netframework#js_aspxclientwebdocumentviewer_performcustomdocumentoperation) method exports the report to PDF and creates an assistant based on the exported document:
157+
158+
```cs
159+
// ...
160+
public override async Task<DocumentOperationResponse> PerformOperationAsync(DocumentOperationRequest request, PrintingSystemBase printingSystem, PrintingSystemBase printingSystemWithEditingFields) {
161+
using(var stream = new MemoryStream()) {
162+
printingSystem.ExportToPdf(stream, printingSystem.ExportOptions.Pdf);
163+
var assistantName = await AIAssistantProvider.CreateDocumentAssistant(stream);
164+
return new DocumentOperationResponse {
165+
DocumentId = request.DocumentId,
166+
CustomData = assistantName,
167+
Succeeded = true
168+
};
169+
}
170+
}
171+
```
172+
173+
See the following files for implementation details:
174+
175+
- [AIDocumentOperationService.cs](./CS/ReportingApp/Services/AIDocumentOperationService.cs)
176+
- [AIAssistantProvider.cs](./CS/ReportingApp/Services/AIAssistantProvider.cs)
148177
149178
#### Communicate with the Assistant
150179
@@ -239,21 +268,9 @@ async function BeforeRender(sender, args) {
239268
}
240269
```
241270
242-
The `AIAssistantProvider` service creates an assistant using the provided PDF documentation (the *documentation.pdf* file):
271+
The `AIAssistantProvider.CreateUserAssistant` method creates an assistant using the *documentation.pdf* file ([end-user documentation for Web Reporting Controls](https://github.com/DevExpress/dotnet-eud) in the PDF format) and the specified prompt. See the [AIAssistantProvider.cs](./CS/ReportingApp/Services/AIAssistantProvider.cs) file for implementation details.
272+
243273
244-
```cs
245-
// ...
246-
public async Task<string> CreateAssistant(AssistantType assistantType, Stream data) {
247-
var assistantName = Guid.NewGuid().ToString();
248-
var assistant = await assistantFactory.CreateAssistant(assistantName);
249-
Assistants.TryAdd(assistantName, assistant);
250-
var prompt = GetPrompt(assistantType);
251-
if(assistantType == AssistantType.UserAssistant) {
252-
await LoadDocumentation(assistant, prompt);
253-
}
254-
return assistantName;
255-
}
256-
```
257274
#### Communicate with the Assistant
258275
259276
Each time a user sends a message, the [`onMessageEntered`](https://js.devexpress.com/jQuery/Documentation/24_2/ApiReference/UI_Components/dxChat/Configuration/#onMessageEntered) event handler passes the request to the assistant:

0 commit comments

Comments
 (0)