From adfdefa98a1f175ad32261d39e40294b1865336d Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 17 Jul 2024 13:31:09 -0500 Subject: [PATCH 1/4] extend email with attachments --- .../BotSharp.Plugin.EmailHandler.csproj | 4 + .../Functions/HandleEmailRequestFn.cs | 107 +++++++++++++++--- .../LlmContexts/LlmContextIn.cs | 28 +++-- .../BotSharp.Plugin.EmailHandler/Using.cs | 23 +++- .../functions/handle_email_request.json | 6 +- .../templates/email_attachment_prompt.liquid | 20 ++++ .../templates/handle_email_request.fn.liquid | 1 + 7 files changed, 151 insertions(+), 38 deletions(-) create mode 100644 src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/email_attachment_prompt.liquid diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/BotSharp.Plugin.EmailHandler.csproj b/src/Plugins/BotSharp.Plugin.EmailHandler/BotSharp.Plugin.EmailHandler.csproj index f5995e96d..d577a232b 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/BotSharp.Plugin.EmailHandler.csproj +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/BotSharp.Plugin.EmailHandler.csproj @@ -12,6 +12,7 @@ + @@ -22,6 +23,9 @@ PreserveNewest + + PreserveNewest + diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs b/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs index 731e338b2..82c1010af 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs @@ -1,12 +1,7 @@ -using BotSharp.Abstraction.Email.Settings; -using BotSharp.Plugin.EmailHandler.LlmContexts; -using MailKit; using MailKit.Net.Smtp; using MailKit.Security; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; using MimeKit; -using System.Net.Http; +using System.IO; namespace BotSharp.Plugin.EmailHandler.Functions; @@ -22,12 +17,13 @@ public class HandleEmailRequestFn : IFunctionCallback private readonly BotSharpOptions _options; private readonly EmailHandlerSettings _emailSettings; - public HandleEmailRequestFn(IServiceProvider services, - ILogger logger, - IHttpClientFactory httpClientFactory, - IHttpContextAccessor context, - BotSharpOptions options, - EmailHandlerSettings emailPluginSettings) + public HandleEmailRequestFn( + IServiceProvider services, + ILogger logger, + IHttpClientFactory httpClientFactory, + IHttpContextAccessor context, + BotSharpOptions options, + EmailHandlerSettings emailPluginSettings) { _services = services; _logger = logger; @@ -42,6 +38,8 @@ public async Task Execute(RoleDialogModel message) var recipient = args?.ToAddress; var body = args?.Content; var subject = args?.Subject; + var isNeedAttachments = args?.IsNeedAttachemnts ?? false; + var bodyBuilder = new BodyBuilder(); try { @@ -49,13 +47,19 @@ public async Task Execute(RoleDialogModel message) mailMessage.From.Add(new MailboxAddress(_emailSettings.Name, _emailSettings.EmailAddress)); mailMessage.To.Add(new MailboxAddress("", recipient)); mailMessage.Subject = subject; - mailMessage.Body = new TextPart("plain") + bodyBuilder.TextBody = body; + + if (isNeedAttachments) { - Text = body - }; + var files = await GetConversationFiles(); + BuildEmailAttachments(bodyBuilder, files); + } + + mailMessage.Body = bodyBuilder.ToMessageBody(); var response = await HandleSendEmailBySMTP(mailMessage); - _logger.LogWarning($"Email successfully send over to {recipient}. Email Subject: {subject} [{response}]"); message.Content = response; + + _logger.LogWarning($"Email successfully send over to {recipient}. Email Subject: {subject} [{response}]"); return true; } catch (Exception ex) @@ -67,7 +71,76 @@ public async Task Execute(RoleDialogModel message) } } - public async Task HandleSendEmailBySMTP(MimeMessage mailMessage) + private async Task> GetConversationFiles() + { + var convService = _services.GetService(); + var fileService = _services.GetRequiredService(); + var conversationId = convService.ConversationId; + var dialogs = convService.GetDialogHistory(fromBreakpoint: false); + var messageIds = dialogs.Select(x => x.MessageId).Distinct().ToList(); + var files = fileService.GetMessageFiles(conversationId, messageIds, FileSourceType.User); + return await SelectFiles(files, dialogs); + } + + private async Task> SelectFiles(IEnumerable files, List dialogs) + { + if (files.IsNullOrEmpty()) return new List(); + + var llmProviderService = _services.GetRequiredService(); + var render = _services.GetRequiredService(); + var db = _services.GetRequiredService(); + + try + { + var promptFiles = files.Select((x, idx) => + { + return $"id: {idx + 1}, file_name: {x.FileName}.{x.FileType}, content_type: {x.ContentType}"; + }).ToList(); + var prompt = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, "email_attachment_prompt"); + prompt = render.Render(prompt, new Dictionary + { + { "file_list", promptFiles } + }); + + var agent = new Agent + { + Id = BuiltInAgentId.UtilityAssistant, + Name = "Utility Assistant", + Instruction = prompt + }; + + var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == "openai"); + var model = llmProviderService.GetProviderModel(provider: provider, id: "gpt-4", multiModal: true); + var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name); + var response = await completion.GetChatCompletions(agent, dialogs); + var content = response?.Content ?? string.Empty; + var fids = JsonSerializer.Deserialize>(content) ?? new List(); + return files.Where((x, idx) => fids.Contains(idx + 1)).ToList(); + } + catch (Exception ex) + { + _logger.LogWarning($"Error when getting the email file response. {ex.Message}\r\n{ex.InnerException}"); + return new List(); + } + } + + private void BuildEmailAttachments(BodyBuilder builder, IEnumerable files) + { + if (files.IsNullOrEmpty()) return; + + foreach (var file in files) + { + if (string.IsNullOrEmpty(file.FileStorageUrl)) continue; + + using var fs = File.OpenRead(file.FileStorageUrl); + var binary = BinaryData.FromStream(fs); + builder.Attachments.Add($"{file.FileName}.{file.FileType}", binary.ToArray(), ContentType.Parse(file.ContentType)); + fs.Close(); + Thread.Sleep(100); + } + } + + private async Task HandleSendEmailBySMTP(MimeMessage mailMessage) { using var smtpClient = new SmtpClient(); await smtpClient.ConnectAsync(_emailSettings.SMTPServer, _emailSettings.SMTPPort, SecureSocketOptions.StartTls); diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/LlmContexts/LlmContextIn.cs b/src/Plugins/BotSharp.Plugin.EmailHandler/LlmContexts/LlmContextIn.cs index a5231c963..ce040597b 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/LlmContexts/LlmContextIn.cs +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/LlmContexts/LlmContextIn.cs @@ -1,20 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Text.Json.Serialization; -using System.Threading.Tasks; -namespace BotSharp.Plugin.EmailHandler.LlmContexts +namespace BotSharp.Plugin.EmailHandler.LlmContexts; + +public class LlmContextIn { - public class LlmContextIn - { - [JsonPropertyName("to_address")] - public string? ToAddress { get; set; } + [JsonPropertyName("to_address")] + public string? ToAddress { get; set; } + + [JsonPropertyName("email_content")] + public string? Content { get; set; } + + [JsonPropertyName("subject")] + public string? Subject { get; set; } - [JsonPropertyName("email_content")] - public string? Content { get; set; } - [JsonPropertyName("subject")] - public string? Subject { get; set; } - } + [JsonPropertyName("is_need_attachments")] + public bool IsNeedAttachemnts { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/Using.cs b/src/Plugins/BotSharp.Plugin.EmailHandler/Using.cs index 80d160dd5..d63748ab5 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/Using.cs +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/Using.cs @@ -1,18 +1,31 @@ global using System; global using System.Collections.Generic; global using System.Text; +global using System.Linq; +global using System.Text.Json; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; +global using Microsoft.AspNetCore.Http; +global using Microsoft.Extensions.Logging; +global using Microsoft.Extensions.DependencyInjection; global using BotSharp.Abstraction.Conversations; global using BotSharp.Abstraction.Plugins; -global using System.Text.Json; global using BotSharp.Abstraction.Conversations.Models; -global using System.Threading.Tasks; global using BotSharp.Abstraction.Functions; global using BotSharp.Abstraction.Agents.Models; global using BotSharp.Abstraction.Templating; -global using Microsoft.Extensions.DependencyInjection; -global using System.Linq; global using BotSharp.Abstraction.Utilities; global using BotSharp.Abstraction.Messaging; global using BotSharp.Abstraction.Messaging.Models.RichContent; global using BotSharp.Abstraction.Options; -global using BotSharp.Abstraction.Messaging.Enums; \ No newline at end of file +global using BotSharp.Abstraction.Messaging.Enums; +global using BotSharp.Abstraction.Agents.Enums; +global using BotSharp.Abstraction.Email.Settings; +global using BotSharp.Abstraction.Files; +global using BotSharp.Abstraction.Files.Enums; +global using BotSharp.Abstraction.Files.Models; +global using BotSharp.Abstraction.MLTasks; +global using BotSharp.Abstraction.Repositories; +global using BotSharp.Core.Infrastructures; +global using BotSharp.Plugin.EmailHandler.LlmContexts; \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json index e59a2150f..25bb874b6 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json @@ -15,8 +15,12 @@ "subject": { "type": "string", "description": "The subject of the email which needs to be send over." + }, + "is_need_attachments": { + "type": "boolean", + "description": "If the user request to send email with attachemnts, then this value should be true. Otherwise, this value should be false." } }, - "required": [ "to_address", "email_content", "subject" ] + "required": [ "to_address", "email_content", "subject", "is_need_attachments" ] } } \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/email_attachment_prompt.liquid b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/email_attachment_prompt.liquid new file mode 100644 index 000000000..0b1b87c3e --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/email_attachment_prompt.liquid @@ -0,0 +1,20 @@ +Please take a look at the files in the [FILES] section from the conversation and select the files based on the conversation with user. +Your response must be a list of file ids. +** Please only output the list. Do not prepend or append anything. + +For example: +Suppose there are three files: + +id: 1, file_name: example_file.png, content_type: image/png +id: 2, file_name: example_file.jpeg, content_type: image/jpeg +id: 3, file_name: example_file.pdf, content_type: application/pdf + +If user wants the first file and the third file, the ouput should be [1, 3]. +If user wants the all the images, the output should be [1, 2]. +If user wants the pdf file, the output should be [3]. +If user does not want any files, the ouput should be []; + +[FILES] +{% for file in file_list -%} +{{ file }}{{ "\r\n" }} +{%- endfor %} \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/handle_email_request.fn.liquid b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/handle_email_request.fn.liquid index 01163ab5f..72c8da303 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/handle_email_request.fn.liquid +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/templates/handle_email_request.fn.liquid @@ -1 +1,2 @@ +Suppose user has uploaded some attachments. Please call handle_email_request if user wants to send out an email. \ No newline at end of file From 37f2a91612546272fe2d62d4ad0a5c735cdcfc56 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 17 Jul 2024 13:32:16 -0500 Subject: [PATCH 2/4] minor change --- .../functions/handle_email_request.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json index 25bb874b6..5aaef8d07 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/handle_email_request.json @@ -18,7 +18,7 @@ }, "is_need_attachments": { "type": "boolean", - "description": "If the user request to send email with attachemnts, then this value should be true. Otherwise, this value should be false." + "description": "If the user request to send email with attachemnt(s), then this value should be true. Otherwise, this value should be false." } }, "required": [ "to_address", "email_content", "subject", "is_need_attachments" ] From c376ef269dfbb391e2e7f057d98e63fb90e8ac6f Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 17 Jul 2024 13:56:33 -0500 Subject: [PATCH 3/4] fix username --- src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs index a8eaac5e7..e289e1bcf 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserIdentity.cs @@ -20,7 +20,7 @@ public string Id [JsonPropertyName("user_name")] public string UserName - => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Name)?.Value!; + => _claims?.FirstOrDefault(x => x.Type == "name")?.Value!; public string Email => _claims?.FirstOrDefault(x => x.Type == ClaimTypes.Email)?.Value!; From c514bed096ba3ccef6712908571e3efdfc191f13 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Wed, 17 Jul 2024 14:28:29 -0500 Subject: [PATCH 4/4] add comments --- .../Files/IBotSharpFileService.cs | 15 ++++++++++++- .../Files/Models/MessageFileModel.cs | 9 ++++++++ .../BotSharpFileService.Conversation.cs | 21 ++++++++++++------- .../Functions/HandleEmailRequestFn.cs | 2 +- .../Functions/ReadImageFn.cs | 2 +- .../Functions/ReadPdfFn.cs | 2 +- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs b/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs index 65db27d3d..3f0f0c5c3 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Files/IBotSharpFileService.cs @@ -3,9 +3,22 @@ namespace BotSharp.Abstraction.Files; public interface IBotSharpFileService { string GetDirectory(string conversationId); - Task> GetChatImages(string conversationId, string source, + + /// + /// Get the files that have been uploaded in the chat. + /// If includeScreenShot is true, it will take the screenshots of non-image files, such as pdf, and return the screenshots instead of the original file. + /// + /// + /// + /// + /// + /// + /// + /// + Task> GetChatFiles(string conversationId, string source, IEnumerable conversations, IEnumerable contentTypes, bool includeScreenShot = false, int? offset = null); + IEnumerable GetMessageFiles(string conversationId, IEnumerable messageIds, string source, bool imageOnly = false); string GetMessageFile(string conversationId, string messageId, string source, string index, string fileName); IEnumerable GetMessagesWithFile(string conversationId, IEnumerable messageIds); diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs index 999f76de0..7cd932692 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs @@ -5,12 +5,21 @@ public class MessageFileModel [JsonPropertyName("message_id")] public string MessageId { get; set; } + /// + /// External file url + /// [JsonPropertyName("file_url")] public string FileUrl { get; set; } + /// + /// Internal file storage url + /// [JsonPropertyName("file_storage_url")] public string FileStorageUrl { get; set; } + /// + /// File name without extension + /// [JsonPropertyName("file_name")] public string FileName { get; set; } diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Conversation.cs b/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Conversation.cs index ff80690a4..1b98f0d93 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Conversation.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/BotSharpFileService.Conversation.cs @@ -6,7 +6,7 @@ namespace BotSharp.Core.Files.Services; public partial class BotSharpFileService { - public async Task> GetChatImages(string conversationId, string source, + public async Task> GetChatFiles(string conversationId, string source, IEnumerable conversations, IEnumerable contentTypes, bool includeScreenShot = false, int? offset = null) { @@ -69,9 +69,7 @@ public IEnumerable GetMessageFiles(string conversationId, IEnu } var fileName = Path.GetFileNameWithoutExtension(file); - var extension = Path.GetExtension(file); - var fileType = extension.Substring(1); - + var fileType = Path.GetExtension(file).Substring(1); var model = new MessageFileModel() { MessageId = messageId, @@ -290,10 +288,13 @@ private async Task> GetMessageFiles(string file, s contentType = GetFileContentType(screenShot); if (!_imageTypes.Contains(contentType)) continue; + var fileName = Path.GetFileNameWithoutExtension(screenShot); + var fileType = Path.GetExtension(file).Substring(1); var model = new MessageFileModel() { MessageId = messageId, - FileName = Path.GetFileName(screenShot), + FileName = fileName, + FileType = fileType, FileStorageUrl = screenShot, ContentType = contentType, FileSource = source @@ -307,10 +308,13 @@ private async Task> GetMessageFiles(string file, s foreach (var image in images) { contentType = GetFileContentType(image); + var fileName = Path.GetFileNameWithoutExtension(image); + var fileType = Path.GetExtension(image).Substring(1); var model = new MessageFileModel() { MessageId = messageId, - FileName = Path.GetFileName(image), + FileName = fileName, + FileType = fileType, FileStorageUrl = image, ContentType = contentType, FileSource = source @@ -321,10 +325,13 @@ private async Task> GetMessageFiles(string file, s } else { + var fileName = Path.GetFileNameWithoutExtension(file); + var fileType = Path.GetExtension(file).Substring(1); var model = new MessageFileModel() { MessageId = messageId, - FileName = Path.GetFileName(file), + FileName = fileName, + FileType = fileType, FileStorageUrl = file, ContentType = contentType, FileSource = source diff --git a/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs b/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs index 82c1010af..984732a9f 100644 --- a/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs +++ b/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs @@ -110,7 +110,7 @@ private async Task> SelectFiles(IEnumerable x == "openai"); - var model = llmProviderService.GetProviderModel(provider: provider, id: "gpt-4", multiModal: true); + var model = llmProviderService.GetProviderModel(provider: provider, id: "gpt-4"); var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name); var response = await completion.GetChatCompletions(agent, dialogs); var content = response?.Content ?? string.Empty; diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs index 9ae192501..66f693532 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs +++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs @@ -52,7 +52,7 @@ private async Task> AssembleFiles(string conversationId, L } var fileService = _services.GetRequiredService(); - var images = await fileService.GetChatImages(conversationId, FileSourceType.User, dialogs, _imageContentTypes); + var images = await fileService.GetChatFiles(conversationId, FileSourceType.User, dialogs, _imageContentTypes); foreach (var dialog in dialogs) { diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs index 0464f186e..85c2afbca 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs +++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadPdfFn.cs @@ -51,7 +51,7 @@ private async Task> AssembleFiles(string conversationId, L } var fileService = _services.GetRequiredService(); - var files = await fileService.GetChatImages(conversationId, FileSourceType.User, dialogs, _pdfContentTypes, includeScreenShot: true); + var files = await fileService.GetChatFiles(conversationId, FileSourceType.User, dialogs, _pdfContentTypes, includeScreenShot: true); foreach (var dialog in dialogs) {