diff --git a/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs index cacef5a0..4d04a2fc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Files/Models/InstructFileModel.cs @@ -3,7 +3,7 @@ namespace BotSharp.Abstraction.Files.Models; public class InstructFileModel : FileBase { /// - /// File extension without dot + /// File extension /// [JsonPropertyName("file_extension")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] @@ -15,4 +15,11 @@ public class InstructFileModel : FileBase [JsonPropertyName("file_url")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? FileUrl { get; set; } = string.Empty; + + /// + /// File url + /// + [JsonPropertyName("content_type")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string? ContentType { get; set; } } diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs index a332028e..339cb049 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Audio.cs @@ -17,7 +17,7 @@ public partial class FileInstructService using var stream = audioBinary.ToStream(); stream.Position = 0; - var fileName = $"{audio.FileName.IfNullOrEmptyAs("audio")}.{audio.FileExtension.IfNullOrEmptyAs("wav")}"; + var fileName = BuildFileName(audio.FileName, audio.FileExtension, "audio", "wav"); var content = await completion.TranscriptTextAsync(stream, fileName, text ?? string.Empty); 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 e1b15d81..b2067e63 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs @@ -22,7 +22,8 @@ public partial class FileInstructService Files = images?.Select(x => new BotSharpFile { FileUrl = x.FileUrl, - FileData = x.FileData + FileData = x.FileData, + ContentType = x.ContentType }).ToList() ?? [] } }); @@ -82,7 +83,7 @@ public partial class FileInstructService using var stream = binary.ToStream(); stream.Position = 0; - var fileName = $"{image.FileName.IfNullOrEmptyAs("image")}.{image.FileExtension.IfNullOrEmptyAs("png")}"; + var fileName = BuildFileName(image.FileName, image.FileExtension, "image", "png"); var message = await completion.GetImageVariation(new Agent() { Id = innerAgentId @@ -118,7 +119,7 @@ public partial class FileInstructService using var stream = binary.ToStream(); stream.Position = 0; - var fileName = $"{image.FileName.IfNullOrEmptyAs("image")}.{image.FileExtension.IfNullOrEmptyAs("png")}"; + var fileName = BuildFileName(image.FileName, image.FileExtension, "image", "png"); var message = await completion.GetImageEdits(new Agent() { Id = innerAgentId @@ -162,8 +163,8 @@ public partial class FileInstructService using var maskStream = maskBinary.ToStream(); maskStream.Position = 0; - var imageName = $"{image.FileName.IfNullOrEmptyAs("image")}.{image.FileExtension.IfNullOrEmptyAs("png")}"; - var maskName = $"{mask.FileName.IfNullOrEmptyAs("mask")}.{mask.FileExtension.IfNullOrEmptyAs("png")}"; + var imageName = BuildFileName(image.FileName, image.FileExtension, "image", "png"); + var maskName = BuildFileName(image.FileName, image.FileExtension, "mask", "png"); var message = await completion.GetImageEdits(new Agent() { Id = innerAgentId diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs index 4a0729d0..25deecd0 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.cs @@ -1,4 +1,6 @@ +using static System.Net.Mime.MediaTypeNames; + namespace BotSharp.Core.Files.Services; public partial class FileInstructService : IFileInstructService @@ -76,5 +78,13 @@ public partial class FileInstructService : IFileInstructService var instruction = agentService.RenderedTemplate(agent, templateName); return instruction; } + + private string BuildFileName(string? name, string? extension, string defaultName, string defaultExtension) + { + var fname = name.IfNullOrEmptyAs(defaultName); + var fextension = extension.IfNullOrEmptyAs(defaultExtension); + fextension = fextension.StartsWith(".") ? fextension.Substring(1) : fextension; + return $"{name}.{fextension}"; + } #endregion } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index 42e0d2c8..73a4b9ae 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -91,7 +91,12 @@ public class InstructModeController : ControllerBase { new RoleDialogModel(AgentRole.User, input.Text) { - Files = input.Files?.Select(x => new BotSharpFile { FileUrl = x.FileUrl, FileData = x.FileData }).ToList() ?? [] + Files = input.Files?.Select(x => new BotSharpFile + { + FileUrl = x.FileUrl, + FileData = x.FileData, + ContentType = x.ContentType + }).ToList() ?? [] } }); @@ -256,7 +261,7 @@ public class InstructModeController : ControllerBase { FileData = fileData, FileName = Path.GetFileNameWithoutExtension(file.FileName), - FileExtension = Path.GetExtension(file.FileName).Substring(1) + FileExtension = Path.GetExtension(file.FileName) }, new InstructOptions { @@ -327,7 +332,7 @@ public class InstructModeController : ControllerBase { FileData = fileData, FileName = Path.GetFileNameWithoutExtension(file.FileName), - FileExtension = Path.GetExtension(file.FileName).Substring(1) + FileExtension = Path.GetExtension(file.FileName) }, new InstructOptions { @@ -404,13 +409,13 @@ public class InstructModeController : ControllerBase { FileData = imageData, FileName = Path.GetFileNameWithoutExtension(image.FileName), - FileExtension = Path.GetExtension(image.FileName).Substring(1) + FileExtension = Path.GetExtension(image.FileName) }, new InstructFileModel { FileData = maskData, FileName = Path.GetFileNameWithoutExtension(mask.FileName), - FileExtension = Path.GetExtension(mask.FileName).Substring(1) + FileExtension = Path.GetExtension(mask.FileName) }, new InstructOptions { @@ -550,7 +555,7 @@ public class InstructModeController : ControllerBase { FileData = audioData, FileName = Path.GetFileNameWithoutExtension(file.FileName), - FileExtension = Path.GetExtension(file.FileName).Substring(1) + FileExtension = Path.GetExtension(file.FileName) }, request?.Text ?? string.Empty, new InstructOptions diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs index b2eaaf46..ab7135ef 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/Chat/ChatCompletionProvider.cs @@ -308,7 +308,7 @@ public class ChatCompletionProvider : IChatCompletion ChatToolCall.CreateFunctionToolCall(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? "{}")) })); - messages.Add(new ToolChatMessage(message.ToolCallId ?? message.FunctionName, message.Content)); + messages.Add(new ToolChatMessage(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.Content)); } else if (message.Role == AgentRole.User) { @@ -323,14 +323,14 @@ public class ChatCompletionProvider : IChatCompletion if (!string.IsNullOrEmpty(file.FileData)) { var (contentType, binary) = FileUtility.GetFileInfoFromData(file.FileData); - var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType, ChatImageDetailLevel.Auto); + var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType.IfNullOrEmptyAs(file.ContentType), ChatImageDetailLevel.Auto); contentParts.Add(contentPart); } else if (!string.IsNullOrEmpty(file.FileStorageUrl)) { var contentType = FileUtility.GetFileContentType(file.FileStorageUrl); var binary = fileStorage.GetFileBytes(file.FileStorageUrl); - var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType, ChatImageDetailLevel.Auto); + var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType.IfNullOrEmptyAs(file.ContentType), ChatImageDetailLevel.Auto); contentParts.Add(contentPart); } else if (!string.IsNullOrEmpty(file.FileUrl)) diff --git a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs index 85304054..42ce1ac9 100644 --- a/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.DeepSeekAI/Providers/Chat/ChatCompletionProvider.cs @@ -270,10 +270,10 @@ public class ChatCompletionProvider : IChatCompletion { messages.Add(new AssistantChatMessage(new List { - ChatToolCall.CreateFunctionToolCall(message.FunctionName, message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) + ChatToolCall.CreateFunctionToolCall(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? string.Empty)) })); - messages.Add(new ToolChatMessage(message.FunctionName, message.Content)); + messages.Add(new ToolChatMessage(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.Content)); } else if (message.Role == AgentRole.User) { diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs index a0e7cc17..1ead28e6 100644 --- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Chat/GeminiChatCompletionProvider.cs @@ -312,7 +312,7 @@ public class GeminiChatCompletionProvider : IChatCompletion { InlineData = new() { - MimeType = contentType ?? file.ContentType, + MimeType = contentType.IfNullOrEmptyAs(file.ContentType), Data = Convert.ToBase64String(binary.ToArray()) } }); @@ -325,7 +325,7 @@ public class GeminiChatCompletionProvider : IChatCompletion { InlineData = new() { - MimeType = contentType, + MimeType = contentType.IfNullOrEmptyAs(file.ContentType), Data = Convert.ToBase64String(binary.ToArray()) } }); diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs index edf51660..17ee1012 100644 --- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Chat/ChatCompletionProvider.cs @@ -274,7 +274,7 @@ public class ChatCompletionProvider : IChatCompletion ChatToolCall.CreateFunctionToolCall(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.FunctionName, BinaryData.FromString(message.FunctionArgs ?? "{}")) })); - messages.Add(new ToolChatMessage(message.ToolCallId ?? message.FunctionName, message.Content)); + messages.Add(new ToolChatMessage(message.ToolCallId.IfNullOrEmptyAs(message.FunctionName), message.Content)); } else if (message.Role == AgentRole.User) { @@ -289,14 +289,14 @@ public class ChatCompletionProvider : IChatCompletion if (!string.IsNullOrEmpty(file.FileData)) { var (contentType, binary) = FileUtility.GetFileInfoFromData(file.FileData); - var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType, ChatImageDetailLevel.Auto); + var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType.IfNullOrEmptyAs(file.ContentType), ChatImageDetailLevel.Auto); contentParts.Add(contentPart); } else if (!string.IsNullOrEmpty(file.FileStorageUrl)) { var contentType = FileUtility.GetFileContentType(file.FileStorageUrl); var binary = fileStorage.GetFileBytes(file.FileStorageUrl); - var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType, ChatImageDetailLevel.Auto); + var contentPart = ChatMessageContentPart.CreateImagePart(binary, contentType.IfNullOrEmptyAs(file.ContentType), ChatImageDetailLevel.Auto); contentParts.Add(contentPart); } else if (!string.IsNullOrEmpty(file.FileUrl))