refine multi modal instruct
This commit is contained in:
parent
517d46a5a7
commit
98291a5e49
|
|
@ -132,12 +132,6 @@ public class RoleDialogModel : ITrackableMessage
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
|
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
|
||||||
public bool IsStreaming { get; set; }
|
public bool IsStreaming { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Additional messages that can be sent sequentially and save to db
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
|
|
||||||
public ChatMessageWrapper? AdditionalMessageWrapper { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public RoleDialogModel()
|
public RoleDialogModel()
|
||||||
{
|
{
|
||||||
|
|
@ -184,26 +178,7 @@ public class RoleDialogModel : ITrackableMessage
|
||||||
Instruction = source.Instruction,
|
Instruction = source.Instruction,
|
||||||
Data = source.Data,
|
Data = source.Data,
|
||||||
IsStreaming = source.IsStreaming,
|
IsStreaming = source.IsStreaming,
|
||||||
Annotations = source.Annotations,
|
Annotations = source.Annotations
|
||||||
AdditionalMessageWrapper = source.AdditionalMessageWrapper
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ChatMessageWrapper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Messages sending interval in milliseconds
|
|
||||||
/// </summary>
|
|
||||||
public int SendingInterval { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the Messages are saved to db
|
|
||||||
/// </summary>
|
|
||||||
public bool SaveToDb { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Messages to send or save
|
|
||||||
/// </summary>
|
|
||||||
public List<RoleDialogModel>? Messages { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -16,6 +16,8 @@ public interface IImageConverter
|
||||||
/// Convert an image to PNG with RGBA
|
/// Convert an image to PNG with RGBA
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="binary"></param>
|
/// <param name="binary"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<BinaryData> ConvertImageToRgbaPng(BinaryData binary) => throw new NotImplementedException();
|
/// <exception cref="NotImplementedException"></exception>
|
||||||
|
Task<BinaryData> ConvertImage(BinaryData binary, ImageConvertOptions? options = null) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ namespace BotSharp.Abstraction.Files;
|
||||||
public class FileCoreSettings
|
public class FileCoreSettings
|
||||||
{
|
{
|
||||||
public string Storage { get; set; } = FileStorageEnum.LocalFileStorage;
|
public string Storage { get; set; } = FileStorageEnum.LocalFileStorage;
|
||||||
public SettingBase Pdf2TextConverter { get; set; }
|
public SettingBase? Pdf2TextConverter { get; set; }
|
||||||
public SettingBase Pdf2ImageConverter { get; set; }
|
public SettingBase? Pdf2ImageConverter { get; set; }
|
||||||
|
public SettingBase? ImageConverter { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SettingBase
|
public class SettingBase
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace BotSharp.Abstraction.Files.Models;
|
||||||
|
|
||||||
|
public class ImageConvertOptions
|
||||||
|
{
|
||||||
|
public string ImageType { get; set; } = "png";
|
||||||
|
public string ColorType { get; set; } = "rgba";
|
||||||
|
}
|
||||||
|
|
@ -33,7 +33,7 @@ public class InstructOptions
|
||||||
public Dictionary<string, object> Data { get; set; } = new();
|
public Dictionary<string, object> Data { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Image converter provider
|
/// Image convert provider
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ImageConverterProvider { get; set; }
|
public string? ImageConvertProvider { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,23 +31,12 @@ public class ConversationStorage : IConversationStorage
|
||||||
|
|
||||||
foreach ( var dialog in dialogs)
|
foreach ( var dialog in dialogs)
|
||||||
{
|
{
|
||||||
var innerList = new List<RoleDialogModel> { dialog };
|
var element = BuildDialogElement(dialog);
|
||||||
if (dialog.AdditionalMessageWrapper != null
|
|
||||||
&& dialog.AdditionalMessageWrapper.SaveToDb
|
|
||||||
&& dialog.AdditionalMessageWrapper.Messages?.Count > 0)
|
|
||||||
{
|
|
||||||
innerList.AddRange(dialog.AdditionalMessageWrapper.Messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in innerList)
|
|
||||||
{
|
|
||||||
var element = BuildDialogElement(item);
|
|
||||||
if (element != null)
|
if (element != null)
|
||||||
{
|
{
|
||||||
dialogElements.Add(element);
|
dialogElements.Add(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
db.AppendConversationDialogs(conversationId, dialogElements);
|
db.AppendConversationDialogs(conversationId, dialogElements);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using BotSharp.Abstraction.Instructs.Models;
|
using BotSharp.Abstraction.Instructs.Models;
|
||||||
using BotSharp.Abstraction.Instructs;
|
using BotSharp.Abstraction.Instructs;
|
||||||
using BotSharp.Abstraction.Files.Converters;
|
|
||||||
|
|
||||||
namespace BotSharp.Core.Files.Services;
|
namespace BotSharp.Core.Files.Services;
|
||||||
|
|
||||||
|
|
@ -82,6 +81,15 @@ public partial class FileInstructService
|
||||||
var innerAgentId = options?.AgentId ?? Guid.Empty.ToString();
|
var innerAgentId = options?.AgentId ?? Guid.Empty.ToString();
|
||||||
var completion = CompletionProvider.GetImageCompletion(_services, provider: options?.Provider ?? "openai", model: options?.Model ?? "dall-e-2");
|
var completion = CompletionProvider.GetImageCompletion(_services, provider: options?.Provider ?? "openai", model: options?.Model ?? "dall-e-2");
|
||||||
var binary = await DownloadFile(image);
|
var binary = await DownloadFile(image);
|
||||||
|
|
||||||
|
// Convert image
|
||||||
|
var converter = GetImageConverter(options?.ImageConvertProvider);
|
||||||
|
if (converter != null)
|
||||||
|
{
|
||||||
|
binary = await converter.ConvertImage(binary);
|
||||||
|
image.FileExtension = "png";
|
||||||
|
}
|
||||||
|
|
||||||
using var stream = binary.ToStream();
|
using var stream = binary.ToStream();
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
|
|
@ -120,10 +128,10 @@ public partial class FileInstructService
|
||||||
var binary = await DownloadFile(image);
|
var binary = await DownloadFile(image);
|
||||||
|
|
||||||
// Convert image
|
// Convert image
|
||||||
var converter = _services.GetServices<IImageConverter>().FirstOrDefault(x => x.Provider == options?.ImageConverterProvider);
|
var converter = GetImageConverter(options?.ImageConvertProvider);
|
||||||
if (converter != null)
|
if (converter != null)
|
||||||
{
|
{
|
||||||
binary = await converter.ConvertImageToRgbaPng(binary);
|
binary = await converter.ConvertImage(binary);
|
||||||
image.FileExtension = "png";
|
image.FileExtension = "png";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,10 +173,21 @@ public partial class FileInstructService
|
||||||
var innerAgentId = options?.AgentId ?? Guid.Empty.ToString();
|
var innerAgentId = options?.AgentId ?? Guid.Empty.ToString();
|
||||||
var instruction = await GetAgentTemplate(innerAgentId, options?.TemplateName);
|
var instruction = await GetAgentTemplate(innerAgentId, options?.TemplateName);
|
||||||
|
|
||||||
var completion = CompletionProvider.GetImageCompletion(_services, provider: options?.Provider ?? "openai", model: options?.Model ?? "dall-e-2");
|
var completion = CompletionProvider.GetImageCompletion(_services, provider: options?.Provider ?? "openai", model: options?.Model ?? "gpt-image-1");
|
||||||
var imageBinary = await DownloadFile(image);
|
var imageBinary = await DownloadFile(image);
|
||||||
var maskBinary = await DownloadFile(mask);
|
var maskBinary = await DownloadFile(mask);
|
||||||
|
|
||||||
|
// Convert image
|
||||||
|
var converter = GetImageConverter(options?.ImageConvertProvider);
|
||||||
|
if (converter != null)
|
||||||
|
{
|
||||||
|
imageBinary = await converter.ConvertImage(imageBinary);
|
||||||
|
image.FileExtension = "png";
|
||||||
|
|
||||||
|
maskBinary = await converter.ConvertImage(maskBinary);
|
||||||
|
mask.FileExtension = "png";
|
||||||
|
}
|
||||||
|
|
||||||
using var imageStream = imageBinary.ToStream();
|
using var imageStream = imageBinary.ToStream();
|
||||||
imageStream.Position = 0;
|
imageStream.Position = 0;
|
||||||
|
|
||||||
|
|
@ -176,7 +195,7 @@ public partial class FileInstructService
|
||||||
maskStream.Position = 0;
|
maskStream.Position = 0;
|
||||||
|
|
||||||
var imageName = BuildFileName(image.FileName, image.FileExtension, "image", "png");
|
var imageName = BuildFileName(image.FileName, image.FileExtension, "image", "png");
|
||||||
var maskName = BuildFileName(image.FileName, image.FileExtension, "mask", "png");
|
var maskName = BuildFileName(mask.FileName, mask.FileExtension, "mask", "png");
|
||||||
var textContent = text.IfNullOrEmptyAs(instruction).IfNullOrEmptyAs(string.Empty);
|
var textContent = text.IfNullOrEmptyAs(instruction).IfNullOrEmptyAs(string.Empty);
|
||||||
var message = await completion.GetImageEdits(new Agent()
|
var message = await completion.GetImageEdits(new Agent()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using BotSharp.Abstraction.Files.Converters;
|
|
||||||
using BotSharp.Abstraction.Instructs.Models;
|
using BotSharp.Abstraction.Instructs.Models;
|
||||||
using BotSharp.Abstraction.Instructs;
|
using BotSharp.Abstraction.Instructs;
|
||||||
|
|
||||||
|
|
@ -39,7 +38,7 @@ public partial class FileInstructService
|
||||||
var instruction = await GetAgentTemplate(innerAgentId, options?.TemplateName);
|
var instruction = await GetAgentTemplate(innerAgentId, options?.TemplateName);
|
||||||
|
|
||||||
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider,
|
var completion = CompletionProvider.GetChatCompletion(_services, provider: provider,
|
||||||
model: options?.Model ?? "gpt-4o", multiModal: true);
|
model: options?.Model ?? "gpt-5-mini", multiModal: true);
|
||||||
var message = await completion.GetChatCompletions(new Agent()
|
var message = await completion.GetChatCompletions(new Agent()
|
||||||
{
|
{
|
||||||
Id = innerAgentId,
|
Id = innerAgentId,
|
||||||
|
|
@ -120,9 +119,8 @@ public partial class FileInstructService
|
||||||
{
|
{
|
||||||
var images = new List<string>();
|
var images = new List<string>();
|
||||||
var settings = _services.GetRequiredService<FileCoreSettings>();
|
var settings = _services.GetRequiredService<FileCoreSettings>();
|
||||||
var imageConverterProvider = options?.ImageConverterProvider;
|
|
||||||
|
|
||||||
var converter = _services.GetServices<IImageConverter>().FirstOrDefault(x => x.Provider == imageConverterProvider);
|
var converter = GetImageConverter(options?.ImageConvertProvider);
|
||||||
if (converter == null || files.IsNullOrEmpty())
|
if (converter == null || files.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return images;
|
return images;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
using BotSharp.Abstraction.Files.Converters;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
using static System.Net.Mime.MediaTypeNames;
|
using static System.Net.Mime.MediaTypeNames;
|
||||||
|
|
||||||
namespace BotSharp.Core.Files.Services;
|
namespace BotSharp.Core.Files.Services;
|
||||||
|
|
@ -86,5 +88,13 @@ public partial class FileInstructService : IFileInstructService
|
||||||
fextension = fextension.StartsWith(".") ? fextension.Substring(1) : fextension;
|
fextension = fextension.StartsWith(".") ? fextension.Substring(1) : fextension;
|
||||||
return $"{name}.{fextension}";
|
return $"{name}.{fextension}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IImageConverter? GetImageConverter(string? provider)
|
||||||
|
{
|
||||||
|
var settings = _services.GetRequiredService<FileCoreSettings>();
|
||||||
|
var convertProvider = provider ?? settings?.ImageConverter?.Provider;
|
||||||
|
var converter = _services.GetServices<IImageConverter>().FirstOrDefault(x => x.Provider == convertProvider);
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ public partial class RoutingService
|
||||||
message.CurrentAgentId = agent.Id;
|
message.CurrentAgentId = agent.Id;
|
||||||
message.IsStreaming = response.IsStreaming;
|
message.IsStreaming = response.IsStreaming;
|
||||||
message.MessageLabel = response.MessageLabel;
|
message.MessageLabel = response.MessageLabel;
|
||||||
message.AdditionalMessageWrapper = null;
|
|
||||||
|
|
||||||
await InvokeFunction(message, dialogs, options);
|
await InvokeFunction(message, dialogs, options);
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +76,6 @@ public partial class RoutingService
|
||||||
message.CurrentAgentId = agent.Id;
|
message.CurrentAgentId = agent.Id;
|
||||||
message.IsStreaming = response.IsStreaming;
|
message.IsStreaming = response.IsStreaming;
|
||||||
message.MessageLabel = response.MessageLabel;
|
message.MessageLabel = response.MessageLabel;
|
||||||
message.AdditionalMessageWrapper = null;
|
|
||||||
dialogs.Add(message);
|
dialogs.Add(message);
|
||||||
Context.SetDialogs(dialogs);
|
Context.SetDialogs(dialogs);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ public partial class RoutingService
|
||||||
message.RichContent = clonedMessage.RichContent;
|
message.RichContent = clonedMessage.RichContent;
|
||||||
message.Data = clonedMessage.Data;
|
message.Data = clonedMessage.Data;
|
||||||
message.MessageLabel = clonedMessage.MessageLabel;
|
message.MessageLabel = clonedMessage.MessageLabel;
|
||||||
message.AdditionalMessageWrapper = clonedMessage.AdditionalMessageWrapper;
|
|
||||||
}
|
}
|
||||||
catch (JsonException ex)
|
catch (JsonException ex)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,46 @@
|
||||||
"description": "Chatbot is used to test the performance of different large models and does not interact with external APIs.",
|
"description": "Chatbot is used to test the performance of different large models and does not interact with external APIs.",
|
||||||
"type": "task",
|
"type": "task",
|
||||||
"createdDateTime": "2024-01-15T10:39:32Z",
|
"createdDateTime": "2024-01-15T10:39:32Z",
|
||||||
"updatedDateTime": "2024-01-15T14:39:32Z",
|
"updatedDateTime": "2025-09-11T20:25:59.292826Z",
|
||||||
"iconUrl": "/images/logo.png",
|
|
||||||
"disabled": false,
|
|
||||||
"isPublic": true,
|
|
||||||
"llmConfig": {
|
"llmConfig": {
|
||||||
"is_inherit": false,
|
"is_inherit": false,
|
||||||
"provider": "openai",
|
"provider": "openai",
|
||||||
"model": "gpt-4o-mini",
|
"model": "gpt-5",
|
||||||
"max_recursion_depth": 3
|
"max_recursion_depth": 3
|
||||||
|
},
|
||||||
|
"isPublic": true,
|
||||||
|
"disabled": false,
|
||||||
|
"iconUrl": "/images/logo.png",
|
||||||
|
"profiles": [],
|
||||||
|
"labels": [],
|
||||||
|
"mergeUtility": false,
|
||||||
|
"utilities": [
|
||||||
|
{
|
||||||
|
"category": "file",
|
||||||
|
"name": "image-generator",
|
||||||
|
"disabled": false,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"function_name": "util-file-generate_image",
|
||||||
|
"template_name": "util-file-generate_image.fn"
|
||||||
}
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "file",
|
||||||
|
"name": "image-editor",
|
||||||
|
"disabled": false,
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"function_name": "util-file-edit_image",
|
||||||
|
"template_name": "util-file-edit_image.fn"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mcpTools": [],
|
||||||
|
"rules": [],
|
||||||
|
"knowledgeBases": [],
|
||||||
|
"inheritAgentId": null,
|
||||||
|
"routingRules": []
|
||||||
}
|
}
|
||||||
|
|
@ -375,7 +375,6 @@ public class ConversationController : ControllerBase
|
||||||
response.RichContent = msg.SecondaryRichContent ?? msg.RichContent;
|
response.RichContent = msg.SecondaryRichContent ?? msg.RichContent;
|
||||||
response.Instruction = msg.Instruction;
|
response.Instruction = msg.Instruction;
|
||||||
response.Data = msg.Data;
|
response.Data = msg.Data;
|
||||||
response.AdditionalMessageWrapper = ChatResponseWrapper.From(msg.AdditionalMessageWrapper, conversationId, inputMsg.MessageId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
|
@ -434,7 +433,6 @@ public class ConversationController : ControllerBase
|
||||||
response.Instruction = msg.Instruction;
|
response.Instruction = msg.Instruction;
|
||||||
response.Data = msg.Data;
|
response.Data = msg.Data;
|
||||||
response.States = state.GetStates();
|
response.States = state.GetStates();
|
||||||
response.AdditionalMessageWrapper = ChatResponseWrapper.From(msg.AdditionalMessageWrapper, conversationId, inputMsg.MessageId);
|
|
||||||
|
|
||||||
await OnChunkReceived(Response, response);
|
await OnChunkReceived(Response, response);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -144,7 +144,7 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/multi-modal/upload")]
|
[HttpPost("/instruct/multi-modal/form")]
|
||||||
public async Task<MultiModalViewModel> MultiModalCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] MultiModalRequest request)
|
public async Task<MultiModalViewModel> MultiModalCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] MultiModalRequest request)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
|
@ -214,29 +214,30 @@ public class InstructModeController : ControllerBase
|
||||||
|
|
||||||
#region Edit image
|
#region Edit image
|
||||||
[HttpPost("/instruct/image-variation")]
|
[HttpPost("/instruct/image-variation")]
|
||||||
public async Task<ImageGenerationViewModel> ImageVariation([FromBody] ImageVariationRequest input)
|
public async Task<ImageGenerationViewModel> ImageVariation([FromBody] ImageVariationFileRequest request)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
||||||
var imageViewModel = new ImageGenerationViewModel();
|
var imageViewModel = new ImageGenerationViewModel();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (input.File == null)
|
if (request.File == null)
|
||||||
{
|
{
|
||||||
return new ImageGenerationViewModel { Message = "Error! Cannot find an image!" };
|
return new ImageGenerationViewModel { Message = "Error! Cannot find an image!" };
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
var message = await fileInstruct.VaryImage(input.File, new InstructOptions
|
var message = await fileInstruct.VaryImage(request.File, new InstructOptions
|
||||||
{
|
{
|
||||||
Provider = input.Provider,
|
Provider = request.Provider,
|
||||||
Model = input.Model,
|
Model = request.Model,
|
||||||
AgentId = input.AgentId
|
AgentId = request.AgentId,
|
||||||
|
ImageConvertProvider = request.ImageConvertProvider
|
||||||
});
|
});
|
||||||
|
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
||||||
|
|
||||||
return imageViewModel;
|
return imageViewModel;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -248,8 +249,8 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/image-variation/upload")]
|
[HttpPost("/instruct/image-variation/form")]
|
||||||
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] MultiModalRequest request)
|
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] ImageVariationRequest request)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
||||||
|
|
@ -269,7 +270,8 @@ public class InstructModeController : ControllerBase
|
||||||
{
|
{
|
||||||
Provider = request?.Provider,
|
Provider = request?.Provider,
|
||||||
Model = request?.Model,
|
Model = request?.Model,
|
||||||
AgentId = request?.AgentId
|
AgentId = request?.AgentId,
|
||||||
|
ImageConvertProvider = request?.ImageConvertProvider
|
||||||
});
|
});
|
||||||
|
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
|
|
@ -305,7 +307,7 @@ public class InstructModeController : ControllerBase
|
||||||
Model = request.Model,
|
Model = request.Model,
|
||||||
AgentId = request.AgentId,
|
AgentId = request.AgentId,
|
||||||
TemplateName = request.TemplateName,
|
TemplateName = request.TemplateName,
|
||||||
ImageConverterProvider = request.ImageConverterProvider
|
ImageConvertProvider = request.ImageConvertProvider
|
||||||
});
|
});
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
||||||
|
|
@ -320,7 +322,7 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/image-edit/upload")]
|
[HttpPost("/instruct/image-edit/form")]
|
||||||
public async Task<ImageGenerationViewModel> ImageEdit(IFormFile file, [FromForm] ImageEditRequest request)
|
public async Task<ImageGenerationViewModel> ImageEdit(IFormFile file, [FromForm] ImageEditRequest request)
|
||||||
{
|
{
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
|
|
@ -343,7 +345,7 @@ public class InstructModeController : ControllerBase
|
||||||
Model = request?.Model,
|
Model = request?.Model,
|
||||||
AgentId = request?.AgentId,
|
AgentId = request?.AgentId,
|
||||||
TemplateName = request?.TemplateName,
|
TemplateName = request?.TemplateName,
|
||||||
ImageConverterProvider = request?.ImageConverterProvider
|
ImageConvertProvider = request?.ImageConvertProvider
|
||||||
});
|
});
|
||||||
|
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
|
|
@ -360,7 +362,7 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/image-mask-edit")]
|
[HttpPost("/instruct/image-mask-edit")]
|
||||||
public async Task<ImageGenerationViewModel> ImageMaskEdit([FromBody] ImageMaskEditRequest request)
|
public async Task<ImageGenerationViewModel> ImageMaskEdit([FromBody] ImageMaskEditFileRequest request)
|
||||||
{
|
{
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
|
@ -380,7 +382,8 @@ public class InstructModeController : ControllerBase
|
||||||
Provider = request.Provider,
|
Provider = request.Provider,
|
||||||
Model = request.Model,
|
Model = request.Model,
|
||||||
AgentId = request.AgentId,
|
AgentId = request.AgentId,
|
||||||
TemplateName = request.TemplateName
|
TemplateName = request.TemplateName,
|
||||||
|
ImageConvertProvider = request.ImageConvertProvider
|
||||||
});
|
});
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
||||||
|
|
@ -395,7 +398,7 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/image-mask-edit/upload")]
|
[HttpPost("/instruct/image-mask-edit/form")]
|
||||||
public async Task<ImageGenerationViewModel> ImageMaskEdit(IFormFile image, IFormFile mask, [FromForm] ImageMaskEditRequest request)
|
public async Task<ImageGenerationViewModel> ImageMaskEdit(IFormFile image, IFormFile mask, [FromForm] ImageMaskEditRequest request)
|
||||||
{
|
{
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
|
|
@ -425,12 +428,12 @@ public class InstructModeController : ControllerBase
|
||||||
Provider = request?.Provider,
|
Provider = request?.Provider,
|
||||||
Model = request?.Model,
|
Model = request?.Model,
|
||||||
AgentId = request?.AgentId,
|
AgentId = request?.AgentId,
|
||||||
TemplateName = request?.TemplateName
|
TemplateName = request?.TemplateName,
|
||||||
|
ImageConvertProvider = request?.ImageConvertProvider
|
||||||
});
|
});
|
||||||
|
|
||||||
imageViewModel.Content = message.Content;
|
imageViewModel.Content = message.Content;
|
||||||
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
imageViewModel.Images = message.GeneratedImages?.Select(x => ImageViewModel.ToViewModel(x)) ?? [];
|
||||||
|
|
||||||
return imageViewModel;
|
return imageViewModel;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -445,21 +448,22 @@ public class InstructModeController : ControllerBase
|
||||||
|
|
||||||
#region Pdf
|
#region Pdf
|
||||||
[HttpPost("/instruct/pdf-completion")]
|
[HttpPost("/instruct/pdf-completion")]
|
||||||
public async Task<PdfCompletionViewModel> PdfCompletion([FromBody] MultiModalFileRequest input)
|
public async Task<PdfCompletionViewModel> PdfCompletion([FromBody] PdfReadFileRequest request)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
||||||
var viewModel = new PdfCompletionViewModel();
|
var viewModel = new PdfCompletionViewModel();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
var content = await fileInstruct.ReadPdf(input.Text, input.Files, new InstructOptions
|
var content = await fileInstruct.ReadPdf(request.Text, request.Files, new InstructOptions
|
||||||
{
|
{
|
||||||
Provider = input.Provider,
|
Provider = request.Provider,
|
||||||
Model = input.Model,
|
Model = request.Model,
|
||||||
AgentId = input.AgentId,
|
AgentId = request.AgentId,
|
||||||
TemplateName = input.TemplateName
|
TemplateName = request.TemplateName,
|
||||||
|
ImageConvertProvider = request.ImageConvertProvider
|
||||||
});
|
});
|
||||||
viewModel.Content = content;
|
viewModel.Content = content;
|
||||||
return viewModel;
|
return viewModel;
|
||||||
|
|
@ -473,8 +477,8 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/pdf-completion/upload")]
|
[HttpPost("/instruct/pdf-completion/form")]
|
||||||
public async Task<PdfCompletionViewModel> PdfCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] MultiModalRequest request)
|
public async Task<PdfCompletionViewModel> PdfCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] PdfReadRequest request)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
||||||
|
|
@ -494,7 +498,8 @@ public class InstructModeController : ControllerBase
|
||||||
Provider = request?.Provider,
|
Provider = request?.Provider,
|
||||||
Model = request?.Model,
|
Model = request?.Model,
|
||||||
AgentId = request?.AgentId,
|
AgentId = request?.AgentId,
|
||||||
TemplateName = request?.TemplateName
|
TemplateName = request?.TemplateName,
|
||||||
|
ImageConvertProvider = request?.ImageConvertProvider
|
||||||
});
|
});
|
||||||
viewModel.Content = content;
|
viewModel.Content = content;
|
||||||
return viewModel;
|
return viewModel;
|
||||||
|
|
@ -511,26 +516,26 @@ public class InstructModeController : ControllerBase
|
||||||
|
|
||||||
#region Audio
|
#region Audio
|
||||||
[HttpPost("/instruct/speech-to-text")]
|
[HttpPost("/instruct/speech-to-text")]
|
||||||
public async Task<SpeechToTextViewModel> SpeechToText([FromBody] SpeechToTextRequest input)
|
public async Task<SpeechToTextViewModel> SpeechToText([FromBody] SpeechToTextFileRequest request)
|
||||||
{
|
{
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
||||||
var viewModel = new SpeechToTextViewModel();
|
var viewModel = new SpeechToTextViewModel();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var audio = input.File;
|
var audio = request.File;
|
||||||
if (audio == null)
|
if (audio == null)
|
||||||
{
|
{
|
||||||
return new SpeechToTextViewModel { Message = "Error! Cannot find a valid audio file!" };
|
return new SpeechToTextViewModel { Message = "Error! Cannot find a valid audio file!" };
|
||||||
}
|
}
|
||||||
var content = await fileInstruct.SpeechToText(audio, input.Text, new InstructOptions
|
var content = await fileInstruct.SpeechToText(audio, request.Text, new InstructOptions
|
||||||
{
|
{
|
||||||
Provider = input.Provider,
|
Provider = request.Provider,
|
||||||
Model = input.Model,
|
Model = request.Model,
|
||||||
AgentId = input.AgentId,
|
AgentId = request.AgentId,
|
||||||
TemplateName = input.TemplateName
|
TemplateName = request.TemplateName
|
||||||
});
|
});
|
||||||
viewModel.Content = content;
|
viewModel.Content = content;
|
||||||
return viewModel;
|
return viewModel;
|
||||||
|
|
@ -544,8 +549,8 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/speech-to-text/upload")]
|
[HttpPost("/instruct/speech-to-text/form")]
|
||||||
public async Task<SpeechToTextViewModel> SpeechToText(IFormFile file, [FromForm] MultiModalRequest request)
|
public async Task<SpeechToTextViewModel> SpeechToText(IFormFile file, [FromForm] SpeechToTextRequest request)
|
||||||
{
|
{
|
||||||
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
|
|
@ -583,13 +588,13 @@ public class InstructModeController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/instruct/text-to-speech")]
|
[HttpPost("/instruct/text-to-speech")]
|
||||||
public async Task<IActionResult> TextToSpeech([FromBody] TextToSpeechRequest input)
|
public async Task<IActionResult> TextToSpeech([FromBody] TextToSpeechRequest request)
|
||||||
{
|
{
|
||||||
var state = _services.GetRequiredService<IConversationStateService>();
|
var state = _services.GetRequiredService<IConversationStateService>();
|
||||||
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
request.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
|
||||||
|
|
||||||
var completion = CompletionProvider.GetAudioSynthesizer(_services, provider: input.Provider, model: input.Model);
|
var completion = CompletionProvider.GetAudioSynthesizer(_services, provider: request.Provider, model: request.Model);
|
||||||
var binaryData = await completion.GenerateAudioAsync(input.Text);
|
var binaryData = await completion.GenerateAudioAsync(request.Text);
|
||||||
var stream = binaryData.ToStream();
|
var stream = binaryData.ToStream();
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,7 @@
|
||||||
using BotSharp.Abstraction.Conversations.Dtos;
|
using BotSharp.Abstraction.Conversations.Dtos;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace BotSharp.OpenAPI.ViewModels.Conversations;
|
namespace BotSharp.OpenAPI.ViewModels.Conversations;
|
||||||
|
|
||||||
public class ChatResponseModel : ChatResponseDto
|
public class ChatResponseModel : ChatResponseDto
|
||||||
{
|
{
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
||||||
[JsonPropertyName("additional_message_wrapper")]
|
|
||||||
public ChatResponseWrapper? AdditionalMessageWrapper { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChatResponseWrapper
|
|
||||||
{
|
|
||||||
[JsonPropertyName("sending_interval")]
|
|
||||||
public int SendingInterval { get; set; }
|
|
||||||
|
|
||||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
||||||
[JsonPropertyName("messages")]
|
|
||||||
public List<ChatResponseModel>? Messages { get; set; }
|
|
||||||
|
|
||||||
public static ChatResponseWrapper? From(ChatMessageWrapper? wrapper, string conversationId, string? messageId = null)
|
|
||||||
{
|
|
||||||
if (wrapper == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ChatResponseWrapper
|
|
||||||
{
|
|
||||||
SendingInterval = wrapper.SendingInterval,
|
|
||||||
Messages = wrapper?.Messages?.Select(x => new ChatResponseModel
|
|
||||||
{
|
|
||||||
ConversationId = conversationId,
|
|
||||||
MessageId = messageId ?? x.MessageId,
|
|
||||||
Text = !string.IsNullOrEmpty(x.SecondaryContent) ? x.SecondaryContent : x.Content,
|
|
||||||
MessageLabel = x.MessageLabel,
|
|
||||||
Function = x.FunctionName,
|
|
||||||
RichContent = x.SecondaryRichContent ?? x.RichContent,
|
|
||||||
Instruction = x.Instruction,
|
|
||||||
Data = x.Data,
|
|
||||||
IsAppend = true
|
|
||||||
})?.ToList()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -21,6 +21,7 @@ public class InstructBaseRequest
|
||||||
public List<InstructState> States { get; set; } = [];
|
public List<InstructState> States { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class MultiModalRequest : InstructBaseRequest
|
public class MultiModalRequest : InstructBaseRequest
|
||||||
{
|
{
|
||||||
[JsonPropertyName("text")]
|
[JsonPropertyName("text")]
|
||||||
|
|
@ -33,25 +34,34 @@ public class MultiModalFileRequest : MultiModalRequest
|
||||||
public List<InstructFileModel> Files { get; set; } = [];
|
public List<InstructFileModel> Files { get; set; } = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ImageGenerationRequest : InstructBaseRequest
|
public class ImageGenerationRequest : InstructBaseRequest
|
||||||
{
|
{
|
||||||
[JsonPropertyName("text")]
|
[JsonPropertyName("text")]
|
||||||
public string Text { get; set; } = string.Empty;
|
public string Text { get; set; } = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ImageVariationRequest : InstructBaseRequest
|
public class ImageVariationRequest : InstructBaseRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("image_convert_provider")]
|
||||||
|
public string? ImageConvertProvider { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImageVariationFileRequest : ImageVariationRequest
|
||||||
{
|
{
|
||||||
[JsonPropertyName("file")]
|
[JsonPropertyName("file")]
|
||||||
public InstructFileModel File { get; set; }
|
public InstructFileModel File { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ImageEditRequest : InstructBaseRequest
|
public class ImageEditRequest : InstructBaseRequest
|
||||||
{
|
{
|
||||||
[JsonPropertyName("text")]
|
[JsonPropertyName("text")]
|
||||||
public string Text { get; set; } = string.Empty;
|
public string Text { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("image_converter_provider")]
|
[JsonPropertyName("image_convert_provider")]
|
||||||
public string? ImageConverterProvider { get; set; }
|
public string? ImageConvertProvider { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImageEditFileRequest : ImageEditRequest
|
public class ImageEditFileRequest : ImageEditRequest
|
||||||
|
|
@ -66,6 +76,12 @@ public class ImageMaskEditRequest : InstructBaseRequest
|
||||||
[JsonPropertyName("text")]
|
[JsonPropertyName("text")]
|
||||||
public string Text { get; set; } = string.Empty;
|
public string Text { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("image_convert_provider")]
|
||||||
|
public string? ImageConvertProvider { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImageMaskEditFileRequest : ImageMaskEditRequest
|
||||||
|
{
|
||||||
[JsonPropertyName("file")]
|
[JsonPropertyName("file")]
|
||||||
public InstructFileModel File { get; set; }
|
public InstructFileModel File { get; set; }
|
||||||
|
|
||||||
|
|
@ -73,11 +89,31 @@ public class ImageMaskEditRequest : InstructBaseRequest
|
||||||
public InstructFileModel Mask { get; set; }
|
public InstructFileModel Mask { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class PdfReadRequest : InstructBaseRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("text")]
|
||||||
|
public string Text { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[JsonPropertyName("image_convert_provider")]
|
||||||
|
public string? ImageConvertProvider { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PdfReadFileRequest : PdfReadRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("files")]
|
||||||
|
public List<InstructFileModel> Files { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public class SpeechToTextRequest : InstructBaseRequest
|
public class SpeechToTextRequest : InstructBaseRequest
|
||||||
{
|
{
|
||||||
[JsonPropertyName("text")]
|
[JsonPropertyName("text")]
|
||||||
public string? Text { get; set; }
|
public string? Text { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SpeechToTextFileRequest : SpeechToTextRequest
|
||||||
|
{
|
||||||
[JsonPropertyName("file")]
|
[JsonPropertyName("file")]
|
||||||
public InstructFileModel File { get; set; }
|
public InstructFileModel File { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,49 +126,6 @@ public class ChatHubConversationHook : ConversationHookBase
|
||||||
await SendEvent(ChatEvent.OnSenderActionGenerated, conv.ConversationId, action);
|
await SendEvent(ChatEvent.OnSenderActionGenerated, conv.ConversationId, action);
|
||||||
await SendEvent(ChatEvent.OnMessageReceivedFromAssistant, conv.ConversationId, data);
|
await SendEvent(ChatEvent.OnMessageReceivedFromAssistant, conv.ConversationId, data);
|
||||||
|
|
||||||
var wrapper = message.AdditionalMessageWrapper;
|
|
||||||
if (wrapper?.SendingInterval > 0 && wrapper?.Messages?.Count > 0)
|
|
||||||
{
|
|
||||||
action.SenderAction = SenderActionEnum.TypingOn;
|
|
||||||
await SendEvent(ChatEvent.OnSenderActionGenerated, conv.ConversationId, action);
|
|
||||||
|
|
||||||
foreach (var item in wrapper.Messages)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(item.Indication))
|
|
||||||
{
|
|
||||||
data = new ChatResponseDto
|
|
||||||
{
|
|
||||||
ConversationId = conv.ConversationId,
|
|
||||||
MessageId = item.MessageId,
|
|
||||||
MessageLabel = item.MessageLabel,
|
|
||||||
Indication = item.Indication,
|
|
||||||
Sender = sender
|
|
||||||
};
|
|
||||||
await SendEvent(ChatEvent.OnIndicationReceived, conv.ConversationId, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.Delay(wrapper.SendingInterval);
|
|
||||||
|
|
||||||
data = new ChatResponseDto
|
|
||||||
{
|
|
||||||
ConversationId = conv.ConversationId,
|
|
||||||
MessageId = item.MessageId,
|
|
||||||
MessageLabel = item.MessageLabel,
|
|
||||||
Text = !string.IsNullOrEmpty(item.SecondaryContent) ? item.SecondaryContent : item.Content,
|
|
||||||
Function = item.FunctionName,
|
|
||||||
RichContent = item.SecondaryRichContent ?? item.RichContent,
|
|
||||||
Data = item.Data,
|
|
||||||
States = state.GetStates(),
|
|
||||||
IsAppend = true,
|
|
||||||
Sender = sender
|
|
||||||
};
|
|
||||||
await SendEvent(ChatEvent.OnMessageReceivedFromAssistant, conv.ConversationId, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
action.SenderAction = SenderActionEnum.TypingOff;
|
|
||||||
await SendEvent(ChatEvent.OnSenderActionGenerated, conv.ConversationId, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
await base.OnResponseGenerated(message);
|
await base.OnResponseGenerated(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,45 @@ public class FileHandlerImageConverter : IImageConverter
|
||||||
|
|
||||||
public string Provider => "file-handler";
|
public string Provider => "file-handler";
|
||||||
|
|
||||||
public async Task<BinaryData> ConvertImageToRgbaPng(BinaryData binary)
|
public async Task<BinaryData> ConvertImage(BinaryData binary, ImageConvertOptions? options = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var image = Image.Load<Rgba32>(binary.ToArray());
|
using var image = Image.Load<Rgba32>(binary.ToArray());
|
||||||
using var memoryStream = new MemoryStream();
|
using var memoryStream = new MemoryStream();
|
||||||
|
|
||||||
|
if (options?.ImageType == "png")
|
||||||
|
{
|
||||||
|
var colorType = PngColorType.RgbWithAlpha;
|
||||||
|
switch (options?.ColorType)
|
||||||
|
{
|
||||||
|
case "grayscale":
|
||||||
|
colorType = PngColorType.Grayscale;
|
||||||
|
break;
|
||||||
|
case "grayscaleWithAlpha":
|
||||||
|
colorType = PngColorType.GrayscaleWithAlpha;
|
||||||
|
break;
|
||||||
|
case "rgb":
|
||||||
|
colorType = PngColorType.Rgb;
|
||||||
|
break;
|
||||||
|
case "palette":
|
||||||
|
colorType = PngColorType.Palette;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
image.SaveAsPng(memoryStream, new PngEncoder
|
||||||
|
{
|
||||||
|
ColorType = colorType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
image.SaveAsPng(memoryStream, new PngEncoder
|
image.SaveAsPng(memoryStream, new PngEncoder
|
||||||
{
|
{
|
||||||
ColorType = PngColorType.RgbWithAlpha
|
ColorType = PngColorType.RgbWithAlpha
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var convertedBinary = BinaryData.FromBytes(memoryStream.ToArray());
|
var convertedBinary = BinaryData.FromBytes(memoryStream.ToArray());
|
||||||
return await Task.FromResult(convertedBinary);
|
return await Task.FromResult(convertedBinary);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ public class EditImageFn : IFunctionCallback
|
||||||
|
|
||||||
var fileStorage = _services.GetRequiredService<IFileStorageService>();
|
var fileStorage = _services.GetRequiredService<IFileStorageService>();
|
||||||
var fileBinary = fileStorage.GetFileBytes(image.FileStorageUrl);
|
var fileBinary = fileStorage.GetFileBytes(image.FileStorageUrl);
|
||||||
var rgbaBinary = await ConvertImageToRgbaWithPng(fileBinary);
|
var rgbaBinary = await ConvertImageToPngWithRgba(fileBinary);
|
||||||
image.FileExtension = "png";
|
image.FileExtension = "png";
|
||||||
|
|
||||||
using var stream = rgbaBinary.ToStream();
|
using var stream = rgbaBinary.ToStream();
|
||||||
|
|
@ -147,7 +147,7 @@ public class EditImageFn : IFunctionCallback
|
||||||
fileStorage.SaveMessageFiles(_conversationId, _messageId, FileSourceType.Bot, files);
|
fileStorage.SaveMessageFiles(_conversationId, _messageId, FileSourceType.Bot, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<BinaryData> ConvertImageToRgbaWithPng(BinaryData binaryFile)
|
private async Task<BinaryData> ConvertImageToPngWithRgba(BinaryData binaryFile)
|
||||||
{
|
{
|
||||||
var provider = _settings?.ImageConverter?.Provider;
|
var provider = _settings?.ImageConverter?.Provider;
|
||||||
var converter = _services.GetServices<IImageConverter>().FirstOrDefault(x => x.Provider == provider);
|
var converter = _services.GetServices<IImageConverter>().FirstOrDefault(x => x.Provider == provider);
|
||||||
|
|
@ -156,6 +156,6 @@ public class EditImageFn : IFunctionCallback
|
||||||
return binaryFile;
|
return binaryFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await converter.ConvertImageToRgbaPng(binaryFile);
|
return await converter.ConvertImage(binaryFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public class AudioSynthesisProvider : IAudioSynthesis
|
||||||
var options = new SpeechGenerationOptions
|
var options = new SpeechGenerationOptions
|
||||||
{
|
{
|
||||||
ResponseFormat = responseFormat,
|
ResponseFormat = responseFormat,
|
||||||
SpeedRatio = speed,
|
SpeedRatio = speed
|
||||||
};
|
};
|
||||||
|
|
||||||
return (voice, options);
|
return (voice, options);
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,12 @@ public class AudioTranscriptionProvider : IAudioTranscription
|
||||||
switch (value)
|
switch (value)
|
||||||
{
|
{
|
||||||
case "json":
|
case "json":
|
||||||
|
format = new AudioTranscriptionFormat("json");
|
||||||
|
break;
|
||||||
|
case "text":
|
||||||
|
format = new AudioTranscriptionFormat("text");
|
||||||
|
break;
|
||||||
|
case "simple":
|
||||||
format = AudioTranscriptionFormat.Simple;
|
format = AudioTranscriptionFormat.Simple;
|
||||||
break;
|
break;
|
||||||
case "srt":
|
case "srt":
|
||||||
|
|
|
||||||
|
|
@ -437,6 +437,9 @@
|
||||||
},
|
},
|
||||||
"Pdf2ImageConverter": {
|
"Pdf2ImageConverter": {
|
||||||
"Provider": ""
|
"Provider": ""
|
||||||
|
},
|
||||||
|
"ImageConverter": {
|
||||||
|
"Provider": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -469,7 +472,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ImageConverter": {
|
"ImageConverter": {
|
||||||
"Provider": null
|
"Provider": "file-handler"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue