feat: 支持图片生成
This commit is contained in:
@@ -2,6 +2,7 @@ using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.AiGateWay;
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Dtos;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.AiGateWay;
|
||||
|
||||
public interface IImageService
|
||||
{
|
||||
/// <summary>Creates an image given a prompt.</summary>
|
||||
/// <param name="imageCreate"></param>
|
||||
/// <param name="aiModelDescribe"></param>
|
||||
/// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns></returns>
|
||||
Task<ImageCreateResponse> CreateImage(
|
||||
ImageCreateRequest imageCreate,
|
||||
AiModelDescribe? aiModelDescribe = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Creates an edited or extended image given an original image and a prompt.
|
||||
/// </summary>
|
||||
/// <param name="imageEditCreateRequest"></param>
|
||||
/// <param name="aiModelDescribe"></param>
|
||||
/// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns></returns>
|
||||
Task<ImageCreateResponse> CreateImageEdit(
|
||||
ImageEditCreateRequest imageEditCreateRequest,
|
||||
AiModelDescribe? aiModelDescribe = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>Creates a variation of a given image.</summary>
|
||||
/// <param name="imageEditCreateRequest"></param>
|
||||
/// <param name="aiModelDescribe"></param>
|
||||
/// <param name="cancellationToken">Propagates notification that operations should be canceled.</param>
|
||||
/// <returns></returns>
|
||||
Task<ImageCreateResponse> CreateImageVariation(
|
||||
ImageVariationCreateRequest imageEditCreateRequest,
|
||||
AiModelDescribe? aiModelDescribe = null,
|
||||
CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using OpenAI.Images;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
using Yi.Framework.AiHub.Domain.AiGateWay;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Dtos;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.AiGateWay.Impl.ThorAzureOpenAI.Images;
|
||||
|
||||
public class AzureOpenAIServiceImageService : IImageService
|
||||
{
|
||||
public async Task<ImageCreateResponse> CreateImage(ImageCreateRequest imageCreate, AiModelDescribe? options = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var createClient = AzureOpenAIFactory.CreateClient(options);
|
||||
|
||||
var client = createClient.GetImageClient(imageCreate.Model);
|
||||
|
||||
// 将size字符串拆分为宽度和高度
|
||||
var size = imageCreate.Size.Split('x');
|
||||
if (size.Length != 2)
|
||||
{
|
||||
throw new ArgumentException("Size must be in the format of 'width x height'");
|
||||
}
|
||||
|
||||
|
||||
var response = await client.GenerateImageAsync(imageCreate.Prompt, new ImageGenerationOptions()
|
||||
{
|
||||
Quality = imageCreate.Quality == "standard" ? GeneratedImageQuality.Standard : GeneratedImageQuality.High,
|
||||
Size = new GeneratedImageSize(Convert.ToInt32(size[0]), Convert.ToInt32(size[1])),
|
||||
Style = imageCreate.Style == "vivid" ? GeneratedImageStyle.Vivid : GeneratedImageStyle.Natural,
|
||||
ResponseFormat =
|
||||
imageCreate.ResponseFormat == "url" ? GeneratedImageFormat.Uri : GeneratedImageFormat.Bytes,
|
||||
// User = imageCreate.User
|
||||
EndUserId = imageCreate.User
|
||||
}, cancellationToken);
|
||||
|
||||
var ret = new ImageCreateResponse()
|
||||
{
|
||||
Results = new List<ImageCreateResponse.ImageDataResult>()
|
||||
};
|
||||
|
||||
if (response.Value.ImageUri != null)
|
||||
{
|
||||
ret.Results.Add(new ImageCreateResponse.ImageDataResult()
|
||||
{
|
||||
Url = response.Value.ImageUri.ToString()
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.Results.Add(new ImageCreateResponse.ImageDataResult()
|
||||
{
|
||||
B64 = Convert.ToBase64String(response.Value.ImageBytes.ToArray())
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public async Task<ImageCreateResponse> CreateImageEdit(ImageEditCreateRequest imageEditCreateRequest,
|
||||
AiModelDescribe? options = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
var url = AzureOpenAIFactory.GetEditImageAddress(options, imageEditCreateRequest.Model);
|
||||
|
||||
var multipartContent = new MultipartFormDataContent();
|
||||
if (imageEditCreateRequest.User != null)
|
||||
{
|
||||
multipartContent.Add(new StringContent(imageEditCreateRequest.User), "user");
|
||||
}
|
||||
|
||||
if (imageEditCreateRequest.ResponseFormat != null)
|
||||
{
|
||||
multipartContent.Add(new StringContent(imageEditCreateRequest.ResponseFormat), "response_format");
|
||||
}
|
||||
|
||||
if (imageEditCreateRequest.Size != null)
|
||||
{
|
||||
multipartContent.Add(new StringContent(imageEditCreateRequest.Size), "size");
|
||||
}
|
||||
|
||||
if (imageEditCreateRequest.N != null)
|
||||
{
|
||||
multipartContent.Add(new StringContent(imageEditCreateRequest.N.ToString()!), "n");
|
||||
}
|
||||
|
||||
if (imageEditCreateRequest.Model != null)
|
||||
{
|
||||
multipartContent.Add(new StringContent(imageEditCreateRequest.Model!), "model");
|
||||
}
|
||||
|
||||
if (imageEditCreateRequest.Mask != null)
|
||||
{
|
||||
multipartContent.Add(new ByteArrayContent(imageEditCreateRequest.Mask), "mask",
|
||||
imageEditCreateRequest.MaskName);
|
||||
}
|
||||
|
||||
multipartContent.Add(new StringContent(imageEditCreateRequest.Prompt), "prompt");
|
||||
multipartContent.Add(new ByteArrayContent(imageEditCreateRequest.Image), "image",
|
||||
imageEditCreateRequest.ImageName);
|
||||
|
||||
return await HttpClientFactory.GetHttpClient(url).PostFileAndReadAsAsync<ImageCreateResponse>(
|
||||
url,
|
||||
multipartContent, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<ImageCreateResponse> CreateImageVariation(ImageVariationCreateRequest imageEditCreateRequest,
|
||||
AiModelDescribe? options = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.AiGateWay;
|
||||
|
||||
public record ThorBaseResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 对象类型
|
||||
/// </summary>
|
||||
[JsonPropertyName("object")]
|
||||
public string? ObjectTypeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool Successful => Error == null;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[JsonPropertyName("error")]
|
||||
public ThorError? Error { get; set; }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user