Skip to content

Commit 768d759

Browse files
committed
update example
1 parent 1674935 commit 768d759

File tree

5 files changed

+64
-41
lines changed

5 files changed

+64
-41
lines changed

CS/ReportingApp/ReportingApp.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,11 @@
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.*-*" />
58-
<PackageReference Include="DevExpress.AIIntegration.Web" Version="25.1.*-*" />
58+
<PackageReference Include="DevExpress.AIIntegration.Web" Version="25.1.*-*" />
5959
<PackageReference Include="DevExpress.Drawing.Skia" Version="25.1.*-*" />
6060
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" />
6161
<PackageReference Include="Microsoft.Web.LibraryManager.Build" Version="2.1.175" />

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: 8 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,13 @@ 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+
}
4244
}
4345

4446
function copyText(text) {

README.md

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ The AI assistant's role depends on the associated DevExpress Reports component:
1818
> [!Note]
1919
> We use the following versions of the `Microsoft.Extensions.AI.*` libraries in our source code:
2020
>
21-
> v25.1.2+ | **9.4.3-preview.1.25230.7**
21+
> - Microsoft.Extensions.AI.Abstractions: **9.5.0**
22+
> - Microsoft.Extensions.AI: **9.5.0**
23+
> - Microsoft.Extensions.AI.OpenAI: **9.5.0-preview.1.25265.7**
2224
>
2325
> We do not guarantee compatibility or correct operation with higher versions.
2426
@@ -76,20 +78,28 @@ Files to Review:
7678

7779
#### AI Assistant Provider
7880

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

8183
```cs
8284
public interface IAIAssistantProvider {
8385
IAIAssistant GetAssistant(string assistantName);
84-
Task<string> CreateAssistant(AssistantType assistantType, Stream data);
85-
Task<string> CreateAssistant(AssistantType assistantType);
86+
Task<string> CreateDocumentAssistant(Stream data);
87+
Task<string> CreateUserAssistant();
8688
void DisposeAssistant(string assistantName);
8789
}
8890
```
8991

92+
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.
93+
94+
For information on OpenAI Assistants, refer to the following documents:
95+
- [OpenAI Assistants API overview](https://platform.openai.com/docs/assistants/overview)
96+
- [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)
97+
- [OpenAI .NET API library](https://github.com/openai/openai-dotnet)
98+
9099
Files to Review:
91100
- [AIAssistantProvider.cs](./CS/ReportingApp/Services/AIAssistantProvider.cs)
92101
- [IAIAssistantProvider.cs](./CS/ReportingApp/Services/IAIAssistantProvider.cs)
102+
- [AIAssistantCreator.cs](./CS/ReportingApp/Services/AIAssistantCreator.cs)
93103

94104

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

133143
#### Access the Assistant
134144

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

137147
```js
138148
async function DocumentReady(sender, args) {
@@ -144,7 +154,27 @@ async function DocumentReady(sender, args) {
144154
}
145155
```
146156
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.
157+
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:
158+
159+
```cs
160+
// ...
161+
public override async Task<DocumentOperationResponse> PerformOperationAsync(DocumentOperationRequest request, PrintingSystemBase printingSystem, PrintingSystemBase printingSystemWithEditingFields) {
162+
using(var stream = new MemoryStream()) {
163+
printingSystem.ExportToPdf(stream, printingSystem.ExportOptions.Pdf);
164+
var assistantName = await AIAssistantProvider.CreateDocumentAssistant(stream);
165+
return new DocumentOperationResponse {
166+
DocumentId = request.DocumentId,
167+
CustomData = assistantName,
168+
Succeeded = true
169+
};
170+
}
171+
}
172+
```
173+
174+
See the following files for implementation details:
175+
176+
- [AIDocumentOperationService.cs](./CS/ReportingApp/Services/AIDocumentOperationService.cs)
177+
- [AIAssistantProvider.cs](./CS/ReportingApp/Services/AIAssistantProvider.cs)
148178
149179
#### Communicate with the Assistant
150180
@@ -239,21 +269,9 @@ async function BeforeRender(sender, args) {
239269
}
240270
```
241271
242-
The `AIAssistantProvider` service creates an assistant using the provided PDF documentation (the *documentation.pdf* file):
272+
The `AIAssistantProvider.CreateUserAssistant` method creates an assistant using the provided PDF documentation (the *documentation.pdf* file) and prompt. See the [AIAssistantProvider.cs](./CS/ReportingApp/Services/AIAssistantProvider.cs) file for implementation details.
273+
243274
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-
```
257275
#### Communicate with the Assistant
258276
259277
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)