refine form data

This commit is contained in:
Jicheng Lu 2025-05-28 11:57:25 -05:00
parent 19e16ff4fe
commit 0469b27a97
6 changed files with 98 additions and 76 deletions

View file

@ -145,11 +145,7 @@ public class ConversationStateService : IConversationStateService
newPair.Values = new List<StateValue> { newValue };
_curStates[name] = newPair;
}
else if (isNoChange)
{
// do nothing
}
else
else if (!isNoChange)
{
_curStates[name].Values.Add(newValue);
}

View file

@ -1,5 +1,4 @@
using BotSharp.Abstraction.Instructs.Models;
using System.IO;
namespace BotSharp.Core.Files.Services;
@ -18,7 +17,7 @@ public partial class FileInstructService
using var stream = audioBinary.ToStream();
stream.Position = 0;
var fileName = $"{audio.FileName ?? "audio"}.{audio.FileExtension ?? "wav"}";
var fileName = $"{audio.FileName.IfNullOrEmptyAs("audio")}.{audio.FileExtension.IfNullOrEmptyAs("wav")}";
var content = await completion.TranscriptTextAsync(stream, fileName, text ?? string.Empty);
stream.Close();
return content;

View file

@ -82,7 +82,7 @@ public partial class FileInstructService
using var stream = binary.ToStream();
stream.Position = 0;
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var fileName = $"{image.FileName.IfNullOrEmptyAs("image")}.{image.FileExtension.IfNullOrEmptyAs("png")}";
var message = await completion.GetImageVariation(new Agent()
{
Id = innerAgentId
@ -118,7 +118,7 @@ public partial class FileInstructService
using var stream = binary.ToStream();
stream.Position = 0;
var fileName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var fileName = $"{image.FileName.IfNullOrEmptyAs("image")}.{image.FileExtension.IfNullOrEmptyAs("png")}";
var message = await completion.GetImageEdits(new Agent()
{
Id = innerAgentId
@ -162,8 +162,8 @@ public partial class FileInstructService
using var maskStream = maskBinary.ToStream();
maskStream.Position = 0;
var imageName = $"{image.FileName ?? "image"}.{image.FileExtension ?? "png"}";
var maskName = $"{mask.FileName ?? "mask"}.{mask.FileExtension ?? "png"}";
var imageName = $"{image.FileName.IfNullOrEmptyAs("image")}.{image.FileExtension.IfNullOrEmptyAs("png")}";
var maskName = $"{mask.FileName.IfNullOrEmptyAs("mask")}.{mask.FileExtension.IfNullOrEmptyAs("png")}";
var message = await completion.GetImageEdits(new Agent()
{
Id = innerAgentId

View file

@ -5,6 +5,7 @@ using BotSharp.Abstraction.Instructs;
using BotSharp.Abstraction.Instructs.Models;
using BotSharp.Core.Infrastructures;
using BotSharp.OpenAPI.ViewModels.Instructs;
using BotSharp.OpenAPI.ViewModels.Instructs.Request;
using static System.Net.Mime.MediaTypeNames;
namespace BotSharp.OpenAPI.Controllers;
@ -118,7 +119,7 @@ public class InstructModeController : ControllerBase
public async Task<string> MultiModalCompletion([FromBody] MultiModalFileRequest input)
{
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
try
{
@ -141,11 +142,10 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/multi-modal/upload")]
public async Task<MultiModalViewModel> MultiModalCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] MultiModalRequest request,
[FromForm] List<MessageState>? states = null, [FromForm] List<string>? list = null)
public async Task<MultiModalViewModel> MultiModalCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] MultiModalRequest request)
{
var state = _services.GetRequiredService<IConversationStateService>();
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var viewModel = new MultiModalViewModel();
try
@ -154,6 +154,7 @@ public class InstructModeController : ControllerBase
{
FileData = FileUtility.BuildFileDataFromFile(x)
}).ToList();
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var content = await fileInstruct.ReadImages(request?.Text ?? string.Empty, fileModels, new InstructOptions
{
@ -180,7 +181,7 @@ public class InstructModeController : ControllerBase
public async Task<ImageGenerationViewModel> ImageGeneration([FromBody] ImageGenerationRequest input)
{
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
@ -212,7 +213,7 @@ public class InstructModeController : ControllerBase
public async Task<ImageGenerationViewModel> ImageVariation([FromBody] ImageVariationRequest input)
{
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
@ -244,23 +245,27 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/image-variation/upload")]
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] string? provider = null,
[FromForm] string? model = null, [FromForm] List<MessageState>? states = null,
[FromForm] string? agentId = null)
public async Task<ImageGenerationViewModel> ImageVariation(IFormFile file, [FromForm] MultiModalRequest request)
{
var state = _services.GetRequiredService<IConversationStateService>();
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var fileData = FileUtility.BuildFileDataFromFile(file);
var message = await fileInstruct.VaryImage(new InstructFileModel { FileData = fileData }, new InstructOptions
var message = await fileInstruct.VaryImage(new InstructFileModel
{
Provider = provider,
Model = model,
AgentId = agentId
FileData = fileData,
FileName = Path.GetFileNameWithoutExtension(file.FileName),
FileExtension = Path.GetExtension(file.FileName).Substring(1)
},
new InstructOptions
{
Provider = request?.Provider,
Model = request?.Model,
AgentId = request?.AgentId
});
imageViewModel.Content = message.Content;
@ -281,7 +286,7 @@ public class InstructModeController : ControllerBase
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
@ -311,24 +316,28 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/image-edit/upload")]
public async Task<ImageGenerationViewModel> ImageEdit(IFormFile file, [FromForm] string text, [FromForm] string? provider = null,
[FromForm] string? model = null, [FromForm] List<MessageState>? states = null,
[FromForm] string? agentId = null, [FromForm] string? templateName = null)
public async Task<ImageGenerationViewModel> ImageEdit(IFormFile file, [FromForm] MultiModalRequest request)
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var state = _services.GetRequiredService<IConversationStateService>();
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
{
var fileData = FileUtility.BuildFileDataFromFile(file);
var message = await fileInstruct.EditImage(text, new InstructFileModel { FileData = fileData }, new InstructOptions
var message = await fileInstruct.EditImage(request?.Text ?? string.Empty, new InstructFileModel
{
Provider = provider,
Model = model,
AgentId = agentId,
TemplateName = templateName
FileData = fileData,
FileName = Path.GetFileNameWithoutExtension(file.FileName),
FileExtension = Path.GetExtension(file.FileName).Substring(1)
},
new InstructOptions
{
Provider = request?.Provider,
Model = request?.Model,
AgentId = request?.AgentId,
TemplateName = request?.TemplateName
});
imageViewModel.Content = message.Content;
@ -350,7 +359,7 @@ public class InstructModeController : ControllerBase
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
@ -382,28 +391,37 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/image-mask-edit/upload")]
public async Task<ImageGenerationViewModel> ImageMaskEdit(IFormFile image, IFormFile mask,
[FromForm] string text, [FromForm] string? provider = null, [FromForm] string? model = null,
[FromForm] List<MessageState>? states = null, [FromForm] string? agentId = null, [FromForm] string? templateName = null)
public async Task<ImageGenerationViewModel> ImageMaskEdit(IFormFile image, IFormFile mask, [FromForm] MultiModalRequest request)
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var state = _services.GetRequiredService<IConversationStateService>();
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var imageViewModel = new ImageGenerationViewModel();
try
{
var imageData = FileUtility.BuildFileDataFromFile(image);
var maskData = FileUtility.BuildFileDataFromFile(mask);
var message = await fileInstruct.EditImage(text,
new InstructFileModel { FileData = imageData },
new InstructFileModel { FileData = maskData }, new InstructOptions
{
Provider = provider,
Model = model,
AgentId = agentId,
TemplateName = templateName
});
var message = await fileInstruct.EditImage(request?.Text ?? string.Empty,
new InstructFileModel
{
FileData = imageData,
FileName = Path.GetFileNameWithoutExtension(image.FileName),
FileExtension = Path.GetExtension(image.FileName).Substring(1)
},
new InstructFileModel
{
FileData = maskData,
FileName = Path.GetFileNameWithoutExtension(mask.FileName),
FileExtension = Path.GetExtension(mask.FileName).Substring(1)
},
new InstructOptions
{
Provider = request?.Provider,
Model = request?.Model,
AgentId = request?.AgentId,
TemplateName = request?.TemplateName
});
imageViewModel.Content = message.Content;
imageViewModel.Images = message.GeneratedImages.Select(x => ImageViewModel.ToViewModel(x)).ToList();
@ -425,7 +443,7 @@ public class InstructModeController : ControllerBase
public async Task<PdfCompletionViewModel> PdfCompletion([FromBody] MultiModalFileRequest input)
{
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var viewModel = new PdfCompletionViewModel();
try
@ -451,29 +469,26 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/pdf-completion/upload")]
public async Task<PdfCompletionViewModel> PdfCompletion(IFormFile file, [FromForm] string text,
[FromForm] string? provider = null, [FromForm] string? model = null, [FromForm] List<MessageState>? states = null,
[FromForm] string? agentId = null, [FromForm] string? templateName = null)
public async Task<PdfCompletionViewModel> PdfCompletion([FromForm] IEnumerable<IFormFile> files, [FromForm] MultiModalRequest request)
{
var state = _services.GetRequiredService<IConversationStateService>();
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var viewModel = new PdfCompletionViewModel();
try
{
var data = FileUtility.BuildFileDataFromFile(file);
var files = new List<InstructFileModel>
var fileModels = files.Select(x => new InstructFileModel
{
new InstructFileModel { FileData = data }
};
FileData = FileUtility.BuildFileDataFromFile(x)
}).ToList();
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var content = await fileInstruct.ReadPdf(text, files, new InstructOptions
var content = await fileInstruct.ReadPdf(request?.Text ?? string.Empty, fileModels, new InstructOptions
{
Provider = provider,
Model = model,
AgentId = agentId,
TemplateName = templateName
Provider = request?.Provider,
Model = request?.Model,
AgentId = request?.AgentId,
TemplateName = request?.TemplateName
});
viewModel.Content = content;
return viewModel;
@ -494,7 +509,7 @@ public class InstructModeController : ControllerBase
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var viewModel = new SpeechToTextViewModel();
try
@ -524,25 +539,29 @@ public class InstructModeController : ControllerBase
}
[HttpPost("/instruct/speech-to-text/upload")]
public async Task<SpeechToTextViewModel> SpeechToText(IFormFile file,
[FromForm] string? provider = null, [FromForm] string? model = null,
[FromForm] string? text = null, [FromForm] List<MessageState>? states = null,
[FromForm] string? agentId = null, [FromForm] string? templateName = null)
public async Task<SpeechToTextViewModel> SpeechToText(IFormFile file, [FromForm] MultiModalRequest request)
{
var fileInstruct = _services.GetRequiredService<IFileInstructService>();
var state = _services.GetRequiredService<IConversationStateService>();
states?.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
request?.States?.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var viewModel = new SpeechToTextViewModel();
try
{
var audioData = FileUtility.BuildFileDataFromFile(file);
var content = await fileInstruct.SpeechToText(new InstructFileModel { FileData = audioData }, text, new InstructOptions
var content = await fileInstruct.SpeechToText(new InstructFileModel
{
FileData = audioData,
FileName = Path.GetFileNameWithoutExtension(file.FileName),
FileExtension = Path.GetExtension(file.FileName).Substring(1)
},
request?.Text ?? string.Empty,
new InstructOptions
{
Provider = provider,
Model = model,
AgentId = agentId,
TemplateName = templateName
Provider = request?.Provider,
Model = request?.Model,
AgentId = request?.AgentId,
TemplateName = request?.TemplateName
});
viewModel.Content = content;
@ -561,7 +580,7 @@ public class InstructModeController : ControllerBase
public async Task<IActionResult> TextToSpeech([FromBody] TextToSpeechRequest input)
{
var state = _services.GetRequiredService<IConversationStateService>();
input.States.ForEach(x => state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External));
input.States.ForEach(x => state.SetState(x.Key, x.Value, source: StateSource.External));
var completion = CompletionProvider.GetAudioSynthesizer(_services, provider: input.Provider, model: input.Model);
var binaryData = await completion.GenerateAudioAsync(input.Text);

View file

@ -1,3 +1,4 @@
using BotSharp.OpenAPI.ViewModels.Instructs.Request;
using System.Text.Json.Serialization;
namespace BotSharp.Abstraction.Instructs.Models;
@ -17,7 +18,7 @@ public class InstructBaseRequest
public virtual string? TemplateName { get; set; }
[JsonPropertyName("states")]
public List<MessageState> States { get; set; } = [];
public List<InstructState> States { get; set; } = [];
}
public class MultiModalRequest : InstructBaseRequest

View file

@ -0,0 +1,7 @@
namespace BotSharp.OpenAPI.ViewModels.Instructs.Request;
public class InstructState
{
public string Key { get; set; }
public string Value { get; set; }
}