Skip to content

Commit 1674935

Browse files
authored
Example updated according to assistant reuse API changes
1 parent c9cb946 commit 1674935

File tree

6 files changed

+92
-47
lines changed

6 files changed

+92
-47
lines changed

CS/ReportingApp/Controllers/AIController.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ public AIController(IAIAssistantProvider assistantProvider) {
1111
}
1212

1313
public async Task<string> CreateUserAssistant() {
14-
var assistantName = await AIAssistantProvider.CreateAssistant(AssistantType.UserAssistant);
15-
return assistantName;
14+
return await AIAssistantProvider.CreateUserAssistant();
1615
}
1716

1817
public async Task<string> GetAnswer([FromForm] string chatId, [FromForm] string text) {

CS/ReportingApp/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@
4444

4545
var chatClient = azureOpenAIClient.GetChatClient(EnvSettings.DeploymentName).AsIChatClient;
4646

47+
var assistantCreator = new AIAssistantCreator(azureOpenAIClient, EnvSettings.DeploymentName);
48+
4749
builder.Services.AddSingleton(chatClient);
50+
builder.Services.AddSingleton(assistantCreator);
4851
builder.Services.AddSingleton<IAIAssistantProvider, AIAssistantProvider>();
4952
builder.Services.AddDevExpressAI(config =>
5053
{
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.ClientModel;
3+
using System.IO;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using OpenAI;
7+
using OpenAI.Assistants;
8+
using OpenAI.Files;
9+
10+
namespace ReportingApp.Services {
11+
#pragma warning disable OPENAI001
12+
public class AIAssistantCreator {
13+
readonly AssistantClient assistantClient;
14+
readonly OpenAIFileClient fileClient;
15+
readonly string deployment;
16+
17+
public AIAssistantCreator(OpenAIClient client, string deployment) {
18+
assistantClient = client.GetAssistantClient();
19+
fileClient = client.GetOpenAIFileClient();
20+
this.deployment = deployment;
21+
}
22+
23+
public async Task<(string assistantId, string threadId)> CreateAssistantAsync(Stream data, string fileName, string instructions, bool useFileSearchTool = true, CancellationToken ct = default) {
24+
data.Position = 0;
25+
26+
ClientResult<OpenAIFile> fileResponse = await fileClient.UploadFileAsync(data, fileName, FileUploadPurpose.Assistants, ct);
27+
OpenAIFile file = fileResponse.Value;
28+
29+
var resources = new ToolResources() {
30+
CodeInterpreter = new CodeInterpreterToolResources(),
31+
FileSearch = useFileSearchTool ? new FileSearchToolResources() : null
32+
};
33+
resources.FileSearch?.NewVectorStores.Add(new VectorStoreCreationHelper([file.Id]));
34+
resources.CodeInterpreter.FileIds.Add(file.Id);
35+
36+
AssistantCreationOptions assistantCreationOptions = new AssistantCreationOptions() {
37+
Name = Guid.NewGuid().ToString(),
38+
Instructions = instructions,
39+
ToolResources = resources
40+
};
41+
assistantCreationOptions.Tools.Add(new CodeInterpreterToolDefinition());
42+
if (useFileSearchTool) {
43+
assistantCreationOptions.Tools.Add(new FileSearchToolDefinition());
44+
}
45+
46+
ClientResult<Assistant> assistantResponse = await assistantClient.CreateAssistantAsync(deployment, assistantCreationOptions, ct);
47+
ClientResult<AssistantThread> threadResponse = await assistantClient.CreateThreadAsync(cancellationToken: ct);
48+
49+
return (assistantResponse.Value.Id, threadResponse.Value.Id);
50+
}
51+
}
52+
#pragma warning restore OPENAI001
53+
}

CS/ReportingApp/Services/AIAssistantProvider.cs

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,68 +2,62 @@
22
using System.Collections.Concurrent;
33
using System.IO;
44
using System.Threading.Tasks;
5-
using DevExpress.AIIntegration.OpenAI.Services;
6-
using DevExpress.AIIntegration.Services.Assistant;
75
using Microsoft.AspNetCore.Hosting;
6+
using DevExpress.AIIntegration.Services.Assistant;
87

98
namespace ReportingApp.Services {
109
public class AIAssistantProvider : IAIAssistantProvider {
10+
const string ASSISTANT_NOT_FOUND_ERROR = "Assistant not found";
11+
const string DOCUMENTATION_FILE_NAME = "documentation.pdf";
12+
const string DOCUMENT_ASSISTANT_PROMPT = "You are a data analysis assistant. Your task is to read information from PDF files and provide users with accurate data-driven answers based on the contents of these files. \n Key Responsibilities: \n - Perform data analysis, including data summaries, calculations, filtering, and trend identification.\n - Clearly explain your analysis process to ensure users understand how you reached your conclusions.\n - Provide precise and accurate responses strictly based on data in the file.\n - If the requested information is not available in the provided file's content, state: \"The requested information cannot be found in the data provided.\"\n - Avoid giving responses when data is insufficient for a reliable answer.\n - Ask clarifying questions when a user’s query is unclear or lacks detail.\n - Your primary goal is to deliver helpful insights that directly address user questions. Do not make assumptions or infer details not supported by data. Respond in plain text only, without sources, footnotes, or annotations.\n Avoid giving information about provided file name, assistants' IDs and other internal data";
13+
const string USER_ASSISTANT_PROMPT = "You are a user interface assistant (you help people use a software program). Your role is to read information from documentation files in PDF format. You assist users by providing accurate answers to their questions based on information from these files. \r\n\r\nTasks:\r\nExtract relevant information from PDF documentation to answer user questions.\r\nClearly explain your reasoning process and give step by step solutions to ensure users understand how you arrived at your answers.\r\nAlways provide precise and accurate information based on content from the documentation file.\r\nIf you cannot find an answer based on provided documentation, explicitly state: 'The requested information cannot be found in documentation provided.'\r\n Respond in plain text only, without markdown, sources, footnotes, or annotations.";
14+
1115
private readonly IAIAssistantFactory assistantFactory;
1216
private readonly IWebHostEnvironment environment;
17+
private readonly AIAssistantCreator assistantCreator;
1318

1419
private ConcurrentDictionary<string, IAIAssistant> Assistants { get; set; } = new ();
15-
public AIAssistantProvider(IAIAssistantFactory assistantFactory, IWebHostEnvironment environment) {
20+
21+
private async Task<string> CreateAssistant(Stream data, string fileName, string prompt) {
22+
(string assistantId, string threadId) = await assistantCreator.CreateAssistantAsync(data, fileName, prompt);
23+
24+
IAIAssistant assistant = await assistantFactory.GetAssistant(assistantId, threadId);
25+
await assistant.InitializeAsync();
26+
27+
string assistantName = Guid.NewGuid().ToString();
28+
Assistants.TryAdd(assistantName, assistant);
29+
30+
return assistantName;
31+
}
32+
33+
public AIAssistantProvider(IAIAssistantFactory assistantFactory, IWebHostEnvironment environment, AIAssistantCreator assistantCreator) {
1634
this.assistantFactory = assistantFactory;
1735
this.environment = environment;
36+
this.assistantCreator = assistantCreator;
1837
}
19-
async Task LoadDocumentation(IAIAssistant assistant, string prompt) {
20-
var dirPath = Path.Combine(environment.ContentRootPath, "Data");
21-
var filePath = Path.Combine(dirPath, "documentation.pdf");
22-
23-
using(FileStream stream = File.OpenRead(filePath)) {
24-
await assistant.InitializeAsync(new OpenAIAssistantOptions("documentation.pdf", stream, prompt));
25-
}
38+
public async Task<string> CreateDocumentAssistant(Stream data) {
39+
return await CreateAssistant(data, Guid.NewGuid().ToString() + ".pdf", DOCUMENT_ASSISTANT_PROMPT);
2640
}
27-
string GetPrompt(AssistantType assistantType) {
28-
switch(assistantType) {
29-
case AssistantType.UserAssistant:
30-
return "You are a user interface assistant (you help people use a software program). Your role is to read information from documentation files in PDF format. You assist users by providing accurate answers to their questions based on information from these files. \r\n\r\nTasks:\r\nExtract relevant information from PDF documentation to answer user questions.\r\nClearly explain your reasoning process and give step by step solutions to ensure users understand how you arrived at your answers.\r\nAlways provide precise and accurate information based on content from the documentation file.\r\nIf you cannot find an answer based on provided documentation, explicitly state: 'The requested information cannot be found in documentation provided.'\r\n Respond in plain text only, without markdown, sources, footnotes, or annotations.";
31-
case AssistantType.DocumentAssistant:
32-
return "You are a data analysis assistant. Your task is to read information from PDF files and provide users with accurate data-driven answers based on the contents of these files. \n Key Responsibilities: \n - Perform data analysis, including data summaries, calculations, filtering, and trend identification.\n - Clearly explain your analysis process to ensure users understand how you reached your conclusions.\n - Provide precise and accurate responses strictly based on data in the file.\n - If the requested information is not available in the provided file's content, state: \"The requested information cannot be found in the data provided.\"\n - Avoid giving responses when data is insufficient for a reliable answer.\n - Ask clarifying questions when a user’s query is unclear or lacks detail.\n - Your primary goal is to deliver helpful insights that directly address user questions. Do not make assumptions or infer details not supported by data. Respond in plain text only, without sources, footnotes, or annotations.\n Avoid giving information about provided file name, assistants' IDs and other internal data";
33-
default:
34-
return "";
35-
}
41+
public async Task<string> CreateUserAssistant() {
42+
string dirPath = Path.Combine(environment.ContentRootPath, "Data");
43+
string filePath = Path.Combine(dirPath, DOCUMENTATION_FILE_NAME);
44+
45+
using (FileStream stream = File.OpenRead(filePath))
46+
return await CreateAssistant(stream, DOCUMENTATION_FILE_NAME, USER_ASSISTANT_PROMPT);
3647
}
3748
public void DisposeAssistant(string assistantName) {
3849
if(Assistants.TryRemove(assistantName, out IAIAssistant assistant)) {
3950
assistant.Dispose();
4051
} else {
41-
throw new Exception("Assistant not found");
52+
throw new Exception(ASSISTANT_NOT_FOUND_ERROR);
4253
}
4354
}
4455
public IAIAssistant GetAssistant(string assistantName) {
4556
if(!string.IsNullOrEmpty(assistantName) && Assistants.TryGetValue(assistantName, out var assistant)) {
4657
return assistant;
4758
} else {
48-
throw new Exception("Assistant not found");
59+
throw new Exception(ASSISTANT_NOT_FOUND_ERROR);
4960
}
5061
}
51-
public async Task<string> CreateAssistant(AssistantType assistantType, Stream data) {
52-
var assistantName = Guid.NewGuid().ToString();
53-
var assistant = await assistantFactory.CreateAssistant(assistantName);
54-
Assistants.TryAdd(assistantName, assistant);
55-
56-
var prompt = GetPrompt(assistantType);
57-
if(assistantType == AssistantType.UserAssistant) {
58-
await LoadDocumentation(assistant, prompt);
59-
} else {
60-
await assistant.InitializeAsync(new OpenAIAssistantOptions(Guid.NewGuid().ToString() + ".pdf", data, prompt));
61-
}
62-
return assistantName;
63-
}
64-
65-
public Task<string> CreateAssistant(AssistantType assistantType) {
66-
return CreateAssistant(assistantType, null);
67-
}
6862
}
6963
}

CS/ReportingApp/Services/AIDocumentOperationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public override bool CanPerformOperation(DocumentOperationRequest request) {
1818
public override async Task<DocumentOperationResponse> PerformOperationAsync(DocumentOperationRequest request, PrintingSystemBase printingSystem, PrintingSystemBase printingSystemWithEditingFields) {
1919
using(var stream = new MemoryStream()) {
2020
printingSystem.ExportToPdf(stream, printingSystem.ExportOptions.Pdf);
21-
var assistantName = await AIAssistantProvider.CreateAssistant(AssistantType.DocumentAssistant, stream);
21+
var assistantName = await AIAssistantProvider.CreateDocumentAssistant(stream);
2222
return new DocumentOperationResponse {
2323
DocumentId = request.DocumentId,
2424
CustomData = assistantName,

CS/ReportingApp/Services/IAIAssistantProvider.cs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,10 @@
33
using System.Threading.Tasks;
44

55
namespace ReportingApp.Services {
6-
public enum AssistantType {
7-
DocumentAssistant,
8-
UserAssistant
9-
}
106
public interface IAIAssistantProvider {
117
IAIAssistant GetAssistant(string assistantName);
12-
Task<string> CreateAssistant(AssistantType assistantType, Stream data);
13-
Task<string> CreateAssistant(AssistantType assistantType);
8+
Task<string> CreateDocumentAssistant(Stream data);
9+
Task<string> CreateUserAssistant();
1410
void DisposeAssistant(string assistantName);
1511
}
1612
}

0 commit comments

Comments
 (0)