diff --git a/BotSharp.sln b/BotSharp.sln
index 8dda48e8..d281450e 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -111,7 +111,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.PythonInter
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Graph", "Graph", "{97A0B191-64D7-4F8A-BFE8-1BFCC5E247E1}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.Graph", "src\Plugins\BotSharp.Plugin.Graph\BotSharp.Plugin.Graph.csproj", "{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.Graph", "src\Plugins\BotSharp.Plugin.Graph\BotSharp.Plugin.Graph.csproj", "{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.AudioHandler", "src\Plugins\BotSharp.Plugin.AudioHandler\BotSharp.Plugin.AudioHandler.csproj", "{F57F4862-F8D4-44A1-AC12-5C131B5C9785}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -449,6 +451,14 @@ Global
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|Any CPU.Build.0 = Release|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|x64.ActiveCfg = Release|Any CPU
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D}.Release|x64.Build.0 = Release|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Debug|x64.Build.0 = Debug|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x64.ActiveCfg = Release|Any CPU
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -503,6 +513,7 @@ Global
{05E6E405-5021-406E-8A5E-0A7CEC881F6D} = {C4C59872-3C8A-450D-83D5-2BE402D610D5}
{97A0B191-64D7-4F8A-BFE8-1BFCC5E247E1} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C}
{EBFE97DA-D0BA-48BA-8B5D-083B60348D1D} = {97A0B191-64D7-4F8A-BFE8-1BFCC5E247E1}
+ {F57F4862-F8D4-44A1-AC12-5C131B5C9785} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19}
diff --git a/src/BotSharp.AppHost/BotSharp.AppHost.csproj b/src/BotSharp.AppHost/BotSharp.AppHost.csproj
index 6e8a2ae3..2a2705db 100644
--- a/src/BotSharp.AppHost/BotSharp.AppHost.csproj
+++ b/src/BotSharp.AppHost/BotSharp.AppHost.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
index 94c9e27c..697f94a5 100644
--- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
+++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj
@@ -1,4 +1,4 @@
-
+
$(TargetFramework)
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
index 2018d6a7..8484c5fb 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs
@@ -1,7 +1,6 @@
using BotSharp.Abstraction.Functions.Models;
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.Models.RichContent;
-using BotSharp.Abstraction.MLTasks;
namespace BotSharp.Abstraction.Conversations.Models;
@@ -75,6 +74,9 @@ public class RoleDialogModel : ITrackableMessage
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public RichContent? RichContent { get; set; }
+ ///
+ /// Rich content for secondary language
+ ///
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public RichContent? SecondaryRichContent { get; set; }
@@ -86,6 +88,9 @@ public class RoleDialogModel : ITrackableMessage
public FunctionCallFromLlm Instruction { get; set; }
+ ///
+ /// Files to be used in conversation
+ ///
public List Files { get; set; } = new List();
///
@@ -94,7 +99,8 @@ public class RoleDialogModel : ITrackableMessage
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("generated_images")]
public List GeneratedImages { get; set; } = new List();
- public float KnowledgeConfidence { get; set; } = 0.5f;
+
+
private RoleDialogModel()
{
}
@@ -134,8 +140,7 @@ public class RoleDialogModel : ITrackableMessage
Payload = source.Payload,
StopCompletion = source.StopCompletion,
Instruction = source.Instruction,
- Data = source.Data,
- KnowledgeConfidence = source.KnowledgeConfidence
+ Data = source.Data
};
}
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Converters/IPdf2ImageConverter.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Converters/IPdf2ImageConverter.cs
index 87df6137..24b28402 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Converters/IPdf2ImageConverter.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Converters/IPdf2ImageConverter.cs
@@ -2,7 +2,7 @@ namespace BotSharp.Abstraction.Files.Converters;
public interface IPdf2ImageConverter
{
- public string Name { get; }
+ public string Provider { get; }
///
/// Convert pdf pages to images, and return a list of image file paths
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/FileCoreSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Files/FileCoreSettings.cs
index 10ccd1a0..dc4ac40b 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/FileCoreSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/FileCoreSettings.cs
@@ -5,6 +5,11 @@ namespace BotSharp.Abstraction.Files;
public class FileCoreSettings
{
public string Storage { get; set; } = FileStorageEnum.LocalFileStorage;
- public string Pdf2TextConverter { get; set; }
- public string Pdf2ImageConverter { get; set; }
+ public SettingBase Pdf2TextConverter { get; set; }
+ public SettingBase Pdf2ImageConverter { get; set; }
}
+
+public class SettingBase
+{
+ public string Provider { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/IFileInstructService.cs b/src/Infrastructure/BotSharp.Abstraction/Files/IFileInstructService.cs
index 78a400e1..f8f4c605 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/IFileInstructService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/IFileInstructService.cs
@@ -3,11 +3,11 @@ namespace BotSharp.Abstraction.Files;
public interface IFileInstructService
{
#region Image
- Task ReadImages(string? provider, string? model, string text, IEnumerable images);
+ Task ReadImages(string? provider, string? model, string text, IEnumerable images);
Task GenerateImage(string? provider, string? model, string text);
- Task VaryImage(string? provider, string? model, BotSharpFile image);
- Task EditImage(string? provider, string? model, string text, BotSharpFile image);
- Task EditImage(string? provider, string? model, string text, BotSharpFile image, BotSharpFile mask);
+ Task VaryImage(string? provider, string? model, InstructFileModel image);
+ Task EditImage(string? provider, string? model, string text, InstructFileModel image);
+ Task EditImage(string? provider, string? model, string text, InstructFileModel image, InstructFileModel mask);
#endregion
#region Pdf
@@ -17,7 +17,11 @@ public interface IFileInstructService
///
/// Pdf files
///
- Task ReadPdf(string? provider, string? model, string? modelId, string prompt, List files);
+ Task ReadPdf(string? provider, string? model, string? modelId, string prompt, List files);
+ #endregion
+
+ #region Audio
+ Task SpeechToText(string? provider, string? model, InstructFileModel audio, string? text = null);
#endregion
#region Select file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/IFileStorageService.cs b/src/Infrastructure/BotSharp.Abstraction/Files/IFileStorageService.cs
index a3e5a32d..373466c4 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/IFileStorageService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/IFileStorageService.cs
@@ -6,6 +6,7 @@ public interface IFileStorageService
{
#region Common
string GetDirectory(string conversationId);
+ IEnumerable GetFiles(string relativePath, string? searchQuery = null);
byte[] GetFileBytes(string fileStorageUrl);
bool SaveFileStreamToPath(string filePath, Stream stream);
bool SaveFileBytesToPath(string filePath, byte[] bytes);
@@ -16,7 +17,6 @@ public interface IFileStorageService
string BuildDirectory(params string[] segments);
#endregion
-
#region Conversation
///
/// Get the message file screenshots for specific content types, e.g., pdf
@@ -24,7 +24,7 @@ public interface IFileStorageService
///
///
///
- Task> GetMessageFileScreenshots(string conversationId, IEnumerable messageIds);
+ Task> GetMessageFileScreenshotsAsync(string conversationId, IEnumerable messageIds);
///
/// Get the files that have been uploaded in the chat. No screenshot images are included.
@@ -37,7 +37,7 @@ public interface IFileStorageService
IEnumerable GetMessageFiles(string conversationId, IEnumerable messageIds, string source, IEnumerable? contentTypes = null);
string GetMessageFile(string conversationId, string messageId, string source, string index, string fileName);
IEnumerable GetMessagesWithFile(string conversationId, IEnumerable messageIds);
- bool SaveMessageFiles(string conversationId, string messageId, string source, List files);
+ bool SaveMessageFiles(string conversationId, string messageId, string source, List files);
///
/// Delete files under messages
@@ -54,10 +54,11 @@ public interface IFileStorageService
#region User
string GetUserAvatar();
- bool SaveUserAvatar(BotSharpFile file);
+ bool SaveUserAvatar(InputFileModel file);
#endregion
+
#region Speech
- Task SaveSpeechFileAsync(string conversationId, string fileName, BinaryData data);
- Task RetrieveSpeechFileAsync(string conversationId, string fileName);
+ bool SaveSpeechFile(string conversationId, string fileName, BinaryData data);
+ BinaryData GetSpeechFile(string conversationId, string fileName);
#endregion
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/BotSharpFile.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/BotSharpFile.cs
index 11a11e46..bc670626 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/BotSharpFile.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/BotSharpFile.cs
@@ -1,7 +1,12 @@
namespace BotSharp.Abstraction.Files.Models;
-public class BotSharpFile : FileBase
+public class BotSharpFile : FileInformation
{
-
+ ///
+ /// File data => format: "data:image/png;base64,aaaaaaaa"
+ ///
+ [JsonPropertyName("file_data")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? FileData { get; set; } = string.Empty;
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileBase.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileBase.cs
index 3483921a..f952e7f9 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileBase.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileBase.cs
@@ -2,20 +2,6 @@ namespace BotSharp.Abstraction.Files.Models;
public class FileBase
{
- ///
- /// External file url
- ///
- [JsonPropertyName("file_url")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string? FileUrl { get; set; } = string.Empty;
-
- ///
- /// Internal file storage url
- ///
- [JsonPropertyName("file_storage_url")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string? FileStorageUrl { get; set; } = string.Empty;
-
///
/// File name without extension
///
@@ -29,18 +15,4 @@ public class FileBase
[JsonPropertyName("file_data")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? FileData { get; set; } = string.Empty;
-
- ///
- /// File content type
- ///
- [JsonPropertyName("content_type")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string? ContentType { get; set; } = string.Empty;
-
- ///
- /// File extension without dot
- ///
- [JsonPropertyName("file_extension")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string? FileExtension { get; set; } = string.Empty;
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileInformation.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileInformation.cs
new file mode 100644
index 00000000..fe767e16
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/FileInformation.cs
@@ -0,0 +1,38 @@
+namespace BotSharp.Abstraction.Files.Models;
+
+public class FileInformation
+{
+ ///
+ /// External file url
+ ///
+ [JsonPropertyName("file_url")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? FileUrl { get; set; } = string.Empty;
+
+ ///
+ /// Internal file storage url
+ ///
+ [JsonPropertyName("file_storage_url")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? FileStorageUrl { get; set; } = string.Empty;
+
+ ///
+ /// File content type
+ ///
+ [JsonPropertyName("content_type")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? ContentType { get; set; } = string.Empty;
+
+ ///
+ /// File name without extension
+ ///
+ [JsonPropertyName("file_name")]
+ public string FileName { get; set; } = string.Empty;
+
+ ///
+ /// File extension without dot
+ ///
+ [JsonPropertyName("file_extension")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? FileExtension { get; set; } = string.Empty;
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/InputFileModel.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InputFileModel.cs
new file mode 100644
index 00000000..7eb350e3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InputFileModel.cs
@@ -0,0 +1,16 @@
+namespace BotSharp.Abstraction.Files.Models;
+
+public class InputFileModel : FileBase
+{
+ ///
+ /// File name with extension
+ ///
+ [JsonPropertyName("file_name")]
+ public new string FileName { get; set; } = string.Empty;
+
+ ///
+ /// File data => format: "data:image/png;base64,aaaaaaaa"
+ ///
+ [JsonPropertyName("file_data")]
+ public new string FileData { get; set; } = string.Empty;
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/InputMessageFiles.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InputMessageFiles.cs
deleted file mode 100644
index 29749bce..00000000
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/InputMessageFiles.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace BotSharp.Abstraction.Files.Models;
-
-public class InputMessageFiles
-{
- public List Files { get; set; } = new List();
- public BotSharpFile? Mask { get; set; }
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs
new file mode 100644
index 00000000..7eaddd5a
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs
@@ -0,0 +1,18 @@
+namespace BotSharp.Abstraction.Files.Models;
+
+public class InstructFileModel : FileBase
+{
+ ///
+ /// File extension without dot
+ ///
+ [JsonPropertyName("file_extension")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? FileExtension { get; set; } = string.Empty;
+
+ ///
+ /// External file url
+ ///
+ [JsonPropertyName("file_url")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? FileUrl { get; set; } = string.Empty;
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs
index 2a0128b6..da2ddec6 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/MessageFileModel.cs
@@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Files.Models;
-public class MessageFileModel : FileBase
+public class MessageFileModel : FileInformation
{
[JsonPropertyName("message_id")]
public string MessageId { get; set; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Utilities/FileUtility.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Utilities/FileUtility.cs
index df33906d..bba60b10 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Files/Utilities/FileUtility.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Files/Utilities/FileUtility.cs
@@ -1,4 +1,6 @@
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.StaticFiles;
+using System.IO;
namespace BotSharp.Abstraction.Files.Utilities;
@@ -26,11 +28,30 @@ public static class FileUtility
return (contentType, Convert.FromBase64String(base64Str));
}
- public static string GetFileContentType(string filePath)
+ public static string BuildFileDataFromFile(string fileName, byte[] bytes)
+ {
+ var contentType = GetFileContentType(fileName);
+ var base64 = Convert.ToBase64String(bytes);
+ return $"data:{contentType};base64,{base64}";
+ }
+
+ public static string BuildFileDataFromFile(IFormFile file)
+ {
+ using var stream = new MemoryStream();
+ file.CopyTo(stream);
+ stream.Position = 0;
+ var contentType = GetFileContentType(file.FileName);
+ var base64 = Convert.ToBase64String(stream.ToArray());
+ stream.Close();
+
+ return $"data:{contentType};base64,{base64}";
+ }
+
+ public static string GetFileContentType(string fileName)
{
string contentType;
var provider = new FileExtensionContentTypeProvider();
- if (!provider.TryGetContentType(filePath, out contentType))
+ if (!provider.TryGetContentType(fileName, out contentType))
{
contentType = string.Empty;
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Graph/IGraphDb.cs b/src/Infrastructure/BotSharp.Abstraction/Graph/IGraphDb.cs
index 64c5388b..b15503e2 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Graph/IGraphDb.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Graph/IGraphDb.cs
@@ -4,7 +4,7 @@ namespace BotSharp.Abstraction.Graph;
public interface IGraphDb
{
- public string Name { get; }
+ public string Provider { get; }
Task Search(string query, GraphSearchOptions options);
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs
index 20825791..1021ea1c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IKnowledgeService.cs
@@ -5,6 +5,9 @@ namespace BotSharp.Abstraction.Knowledges;
public interface IKnowledgeService
{
+ #region Vector
+ Task CreateVectorCollection(string collectionName, int dimension);
+ Task DeleteVectorCollection(string collectionName);
Task> GetVectorCollections();
Task> SearchVectorKnowledge(string query, string collectionName, VectorSearchOptions options);
Task FeedVectorKnowledge(string collectionName, KnowledgeCreationModel model);
@@ -12,6 +15,10 @@ public interface IKnowledgeService
Task DeleteVectorCollectionData(string collectionName, string id);
Task CreateVectorCollectionData(string collectionName, VectorCreateModel create);
Task UpdateVectorCollectionData(string collectionName, VectorUpdateModel update);
+ #endregion
+
+ #region Graph
Task SearchGraphKnowledge(string query, GraphSearchOptions options);
Task SearchKnowledge(string query, string collectionName, VectorSearchOptions vectorOptions, GraphSearchOptions graphOptions);
+ #endregion
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IPdf2TextConverter.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IPdf2TextConverter.cs
index b8f2d47b..d6edad54 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/IPdf2TextConverter.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/IPdf2TextConverter.cs
@@ -2,7 +2,7 @@ namespace BotSharp.Abstraction.Knowledges
{
public interface IPdf2TextConverter
{
- public string Name { get; }
+ public string Provider { get; }
Task ConvertPdfToText(string filePath, int? startPageNum, int? endPageNum);
}
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/ITextChopper.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/ITextChopper.cs
deleted file mode 100644
index 7d06a8a4..00000000
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/ITextChopper.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using BotSharp.Abstraction.Knowledges.Models;
-
-namespace BotSharp.Abstraction.Knowledges;
-
-///
-/// Chop large content into chunks
-///
-public interface ITextChopper
-{
- List Chop(string content, ChunkOption option);
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs
index 963a2b3b..217dafb9 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Knowledges/Settings/KnowledgeBaseSettings.cs
@@ -4,8 +4,8 @@ namespace BotSharp.Abstraction.Knowledges.Settings;
public class KnowledgeBaseSettings
{
- public string VectorDb { get; set; }
- public string GraphDb { get; set; }
+ public SettingBase VectorDb { get; set; }
+ public SettingBase GraphDb { get; set; }
public DefaultKnowledgeBaseSetting Default { get; set; }
public List Collections { get; set; } = new();
@@ -23,9 +23,13 @@ public class VectorCollectionSetting
public KnowledgeTextEmbeddingSetting TextEmbedding { get; set; }
}
-public class KnowledgeTextEmbeddingSetting
+public class KnowledgeTextEmbeddingSetting : SettingBase
{
- public string Provider { get; set; }
public string Model { get; set; }
public int Dimension { get; set; }
+}
+
+public class SettingBase
+{
+ public string Provider { get; set; }
}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IAudioCompletion.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IAudioCompletion.cs
new file mode 100644
index 00000000..54ed2d7d
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IAudioCompletion.cs
@@ -0,0 +1,13 @@
+using System.IO;
+
+namespace BotSharp.Abstraction.MLTasks;
+
+public interface IAudioCompletion
+{
+ string Provider { get; }
+
+ Task GenerateTextFromAudioAsync(Stream audio, string audioFileName, string? text = null);
+ Task GenerateAudioFromTextAsync(string text);
+
+ void SetModelName(string model);
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/ISpeechToText.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/ISpeechToText.cs
deleted file mode 100644
index 9e0dd574..00000000
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/ISpeechToText.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace BotSharp.Abstraction.MLTasks;
-
-public interface ISpeechToText
-{
- string Provider { get; }
-
- Task GenerateTextFromAudioAsync(string filePath);
- // Task AudioToTextTranscript(Stream stream);
- Task SetModelName(string modelType);
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/ITextToSpeech.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/ITextToSpeech.cs
deleted file mode 100644
index 344fad0e..00000000
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/ITextToSpeech.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-namespace BotSharp.Abstraction.MLTasks
-{
- public interface ITextToSpeech
- {
- ///
- /// The LLM provider like Microsoft Azure, OpenAI, ClaudAI
- ///
- string Provider { get; }
-
- ///
- /// Set model name, one provider can consume different model or version(s)
- ///
- /// deployment name
- void SetModelName(string model);
-
- Task GenerateSpeechFromTextAsync(string text, ITextToSpeechOptions? options = null);
- }
-
- public interface ITextToSpeechOptions
- {
-
- }
-}
diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs
index cc7cfba0..008f528b 100644
--- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/Settings/LlmModelSetting.cs
@@ -68,5 +68,6 @@ public enum LlmModelType
Text = 1,
Chat = 2,
Image = 3,
- Embedding = 4
+ Embedding = 4,
+ Audio = 5
}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs b/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs
new file mode 100644
index 00000000..f981ba6e
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Models/KeyValue.cs
@@ -0,0 +1,10 @@
+namespace BotSharp.Abstraction.Models;
+
+public class KeyValue
+{
+ [JsonPropertyName("key")]
+ public string Key { get; set; }
+
+ [JsonPropertyName("value")]
+ public string Value { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs
index 24e4152c..9ea5917c 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Models/MessageConfig.cs
@@ -1,6 +1,6 @@
namespace BotSharp.Abstraction.Models;
-public class MessageConfig : InputMessageFiles
+public class MessageConfig
{
///
/// Completion Provider
@@ -15,7 +15,7 @@ public class MessageConfig : InputMessageFiles
public virtual string? Model { get; set; } = null;
///
- /// Model name
+ /// Model id
///
[JsonPropertyName("model_id")]
public virtual string? ModelId { get; set; } = null;
@@ -34,7 +34,7 @@ public class MessageConfig : InputMessageFiles
///
/// Conversation states from input
///
- public List States { get; set; } = new List();
+ public List States { get; set; } = new();
///
/// Agent task id
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs
new file mode 100644
index 00000000..ec519f04
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Extensions/VectorStorageExtension.cs
@@ -0,0 +1,29 @@
+using BotSharp.Abstraction.Knowledges.Enums;
+using BotSharp.Abstraction.VectorStorage.Models;
+
+namespace BotSharp.Abstraction.VectorStorage.Extensions;
+
+public static class VectorStorageExtension
+{
+ public static string ToQuestionAnswer(this VectorSearchResult data)
+ {
+ if (data?.Data == null) return string.Empty;
+
+ return $"Question: {data.Data[KnowledgePayloadName.Text]}\r\nAnswer: {data.Data[KnowledgePayloadName.Answer]}";
+ }
+
+ public static string ToPayloadPair(this VectorSearchResult data, IList payloads)
+ {
+ if (data?.Data == null || payloads.IsNullOrEmpty()) return string.Empty;
+
+ var results = data.Data.Where(x => payloads.Contains(x.Key))
+ .OrderBy(x => payloads.IndexOf(x.Key))
+ .Select(x =>
+ {
+ return $"{x.Key}: {x.Value}";
+ })
+ .ToList();
+
+ return string.Join("\r\n", results.Where(x => !string.IsNullOrWhiteSpace(x)));
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs
index 53b921a1..cedacb46 100644
--- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/IVectorDb.cs
@@ -4,12 +4,13 @@ namespace BotSharp.Abstraction.VectorStorage;
public interface IVectorDb
{
- string Name { get; }
+ string Provider { get; }
Task> GetCollections();
Task> GetPagedCollectionData(string collectionName, VectorFilter filter);
Task> GetCollectionData(string collectionName, IEnumerable ids, bool withPayload = false, bool withVector = false);
- Task CreateCollection(string collectionName, int dim);
+ Task CreateCollection(string collectionName, int dimension);
+ Task DeleteCollection(string collectionName);
Task Upsert(string collectionName, Guid id, float[] vector, string text, Dictionary? payload = null);
Task> Search(string collectionName, float[] vector, IEnumerable? fields, int limit = 5, float confidence = 0.5f, bool withVector = false);
Task DeleteCollectionData(string collectionName, Guid id);
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs
index 91abcc25..85b9dec2 100644
--- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorFilter.cs
@@ -4,4 +4,7 @@ public class VectorFilter : StringIdPagination
{
[JsonPropertyName("with_vector")]
public bool WithVector { get; set; }
-}
+
+ [JsonPropertyName("search_pairs")]
+ public IEnumerable? SearchPairs { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs
index ce39edbf..f2c582ce 100644
--- a/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/VectorStorage/Models/VectorSearchResult.cs
@@ -1,3 +1,5 @@
+using BotSharp.Abstraction.Knowledges.Enums;
+
namespace BotSharp.Abstraction.VectorStorage.Models;
public class VectorSearchResult : VectorCollectionData
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index 05d485b7..ff10a517 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -1,4 +1,4 @@
-
+
$(TargetFramework)
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
index f06e2ba2..05653d9c 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs
@@ -6,6 +6,7 @@ using BotSharp.Abstraction.Routing.Planning;
using BotSharp.Abstraction.Settings;
using BotSharp.Abstraction.Templating;
using BotSharp.Core.Instructs;
+using BotSharp.Core.Knowledges.Services;
using BotSharp.Core.Messaging;
using BotSharp.Core.Routing.Planning;
using BotSharp.Core.Templating;
@@ -54,6 +55,8 @@ public class ConversationPlugin : IBotSharpPlugin
services.AddScoped();
services.AddScoped();
services.AddScoped();
+
+ services.AddScoped();
}
public bool AttachMenu(List menu)
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs
new file mode 100644
index 00000000..e2aa844c
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs
@@ -0,0 +1,20 @@
+using System.IO;
+
+namespace BotSharp.Core.Files.Services;
+
+public partial class FileInstructService
+{
+ public async Task SpeechToText(string? provider, string? model, InstructFileModel audio, string? text = null)
+ {
+ var completion = CompletionProvider.GetAudioCompletion(_services, provider: provider ?? "openai", model: model ?? "whisper-1");
+ var audioBytes = await DownloadFile(audio);
+ using var stream = new MemoryStream();
+ stream.Write(audioBytes, 0, audioBytes.Length);
+ stream.Position = 0;
+
+ var fileName = $"{audio.FileName ?? "audio"}.{audio.FileExtension ?? "wav"}";
+ var content = await completion.GenerateTextFromAudioAsync(stream, fileName, text);
+ stream.Close();
+ return content;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs
index c9d35cb7..cd65c16a 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs
@@ -4,7 +4,7 @@ namespace BotSharp.Core.Files.Services;
public partial class FileInstructService
{
- public async Task ReadImages(string? provider, string? model, string text, IEnumerable images)
+ public async Task ReadImages(string? provider, string? model, string text, IEnumerable images)
{
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider ?? "openai", model: model ?? "gpt-4o", multiModal: true);
var message = await completion.GetChatCompletions(new Agent()
@@ -14,10 +14,10 @@ public partial class FileInstructService
{
new RoleDialogModel(AgentRole.User, text)
{
- Files = images?.ToList() ?? new List()
+ Files = images?.Select(x => new BotSharpFile { FileUrl = x.FileUrl, FileData = x.FileData }).ToList() ?? new List()
}
});
- return message;
+ return message.Content;
}
public async Task GenerateImage(string? provider, string? model, string text)
@@ -30,7 +30,7 @@ public partial class FileInstructService
return message;
}
- public async Task VaryImage(string? provider, string? model, BotSharpFile image)
+ public async Task VaryImage(string? provider, string? model, InstructFileModel image)
{
if (string.IsNullOrWhiteSpace(image?.FileUrl) && string.IsNullOrWhiteSpace(image?.FileData))
{
@@ -43,16 +43,17 @@ public partial class FileInstructService
stream.Write(bytes, 0, bytes.Length);
stream.Position = 0;
+ var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var message = await completion.GetImageVariation(new Agent()
{
Id = Guid.Empty.ToString()
- }, new RoleDialogModel(AgentRole.User, string.Empty), stream, image.FileName ?? string.Empty);
+ }, new RoleDialogModel(AgentRole.User, string.Empty), stream, fileName);
stream.Close();
return message;
}
- public async Task EditImage(string? provider, string? model, string text, BotSharpFile image)
+ public async Task EditImage(string? provider, string? model, string text, InstructFileModel image)
{
if (string.IsNullOrWhiteSpace(image?.FileUrl) && string.IsNullOrWhiteSpace(image?.FileData))
{
@@ -65,16 +66,17 @@ public partial class FileInstructService
stream.Write(bytes, 0, bytes.Length);
stream.Position = 0;
+ var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var message = await completion.GetImageEdits(new Agent()
{
Id = Guid.Empty.ToString()
- }, new RoleDialogModel(AgentRole.User, text), stream, image.FileName ?? string.Empty);
+ }, new RoleDialogModel(AgentRole.User, text), stream, fileName);
stream.Close();
return message;
}
- public async Task EditImage(string? provider, string? model, string text, BotSharpFile image, BotSharpFile mask)
+ public async Task EditImage(string? provider, string? model, string text, InstructFileModel image, InstructFileModel mask)
{
if ((string.IsNullOrWhiteSpace(image?.FileUrl) && string.IsNullOrWhiteSpace(image?.FileData)) ||
(string.IsNullOrWhiteSpace(mask?.FileUrl) && string.IsNullOrWhiteSpace(mask?.FileData)))
@@ -94,10 +96,12 @@ public partial class FileInstructService
maskStream.Write(maskBytes, 0, maskBytes.Length);
maskStream.Position = 0;
+ var imageName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
+ var maskName = $"{mask.FileName ?? "mask"}.{mask.FileExtension ?? "png"}";
var message = await completion.GetImageEdits(new Agent()
{
Id = Guid.Empty.ToString()
- }, new RoleDialogModel(AgentRole.User, text), imageStream, image.FileName ?? string.Empty, maskStream, mask.FileName ?? string.Empty);
+ }, new RoleDialogModel(AgentRole.User, text), imageStream, imageName, maskStream, maskName);
imageStream.Close();
maskStream.Close();
@@ -105,7 +109,7 @@ public partial class FileInstructService
}
#region Private methods
- private async Task DownloadFile(BotSharpFile file)
+ private async Task DownloadFile(InstructFileModel file)
{
var bytes = new byte[0];
if (!string.IsNullOrEmpty(file.FileUrl))
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs
index 2aec257b..29dfdaf9 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs
@@ -4,7 +4,7 @@ namespace BotSharp.Core.Files.Services;
public partial class FileInstructService
{
- public async Task ReadPdf(string? provider, string? model, string? modelId, string prompt, List files)
+ public async Task ReadPdf(string? provider, string? model, string? modelId, string prompt, List files)
{
var content = string.Empty;
@@ -50,7 +50,7 @@ public partial class FileInstructService
}
#region Private methods
- private async Task> DownloadFiles(string dir, List files, string extension = "pdf")
+ private async Task> DownloadFiles(string dir, List files, string extension = "pdf")
{
if (string.IsNullOrWhiteSpace(dir) || files.IsNullOrEmpty())
{
@@ -80,9 +80,9 @@ public partial class FileInstructService
var fileDir = _fileStorage.BuildDirectory(dir, guid);
DeleteIfExistDirectory(fileDir, true);
- var pdfDir = _fileStorage.BuildDirectory(fileDir, $"{guid}.{extension}");
- _fileStorage.SaveFileBytesToPath(pdfDir, bytes);
- locs.Add(pdfDir);
+ var outputDir = _fileStorage.BuildDirectory(fileDir, $"{guid}.{extension}");
+ _fileStorage.SaveFileBytesToPath(outputDir, bytes);
+ locs.Add(outputDir);
}
}
catch (Exception ex)
@@ -98,7 +98,7 @@ public partial class FileInstructService
{
var images = new List();
var settings = _services.GetRequiredService();
- var converter = _services.GetServices().FirstOrDefault(x => x.Name == settings.Pdf2ImageConverter);
+ var converter = _services.GetServices().FirstOrDefault(x => x.Provider == settings.Pdf2ImageConverter.Provider);
if (converter == null || files.IsNullOrEmpty())
{
return images;
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs
index acd0ddaa..416d9f30 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs
@@ -1,3 +1,4 @@
+
namespace BotSharp.Core.Files.Services;
public partial class FileInstructService : IFileInstructService
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
index e90c7812..1aaba575 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Audio.cs
@@ -1,28 +1,38 @@
using System.IO;
-namespace BotSharp.Core.Files.Services
+namespace BotSharp.Core.Files.Services;
+
+public partial class LocalFileStorageService
{
- public partial class LocalFileStorageService
+ public bool SaveSpeechFile(string conversationId, string fileName, BinaryData data)
{
- public async Task SaveSpeechFileAsync(string conversationId, string fileName, BinaryData data)
+ try
{
var dir = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, TEXT_TO_SPEECH_FOLDER);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
- var filePath = Path.Combine(dir, fileName);
- if (File.Exists(filePath)) return;
- using var file = File.Create(filePath);
- using var input = data.ToStream();
- await input.CopyToAsync(file);
- }
- public async Task RetrieveSpeechFileAsync(string conversationId, string fileName)
+ var filePath = Path.Combine(dir, fileName);
+ if (File.Exists(filePath)) return false;
+
+ using var fs = File.Create(filePath);
+ using var ds = data.ToStream();
+ ds.CopyTo(fs);
+ return true;
+ }
+ catch (Exception ex)
{
- var path = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, TEXT_TO_SPEECH_FOLDER, fileName);
- using var file = new FileStream(path, FileMode.Open, FileAccess.Read);
- return await BinaryData.FromStreamAsync(file);
+ _logger.LogWarning($"Error when saving speech file. {fileName} ({conversationId})\r\n{ex.Message}\r\n{ex.InnerException}");
+ return false;
}
}
+
+ public BinaryData GetSpeechFile(string conversationId, string fileName)
+ {
+ var path = Path.Combine(_baseDir, CONVERSATION_FOLDER, conversationId, TEXT_TO_SPEECH_FOLDER, fileName);
+ using var file = new FileStream(path, FileMode.Open, FileAccess.Read);
+ return BinaryData.FromStream(file);
+ }
}
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs
index c49edbce..b16c2c2c 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Common.cs
@@ -14,6 +14,22 @@ public partial class LocalFileStorageService
return dir;
}
+ public IEnumerable GetFiles(string relativePath, string? searchPattern = null)
+ {
+ if (string.IsNullOrWhiteSpace(relativePath))
+ {
+ return Enumerable.Empty();
+ }
+
+ var path = Path.Combine(_baseDir, relativePath);
+
+ if (!string.IsNullOrWhiteSpace(searchPattern))
+ {
+ return Directory.GetFiles(path, searchPattern);
+ }
+ return Directory.GetFiles(path);
+ }
+
public byte[] GetFileBytes(string fileStorageUrl)
{
using var stream = File.OpenRead(fileStorageUrl);
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs
index 8c2ed831..5638179c 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.Conversation.cs
@@ -6,7 +6,7 @@ namespace BotSharp.Core.Files.Services;
public partial class LocalFileStorageService
{
- public async Task> GetMessageFileScreenshots(string conversationId, IEnumerable messageIds)
+ public async Task> GetMessageFileScreenshotsAsync(string conversationId, IEnumerable messageIds)
{
var files = new List();
if (string.IsNullOrEmpty(conversationId) || messageIds.IsNullOrEmpty())
@@ -118,7 +118,7 @@ public partial class LocalFileStorageService
return foundMsgs;
}
- public bool SaveMessageFiles(string conversationId, string messageId, string source, List files)
+ public bool SaveMessageFiles(string conversationId, string messageId, string source, List files)
{
if (files.IsNullOrEmpty()) return false;
@@ -276,7 +276,7 @@ public partial class LocalFileStorageService
private IPdf2ImageConverter? GetPdf2ImageConverter()
{
var settings = _services.GetRequiredService();
- var converter = _services.GetServices().FirstOrDefault(x => x.Name == settings.Pdf2ImageConverter);
+ var converter = _services.GetServices().FirstOrDefault(x => x.Provider == settings.Pdf2ImageConverter.Provider);
return converter;
}
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs
index 43ff9eed..d1e962cd 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.User.cs
@@ -16,7 +16,7 @@ public partial class LocalFileStorageService
return found;
}
- public bool SaveUserAvatar(BotSharpFile file)
+ public bool SaveUserAvatar(InputFileModel file)
{
if (file == null || string.IsNullOrEmpty(file.FileData)) return false;
diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.cs
index 94ee2beb..750803c4 100644
--- a/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.cs
+++ b/src/Infrastructure/BotSharp.Core/Files/Services/Storage/LocalFileStorageService.cs
@@ -10,12 +10,6 @@ public partial class LocalFileStorageService : IFileStorageService
private readonly ILogger _logger;
private readonly string _baseDir;
- private readonly IEnumerable _audioTypes = new List
- {
- "mp3",
- "wav"
- };
-
private const string CONVERSATION_FOLDER = "conversations";
private const string FILE_FOLDER = "files";
private const string USER_FILE_FOLDER = "user";
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
index 874a063e..d6746e09 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs
@@ -28,6 +28,10 @@ public class CompletionProvider
{
return GetImageCompletion(services, provider: provider, model: model);
}
+ else if (settings.Type == LlmModelType.Audio)
+ {
+ return GetAudioCompletion(services, provider: provider, model: model);
+ }
else
{
return GetChatCompletion(services, provider: provider, model: model, agentConfig: agentConfig);
@@ -108,7 +112,7 @@ public class CompletionProvider
if (completer == null)
{
var logger = services.GetRequiredService>();
- logger.LogError($"Can't resolve completion provider by {provider}");
+ logger.LogError($"Can't resolve text-embedding provider by {provider}");
}
@@ -120,35 +124,19 @@ public class CompletionProvider
return completer;
}
- public static ITextToSpeech GetTextToSpeech(
+ public static IAudioCompletion GetAudioCompletion(
IServiceProvider services,
string provider,
string model)
{
- var completions = services.GetServices();
+ var completions = services.GetServices();
var completer = completions.FirstOrDefault(x => x.Provider == provider);
if (completer == null)
{
var logger = services.GetRequiredService>();
- logger.LogError($"Can't resolve text2speech provider by {provider}");
+ logger.LogError($"Can't resolve audio-completion provider by {provider}");
}
- completer.SetModelName(model);
- return completer;
- }
- public static ISpeechToText GetSpeechToText(
- IServiceProvider services,
- string provider,
- string model
- )
- {
- var completions = services.GetServices();
- var completer = completions.FirstOrDefault(x => x.Provider == provider);
- if (completer == null)
- {
- var logger = services.GetRequiredService>();
- logger.LogError($"Can't resolve speech2text provider by {provider}");
- }
completer.SetModelName(model);
return completer;
}
diff --git a/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/KnowledgeSettingHelper.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/KnowledgeSettingHelper.cs
new file mode 100644
index 00000000..a278d7bf
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/KnowledgeSettingHelper.cs
@@ -0,0 +1,36 @@
+using BotSharp.Abstraction.Knowledges.Settings;
+using BotSharp.Abstraction.MLTasks;
+
+namespace BotSharp.Core.Knowledges.Helpers;
+
+public static class KnowledgeSettingHelper
+{
+ public static ITextEmbedding GetTextEmbeddingSetting(IServiceProvider services, string collectionName)
+ {
+ var settings = services.GetRequiredService();
+ var found = settings.Collections.FirstOrDefault(x => x.Name == collectionName)?.TextEmbedding;
+ if (found == null)
+ {
+ found = settings.Default.TextEmbedding;
+ }
+
+ var embedding = services.GetServices().FirstOrDefault(x => x.Provider == found.Provider);
+ var dimension = found.Dimension;
+
+ if (found.Dimension <= 0)
+ {
+ dimension = GetLlmTextEmbeddingDimension(services, found.Provider, found.Model);
+ }
+
+ embedding.SetModelName(found.Model);
+ embedding.SetDimension(dimension);
+ return embedding;
+ }
+
+ private static int GetLlmTextEmbeddingDimension(IServiceProvider services, string provider, string model)
+ {
+ var settings = services.GetRequiredService();
+ var found = settings.GetSetting(provider, model);
+ return found?.Dimension ?? 0;
+ }
+}
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/TextChopperService.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/TextChopper.cs
similarity index 78%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/TextChopperService.cs
rename to src/Infrastructure/BotSharp.Core/Knowledges/Helpers/TextChopper.cs
index 88c77641..68b58539 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/TextChopperService.cs
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Helpers/TextChopper.cs
@@ -1,17 +1,18 @@
+using BotSharp.Abstraction.Knowledges.Models;
using System.Text.RegularExpressions;
-namespace BotSharp.Plugin.KnowledgeBase.Services;
+namespace BotSharp.Core.Knowledges.Helpers;
-public class TextChopperService : ITextChopper
+public static class TextChopper
{
- public List Chop(string content, ChunkOption option)
+ public static List Chop(string content, ChunkOption option)
{
content = Regex.Replace(content, @"\.{2,}", " ");
content = Regex.Replace(content, @"_{2,}", " ");
return option.SplitByWord ? ChopByWord(content, option) : ChopByChar(content, option);
}
- private List ChopByWord(string content, ChunkOption option)
+ private static List ChopByWord(string content, ChunkOption option)
{
var chunks = new List();
@@ -34,7 +35,7 @@ public class TextChopperService : ITextChopper
return chunks;
}
- private List ChopByChar(string content, ChunkOption option)
+ private static List ChopByChar(string content, ChunkOption option)
{
var chunks = new List();
var currentPos = 0;
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Create.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Create.cs
similarity index 65%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Create.cs
rename to src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Create.cs
index 9b185867..d8b82fb5 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Create.cs
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Create.cs
@@ -1,11 +1,15 @@
-namespace BotSharp.Plugin.KnowledgeBase.Services;
+using BotSharp.Abstraction.Knowledges.Models;
+using BotSharp.Abstraction.VectorStorage.Models;
+using BotSharp.Core.Knowledges.Helpers;
+
+namespace BotSharp.Core.Knowledges.Services;
public partial class KnowledgeService
{
public async Task FeedVectorKnowledge(string collectionName, KnowledgeCreationModel knowledge)
{
var index = 0;
- var lines = _textChopper.Chop(knowledge.Content, new ChunkOption
+ var lines = TextChopper.Chop(knowledge.Content, new ChunkOption
{
Size = 1024,
Conjunction = 32,
@@ -25,6 +29,25 @@ public partial class KnowledgeService
}
}
+ public async Task CreateVectorCollection(string collectionName, int dimension)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(collectionName))
+ {
+ return false;
+ }
+
+ var db = GetVectorDb();
+ return await db.CreateCollection(collectionName, dimension);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning($"Error when creating a vector collection ({collectionName}). {ex.Message}\r\n{ex.InnerException}");
+ return false;
+ }
+ }
+
public async Task CreateVectorCollectionData(string collectionName, VectorCreateModel create)
{
try
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Delete.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Delete.cs
similarity index 51%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Delete.cs
rename to src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Delete.cs
index e78990a7..404b4e2c 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Delete.cs
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Delete.cs
@@ -1,7 +1,26 @@
-namespace BotSharp.Plugin.KnowledgeBase.Services;
+namespace BotSharp.Core.Knowledges.Services;
public partial class KnowledgeService
{
+ public async Task DeleteVectorCollection(string collectionName)
+ {
+ try
+ {
+ if (string.IsNullOrWhiteSpace(collectionName))
+ {
+ return false;
+ }
+
+ var db = GetVectorDb();
+ return await db.DeleteCollection(collectionName);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning($"Error when deleting collection ({collectionName}). {ex.Message}\r\n{ex.InnerException}");
+ return false;
+ }
+ }
+
public async Task DeleteVectorCollectionData(string collectionName, string id)
{
try
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Get.cs
similarity index 96%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
rename to src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Get.cs
index ee36780e..69093659 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Get.cs
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Get.cs
@@ -1,6 +1,8 @@
using BotSharp.Abstraction.Graph.Models;
+using BotSharp.Abstraction.Knowledges.Models;
+using BotSharp.Abstraction.VectorStorage.Models;
-namespace BotSharp.Plugin.KnowledgeBase.Services;
+namespace BotSharp.Core.Knowledges.Services;
public partial class KnowledgeService
{
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Update.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Update.cs
similarity index 91%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Update.cs
rename to src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Update.cs
index 0fa1f5cd..b9652f61 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.Update.cs
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.Update.cs
@@ -1,4 +1,6 @@
-namespace BotSharp.Plugin.KnowledgeBase.Services;
+using BotSharp.Abstraction.VectorStorage.Models;
+
+namespace BotSharp.Core.Knowledges.Services;
public partial class KnowledgeService
{
diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.cs
similarity index 64%
rename from src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs
rename to src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.cs
index eec49891..2c0853d0 100644
--- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/Services/KnowledgeService.cs
+++ b/src/Infrastructure/BotSharp.Core/Knowledges/Services/KnowledgeService.cs
@@ -1,38 +1,41 @@
-namespace BotSharp.Plugin.KnowledgeBase.Services;
+using BotSharp.Abstraction.Graph;
+using BotSharp.Abstraction.Knowledges.Settings;
+using BotSharp.Abstraction.MLTasks;
+using BotSharp.Abstraction.VectorStorage;
+using BotSharp.Core.Knowledges.Helpers;
+
+namespace BotSharp.Core.Knowledges.Services;
public partial class KnowledgeService : IKnowledgeService
{
private readonly IServiceProvider _services;
private readonly KnowledgeBaseSettings _settings;
- private readonly ITextChopper _textChopper;
private readonly ILogger _logger;
public KnowledgeService(
IServiceProvider services,
KnowledgeBaseSettings settings,
- ITextChopper textChopper,
ILogger logger)
{
_services = services;
_settings = settings;
- _textChopper = textChopper;
_logger = logger;
}
private IVectorDb GetVectorDb()
{
- var db = _services.GetServices().FirstOrDefault(x => x.Name == _settings.VectorDb);
+ var db = _services.GetServices().FirstOrDefault(x => x.Provider == _settings.VectorDb.Provider);
return db;
}
private IGraphDb GetGraphDb()
{
- var db = _services.GetServices().FirstOrDefault(x => x.Name == _settings.GraphDb);
+ var db = _services.GetServices().FirstOrDefault(x => x.Provider == _settings.GraphDb.Provider);
return db;
}
private ITextEmbedding GetTextEmbedding(string collection)
{
- return KnowledgeSettingUtility.GetTextEmbeddingSetting(_services, collection);
+ return KnowledgeSettingHelper.GetTextEmbeddingSetting(_services, collection);
}
}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs
index 72549e51..0fcaa5a1 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.GetPlanner.cs
@@ -1,4 +1,3 @@
-using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Planning;
using BotSharp.Core.Routing.Planning;
diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid
index 0332af76..4c9f51c3 100644
--- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid
+++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/database_knowledge.liquid
@@ -1,8 +1,10 @@
-You are a knowledge generator assistant. Based on the provided mysql table structure, including tablename, fieldname,data type and comments, generate the related knowledge for DBA and BA. When user ask the question, they don't know the table name.
-the summarized question/answer should:
+You are a knowledge generator assistant. Based on the provided mysql table structure, including tablename, fieldname, data type and comments, generate the related knowledge for DBA and BA. When users ask the question, they don't know the table name.
+
+The summarized question/answer should:
1. help user to identify the location of tables to find further information
2. identify the table structure and data relationship based on the task description
-3. summarize all the table to table relationship information based on the FOREIGN KEY, and include both table in the answer
+3. summarize all the tables to table relationship information based on the FOREIGN KEY, and include both tables in the answer
+
Go through all the columns and generate multiple question & answer pairs.
The output should be question/answer pair list in JSON: [{"question":"","answer":""}]. And the new line should be replaced with \r\n.
diff --git a/src/Infrastructure/BotSharp.Logger/Hooks/VerboseLogHook.cs b/src/Infrastructure/BotSharp.Logger/Hooks/VerboseLogHook.cs
index cf6985e9..afb8dd01 100644
--- a/src/Infrastructure/BotSharp.Logger/Hooks/VerboseLogHook.cs
+++ b/src/Infrastructure/BotSharp.Logger/Hooks/VerboseLogHook.cs
@@ -23,10 +23,13 @@ public class VerboseLogHook : IContentGeneratingHook
{
if (!_convSettings.ShowVerboseLog) return;
- var dialog = conversations.Last();
- var log = $"{dialog.Role}: {dialog.Content} [msg_id: {dialog.MessageId}] ==>";
- _logger.LogInformation(log);
-
+ var dialog = conversations.LastOrDefault();
+ if (dialog != null)
+ {
+ var log = $"{dialog.Role}: {dialog.Content} [msg_id: {dialog.MessageId}] ==>";
+ _logger.LogInformation(log);
+ }
+
await Task.CompletedTask;
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
index 24002225..9094107d 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
+++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj
@@ -1,4 +1,4 @@
-
+
$(TargetFramework)
@@ -19,6 +19,7 @@
+
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
index 9b964dff..565677f7 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
@@ -294,9 +294,7 @@ public class ConversationController : ControllerBase
}
[HttpPost("/conversation/{agentId}/{conversationId}/sse")]
- public async Task SendMessageSse([FromRoute] string agentId,
- [FromRoute] string conversationId,
- [FromBody] NewMessageModel input)
+ public async Task SendMessageSse([FromRoute] string agentId, [FromRoute] string conversationId, [FromBody] NewMessageModel input)
{
var conv = _services.GetRequiredService();
var inputMsg = new RoleDialogModel(AgentRole.User, input.Text)
@@ -391,7 +389,7 @@ public class ConversationController : ControllerBase
}
[HttpPost("/agent/{agentId}/conversation/{conversationId}/upload")]
- public async Task UploadConversationMessageFiles([FromRoute] string agentId, [FromRoute] string conversationId, [FromBody] NewMessageModel input)
+ public async Task UploadConversationMessageFiles([FromRoute] string agentId, [FromRoute] string conversationId, [FromBody] InputMessageFiles input)
{
var convService = _services.GetRequiredService();
convService.SetConversationId(conversationId, input.States);
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
index 48fdafe1..bc02e846 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Files.Utilities;
using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Core.Infrastructures;
@@ -20,8 +21,7 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/{agentId}")]
- public async Task InstructCompletion([FromRoute] string agentId,
- [FromBody] InstructMessageModel input)
+ public async Task InstructCompletion([FromRoute] string agentId, [FromBody] InstructMessageModel input)
{
var state = _services.GetRequiredService();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
@@ -79,7 +79,7 @@ public class InstructModeController : ControllerBase
#region Read image
[HttpPost("/instruct/multi-modal")]
- public async Task MultiModalCompletion([FromBody] IncomingMessageModel input)
+ public async Task MultiModalCompletion([FromBody] MultiModalRequest input)
{
var state = _services.GetRequiredService();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
@@ -87,21 +87,50 @@ public class InstructModeController : ControllerBase
try
{
var fileInstruct = _services.GetRequiredService();
- var message = await fileInstruct.ReadImages(input.Provider, input.Model, input.Text, input.Files);
- return message.Content;
+ var content = await fileInstruct.ReadImages(input.Provider, input.Model, input.Text, input.Files);
+ return content;
}
catch (Exception ex)
{
- var error = $"Error in analyzing files. {ex.Message}";
+ var error = $"Error in reading images. {ex.Message}";
_logger.LogError(error);
return error;
}
}
+
+ [HttpPost("/instruct/multi-modal/upload")]
+ public async Task MultiModalCompletion(IFormFile file, [FromForm] string text, [FromForm] string? provider = null,
+ [FromForm] string? model = null, [FromForm] List? states = null)
+ {
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var viewModel = new MultiModalViewModel();
+
+ try
+ {
+ var data = FileUtility.BuildFileDataFromFile(file);
+ var files = new List
+ {
+ new InstructFileModel { FileData = data }
+ };
+ var fileInstruct = _services.GetRequiredService();
+ var content = await fileInstruct.ReadImages(provider, model, text, files);
+ viewModel.Content = content;
+ return viewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in reading image upload. {ex.Message}";
+ _logger.LogError(error);
+ viewModel.Message = error;
+ return viewModel;
+ }
+ }
#endregion
#region Generate image
[HttpPost("/instruct/image-generation")]
- public async Task ImageGeneration([FromBody] IncomingMessageModel input)
+ public async Task ImageGeneration([FromBody] ImageGenerationRequest input)
{
var state = _services.GetRequiredService();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
@@ -127,7 +156,7 @@ public class InstructModeController : ControllerBase
#region Edit image
[HttpPost("/instruct/image-variation")]
- public async Task ImageVariation([FromBody] IncomingMessageModel input)
+ public async Task ImageVariation([FromBody] ImageVariationRequest input)
{
var state = _services.GetRequiredService();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
@@ -135,16 +164,16 @@ public class InstructModeController : ControllerBase
try
{
- var image = input.Files.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.FileUrl) || !string.IsNullOrWhiteSpace(x.FileData));
- if (image == null)
+ if (input.File == null)
{
return new ImageGenerationViewModel { Message = "Error! Cannot find an image!" };
}
var fileInstruct = _services.GetRequiredService();
- var message = await fileInstruct.VaryImage(input.Provider, input.Model, image);
+ var message = await fileInstruct.VaryImage(input.Provider, input.Model, input.File);
imageViewModel.Content = message.Content;
imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
+
return imageViewModel;
}
catch (Exception ex)
@@ -156,8 +185,43 @@ public class InstructModeController : ControllerBase
}
}
+ [HttpPost("/instruct/image-variation/upload")]
+ public async Task ImageVariation(IFormFile file, [FromForm] string? provider = null,
+ [FromForm] string? model = null, [FromForm] List? states = null)
+ {
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var imageViewModel = new ImageGenerationViewModel();
+
+ try
+ {
+ using var stream = new MemoryStream();
+ file.CopyTo(stream);
+ stream.Position = 0;
+
+ var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-2");
+ var message = await completion.GetImageVariation(new Agent()
+ {
+ Id = Guid.Empty.ToString()
+ }, new RoleDialogModel(AgentRole.User, string.Empty), stream, file.FileName);
+
+ imageViewModel.Content = message.Content;
+ imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
+ stream.Close();
+
+ return imageViewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in image variation upload. {ex.Message}";
+ _logger.LogError(error);
+ imageViewModel.Message = error;
+ return imageViewModel;
+ }
+ }
+
[HttpPost("/instruct/image-edit")]
- public async Task ImageEdit([FromBody] IncomingMessageModel input)
+ public async Task ImageEdit([FromBody] ImageEditRequest input)
{
var fileInstruct = _services.GetRequiredService();
var state = _services.GetRequiredService();
@@ -166,12 +230,11 @@ public class InstructModeController : ControllerBase
try
{
- var image = input.Files.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.FileUrl) || !string.IsNullOrWhiteSpace(x.FileData));
- if (image == null)
+ if (input.File == null)
{
- return new ImageGenerationViewModel { Message = "Error! Cannot find an image!" };
+ return new ImageGenerationViewModel { Message = "Error! Cannot find a valid image file!" };
}
- var message = await fileInstruct.EditImage(input.Provider, input.Model, input.Text, image);
+ var message = await fileInstruct.EditImage(input.Provider, input.Model, input.Text, input.File);
imageViewModel.Content = message.Content;
imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
return imageViewModel;
@@ -185,8 +248,44 @@ public class InstructModeController : ControllerBase
}
}
+ [HttpPost("/instruct/image-edit/upload")]
+ public async Task ImageEdit(IFormFile file, [FromForm] string text, [FromForm] string? provider = null,
+ [FromForm] string? model = null, [FromForm] List? states = null)
+ {
+ var fileInstruct = _services.GetRequiredService();
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var imageViewModel = new ImageGenerationViewModel();
+
+ try
+ {
+ using var stream = new MemoryStream();
+ file.CopyTo(stream);
+ stream.Position = 0;
+
+ var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-2");
+ var message = await completion.GetImageEdits(new Agent()
+ {
+ Id = Guid.Empty.ToString()
+ }, new RoleDialogModel(AgentRole.User, text), stream, file.FileName);
+
+ imageViewModel.Content = message.Content;
+ imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
+ stream.Close();
+
+ return imageViewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in image edit upload. {ex.Message}";
+ _logger.LogError(error);
+ imageViewModel.Message = error;
+ return imageViewModel;
+ }
+ }
+
[HttpPost("/instruct/image-mask-edit")]
- public async Task ImageMaskEdit([FromBody] IncomingMessageModel input)
+ public async Task ImageMaskEdit([FromBody] ImageMaskEditRequest input)
{
var fileInstruct = _services.GetRequiredService();
var state = _services.GetRequiredService();
@@ -195,11 +294,11 @@ public class InstructModeController : ControllerBase
try
{
- var image = input.Files.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.FileUrl) || !string.IsNullOrWhiteSpace(x.FileData));
+ var image = input.File;
var mask = input.Mask;
if (image == null || mask == null)
{
- return new ImageGenerationViewModel { Message = "Error! Cannot find an image or mask!" };
+ return new ImageGenerationViewModel { Message = "Error! Cannot find a valid image or mask!" };
}
var message = await fileInstruct.EditImage(input.Provider, input.Model, input.Text, image, mask);
imageViewModel.Content = message.Content;
@@ -214,11 +313,52 @@ public class InstructModeController : ControllerBase
return imageViewModel;
}
}
+
+ [HttpPost("/instruct/image-mask-edit/upload")]
+ public async Task ImageMaskEdit(IFormFile image, IFormFile mask, [FromForm] string text, [FromForm] string? provider = null,
+ [FromForm] string? model = null, [FromForm] List? states = null)
+ {
+ var fileInstruct = _services.GetRequiredService();
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var imageViewModel = new ImageGenerationViewModel();
+
+ try
+ {
+ using var imageStream = new MemoryStream();
+ image.CopyTo(imageStream);
+ imageStream.Position = 0;
+
+ using var maskStream = new MemoryStream();
+ mask.CopyTo(maskStream);
+ maskStream.Position = 0;
+
+ var completion = CompletionProvider.GetImageCompletion(_services, provider: provider ?? "openai", model: model ?? "dall-e-2");
+ var message = await completion.GetImageEdits(new Agent()
+ {
+ Id = Guid.Empty.ToString()
+ }, new RoleDialogModel(AgentRole.User, text), imageStream, image.FileName, maskStream, mask.FileName);
+
+ imageViewModel.Content = message.Content;
+ imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
+ imageStream.Close();
+ maskStream.Close();
+
+ return imageViewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in image mask edit upload. {ex.Message}";
+ _logger.LogError(error);
+ imageViewModel.Message = error;
+ return imageViewModel;
+ }
+ }
#endregion
#region Pdf
[HttpPost("/instruct/pdf-completion")]
- public async Task PdfCompletion([FromBody] IncomingMessageModel input)
+ public async Task PdfCompletion([FromBody] MultiModalRequest input)
{
var state = _services.GetRequiredService();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
@@ -239,5 +379,109 @@ public class InstructModeController : ControllerBase
return viewModel;
}
}
+
+ [HttpPost("/instruct/pdf-completion/upload")]
+ public async Task PdfCompletion(IFormFile file, [FromForm] string text, [FromForm] string? provider = null,
+ [FromForm] string? model = null, [FromForm] string? modelId = null, [FromForm] List? states = null)
+ {
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var viewModel = new PdfCompletionViewModel();
+
+ try
+ {
+ var data = FileUtility.BuildFileDataFromFile(file);
+ var files = new List
+ {
+ new InstructFileModel { FileData = data }
+ };
+
+ var fileInstruct = _services.GetRequiredService();
+ var content = await fileInstruct.ReadPdf(provider, model, modelId, text, files);
+ viewModel.Content = content;
+ return viewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in pdf completion upload. {ex.Message}";
+ _logger.LogError(error);
+ viewModel.Message = error;
+ return viewModel;
+ }
+ }
+ #endregion
+
+ #region Audio
+ [HttpPost("/instruct/speech-to-text")]
+ public async Task SpeechToText([FromBody] SpeechToTextRequest input)
+ {
+ var fileInstruct = _services.GetRequiredService();
+ var state = _services.GetRequiredService();
+ input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var viewModel = new SpeechToTextViewModel();
+
+ try
+ {
+ var audio = input.File;
+ if (audio == null)
+ {
+ return new SpeechToTextViewModel { Message = "Error! Cannot find a valid audio file!" };
+ }
+ var content = await fileInstruct.SpeechToText(input.Provider, input.Model, audio);
+ viewModel.Content = content;
+ return viewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in speech to text. {ex.Message}";
+ _logger.LogError(error);
+ viewModel.Message = error;
+ return viewModel;
+ }
+ }
+
+ [HttpPost("/instruct/speech-to-text/upload")]
+ public async Task SpeechToText(IFormFile file, [FromForm] string? provider = null, [FromForm] string? model = null,
+ [FromForm] string? text = null, [FromForm] List? states = null)
+ {
+ var fileInstruct = _services.GetRequiredService();
+ var state = _services.GetRequiredService();
+ states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+ var viewModel = new SpeechToTextViewModel();
+
+ try
+ {
+ using var stream = new MemoryStream();
+ file.CopyTo(stream);
+ stream.Position = 0;
+
+ var completion = CompletionProvider.GetAudioCompletion(_services, provider: provider ?? "openai", model: model ?? "whisper-1");
+ var content = await completion.GenerateTextFromAudioAsync(stream, file.FileName, text);
+ viewModel.Content = content;
+ stream.Close();
+ return viewModel;
+ }
+ catch (Exception ex)
+ {
+ var error = $"Error in speech-to-text upload. {ex.Message}";
+ _logger.LogError(error);
+ viewModel.Message = error;
+ return viewModel;
+ }
+ }
+
+ [HttpPost("/instruct/text-to-speech")]
+ public async Task TextToSpeech([FromBody] TextToSpeechRequest input)
+ {
+ var state = _services.GetRequiredService();
+ input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
+
+ var completion = CompletionProvider.GetAudioCompletion(_services, provider: input.Provider ?? "openai", model: input.Model ?? "tts-1");
+ var binaryData = await completion.GenerateAudioFromTextAsync(input.Text);
+ var stream = binaryData.ToStream();
+ stream.Position = 0;
+
+ return new FileStreamResult(stream, "audio/mpeg") { FileDownloadName = "output.mp3" };
+ }
#endregion
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs
index deb21378..827c2d7c 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/KnowledgeBaseController.cs
@@ -18,12 +18,25 @@ public class KnowledgeBaseController : ControllerBase
_services = services;
}
+ #region Vector
[HttpGet("knowledge/vector/collections")]
public async Task> GetVectorCollections()
{
return await _knowledgeService.GetVectorCollections();
}
+ [HttpPost("knowledge/vector/{collection}/create-collection/{dimension}")]
+ public async Task CreateVectorCollection([FromRoute] string collection, [FromRoute] int dimension)
+ {
+ return await _knowledgeService.CreateVectorCollection(collection, dimension);
+ }
+
+ [HttpDelete("knowledge/vector/{collection}/delete-collection")]
+ public async Task GetVectorCollections([FromRoute] string collection)
+ {
+ return await _knowledgeService.DeleteVectorCollection(collection);
+ }
+
[HttpPost("/knowledge/vector/{collection}/search")]
public async Task> SearchVectorKnowledge([FromRoute] string collection, [FromBody] SearchVectorKnowledgeRequest request)
{
@@ -91,7 +104,7 @@ public class KnowledgeBaseController : ControllerBase
public async Task UploadVectorKnowledge([FromRoute] string collection, IFormFile file, [FromForm] int? startPageNum, [FromForm] int? endPageNum)
{
var setttings = _services.GetRequiredService();
- var textConverter = _services.GetServices().FirstOrDefault(x => x.Name == setttings.Pdf2TextConverter);
+ var textConverter = _services.GetServices().FirstOrDefault(x => x.Provider == setttings.Pdf2TextConverter.Provider);
var filePath = Path.GetTempFileName();
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
@@ -109,7 +122,10 @@ public class KnowledgeBaseController : ControllerBase
System.IO.File.Delete(filePath);
return Ok(new { count = 1, file.Length });
}
+ #endregion
+
+ #region Graph
[HttpPost("/knowledge/graph/search")]
public async Task SearchGraphKnowledge([FromBody] SearchGraphKnowledgeRequest request)
{
@@ -124,7 +140,10 @@ public class KnowledgeBaseController : ControllerBase
Result = result.Result
};
}
+ #endregion
+
+ #region Knowledge
[HttpPost("/knowledge/search")]
public async Task SearchKnowledge([FromBody] SearchKnowledgeRequest request)
{
@@ -148,4 +167,5 @@ public class KnowledgeBaseController : ControllerBase
GraphResult = result?.GraphResult != null ? new GraphKnowledgeViewModel { Result = result.GraphResult.Result } : null
};
}
+ #endregion
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/LlmProviderController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/LlmProviderController.cs
index 5571d9fa..02282b85 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/LlmProviderController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/LlmProviderController.cs
@@ -25,6 +25,6 @@ public class LlmProviderController : ControllerBase
public IEnumerable GetLlmProviderModels([FromRoute] string provider)
{
var list = _llmProvider.GetProviderModels(provider);
- return list.Where(x => !x.ImageGeneration);
+ return list.Where(x => x.Type == LlmModelType.Chat);
}
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs
index a7d4c449..16399334 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/UserController.cs
@@ -135,9 +135,14 @@ public class UserController : ControllerBase
#region Avatar
[HttpPost("/user/avatar")]
- public bool UploadUserAvatar([FromBody] BotSharpFile file)
+ public bool UploadUserAvatar([FromBody] UserAvatarModel input)
{
var fileStorage = _services.GetRequiredService();
+ var file = new InputFileModel
+ {
+ FileName = input.FileName,
+ FileData = input.FileData,
+ };
return fileStorage.SaveUserAvatar(file);
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/InputMessageFiles.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/InputMessageFiles.cs
new file mode 100644
index 00000000..fdf088bb
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/InputMessageFiles.cs
@@ -0,0 +1,7 @@
+namespace BotSharp.OpenAPI.ViewModels.Conversations;
+
+public class InputMessageFiles
+{
+ public List States { get; set; } = new();
+ public List Files { get; set; } = new();
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/ImageGenerationViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/ImageGenerationViewModel.cs
index 0050de01..ea8dc076 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/ImageGenerationViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/ImageGenerationViewModel.cs
@@ -2,18 +2,11 @@ using System.Text.Json.Serialization;
namespace BotSharp.OpenAPI.ViewModels.Instructs;
-public class ImageGenerationViewModel
+public class ImageGenerationViewModel : InstructBaseViewModel
{
- [JsonPropertyName("content")]
- public string Content { get; set; } = string.Empty;
-
[JsonPropertyName("images")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public IEnumerable Images { get; set; } = new List();
-
- [JsonPropertyName("message")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string? Message { get; set; }
}
public class ImageViewModel
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructBaseRequest.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructBaseRequest.cs
new file mode 100644
index 00000000..39a6439d
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructBaseRequest.cs
@@ -0,0 +1,75 @@
+using System.Text.Json.Serialization;
+
+namespace BotSharp.Abstraction.Instructs.Models;
+
+public class InstructBaseRequest
+{
+ [JsonPropertyName("provider")]
+ public virtual string? Provider { get; set; } = null;
+
+ [JsonPropertyName("model")]
+ public virtual string? Model { get; set; } = null;
+
+ [JsonPropertyName("model_id")]
+ public virtual string? ModelId { get; set; } = null;
+
+ [JsonPropertyName("states")]
+ public List States { get; set; } = new();
+}
+
+public class MultiModalRequest : InstructBaseRequest
+{
+ [JsonPropertyName("text")]
+ public string Text { get; set; } = string.Empty;
+
+ [JsonPropertyName("files")]
+ public List Files { get; set; } = new();
+}
+
+public class ImageGenerationRequest : InstructBaseRequest
+{
+ [JsonPropertyName("text")]
+ public string Text { get; set; } = string.Empty;
+}
+
+public class ImageVariationRequest : InstructBaseRequest
+{
+ [JsonPropertyName("file")]
+ public InstructFileModel File { get; set; }
+}
+
+public class ImageEditRequest : InstructBaseRequest
+{
+ [JsonPropertyName("text")]
+ public string Text { get; set; } = string.Empty;
+
+ [JsonPropertyName("file")]
+ public InstructFileModel File { get; set; }
+}
+
+public class ImageMaskEditRequest : InstructBaseRequest
+{
+ [JsonPropertyName("text")]
+ public string Text { get; set; } = string.Empty;
+
+ [JsonPropertyName("file")]
+ public InstructFileModel File { get; set; }
+
+ [JsonPropertyName("mask")]
+ public InstructFileModel Mask { get; set; }
+}
+
+public class SpeechToTextRequest : InstructBaseRequest
+{
+ [JsonPropertyName("text")]
+ public string? Text { get; set; }
+
+ [JsonPropertyName("file")]
+ public InstructFileModel File { get; set; }
+}
+
+public class TextToSpeechRequest : InstructBaseRequest
+{
+ [JsonPropertyName("text")]
+ public string Text { get; set; }
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructBaseViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructBaseViewModel.cs
new file mode 100644
index 00000000..0b20fca3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructBaseViewModel.cs
@@ -0,0 +1,13 @@
+using System.Text.Json.Serialization;
+
+namespace BotSharp.OpenAPI.ViewModels.Instructs;
+
+public class InstructBaseViewModel
+{
+ [JsonPropertyName("content")]
+ public string Content { get; set; } = string.Empty;
+
+ [JsonPropertyName("message")]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Message { get; set; }
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs
index 3b265e04..b736330f 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs
@@ -1,5 +1,3 @@
-using BotSharp.Abstraction.Conversations.Enums;
-using BotSharp.Abstraction.Conversations.Models;
namespace BotSharp.OpenAPI.ViewModels.Instructs;
public class InstructMessageModel : IncomingMessageModel
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/MultiModalViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/MultiModalViewModel.cs
new file mode 100644
index 00000000..a7b15262
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/MultiModalViewModel.cs
@@ -0,0 +1,5 @@
+namespace BotSharp.OpenAPI.ViewModels.Instructs;
+
+public class MultiModalViewModel : InstructBaseViewModel
+{
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/PdfCompletionViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/PdfCompletionViewModel.cs
index 13ed3eb9..7ac594e6 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/PdfCompletionViewModel.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/PdfCompletionViewModel.cs
@@ -1,13 +1,5 @@
-using System.Text.Json.Serialization;
-
namespace BotSharp.OpenAPI.ViewModels.Instructs;
-public class PdfCompletionViewModel
+public class PdfCompletionViewModel : InstructBaseViewModel
{
- [JsonPropertyName("content")]
- public string Content { get; set; } = string.Empty;
-
- [JsonPropertyName("message")]
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- public string? Message { get; set; }
}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/SpeechToTextViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/SpeechToTextViewModel.cs
new file mode 100644
index 00000000..d681986d
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/SpeechToTextViewModel.cs
@@ -0,0 +1,5 @@
+namespace BotSharp.OpenAPI.ViewModels.Instructs;
+
+public class SpeechToTextViewModel : InstructBaseViewModel
+{
+}
diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserAvatarModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserAvatarModel.cs
new file mode 100644
index 00000000..0eab88e5
--- /dev/null
+++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Users/UserAvatarModel.cs
@@ -0,0 +1,18 @@
+using System.Text.Json.Serialization;
+
+namespace BotSharp.OpenAPI.ViewModels.Users;
+
+public class UserAvatarModel
+{
+ ///
+ /// File name with extension
+ ///
+ [JsonPropertyName("file_name")]
+ public string FileName { get; set; } = string.Empty;
+
+ ///
+ /// File data, e.g., "data:image/png;base64,aaaaaaaa"
+ ///
+ [JsonPropertyName("file_data")]
+ public string FileData { get; set; } = string.Empty;
+}
diff --git a/src/Plugins/BotSharp.Plugin.AudioHandler/AudioHandlerPlugin.cs b/src/Plugins/BotSharp.Plugin.AudioHandler/AudioHandlerPlugin.cs
index 304aa97b..2c289907 100644
--- a/src/Plugins/BotSharp.Plugin.AudioHandler/AudioHandlerPlugin.cs
+++ b/src/Plugins/BotSharp.Plugin.AudioHandler/AudioHandlerPlugin.cs
@@ -1,31 +1,24 @@
using BotSharp.Plugin.AudioHandler.Settings;
-using BotSharp.Plugin.AudioHandler.Provider;
using BotSharp.Abstraction.Settings;
-namespace BotSharp.Plugin.AudioHandler
+namespace BotSharp.Plugin.AudioHandler;
+
+public class AudioHandlerPlugin : IBotSharpPlugin
{
- public class AudioHandlerPlugin : IBotSharpPlugin
+ public string Id => "9d22014c-4f45-466a-9e82-a74e67983df8";
+ public string Name => "Audio Handler";
+ public string Description => "Process audio input and transform it into text output.";
+ public void RegisterDI(IServiceCollection services, IConfiguration config)
{
- public string Id => "9d22014c-4f45-466a-9e82-a74e67983df8";
- public string Name => "Audio Handler";
- public string Description => "Process audio input and transform it into text output.";
- public void RegisterDI(IServiceCollection services, IConfiguration config)
+ services.AddScoped(provider =>
{
- //var settings = new AudioHandlerSettings();
- //config.Bind("AudioHandler", settings);
- //services.AddSingleton(x => settings);
+ var settingService = provider.GetRequiredService();
+ return settingService.Bind("AudioHandler");
+ });
- services.AddScoped(provider =>
- {
- var settingService = provider.GetRequiredService();
- return settingService.Bind("AudioHandler");
- });
-
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- services.AddScoped();
- }
+ services.AddScoped();
+ services.AddScoped();
+ services.AddScoped();
}
}
diff --git a/src/Plugins/BotSharp.Plugin.AudioHandler/BotSharp.Plugin.AudioHandler.csproj b/src/Plugins/BotSharp.Plugin.AudioHandler/BotSharp.Plugin.AudioHandler.csproj
index 7218d40c..4ae8c7d2 100644
--- a/src/Plugins/BotSharp.Plugin.AudioHandler/BotSharp.Plugin.AudioHandler.csproj
+++ b/src/Plugins/BotSharp.Plugin.AudioHandler/BotSharp.Plugin.AudioHandler.csproj
@@ -22,5 +22,19 @@
+
+
+
+
+
+
+
+
+