using BotSharp.Abstraction.Messaging.Models.RichContent.Template; using BotSharp.Plugin.EmailHandler.Models; using BotSharp.Plugin.EmailHandler.Providers; using MailKit; namespace BotSharp.Plugin.EmailReader.Functions; public class HandleEmailReaderFn : IFunctionCallback { public string Name => "util-email-handle_email_reader"; public readonly static string PROMPT_SUMMARY = "Provide a text summary of the following content."; public readonly static string RICH_CONTENT_SUMMARIZE = "is_email_summarize: true. messageId"; public readonly static string RICH_CONTENT_READ_EMAIL = "Read the email by messageId"; public readonly static string RICH_CONTENT_MARK_READ = "mark_as_read: true. messageId"; public string Indication => "Handling email read"; private readonly IServiceProvider _services; private readonly ILogger _logger; private readonly IHttpContextAccessor _context; private readonly BotSharpOptions _options; private readonly EmailReaderSettings _emailSettings; private readonly IConversationStateService _state; private readonly IEmailReader _emailProvider; public HandleEmailReaderFn( IServiceProvider services, ILogger logger, IHttpContextAccessor context, BotSharpOptions options, EmailReaderSettings emailPluginSettings, IConversationStateService state, IEmailReader emailProvider) { _services = services; _logger = logger; _context = context; _options = options; _emailSettings = emailPluginSettings; _state = state; _emailProvider = emailProvider; } public async Task Execute(RoleDialogModel message) { var args = JsonSerializer.Deserialize(message.FunctionArgs, _options.JsonSerializerOptions); var isMarkRead = args?.IsMarkRead ?? false; var isSummarize = args?.IsSummarize ?? false; var messageId = args?.MessageId; try { if (!string.IsNullOrEmpty(messageId)) { if (isMarkRead) { await _emailProvider.MarkEmailAsReadById(messageId); message.Content = $"The email message has been marked as read."; return true; } var emailMessage = await _emailProvider.GetEmailById(messageId); if (isSummarize) { var prompt = $"{PROMPT_SUMMARY} The content was sent by {emailMessage.From.ToString()}. Details: {emailMessage.TextBody}"; var agent = new Agent { Id = BuiltInAgentId.UtilityAssistant, Name = "Utility Assistant", Instruction = prompt }; var llmProviderService = _services.GetRequiredService(); var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == "openai"); var model = llmProviderService.GetProviderModel(provider: provider, id: "gpt-4"); var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name); var convService = _services.GetService(); var conversationId = convService.ConversationId; var dialogs = convService.GetDialogHistory(fromBreakpoint: false); var response = await completion.GetChatCompletions(agent, dialogs); var content = response?.Content ?? string.Empty; message.Content = content; message.RichContent = BuildRichContentForSummary(_state.GetConversationId(), message.Content); return true; } UniqueId.TryParse(messageId, out UniqueId uid); message.RichContent = BuildRichContentForEmail(emailMessage, uid.ToString()); return true; } var emails = await _emailProvider.GetUnreadEmails(); message.Content = "Please choose which one to read for you."; message.RichContent = BuildRichContentForSubject(emails.OrderByDescending(x => x.CreateDate).ToList()); return true; } catch (Exception ex) { var msg = $"Failed to read the emails. {ex.Message}"; _logger.LogError($"{msg}\n(Error: {ex.Message})"); message.Content = msg; return false; } } public RichContent BuildRichContentForSummary(string conversationId, string content, string editorType = EditorTypeEnum.Text) { return new RichContent() { FillPostback = true, Editor = editorType, Recipient = new Recipient() { Id = conversationId }, Message = new ButtonTemplateMessage() { Text = content, } }; } private RichContent BuildRichContentForSubject(List emailSubjects) { var text = "Please let me know which message I need to read?"; return new RichContent { FillPostback = true, Editor = EditorTypeEnum.None, Recipient = new Recipient { Id = _state.GetConversationId() }, Message = new GenericTemplateMessage { Text = text, Elements = GetElements(emailSubjects) } }; } private RichContent BuildRichContentForEmail(EmailModel email, string uid) { var text = "The email details are given below. \n"; return new RichContent { FillPostback = true, Editor = EditorTypeEnum.None, Recipient = new Recipient { Id = _state.GetConversationId() }, Message = new GenericTemplateMessage { Text = $"{text}From: {email.From.ToString()}\nSubject: {email.Subject}\n{email.Body}", Elements = GetElements(uid) } }; } private static List GetElements(string uid) { var element = new EmailSubjectElement() { Buttons = new ElementButton[] { BuildMarkReadElementButton(uid) } }; return new List() { element }; } private static List GetElements(List emails) { var elements = emails.Select(e => new EmailSubjectElement { Title = $"Subject: {e.Subject}", Subtitle = $"From: {e.From}
Date: {e.CreateDate}", Buttons = BuildElementButton(e) }).ToList(); return elements; } private static ElementButton[] BuildElementButton(EmailModel email) { var elements = new List() { }; elements.Add(new ElementButton { Title = "Read", Payload = $"{RICH_CONTENT_READ_EMAIL}: {email.UId}.", Type = "text", }); elements.Add(new ElementButton { Title = "Summarize", Payload = $"{RICH_CONTENT_SUMMARIZE}: {email.UId}.", Type = "text", }); return elements.ToArray(); } private static ElementButton BuildMarkReadElementButton(string uId) { return new ElementButton { Title = "Mark as read", Payload = $"{RICH_CONTENT_MARK_READ}: {uId}.", Type = "text", }; } }