Merge pull request #579 from iceljc/features/refine-file-select

use select file option
This commit is contained in:
iceljc 2024-08-07 22:13:02 -05:00 committed by GitHub
commit c2ed5e4030
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 218 additions and 161 deletions

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
@ -28,9 +28,11 @@
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Memory.Data" Version="8.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.4" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />

View file

@ -21,9 +21,6 @@ public interface IFileInstructService
#endregion
#region Select file
Task<IEnumerable<MessageFileModel>> SelectMessageFiles(string conversationId,
string? agentId = null, string? template = null, string? description = null,
bool includeBotFile = false, bool fromBreakpoint = false,
int? offset = null, IEnumerable<string>? contentTypes = null);
Task<IEnumerable<MessageFileModel>> SelectMessageFiles(string conversationId, SelectFileOptions options);
#endregion
}

View file

@ -2,7 +2,7 @@ using System.IO;
namespace BotSharp.Abstraction.Files;
public interface IFileBasicService
public interface IFileStorageService
{
#region Conversation
/// <summary>

View file

@ -1,23 +1,7 @@
namespace BotSharp.Abstraction.Files.Models;
public class BotSharpFile
public class BotSharpFile : FileBase
{
[JsonPropertyName("file_name")]
public string FileName { get; set; } = string.Empty;
/// <summary>
/// File data, e.g., "data:image/png;base64,aaaaaaaa"
/// </summary>
[JsonPropertyName("file_data")]
public string FileData { get; set; } = string.Empty;
[JsonPropertyName("file_url")]
public string FileUrl { get; set; } = string.Empty;
[JsonPropertyName("content_type")]
public string ContentType { get; set; } = string.Empty;
[JsonPropertyName("file_storage_url")]
public string FileStorageUrl { get; set; } = string.Empty;
}

View file

@ -0,0 +1,46 @@
namespace BotSharp.Abstraction.Files.Models;
public class FileBase
{
/// <summary>
/// External file url
/// </summary>
[JsonPropertyName("file_url")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FileUrl { get; set; } = string.Empty;
/// <summary>
/// Internal file storage url
/// </summary>
[JsonPropertyName("file_storage_url")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FileStorageUrl { get; set; } = string.Empty;
/// <summary>
/// File name without extension
/// </summary>
[JsonPropertyName("file_name")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FileName { get; set; } = string.Empty;
/// <summary>
/// File data, e.g., "data:image/png;base64,aaaaaaaa"
/// </summary>
[JsonPropertyName("file_data")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FileData { get; set; } = string.Empty;
/// <summary>
/// File content type
/// </summary>
[JsonPropertyName("content_type")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? ContentType { get; set; } = string.Empty;
/// <summary>
/// File extension without dot
/// </summary>
[JsonPropertyName("file_type")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FileType { get; set; } = string.Empty;
}

View file

@ -1,34 +1,10 @@
namespace BotSharp.Abstraction.Files.Models;
public class MessageFileModel
public class MessageFileModel : FileBase
{
[JsonPropertyName("message_id")]
public string MessageId { get; set; }
/// <summary>
/// External file url
/// </summary>
[JsonPropertyName("file_url")]
public string FileUrl { get; set; }
/// <summary>
/// Internal file storage url
/// </summary>
[JsonPropertyName("file_storage_url")]
public string FileStorageUrl { get; set; }
/// <summary>
/// File name without extension
/// </summary>
[JsonPropertyName("file_name")]
public string FileName { get; set; }
[JsonPropertyName("file_type")]
public string FileType { get; set; }
[JsonPropertyName("content_type")]
public string ContentType { get; set; }
[JsonPropertyName("file_source")]
public string FileSource { get; set; } = FileSourceType.User;

View file

@ -0,0 +1,14 @@
namespace BotSharp.Abstraction.Files.Models;
public class SelectFileOptions
{
public string? Provider { get; set; }
public string? ModelId { get; set; }
public string? AgentId { get; set; }
public string? Template { get; set; }
public string? Description { get; set; }
public bool IncludeBotFile { get; set; }
public bool FromBreakpoint { get; set; }
public int? Offset { get; set; }
public IEnumerable<string>? ContentTypes { get; set; }
}

View file

@ -1,4 +1,10 @@
using BotSharp.Abstraction.Repositories.Enums;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Mime;
namespace BotSharp.Abstraction.Files.Utilities;
@ -37,4 +43,25 @@ public static class FileUtility
return contentType;
}
public static async Task<byte[]> GetFileBytes(IServiceProvider services, FileBase file)
{
var bytes = new byte[0];
var settings = services.GetRequiredService<FileStorageSettings>();
if (settings.Default == FileStorageEnum.LocalFileStorage)
{
using var fs = File.OpenRead(file.FileStorageUrl);
var binary = BinaryData.FromStream(fs);
bytes = binary.ToArray();
fs.Close();
}
else
{
var http = services.GetRequiredService<IHttpClientFactory>();
using var client = http.CreateClient();
bytes = await client.GetByteArrayAsync(file.FileUrl);
}
return bytes;
}
}

View file

@ -5,10 +5,9 @@ public partial class ConversationService : IConversationService
public async Task<bool> TruncateConversation(string conversationId, string messageId, string? newMessageId = null)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var fileService = _services.GetRequiredService<IFileBasicService>();
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var deleteMessageIds = db.TruncateConversation(conversationId, messageId, cleanLog: true);
fileService.DeleteMessageFiles(conversationId, deleteMessageIds, messageId, newMessageId);
fileStorage.DeleteMessageFiles(conversationId, deleteMessageIds, messageId, newMessageId);
var hooks = _services.GetServices<IConversationHook>().ToList();
foreach (var hook in hooks)

View file

@ -37,9 +37,9 @@ public partial class ConversationService : IConversationService
public async Task<bool> DeleteConversations(IEnumerable<string> ids)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var fileService = _services.GetRequiredService<IFileBasicService>();
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var isDeleted = db.DeleteConversations(ids);
fileService.DeleteConversationFiles(ids);
fileStorage.DeleteConversationFiles(ids);
return await Task.FromResult(isDeleted);
}

View file

@ -10,17 +10,18 @@ public class FilePlugin : IBotSharpPlugin
public string Name => "File";
public string Description => "Provides file analysis.";
public string Description => "Provides file storage and analysis.";
public void RegisterDI(IServiceCollection services, IConfiguration config)
{
var myFileStorageSettings = new FileStorageSettings();
config.Bind("FileStorage", myFileStorageSettings);
services.AddSingleton(myFileStorageSettings);
if (myFileStorageSettings.Default == FileStorageEnum.LocalFileStorage)
{
services.AddScoped<IFileBasicService, FileBasicService>();
services.AddScoped<IFileStorageService, LocalFileStorageService>();
}
services.AddScoped<IFileInstructService, FileInstructService>();
}

View file

@ -2,7 +2,7 @@ using System.IO;
namespace BotSharp.Core.Files.Services;
public partial class FileBasicService
public partial class LocalFileStorageService
{
public string GetDirectory(string conversationId)
{

View file

@ -4,7 +4,7 @@ using System.IO;
namespace BotSharp.Core.Files.Services;
public partial class FileBasicService
public partial class LocalFileStorageService
{
public async Task<IEnumerable<MessageFileModel>> GetChatFiles(string conversationId, string source,
IEnumerable<RoleDialogModel> dialogs, IEnumerable<string>? contentTypes = null,

View file

@ -2,7 +2,7 @@ using System.IO;
namespace BotSharp.Core.Files.Services;
public partial class FileBasicService
public partial class LocalFileStorageService
{
public string GetUserAvatar()
{

View file

@ -2,12 +2,12 @@ using System.IO;
namespace BotSharp.Core.Files.Services;
public partial class FileBasicService : IFileBasicService
public partial class LocalFileStorageService : IFileStorageService
{
private readonly BotSharpDatabaseSettings _dbSettings;
private readonly IServiceProvider _services;
private readonly IUserIdentity _user;
private readonly ILogger<FileBasicService> _logger;
private readonly ILogger<LocalFileStorageService> _logger;
private readonly string _baseDir;
private readonly IEnumerable<string> _imageTypes = new List<string>
{
@ -24,10 +24,10 @@ public partial class FileBasicService : IFileBasicService
private const string USER_AVATAR_FOLDER = "avatar";
private const string SESSION_FOLDER = "sessions";
public FileBasicService(
public LocalFileStorageService(
BotSharpDatabaseSettings dbSettings,
IUserIdentity user,
ILogger<FileBasicService> logger,
ILogger<LocalFileStorageService> logger,
IServiceProvider services)
{
_dbSettings = dbSettings;

View file

@ -16,8 +16,8 @@ public partial class FileInstructService
var guid = Guid.NewGuid().ToString();
var sessionDir = _fileBasic.BuildDirectory(SESSION_FOLDER, guid);
DeleteIfExistDirectory(sessionDir);
var sessionDir = _fileStorage.BuildDirectory(SESSION_FOLDER, guid);
DeleteIfExistDirectory(sessionDir, true);
try
{
@ -46,7 +46,7 @@ public partial class FileInstructService
}
finally
{
_fileBasic.DeleteDirectory(sessionDir);
_fileStorage.DeleteDirectory(sessionDir);
}
}
@ -78,11 +78,11 @@ public partial class FileInstructService
if (!bytes.IsNullOrEmpty())
{
var guid = Guid.NewGuid().ToString();
var fileDir = _fileBasic.BuildDirectory(dir, guid);
DeleteIfExistDirectory(fileDir);
var fileDir = _fileStorage.BuildDirectory(dir, guid);
DeleteIfExistDirectory(fileDir, true);
var pdfDir = _fileBasic.BuildDirectory(fileDir, $"{guid}.{extension}");
_fileBasic.SaveFileBytesToPath(pdfDir, bytes);
var pdfDir = _fileStorage.BuildDirectory(fileDir, $"{guid}.{extension}");
_fileStorage.SaveFileBytesToPath(pdfDir, bytes);
locs.Add(pdfDir);
}
}
@ -108,8 +108,8 @@ public partial class FileInstructService
{
try
{
var dir = _fileBasic.GetParentDir(file);
var folder = _fileBasic.BuildDirectory(dir, "screenshots");
var dir = _fileStorage.GetParentDir(file);
var folder = _fileStorage.BuildDirectory(dir, "screenshots");
var urls = await converter.ConvertPdfToImages(file, folder);
images.AddRange(urls);
}

View file

@ -5,10 +5,7 @@ namespace BotSharp.Core.Files.Services;
public partial class FileInstructService
{
public async Task<IEnumerable<MessageFileModel>> SelectMessageFiles(string conversationId,
string? agentId = null, string? template = null, string? description = null,
bool includeBotFile = false, bool fromBreakpoint = false,
int? offset = null, IEnumerable<string>? contentTypes = null)
public async Task<IEnumerable<MessageFileModel>> SelectMessageFiles(string conversationId, SelectFileOptions options)
{
if (string.IsNullOrEmpty(conversationId))
{
@ -16,13 +13,13 @@ public partial class FileInstructService
}
var convService = _services.GetRequiredService<IConversationService>();
var dialogs = convService.GetDialogHistory(fromBreakpoint: fromBreakpoint);
var messageIds = GetMessageIds(dialogs, offset);
var dialogs = convService.GetDialogHistory(fromBreakpoint: options.FromBreakpoint);
var messageIds = GetMessageIds(dialogs, options.Offset);
var files = _fileBasic.GetMessageFiles(conversationId, messageIds, FileSourceType.User, contentTypes);
if (includeBotFile)
var files = _fileStorage.GetMessageFiles(conversationId, messageIds, FileSourceType.User, options.ContentTypes);
if (options.IncludeBotFile)
{
var botFiles = _fileBasic.GetMessageFiles(conversationId, messageIds, FileSourceType.Bot, contentTypes);
var botFiles = _fileStorage.GetMessageFiles(conversationId, messageIds, FileSourceType.Bot, options.ContentTypes);
files = files.Concat(botFiles);
}
@ -31,11 +28,10 @@ public partial class FileInstructService
return Enumerable.Empty<MessageFileModel>();
}
return await SelectFiles(agentId, template, description, files, dialogs);
return await SelectFiles(files, dialogs, options);
}
private async Task<IEnumerable<MessageFileModel>> SelectFiles(string? agentId, string? template, string? description,
IEnumerable<MessageFileModel> files, List<RoleDialogModel> dialogs)
private async Task<IEnumerable<MessageFileModel>> SelectFiles(IEnumerable<MessageFileModel> files, IEnumerable<RoleDialogModel> dialogs, SelectFileOptions options)
{
if (files.IsNullOrEmpty()) return new List<MessageFileModel>();
@ -50,8 +46,8 @@ public partial class FileInstructService
return $"id: {idx + 1}, file_name: {x.FileName}.{x.FileType}, content_type: {x.ContentType}, author: {x.FileSource}";
}).ToList();
agentId = !string.IsNullOrWhiteSpace(agentId) ? agentId : BuiltInAgentId.UtilityAssistant;
template = !string.IsNullOrWhiteSpace(template) ? template : "select_file_prompt";
var agentId = !string.IsNullOrWhiteSpace(options.AgentId) ? options.AgentId : BuiltInAgentId.UtilityAssistant;
var template = !string.IsNullOrWhiteSpace(options.Template) ? options.Template : "select_file_prompt";
var foundAgent = db.GetAgent(agentId);
var prompt = db.GetAgentTemplate(BuiltInAgentId.UtilityAssistant, template);
@ -67,19 +63,29 @@ public partial class FileInstructService
Instruction = prompt
};
var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == "openai");
var model = llmProviderService.GetProviderModel(provider: provider, id: "gpt-4");
var message = dialogs.LastOrDefault();
var text = !string.IsNullOrWhiteSpace(options.Description) ? options.Description : message?.Content;
if (message == null)
{
message = new RoleDialogModel(AgentRole.User, text);
}
else
{
message = RoleDialogModel.From(message, AgentRole.User, text);
}
var providerName = options.Provider ?? "openai";
var modelId = options?.ModelId ?? "gpt-4";
var provider = llmProviderService.GetProviders().FirstOrDefault(x => x == providerName);
var model = llmProviderService.GetProviderModel(provider: provider, id: modelId);
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider, model: model.Name);
var message = dialogs.Last();
if (!string.IsNullOrWhiteSpace(description))
{
message = RoleDialogModel.From(message, AgentRole.User, description);
}
var response = await completion.GetChatCompletions(agent, new List<RoleDialogModel> { message });
var content = response?.Content ?? string.Empty;
var selecteds = JsonSerializer.Deserialize<FileSelectContext>(content);
var selecteds = JsonSerializer.Deserialize<FileSelectContext>(content, new JsonSerializerOptions
{
AllowTrailingCommas = true
});
var fids = selecteds?.Selecteds ?? new List<int>();
return files.Where((x, idx) => fids.Contains(idx + 1)).ToList();
}

View file

@ -2,31 +2,31 @@ namespace BotSharp.Core.Files.Services;
public partial class FileInstructService : IFileInstructService
{
private readonly IFileBasicService _fileBasic;
private readonly IFileStorageService _fileStorage;
private readonly IServiceProvider _services;
private readonly ILogger<FileInstructService> _logger;
private const string SESSION_FOLDER = "sessions";
public FileInstructService(
IFileBasicService fileBasic,
IFileStorageService fileStorate,
ILogger<FileInstructService> logger,
IServiceProvider services)
{
_fileBasic = fileBasic;
_fileStorage = fileStorate;
_logger = logger;
_services = services;
}
private void DeleteIfExistDirectory(string? dir)
private void DeleteIfExistDirectory(string? dir, bool createNew = false)
{
if (_fileBasic.ExistDirectory(dir))
if (_fileStorage.ExistDirectory(dir))
{
_fileBasic.DeleteDirectory(dir);
_fileStorage.DeleteDirectory(dir);
}
else
else if (createNew)
{
_fileBasic.CreateDirectory(dir);
_fileStorage.CreateDirectory(dir);
}
}
}

View file

@ -81,10 +81,10 @@ public class ConversationController : ControllerBase
var userService = _services.GetRequiredService<IUserService>();
var agentService = _services.GetRequiredService<IAgentService>();
var fileService = _services.GetRequiredService<IFileBasicService>();
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var messageIds = history.Select(x => x.MessageId).Distinct().ToList();
var fileMessages = fileService.GetMessagesWithFile(conversationId, messageIds);
var fileMessages = fileStorage.GetMessagesWithFile(conversationId, messageIds);
var dialogs = new List<ChatResponseModel>();
foreach (var message in history)
@ -349,15 +349,15 @@ public class ConversationController : ControllerBase
{
if (files != null && files.Length > 0)
{
var fileService = _services.GetRequiredService<IFileBasicService>();
var dir = fileService.GetDirectory(conversationId);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var dir = fileStorage.GetDirectory(conversationId);
foreach (var file in files)
{
// Save the file, process it, etc.
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var filePath = Path.Combine(dir, fileName);
fileService.SaveFileStreamToPath(filePath, file.OpenReadStream());
fileStorage.SaveFileStreamToPath(filePath, file.OpenReadStream());
}
return Ok(new { message = "File uploaded successfully." });
@ -372,25 +372,25 @@ public class ConversationController : ControllerBase
var convService = _services.GetRequiredService<IConversationService>();
convService.SetConversationId(conversationId, input.States);
var conv = await convService.GetConversationRecordOrCreateNew(agentId);
var fileService = _services.GetRequiredService<IFileBasicService>();
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var messageId = Guid.NewGuid().ToString();
var isSaved = fileService.SaveMessageFiles(conv.Id, messageId, FileSourceType.User, input.Files);
var isSaved = fileStorage.SaveMessageFiles(conv.Id, messageId, FileSourceType.User, input.Files);
return isSaved ? messageId : string.Empty;
}
[HttpGet("/conversation/{conversationId}/files/{messageId}/{source}")]
public IEnumerable<MessageFileViewModel> GetConversationMessageFiles([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string source)
{
var fileService = _services.GetRequiredService<IFileBasicService>();
var files = fileService.GetMessageFiles(conversationId, new List<string> { messageId }, source);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var files = fileStorage.GetMessageFiles(conversationId, new List<string> { messageId }, source);
return files?.Select(x => MessageFileViewModel.Transform(x))?.ToList() ?? new List<MessageFileViewModel>();
}
[HttpGet("/conversation/{conversationId}/message/{messageId}/{source}/file/{index}/{fileName}")]
public IActionResult GetMessageFile([FromRoute] string conversationId, [FromRoute] string messageId, [FromRoute] string source, [FromRoute] string index, [FromRoute] string fileName)
{
var fileService = _services.GetRequiredService<IFileBasicService>();
var file = fileService.GetMessageFile(conversationId, messageId, source, index, fileName);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var file = fileStorage.GetMessageFile(conversationId, messageId, source, index, fileName);
if (string.IsNullOrEmpty(file))
{
return NotFound();

View file

@ -137,15 +137,15 @@ public class UserController : ControllerBase
[HttpPost("/user/avatar")]
public bool UploadUserAvatar([FromBody] BotSharpFile file)
{
var fileService = _services.GetRequiredService<IFileBasicService>();
return fileService.SaveUserAvatar(file);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
return fileStorage.SaveUserAvatar(file);
}
[HttpGet("/user/avatar")]
public IActionResult GetUserAvatar()
{
var fileService = _services.GetRequiredService<IFileBasicService>();
var file = fileService.GetUserAvatar();
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var file = fileStorage.GetUserAvatar();
if (string.IsNullOrEmpty(file))
{
return NotFound();
@ -158,8 +158,8 @@ public class UserController : ControllerBase
#region Private methods
private FileContentResult BuildFileResult(string file)
{
var fileService = _services.GetRequiredService<IFileBasicService>();
var bytes = fileService.GetFileBytes(file);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var bytes = fileStorage.GetFileBytes(file);
return File(bytes, "application/octet-stream", Path.GetFileName(file));
}
#endregion

View file

@ -1,17 +1,7 @@
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Files;
using BotSharp.Abstraction.Messaging.Models.RichContent.Template;
using BotSharp.Abstraction.MLTasks;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.EmailHandler.Models;
using BotSharp.Plugin.EmailHandler.Providers;
using MailKit;
using MailKit.Net.Imap;
using MailKit.Search;
using MailKit.Security;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MimeKit;
namespace BotSharp.Plugin.EmailReader.Functions;
@ -31,13 +21,14 @@ public class HandleEmailReaderFn : IFunctionCallback
private readonly IConversationStateService _state;
private readonly IEmailReader _emailProvider;
public HandleEmailReaderFn(IServiceProvider services,
ILogger<HandleEmailReaderFn> logger,
IHttpContextAccessor context,
BotSharpOptions options,
EmailReaderSettings emailPluginSettings,
IConversationStateService state,
IEmailReader emailProvider)
public HandleEmailReaderFn(
IServiceProvider services,
ILogger<HandleEmailReaderFn> logger,
IHttpContextAccessor context,
BotSharpOptions options,
EmailReaderSettings emailPluginSettings,
IConversationStateService state,
IEmailReader emailProvider)
{
_services = services;
_logger = logger;

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Files.Utilities;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
@ -52,7 +53,7 @@ public class HandleEmailSenderFn : IFunctionCallback
if (isNeedAttachments)
{
var files = await GetConversationFiles();
BuildEmailAttachments(bodyBuilder, files);
await BuildEmailAttachments(bodyBuilder, files);
}
mailMessage.Body = bodyBuilder.ToMessageBody();
@ -65,7 +66,7 @@ public class HandleEmailSenderFn : IFunctionCallback
catch (Exception ex)
{
var msg = $"Failed to send the email. {ex.Message}";
_logger.LogError($"{msg}\n(Error: {ex.Message})");
_logger.LogError($"{msg}\n(Error: {ex.Message}\r\n{ex.InnerException})");
message.Content = msg;
return false;
}
@ -77,11 +78,11 @@ public class HandleEmailSenderFn : IFunctionCallback
var conversationId = convService.ConversationId;
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var selecteds = await fileInstruct.SelectMessageFiles(conversationId, includeBotFile: true);
var selecteds = await fileInstruct.SelectMessageFiles(conversationId, new SelectFileOptions { IncludeBotFile = true });
return selecteds;
}
private void BuildEmailAttachments(BodyBuilder builder, IEnumerable<MessageFileModel> files)
private async Task BuildEmailAttachments(BodyBuilder builder, IEnumerable<MessageFileModel> files)
{
if (files.IsNullOrEmpty()) return;
@ -89,10 +90,8 @@ public class HandleEmailSenderFn : IFunctionCallback
{
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();
var fileBytes = await FileUtility.GetFileBytes(_services, file);
builder.Attachments.Add($"{file.FileName}.{file.FileType}", fileBytes, ContentType.Parse(file.ContentType));
Thread.Sleep(100);
}
}

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Files.Utilities;
using BotSharp.Abstraction.Templating;
using System.IO;
@ -51,7 +52,11 @@ public class EditImageFn : IFunctionCallback
private async Task<MessageFileModel?> SelectImage(string? description)
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var selecteds = await fileInstruct.SelectMessageFiles(_conversationId, description: description, contentTypes: new List<string> { MediaTypeNames.Image.Png });
var selecteds = await fileInstruct.SelectMessageFiles(_conversationId, new SelectFileOptions
{
Description = description,
ContentTypes = new List<string> { MediaTypeNames.Image.Png }
});
return selecteds?.FirstOrDefault();
}
@ -73,7 +78,10 @@ public class EditImageFn : IFunctionCallback
Name = "Utility Assistant"
};
using var stream = File.OpenRead(image.FileStorageUrl);
var fileBytes = await FileUtility.GetFileBytes(_services, image);
using var stream = new MemoryStream();
stream.Write(fileBytes);
stream.Position = 0;
var result = await completion.GetImageEdits(agent, dialog, stream, image.FileName ?? string.Empty);
stream.Close();
SaveGeneratedImage(result?.GeneratedImages?.FirstOrDefault());
@ -101,7 +109,7 @@ public class EditImageFn : IFunctionCallback
}
};
var fileService = _services.GetRequiredService<IFileBasicService>();
fileService.SaveMessageFiles(_conversationId, _messageId, FileSourceType.Bot, files);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
fileStorage.SaveMessageFiles(_conversationId, _messageId, FileSourceType.Bot, files);
}
}

View file

@ -83,7 +83,7 @@ public class GenerateImageFn : IFunctionCallback
FileData = $"data:{MediaTypeNames.Image.Png};base64,{x.ImageData}"
}).ToList();
var fileService = _services.GetRequiredService<IFileBasicService>();
fileService.SaveMessageFiles(_conversationId, _messageId, FileSourceType.Bot, files);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
fileStorage.SaveMessageFiles(_conversationId, _messageId, FileSourceType.Bot, files);
}
}

View file

@ -51,8 +51,8 @@ public class ReadImageFn : IFunctionCallback
return new List<RoleDialogModel>();
}
var fileService = _services.GetRequiredService<IFileBasicService>();
var images = await fileService.GetChatFiles(conversationId, FileSourceType.User, dialogs, _imageContentTypes);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var images = await fileStorage.GetChatFiles(conversationId, FileSourceType.User, dialogs, _imageContentTypes);
foreach (var dialog in dialogs)
{
@ -62,6 +62,7 @@ public class ReadImageFn : IFunctionCallback
dialog.Files = found.Select(x => new BotSharpFile
{
ContentType = x.ContentType,
FileUrl = x.FileUrl,
FileStorageUrl = x.FileStorageUrl
}).ToList();
}

View file

@ -50,8 +50,8 @@ public class ReadPdfFn : IFunctionCallback
return new List<RoleDialogModel>();
}
var fileService = _services.GetRequiredService<IFileBasicService>();
var files = await fileService.GetChatFiles(conversationId, FileSourceType.User, dialogs, _pdfContentTypes, includeScreenShot: true);
var fileStorage = _services.GetRequiredService<IFileStorageService>();
var files = await fileStorage.GetChatFiles(conversationId, FileSourceType.User, dialogs, _pdfContentTypes, includeScreenShot: true);
foreach (var dialog in dialogs)
{
@ -61,6 +61,7 @@ public class ReadPdfFn : IFunctionCallback
dialog.Files = found.Select(x => new BotSharpFile
{
ContentType = x.ContentType,
FileUrl = x.FileUrl,
FileStorageUrl = x.FileStorageUrl
}).ToList();
}

View file

@ -74,7 +74,7 @@ public partial class TencentCosService
var model = new MessageFileModel()
{
MessageId = messageId,
FileUrl = $"https://{_fullBuketName}.cos.{_settings.Region}.myqcloud.com/{file}",
FileUrl = BuilFileUrl(file),
FileStorageUrl = file,
FileName = fileName,
FileType = fileType,
@ -140,9 +140,7 @@ public partial class TencentCosService
try
{
var (_, bytes) = FileUtility.GetFileInfoFromData(file.FileData);
var subDir = $"{dir}/{source}/{i + 1}";
_cosClient.BucketClient.UploadBytes($"{subDir}/{file.FileName}", bytes);
}
catch (Exception ex)
@ -257,7 +255,6 @@ public partial class TencentCosService
if (!_imageTypes.Contains(contentType) && includeScreenShot)
{
var screenShotDir = $"{fileDir}/{SCREENSHOT_FILE_FOLDER}/";
var fileList = _cosClient.BucketClient.GetDirFiles(screenShotDir);
if (!fileList.IsNullOrEmpty())
@ -274,6 +271,7 @@ public partial class TencentCosService
MessageId = messageId,
FileName = fileName,
FileType = fileType,
FileUrl = BuilFileUrl(screenShot),
FileStorageUrl = screenShot,
ContentType = contentType,
FileSource = source
@ -294,6 +292,7 @@ public partial class TencentCosService
MessageId = messageId,
FileName = fileName,
FileType = fileType,
FileUrl = BuilFileUrl(image),
FileStorageUrl = image,
ContentType = contentType,
FileSource = source
@ -311,6 +310,7 @@ public partial class TencentCosService
MessageId = messageId,
FileName = fileName,
FileType = fileType,
FileUrl = BuilFileUrl(file),
FileStorageUrl = file,
ContentType = contentType,
FileSource = source
@ -346,5 +346,10 @@ public partial class TencentCosService
var converters = _services.GetServices<IPdf2ImageConverter>();
return converters.FirstOrDefault();
}
private string BuilFileUrl(string file)
{
return $"https://{_fullBuketName}.cos.{_settings.Region}.myqcloud.com/{file}";
}
#endregion
}

View file

@ -5,7 +5,7 @@ using System.Net.Mime;
namespace BotSharp.Plugin.TencentCos.Services;
public partial class TencentCosService : IFileBasicService
public partial class TencentCosService : IFileStorageService
{
private readonly TencentCosClient _cosClient;
private readonly TencentCosSettings _settings;

View file

@ -31,7 +31,7 @@ public class TencentCosPlugin : IBotSharpPlugin
services.AddScoped<TencentCosClient>();
services.AddScoped<IFileBasicService, TencentCosService>();
services.AddScoped<IFileStorageService, TencentCosService>();
}
}
}