Skip to content

Features/refine file select #578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
Expand All @@ -25,6 +25,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
<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.Logging.Abstractions" Version="8.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace BotSharp.Abstraction.Files;

public interface IBotSharpFileService
public interface IFileBasicService
{
#region Conversation
/// <summary>
Expand All @@ -11,13 +11,13 @@ public interface IBotSharpFileService
/// </summary>
/// <param name="conversationId"></param>
/// <param name="source"></param>
/// <param name="conversations"></param>
/// <param name="dialogs"></param>
/// <param name="contentTypes"></param>
/// <param name="includeScreenShot"></param>
/// <param name="offset"></param>
/// <returns></returns>
Task<IEnumerable<MessageFileModel>> GetChatFiles(string conversationId, string source,
IEnumerable<RoleDialogModel> conversations, IEnumerable<string> contentTypes,
IEnumerable<RoleDialogModel> dialogs, IEnumerable<string>? contentTypes,
bool includeScreenShot = false, int? offset = null);

/// <summary>
Expand All @@ -28,7 +28,7 @@ Task<IEnumerable<MessageFileModel>> GetChatFiles(string conversationId, string s
/// <param name="source"></param>
/// <param name="imageOnly"></param>
/// <returns></returns>
IEnumerable<MessageFileModel> GetMessageFiles(string conversationId, IEnumerable<string> messageIds, string source, bool imageOnly = false);
IEnumerable<MessageFileModel> GetMessageFiles(string conversationId, IEnumerable<string> messageIds, string source, IEnumerable<string>? contentTypes = null);
string GetMessageFile(string conversationId, string messageId, string source, string index, string fileName);
IEnumerable<MessageFileModel> GetMessagesWithFile(string conversationId, IEnumerable<string> messageIds);
bool SaveMessageFiles(string conversationId, string messageId, string source, List<BotSharpFile> files);
Expand All @@ -45,38 +45,20 @@ Task<IEnumerable<MessageFileModel>> GetChatFiles(string conversationId, string s
bool DeleteConversationFiles(IEnumerable<string> conversationIds);
#endregion

#region Image
Task<RoleDialogModel> GenerateImage(string? provider, string? model, string text);
Task<RoleDialogModel> VaryImage(string? provider, string? model, BotSharpFile image);
Task<RoleDialogModel> EditImage(string? provider, string? model, string text, BotSharpFile image);
Task<RoleDialogModel> EditImage(string? provider, string? model, string text, BotSharpFile image, BotSharpFile mask);
#endregion

#region Pdf
/// <summary>
/// Take screenshots of pdf pages and get response from llm
/// </summary>
/// <param name="prompt"></param>
/// <param name="files">Pdf files</param>
/// <returns></returns>
Task<string> ReadPdf(string? provider, string? model, string? modelId, string prompt, List<BotSharpFile> files);
#endregion

#region User
string GetUserAvatar();
bool SaveUserAvatar(BotSharpFile file);
#endregion

#region Common
/// <summary>
/// Get file bytes and content type from data, e.g., "data:image/png;base64,aaaaaaaaa"
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
(string, byte[]) GetFileInfoFromData(string data);
string GetDirectory(string conversationId);
string GetFileContentType(string filePath);
byte[] GetFileBytes(string fileStorageUrl);
bool SavefileToPath(string filePath, Stream stream);
bool SaveFileStreamToPath(string filePath, Stream stream);
bool SaveFileBytesToPath(string filePath, byte[] bytes);
string GetParentDir(string dir, int level = 1);
bool ExistDirectory(string? dir);
void CreateDirectory(string dir);
void DeleteDirectory(string dir);
string BuildDirectory(params string[] segments);
#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace BotSharp.Abstraction.Files;

public interface IFileInstructService
{
#region Image
Task<RoleDialogModel> ReadImages(string? provider, string? model, string text, IEnumerable<BotSharpFile> images);
Task<RoleDialogModel> GenerateImage(string? provider, string? model, string text);
Task<RoleDialogModel> VaryImage(string? provider, string? model, BotSharpFile image);
Task<RoleDialogModel> EditImage(string? provider, string? model, string text, BotSharpFile image);
Task<RoleDialogModel> EditImage(string? provider, string? model, string text, BotSharpFile image, BotSharpFile mask);
#endregion

#region Pdf
/// <summary>
/// Take screenshots of pdf pages and get response from llm
/// </summary>
/// <param name="prompt"></param>
/// <param name="files">Pdf files</param>
/// <returns></returns>
Task<string> ReadPdf(string? provider, string? model, string? modelId, string prompt, List<BotSharpFile> files);
#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);
#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace BotSharp.Abstraction.Files.Models;

public class FileSelectContext
{
[JsonPropertyName("selected_ids")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IEnumerable<int>? Selecteds { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ public MessageFileModel()

public override string ToString()
{
return $"File name: {FileName}, File type: {FileType}, Content type: {ContentType}";
return $"File name: {FileName}, File type: {FileType}, Content type: {ContentType}, Source: {FileSource}";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Microsoft.AspNetCore.StaticFiles;

namespace BotSharp.Abstraction.Files.Utilities;

public static class FileUtility
{
/// <summary>
/// Get file bytes and content type from data, e.g., "data:image/png;base64,aaaaaaaaa"
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static (string, byte[]) GetFileInfoFromData(string data)
{
if (string.IsNullOrEmpty(data))
{
return (string.Empty, new byte[0]);
}

var typeStartIdx = data.IndexOf(':');
var typeEndIdx = data.IndexOf(';');
var contentType = data.Substring(typeStartIdx + 1, typeEndIdx - typeStartIdx - 1);

var base64startIdx = data.IndexOf(',');
var base64Str = data.Substring(base64startIdx + 1);

return (contentType, Convert.FromBase64String(base64Str));
}

public static string GetFileContentType(string filePath)
{
string contentType;
var provider = new FileExtensionContentTypeProvider();
if (!provider.TryGetContentType(filePath, out contentType))
{
contentType = string.Empty;
}

return contentType;
}
}
19 changes: 13 additions & 6 deletions src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@
<NoWarn>1701;1702</NoWarn>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Planning\**" />
<Compile Remove="Translation\Models\**" />
<EmbeddedResource Remove="Planning\**" />
<EmbeddedResource Remove="Translation\Models\**" />
<None Remove="Planning\**" />
<None Remove="Translation\Models\**" />
</ItemGroup>

<ItemGroup>
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\agent.json" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\instruction.liquid" />
Expand All @@ -69,6 +78,7 @@
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\planner_prompt.two_stage.2nd.task.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\response_with_function.liquid" />
<None Remove="data\agents\01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a\templates\translation_prompt.liquid" />
<None Remove="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\select_file_prompt.liquid" />
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\agent.json" />
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\instruction.liquid" />
<None Remove="data\agents\dfd9b46d-d00c-40af-8a75-3fbdc2b89869\templates\instruction.executor.liquid" />
Expand Down Expand Up @@ -155,6 +165,9 @@
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\instruction.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\agents\6745151e-6d46-4a02-8de4-1c4f21c7da95\templates\select_file_prompt.liquid">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="data\plugins\config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Expand All @@ -172,7 +185,6 @@
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" />
<PackageReference Include="EntityFrameworkCore.BootKit" Version="8.5.0" />
<PackageReference Include="Fluid.Core" Version="2.11.1" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Nanoid" Version="3.1.0" />
</ItemGroup>
Expand All @@ -181,9 +193,4 @@
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
</ItemGroup>

<ItemGroup>
<Folder Include="Planning\" />
<Folder Include="Translation\Models\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ 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<IBotSharpFileService>();
var fileService = _services.GetRequiredService<IFileBasicService>();
var deleteMessageIds = db.TruncateConversation(conversationId, messageId, cleanLog: true);

fileService.DeleteMessageFiles(conversationId, deleteMessageIds, messageId, newMessageId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public ConversationService(
public async Task<bool> DeleteConversations(IEnumerable<string> ids)
{
var db = _services.GetRequiredService<IBotSharpRepository>();
var fileService = _services.GetRequiredService<IBotSharpFileService>();
var fileService = _services.GetRequiredService<IFileBasicService>();
var isDeleted = db.DeleteConversations(ids);
fileService.DeleteConversationFiles(ids);
return await Task.FromResult(isDeleted);
Expand Down
3 changes: 2 additions & 1 deletion src/Infrastructure/BotSharp.Core/Files/FilePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public void RegisterDI(IServiceCollection services, IConfiguration config)

if (myFileStorageSettings.Default == FileStorageEnum.LocalFileStorage)
{
services.AddScoped<IBotSharpFileService, BotSharpFileService>();
services.AddScoped<IFileBasicService, FileBasicService>();
}
services.AddScoped<IFileInstructService, FileInstructService>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.IO;

namespace BotSharp.Core.Files.Services;

public partial class FileBasicService
{
public string GetDirectory(string conversationId)
{
var dir = Path.Combine(_dbSettings.FileRepository, CONVERSATION_FOLDER, conversationId, "attachments");
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
return dir;
}

public byte[] GetFileBytes(string fileStorageUrl)
{
using var stream = File.OpenRead(fileStorageUrl);
var bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
return bytes;
}

public bool SaveFileStreamToPath(string filePath, Stream stream)
{
if (string.IsNullOrEmpty(filePath)) return false;

using (var fileStream = new FileStream(filePath, FileMode.Create))
{
stream.CopyTo(fileStream);
}
return true;
}

public bool SaveFileBytesToPath(string filePath, byte[] bytes)
{
using (var fs = new FileStream(filePath, FileMode.Create))
{
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
fs.Close();
}
return true;
}

public string GetParentDir(string dir, int level = 1)
{
var segs = dir.Split(Path.DirectorySeparatorChar);
return string.Join(Path.DirectorySeparatorChar, segs.SkipLast(level));
}

public string BuildDirectory(params string[] segments)
{
var relativePath = Path.Combine(segments);
return Path.Combine(_baseDir, relativePath);
}

public void CreateDirectory(string dir)
{
Directory.CreateDirectory(dir);
}

public bool ExistDirectory(string? dir)
{
return !string.IsNullOrEmpty(dir) && Directory.Exists(dir);
}

public void DeleteDirectory(string dir)
{
Directory.Delete(dir, true);
}
}
Loading