BotSharp/src/Plugins/BotSharp.Plugin.EmailHandler/Functions/HandleEmailRequestFn.cs

155 lines
6.3 KiB
C#
Raw Normal View History

using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
2024-07-17 18:31:09 +00:00
using System.IO;
2024-07-11 16:02:14 +00:00
namespace BotSharp.Plugin.EmailHandler.Functions;
public class HandleEmailRequestFn : IFunctionCallback
{
2024-07-11 16:02:14 +00:00
public string Name => "handle_email_request";
public string Indication => "Handling email request";
2024-07-11 16:02:14 +00:00
private readonly IServiceProvider _services;
private readonly ILogger<HandleEmailRequestFn> _logger;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IHttpContextAccessor _context;
private readonly BotSharpOptions _options;
private readonly EmailHandlerSettings _emailSettings;
2024-07-17 18:31:09 +00:00
public HandleEmailRequestFn(
IServiceProvider services,
ILogger<HandleEmailRequestFn> logger,
IHttpClientFactory httpClientFactory,
IHttpContextAccessor context,
BotSharpOptions options,
EmailHandlerSettings emailPluginSettings)
2024-07-11 16:02:14 +00:00
{
_services = services;
_logger = logger;
_httpClientFactory = httpClientFactory;
_context = context;
_options = options;
_emailSettings = emailPluginSettings;
}
public async Task<bool> Execute(RoleDialogModel message)
{
var args = JsonSerializer.Deserialize<LlmContextIn>(message.FunctionArgs, _options.JsonSerializerOptions);
var recipient = args?.ToAddress;
var body = args?.Content;
var subject = args?.Subject;
2024-07-17 18:31:09 +00:00
var isNeedAttachments = args?.IsNeedAttachemnts ?? false;
var bodyBuilder = new BodyBuilder();
2024-07-11 16:02:14 +00:00
try
{
var mailMessage = new MimeMessage();
mailMessage.From.Add(new MailboxAddress(_emailSettings.Name, _emailSettings.EmailAddress));
mailMessage.To.Add(new MailboxAddress("", recipient));
mailMessage.Subject = subject;
2024-07-17 18:31:09 +00:00
bodyBuilder.TextBody = body;
if (isNeedAttachments)
{
2024-07-17 18:31:09 +00:00
var files = await GetConversationFiles();
BuildEmailAttachments(bodyBuilder, files);
}
mailMessage.Body = bodyBuilder.ToMessageBody();
2024-07-18 03:00:00 +00:00
var response = await SendEmailBySMTP(mailMessage);
2024-07-11 16:02:14 +00:00
message.Content = response;
2024-07-17 18:31:09 +00:00
_logger.LogWarning($"Email successfully send over to {recipient}. Email Subject: {subject} [{response}]");
2024-07-11 16:02:14 +00:00
return true;
}
2024-07-11 16:02:14 +00:00
catch (Exception ex)
{
2024-07-11 16:02:14 +00:00
var msg = $"Failed to send the email. {ex.Message}";
_logger.LogError($"{msg}\n(Error: {ex.Message})");
message.Content = msg;
return false;
}
}
2024-07-11 16:02:14 +00:00
2024-07-17 18:31:09 +00:00
private async Task<IEnumerable<MessageFileModel>> GetConversationFiles()
{
2024-07-19 19:18:22 +00:00
var convService = _services.GetRequiredService<IConversationService>();
2024-07-17 18:31:09 +00:00
var fileService = _services.GetRequiredService<IBotSharpFileService>();
var conversationId = convService.ConversationId;
var dialogs = convService.GetDialogHistory(fromBreakpoint: false);
var messageIds = dialogs.Select(x => x.MessageId).Distinct().ToList();
var userFiles = fileService.GetMessageFiles(conversationId, messageIds, FileSourceType.User);
var botFiles = fileService.GetMessageFiles(conversationId, messageIds, FileSourceType.Bot);
return await SelectFiles(userFiles.Concat(botFiles), dialogs);
2024-07-17 18:31:09 +00:00
}
private async Task<IEnumerable<MessageFileModel>> SelectFiles(IEnumerable<MessageFileModel> files, List<RoleDialogModel> dialogs)
{
if (files.IsNullOrEmpty()) return new List<MessageFileModel>();
var llmProviderService = _services.GetRequiredService<ILlmProviderService>();
var render = _services.GetRequiredService<ITemplateRender>();
var db = _services.GetRequiredService<IBotSharpRepository>();
try
{
var promptFiles = files.Select((x, idx) =>
{
2024-07-25 04:08:30 +00:00
return $"id: {idx + 1}, file_name: {x.FileName}.{x.FileType}, content_type: {x.ContentType}, author: {x.FileSource}";
2024-07-17 18:31:09 +00:00
}).ToList();
2024-07-18 02:41:25 +00:00
var prompt = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, "select_attachment_prompt");
2024-07-17 18:31:09 +00:00
prompt = render.Render(prompt, new Dictionary<string, object>
{
{ "file_list", promptFiles }
});
var agent = new Agent
{
Id = BuiltInAgentId.UtilityAssistant,
Name = "Utility Assistant",
Instruction = prompt
};
var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == "openai");
2024-07-17 19:28:29 +00:00
var model = llmProviderService.GetProviderModel(provider: provider, id: "gpt-4");
2024-07-17 18:31:09 +00:00
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name);
2024-07-25 04:08:30 +00:00
var latest = dialogs.LastOrDefault();
var response = await completion.GetChatCompletions(agent, new List<RoleDialogModel> { latest });
2024-07-17 18:31:09 +00:00
var content = response?.Content ?? string.Empty;
var selecteds = JsonSerializer.Deserialize<LlmContextOut>(content);
var fids = selecteds?.Selecteds ?? new List<int>();
2024-07-17 18:31:09 +00:00
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<MessageFileModel>();
}
}
private void BuildEmailAttachments(BodyBuilder builder, IEnumerable<MessageFileModel> 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);
}
}
2024-07-18 03:00:00 +00:00
private async Task<string> SendEmailBySMTP(MimeMessage mailMessage)
2024-07-11 16:02:14 +00:00
{
using var smtpClient = new SmtpClient();
await smtpClient.ConnectAsync(_emailSettings.SMTPServer, _emailSettings.SMTPPort, SecureSocketOptions.StartTls);
await smtpClient.AuthenticateAsync(_emailSettings.EmailAddress, _emailSettings.Password);
var response = await smtpClient.SendAsync(mailMessage);
return response ?? "Email sent";
2024-07-11 16:02:14 +00:00
}
}