diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageCreateRequest.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageCreateRequest.cs
new file mode 100644
index 00000000..c41b6c7b
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageCreateRequest.cs
@@ -0,0 +1,54 @@
+using System.Text.Json.Serialization;
+
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
+
+///
+/// Image Create Request Model
+///
+public record ImageCreateRequest : SharedImageRequestBaseModel
+{
+ public ImageCreateRequest()
+ {
+ }
+
+ public ImageCreateRequest(string prompt)
+ {
+ Prompt = prompt;
+ }
+
+ ///
+ /// 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
+ ///
+ [JsonPropertyName("prompt")]
+ public string Prompt { get; set; }
+
+ ///
+ /// 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.
+ ///
Check for possible values
+ ///
+ [JsonPropertyName("quality")]
+ public string? Quality { get; set; }
+
+ ///
+ /// 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.
+ ///
Check for possible values
+ ///
+ [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; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageCreateResponse.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageCreateResponse.cs
new file mode 100644
index 00000000..e5739815
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageCreateResponse.cs
@@ -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 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; }
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageEditCreateRequest.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageEditCreateRequest.cs
new file mode 100644
index 00000000..cc3f3e51
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageEditCreateRequest.cs
@@ -0,0 +1,51 @@
+using System.Text.Json.Serialization;
+
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
+
+public record ImageEditCreateRequest : SharedImageRequestBaseModel
+{
+ ///
+ /// The image to edit. Must be a valid PNG file, less than 4MB, and square.
+ ///
+ public byte[]? Image { get; set; }
+
+ ///
+ /// Image file name
+ ///
+ public string ImageName { get; set; }
+
+ ///
+ /// 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.
+ ///
+ public byte[]? Mask { get; set; }
+
+ ///
+ /// Mask file name
+ ///
+ public string? MaskName { get; set; }
+
+ [JsonPropertyName("quality")]
+ public string Quality { get; set; }
+
+ ///
+ /// A text description of the desired image(s). The maximum length is 1000 characters.
+ ///
+ [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; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageVariationCreateRequest.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageVariationCreateRequest.cs
new file mode 100644
index 00000000..208c0aea
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/ImageVariationCreateRequest.cs
@@ -0,0 +1,14 @@
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
+
+public record ImageVariationCreateRequest : SharedImageRequestBaseModel
+{
+ ///
+ /// The image to edit. Must be a valid PNG file, less than 4MB, and square.
+ ///
+ public byte[] Image { get; set; }
+
+ ///
+ /// Image file name
+ ///
+ public string ImageName { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/SharedImageRequestBaseModel.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/SharedImageRequestBaseModel.cs
new file mode 100644
index 00000000..987e2792
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/Images/SharedImageRequestBaseModel.cs
@@ -0,0 +1,42 @@
+using System.Text.Json.Serialization;
+
+namespace Yi.Framework.AiHub.Application.Contracts.Dtos.OpenAi.Images;
+
+public record SharedImageRequestBaseModel
+{
+ ///
+ /// The number of images to generate. Must be between 1 and 10.
+ /// For dall-e-3 model, only n=1 is supported.
+ ///
+ [JsonPropertyName("n")]
+ public int? N { get; set; }
+
+ ///
+ /// 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.
+ ///
Check for possible values
+ ///
+ [JsonPropertyName("size")]
+ public string? Size { get; set; }
+
+ ///
+ /// The format in which the generated images are returned. Must be one of url or b64_json
+ ///
+ [JsonPropertyName("response_format")]
+ public string? ResponseFormat { get; set; }
+
+ ///
+ /// A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
+ /// Learn more.
+ ///
+ [JsonPropertyName("user")]
+ public string? User { get; set; }
+
+ ///
+ /// 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.
+ ///
+ [JsonPropertyName("model")]
+ public string? Model { get; set; }
+}
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/ThorBaseResponse.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorBaseResponse.cs
similarity index 80%
rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/ThorBaseResponse.cs
rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorBaseResponse.cs
index bbbf4be4..9896f3d3 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/ThorBaseResponse.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/OpenAi/ThorBaseResponse.cs
@@ -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
{
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs
index 8f03ae7e..5d3954c1 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/AiChatService.cs
@@ -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> 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);
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
index 4df08fe8..08c6a233 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs
@@ -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 _aiModelRepository;
-
+ private readonly AiBlacklistManager _aiBlacklistManager;
public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger logger,
TokenManager tokenManager, AiGateWayManager aiGateWayManager,
- ISqlSugarRepository aiModelRepository)
+ ISqlSugarRepository aiModelRepository, AiBlacklistManager aiBlacklistManager)
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
_tokenManager = tokenManager;
_aiGateWayManager = aiGateWayManager;
_aiModelRepository = aiModelRepository;
+ _aiBlacklistManager = aiBlacklistManager;
}
///
@@ -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
}
}
+ ///
+ /// 图片生成
+ ///
+ ///
+ ///
+ [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);
+ }
+
+
///
/// 获取模型列表
///
@@ -63,6 +82,7 @@ public class OpenApiService : ApplicationService
public async Task ModelsAsync()
{
var data = await _aiModelRepository._DbQueryable
+ .Where(x => x.ModelType == ModelTypeEnum.Chat)
.OrderByDescending(x => x.OrderNum)
.Select(x => new ModelsDataDto
{
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs
new file mode 100644
index 00000000..e1167ce2
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/ModelTypeEnum.cs
@@ -0,0 +1,8 @@
+namespace Yi.Framework.AiHub.Domain.Shared.Enums;
+
+
+public enum ModelTypeEnum
+{
+ Chat = 0,
+ Image = 1
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/HttpClientExtensions.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/HttpClientExtensions.cs
index dbfee79f..fb77d420 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/HttpClientExtensions.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/HttpClientExtensions.cs
@@ -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;
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/IImageService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/IImageService.cs
new file mode 100644
index 00000000..8f429686
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/IImageService.cs
@@ -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
+{
+ /// Creates an image given a prompt.
+ ///
+ ///
+ /// Propagates notification that operations should be canceled.
+ ///
+ Task CreateImage(
+ ImageCreateRequest imageCreate,
+ AiModelDescribe? aiModelDescribe = null,
+ CancellationToken cancellationToken = default);
+
+ ///
+ /// Creates an edited or extended image given an original image and a prompt.
+ ///
+ ///
+ ///
+ /// Propagates notification that operations should be canceled.
+ ///
+ Task CreateImageEdit(
+ ImageEditCreateRequest imageEditCreateRequest,
+ AiModelDescribe? aiModelDescribe = null,
+ CancellationToken cancellationToken = default);
+
+ /// Creates a variation of a given image.
+ ///
+ ///
+ /// Propagates notification that operations should be canceled.
+ ///
+ Task CreateImageVariation(
+ ImageVariationCreateRequest imageEditCreateRequest,
+ AiModelDescribe? aiModelDescribe = null,
+ CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorAzureOpenAI/Images/AzureOpenAIServiceImageService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorAzureOpenAI/Images/AzureOpenAIServiceImageService.cs
new file mode 100644
index 00000000..1fb23295
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiGateWay/Impl/ThorAzureOpenAI/Images/AzureOpenAIServiceImageService.cs
@@ -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 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()
+ };
+
+ 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 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(
+ url,
+ multipartContent, cancellationToken);
+ }
+
+ public Task CreateImageVariation(ImageVariationCreateRequest imageEditCreateRequest,
+ AiModelDescribe? options = null,
+ CancellationToken cancellationToken = default(CancellationToken))
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiModelEntity.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiModelEntity.cs
index ba363fda..b1149eb8 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiModelEntity.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiModelEntity.cs
@@ -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模型定义
///
[SugarTable("Ai_Model")]
-public class AiModelEntity : Entity, IOrderNum,ISoftDelete
+public class AiModelEntity : Entity, IOrderNum, ISoftDelete
{
///
/// 处理名
@@ -44,9 +45,14 @@ public class AiModelEntity : Entity, IOrderNum,ISoftDelete
/// ai应用id
///
public Guid AiAppId { get; set; }
-
+
///
/// 额外信息
///
public string? ExtraInfo { get; set; }
+
+ ///
+ /// 模型类型
+ ///
+ public ModelTypeEnum ModelType { get; set; }
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
index 70f47354..042693a5 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiGateWayManager.cs
@@ -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()
@@ -261,4 +265,61 @@ public class AiGateWayManager : DomainService
await _usageStatisticsManager.SetUsageAsync(userId, request.Model, tokenUsage);
}
+
+
+ ///
+ /// 图片生成
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ 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(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);
+ }
+ }
}
\ No newline at end of file