feat: 支持图片生成
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
|
||||
/// <summary>
|
||||
/// Image Create Request Model
|
||||
/// </summary>
|
||||
public record ImageCreateRequest : SharedImageRequestBaseModel
|
||||
{
|
||||
public ImageCreateRequest()
|
||||
{
|
||||
}
|
||||
|
||||
public ImageCreateRequest(string prompt)
|
||||
{
|
||||
Prompt = prompt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A text description of the desired image(s). The maximum length is 1000 characters for dall-e-2 and 4000 characters for dall-e-3
|
||||
/// </summary>
|
||||
[JsonPropertyName("prompt")]
|
||||
public string Prompt { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The quality of the image that will be generated. Possible values are 'standard' or 'hd' (default is 'standard').
|
||||
/// Hd creates images with finer details and greater consistency across the image.
|
||||
/// This param is only supported for dall-e-3 model.
|
||||
/// <br /><br />Check <see cref="StaticValues.ImageStatics.Quality"/> for possible values
|
||||
/// </summary>
|
||||
[JsonPropertyName("quality")]
|
||||
public string? Quality { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The style of the generated images. Must be one of vivid or natural.
|
||||
/// Vivid causes the model to lean towards generating hyper-real and dramatic images.
|
||||
/// Natural causes the model to produce more natural, less hyper-real looking images. This param is only supported for dall-e-3.
|
||||
/// <br /><br />Check <see cref="StaticValues.ImageStatics.Style"/> for possible values
|
||||
/// </summary>
|
||||
[JsonPropertyName("style")]
|
||||
public string? Style { get; set; }
|
||||
|
||||
[JsonPropertyName("background")]
|
||||
public string? Background { get; set; }
|
||||
|
||||
[JsonPropertyName("moderation")]
|
||||
public string? Moderation { get; set; }
|
||||
|
||||
[JsonPropertyName("output_compression")]
|
||||
public string? OutputCompression { get; set; }
|
||||
|
||||
[JsonPropertyName("output_format")]
|
||||
public string? OutputFormat { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
|
||||
public record ImageCreateResponse : ThorBaseResponse
|
||||
{
|
||||
[JsonPropertyName("data")] public List<ImageDataResult> Results { get; set; }
|
||||
|
||||
[JsonPropertyName("usage")] public ThorUsageResponse? Usage { get; set; } = new();
|
||||
|
||||
|
||||
|
||||
public record ImageDataResult
|
||||
{
|
||||
[JsonPropertyName("url")] public string Url { get; set; }
|
||||
[JsonPropertyName("b64_json")] public string B64 { get; set; }
|
||||
[JsonPropertyName("revised_prompt")] public string RevisedPrompt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
|
||||
public record ImageEditCreateRequest : SharedImageRequestBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
|
||||
/// </summary>
|
||||
public byte[]? Image { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Image file name
|
||||
/// </summary>
|
||||
public string ImageName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// An additional image whose fully transparent areas (e.g. where alpha is zero) indicate where image should be edited.
|
||||
/// Must be a valid PNG file, less than 4MB, and have the same dimensions as image.
|
||||
/// </summary>
|
||||
public byte[]? Mask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Mask file name
|
||||
/// </summary>
|
||||
public string? MaskName { get; set; }
|
||||
|
||||
[JsonPropertyName("quality")]
|
||||
public string Quality { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A text description of the desired image(s). The maximum length is 1000 characters.
|
||||
/// </summary>
|
||||
[JsonPropertyName("prompt")]
|
||||
public string Prompt { get; set; }
|
||||
|
||||
[JsonPropertyName("background")]
|
||||
public string? Background { get; set; }
|
||||
|
||||
[JsonPropertyName("moderation")]
|
||||
public string? Moderation { get; set; }
|
||||
|
||||
[JsonPropertyName("output_compression")]
|
||||
public string? OutputCompression { get; set; }
|
||||
|
||||
[JsonPropertyName("output_format")]
|
||||
public string? OutputFormat { get; set; }
|
||||
|
||||
[JsonPropertyName("style")]
|
||||
public string? Style { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
|
||||
public record ImageVariationCreateRequest : SharedImageRequestBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The image to edit. Must be a valid PNG file, less than 4MB, and square.
|
||||
/// </summary>
|
||||
public byte[] Image { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Image file name
|
||||
/// </summary>
|
||||
public string ImageName { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
|
||||
public record SharedImageRequestBaseModel
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of images to generate. Must be between 1 and 10.
|
||||
/// For dall-e-3 model, only n=1 is supported.
|
||||
/// </summary>
|
||||
[JsonPropertyName("n")]
|
||||
public int? N { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The size of the generated images.
|
||||
/// Must be one of 256x256, 512x512, or 1024x1024 for dall-e-2.
|
||||
/// Must be one of 1024x1024, 1792x1024, or 1024x1792 for dall-e-3 models.
|
||||
/// <br /><br />Check <see cref="StaticValues.ImageStatics.Size"/> for possible values
|
||||
/// </summary>
|
||||
[JsonPropertyName("size")]
|
||||
public string? Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The format in which the generated images are returned. Must be one of url or b64_json
|
||||
/// </summary>
|
||||
[JsonPropertyName("response_format")]
|
||||
public string? ResponseFormat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||
/// <a href="https://platform.openai.com/docs/usage-policies/end-user-ids">Learn more</a>.
|
||||
/// </summary>
|
||||
[JsonPropertyName("user")]
|
||||
public string? User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The model to use for image generation. Must be one of dall-e-2 or dall-e-3
|
||||
/// For ImageEditCreateRequest and for ImageVariationCreateRequest only dall-e-2 modell is supported at this time.
|
||||
/// </summary>
|
||||
[JsonPropertyName("model")]
|
||||
public string? Model { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.AiGateWay;
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
|
||||
|
||||
public record ThorBaseResponse
|
||||
{
|
||||
@@ -18,6 +18,7 @@ using Yi.Framework.AiHub.Domain.Entities.Model;
|
||||
using Yi.Framework.AiHub.Domain.Extensions;
|
||||
using Yi.Framework.AiHub.Domain.Managers;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Dtos;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
using Yi.Framework.Rbac.Application.Contracts.IServices;
|
||||
using Yi.Framework.Rbac.Domain.Shared.Dtos;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
@@ -68,6 +69,7 @@ public class AiChatService : ApplicationService
|
||||
public async Task<List<ModelGetListOutput>> GetModelAsync()
|
||||
{
|
||||
var output = await _aiModelRepository._DbQueryable
|
||||
.Where(x => x.ModelType == ModelTypeEnum.Chat)
|
||||
.OrderByDescending(x => x.OrderNum)
|
||||
.Select(x => new ModelGetListOutput
|
||||
{
|
||||
@@ -115,6 +117,7 @@ public class AiChatService : ApplicationService
|
||||
throw new UserFriendlyException("未登录用户,只能使用未加速的DeepSeek-R1,请登录后重试");
|
||||
}
|
||||
}
|
||||
|
||||
//ai网关代理httpcontext
|
||||
await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input,
|
||||
CurrentUser.Id, sessionId, cancellationToken);
|
||||
|
||||
@@ -3,9 +3,11 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Volo.Abp.Application.Services;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
||||
using Yi.Framework.AiHub.Domain.Extensions;
|
||||
using Yi.Framework.AiHub.Domain.Managers;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.AiHub.Application.Services;
|
||||
@@ -17,16 +19,17 @@ public class OpenApiService : ApplicationService
|
||||
private readonly TokenManager _tokenManager;
|
||||
private readonly AiGateWayManager _aiGateWayManager;
|
||||
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
|
||||
|
||||
private readonly AiBlacklistManager _aiBlacklistManager;
|
||||
public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger<OpenApiService> logger,
|
||||
TokenManager tokenManager, AiGateWayManager aiGateWayManager,
|
||||
ISqlSugarRepository<AiModelEntity> aiModelRepository)
|
||||
ISqlSugarRepository<AiModelEntity> aiModelRepository, AiBlacklistManager aiBlacklistManager)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
_tokenManager = tokenManager;
|
||||
_aiGateWayManager = aiGateWayManager;
|
||||
_aiModelRepository = aiModelRepository;
|
||||
_aiBlacklistManager = aiBlacklistManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,6 +44,7 @@ public class OpenApiService : ApplicationService
|
||||
//前面都是校验,后面才是真正的调用
|
||||
var httpContext = this._httpContextAccessor.HttpContext;
|
||||
var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
|
||||
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
||||
//ai网关代理httpcontext
|
||||
if (input.Stream == true)
|
||||
{
|
||||
@@ -55,6 +59,21 @@ public class OpenApiService : ApplicationService
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 图片生成
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
[HttpPost("openApi/v1/images/generations")]
|
||||
public async Task ImagesGenerationsAsync([FromBody] ImageCreateRequest input, CancellationToken cancellationToken)
|
||||
{
|
||||
var httpContext = this._httpContextAccessor.HttpContext;
|
||||
var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
|
||||
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
||||
await _aiGateWayManager.CreateImageForStatisticsAsync(httpContext, userId, null, input);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取模型列表
|
||||
/// </summary>
|
||||
@@ -63,6 +82,7 @@ public class OpenApiService : ApplicationService
|
||||
public async Task<ModelsListDto> ModelsAsync()
|
||||
{
|
||||
var data = await _aiModelRepository._DbQueryable
|
||||
.Where(x => x.ModelType == ModelTypeEnum.Chat)
|
||||
.OrderByDescending(x => x.OrderNum)
|
||||
.Select(x => new ModelsDataDto
|
||||
{
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
|
||||
|
||||
public enum ModelTypeEnum
|
||||
{
|
||||
Chat = 0,
|
||||
Image = 1
|
||||
}
|
||||
@@ -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,5 +1,6 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Domain.Entities;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||
using Yi.Framework.Core.Data;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Entities.Model;
|
||||
@@ -8,7 +9,7 @@ namespace Yi.Framework.AiHub.Domain.Entities.Model;
|
||||
/// ai模型定义
|
||||
/// </summary>
|
||||
[SugarTable("Ai_Model")]
|
||||
public class AiModelEntity : Entity<Guid>, IOrderNum,ISoftDelete
|
||||
public class AiModelEntity : Entity<Guid>, IOrderNum, ISoftDelete
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理名
|
||||
@@ -44,9 +45,14 @@ public class AiModelEntity : Entity<Guid>, IOrderNum,ISoftDelete
|
||||
/// ai应用id
|
||||
/// </summary>
|
||||
public Guid AiAppId { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 额外信息
|
||||
/// </summary>
|
||||
public string? ExtraInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型类型
|
||||
/// </summary>
|
||||
public ModelTypeEnum ModelType { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@@ -9,9 +10,12 @@ using Newtonsoft.Json.Serialization;
|
||||
using Volo.Abp.Domain.Services;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
|
||||
using Yi.Framework.AiHub.Domain.AiGateWay;
|
||||
using Yi.Framework.AiHub.Domain.AiGateWay.Exceptions;
|
||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
||||
using Yi.Framework.AiHub.Domain.Shared.Dtos;
|
||||
using Yi.Framework.Core.Extensions;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Managers;
|
||||
@@ -213,7 +217,7 @@ public class AiGateWayManager : DomainService
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, $"Ai对话异常");
|
||||
var errorContent = $"Ai异常,异常信息:\n当前Ai模型:{request.Model}\n异常信息:{e.Message}\n异常堆栈:{e}";
|
||||
var errorContent = $"对话Ai异常,异常信息:\n当前Ai模型:{request.Model}\n异常信息:{e.Message}\n异常堆栈:{e}";
|
||||
var model = new ThorChatCompletionsResponse()
|
||||
{
|
||||
Choices = new List<ThorChatChoiceResponse>()
|
||||
@@ -261,4 +265,61 @@ public class AiGateWayManager : DomainService
|
||||
|
||||
await _usageStatisticsManager.SetUsageAsync(userId, request.Model, tokenUsage);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 图片生成
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="sessionId"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <exception cref="BusinessException"></exception>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task CreateImageForStatisticsAsync(HttpContext context,Guid? userId,Guid? sessionId, ImageCreateRequest request)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = request.Model;
|
||||
if (string.IsNullOrEmpty(model)) model = "dall-e-2";
|
||||
|
||||
var modelDescribe = await GetModelAsync(model);
|
||||
|
||||
// 获取渠道指定的实现类型的服务
|
||||
var imageService =
|
||||
LazyServiceProvider.GetRequiredKeyedService<IImageService>(modelDescribe.HandlerName);
|
||||
|
||||
var response = await imageService.CreateImage(request, modelDescribe);
|
||||
|
||||
if (response.Error != null || response.Results.Count == 0)
|
||||
{
|
||||
throw new BusinessException(response.Error?.Message ?? "图片生成失败", response.Error?.Code?.ToString());
|
||||
}
|
||||
|
||||
await context.Response.WriteAsJsonAsync(response);
|
||||
|
||||
await _aiMessageManager.CreateUserMessageAsync(userId, sessionId,
|
||||
new MessageInputDto
|
||||
{
|
||||
Content = request.Prompt,
|
||||
ModelId = model,
|
||||
TokenUsage = response.Usage,
|
||||
});
|
||||
|
||||
await _aiMessageManager.CreateSystemMessageAsync(userId, sessionId,
|
||||
new MessageInputDto
|
||||
{
|
||||
Content = response.Results?.FirstOrDefault()?.Url,
|
||||
ModelId = model,
|
||||
TokenUsage = response.Usage
|
||||
});
|
||||
|
||||
await _usageStatisticsManager.SetUsageAsync(userId, model, response.Usage);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var errorContent = $"图片生成Ai异常,异常信息:\n当前Ai模型:{request.Model}\n异常信息:{e.Message}\n异常堆栈:{e}";
|
||||
throw new UserFriendlyException(errorContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user