diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/ModelGetListOutput.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/ModelGetListOutput.cs
index 556599c0..786c8d98 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/ModelGetListOutput.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/ModelGetListOutput.cs
@@ -5,7 +5,7 @@ public class ModelGetListOutput
///
/// 模型ID
///
- public long Id { get; set; }
+ public Guid Id { get; set; }
///
/// 模型分类
@@ -20,7 +20,7 @@ public class ModelGetListOutput
///
/// 模型描述
///
- public string ModelDescribe { get; set; }
+ public string? ModelDescribe { get; set; }
///
/// 模型价格
@@ -55,5 +55,5 @@ public class ModelGetListOutput
///
/// 备注信息
///
- public string Remark { get; set; }
+ public string? Remark { get; set; }
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Options/AiGateWayOptions.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Options/AiGateWayOptions.cs
deleted file mode 100644
index 914b8a6a..00000000
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Options/AiGateWayOptions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Yi.Framework.AiHub.Application.Contracts.Options;
-
-public class AiGateWayOptions
-{
- public AiChatOptionDic Chats { get; set; }
-}
-
-public class AiChatOptionDic : Dictionary
-{
-}
-
-public class AiChatModelOptions
-{
- public List ModelIds { get; set; }
- public string Endpoint { get; set; }
- public string ApiKey { get; set; }
-}
\ No newline at end of file
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 efb6a5d5..9b5e0808 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
@@ -5,17 +5,17 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
-using Microsoft.Identity.Client;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using OpenAI.Chat;
using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Application.Contracts.Dtos;
-using Yi.Framework.AiHub.Application.Contracts.Options;
+using Yi.Framework.AiHub.Domain.Entities;
using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.Rbac.Application.Contracts.IServices;
using Yi.Framework.Rbac.Domain.Shared.Dtos;
+using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Application.Services;
@@ -24,16 +24,17 @@ namespace Yi.Framework.AiHub.Application.Services;
///
public class AiChatService : ApplicationService
{
- private readonly AiGateWayOptions _options;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly AiMessageManager _aiMessageManager;
+ private readonly ISqlSugarRepository _aiModelRepository;
+ private readonly AiBlacklistManager _aiBlacklistManager;
- public AiChatService(IOptions options, IHttpContextAccessor httpContextAccessor,
- AiMessageManager aiMessageManager)
+ public AiChatService(IHttpContextAccessor httpContextAccessor,
+ AiMessageManager aiMessageManager, AiBlacklistManager aiBlacklistManager)
{
- _options = options.Value;
this._httpContextAccessor = httpContextAccessor;
_aiMessageManager = aiMessageManager;
+ _aiBlacklistManager = aiBlacklistManager;
}
@@ -56,18 +57,20 @@ public class AiChatService : ApplicationService
///
public async Task> GetModelAsync()
{
- var output = _options.Chats.SelectMany(x => x.Value.ModelIds)
- .Select(x => new ModelGetListOutput()
- {
- Id = 001,
- Category = "chat",
- ModelName = x,
- ModelDescribe = "这是一个直连模型",
- ModelPrice = 4,
- ModelType = "1",
- ModelShow = "0",
- Remark = "直连模型"
- }).ToList();
+ var output = await _aiModelRepository._DbQueryable.Select(x => new ModelGetListOutput
+ {
+ Id = x.Id,
+ Category = "chat",
+ ModelName = x.Name,
+ ModelDescribe = x.Description,
+ ModelPrice = 0,
+ ModelType = "1",
+ ModelShow = "0",
+ SystemPrompt = null,
+ ApiHost = null,
+ ApiKey = null,
+ Remark = x.Description
+ }).ToListAsync();
return output;
}
@@ -79,6 +82,25 @@ public class AiChatService : ApplicationService
///
public async Task PostSendAsync(SendMessageInput input, CancellationToken cancellationToken)
{
+ //除了免费模型,其他的模型都要校验
+ if (input.Model != "DeepSeek-R1-0528")
+ {
+ //有token,需要黑名单校验
+ if (CurrentUser.IsAuthenticated)
+ {
+ await _aiBlacklistManager.VerifiyAiBlacklist(CurrentUser.GetId());
+ if (!CurrentUser.Roles.Contains("YiXinAi-Vip"))
+ {
+ throw new UserFriendlyException("该模型需要VIP用户才能使用,请购买VIP后重新登录重试");
+ }
+ }
+ else
+ {
+ throw new UserFriendlyException("未登录用户,只能使用未加速的DeepSeek-R1,请登录后重试");
+ }
+ }
+
+ //前面都是校验,后面才是真正的调用
var httpContext = this._httpContextAccessor.HttpContext;
var response = httpContext.Response;
// 设置响应头,声明是 SSE 流
@@ -116,7 +138,7 @@ public class AiChatService : ApplicationService
// 启动一个后台任务来消费队列
var outputTask = Task.Run(async () =>
{
- while (!(isComplete&&messageQueue.IsEmpty))
+ while (!(isComplete && messageQueue.IsEmpty))
{
if (messageQueue.TryDequeue(out var message))
{
@@ -153,16 +175,15 @@ public class AiChatService : ApplicationService
await outputTask;
if (CurrentUser.IsAuthenticated && input.SessionId.HasValue)
{
- // 等待接入token
- // await _aiMessageManager.CreateMessageAsync(CurrentUser.GetId(), input.SessionId.Value, new MessageInputDto
- // {
- // Content = null,
- // Role = null,
- // DeductCost = 0,
- // TotalTokens = 0,
- // ModelId = null,
- // Remark = null
- // });
+ await _aiMessageManager.CreateMessageAsync(CurrentUser.GetId(), input.SessionId.Value, new MessageInputDto
+ {
+ Content = input.Messages.LastOrDefault().Content,
+ Role = input.Messages.LastOrDefault().Role,
+ DeductCost = 0,
+ TotalTokens = 0,
+ ModelId = input.Model,
+ Remark = null
+ });
}
}
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/AiModelDescribe.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/AiModelDescribe.cs
new file mode 100644
index 00000000..06572d65
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Dtos/AiModelDescribe.cs
@@ -0,0 +1,49 @@
+namespace Yi.Framework.AiHub.Domain.Shared.Dtos;
+
+public class AiModelDescribe
+{
+ ///
+ /// 应用id
+ ///
+ public Guid AppId { get; set; }
+
+ ///
+ /// 应用名称
+ ///
+ public string AppName { get; set; }
+
+ ///
+ /// 应用终结点
+ ///
+ public string Endpoint { get; set; }
+
+ ///
+ /// 应用key
+ ///
+ public string ApiKey { get; set; }
+
+ ///
+ /// 排序
+ ///
+ public int OrderNum { get; set; }
+
+ ///
+ /// 处理名
+ ///
+ public string HandlerName { get; set; }
+
+ ///
+ /// 模型id
+ ///
+ public string ModelId { get; set; }
+
+ ///
+ /// 模型名称
+ ///
+ public string ModelName { get; set; }
+
+ ///
+ /// 模型描述
+ ///
+ public string? Description { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj
index c5a91f0e..248e1dc2 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Yi.Framework.AiHub.Domain.Shared.csproj
@@ -7,7 +7,6 @@
-
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs
index 76ca58c6..fdc56878 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/IChatService.cs
@@ -1,8 +1,10 @@
using OpenAI.Chat;
+using Yi.Framework.AiHub.Domain.Shared.Dtos;
namespace Yi.Framework.AiHub.Domain.AiChat;
public interface IChatService
{
- public IAsyncEnumerable CompleteChatAsync(string modelId, List messages,CancellationToken cancellationToken);
+ public IAsyncEnumerable CompleteChatAsync(AiModelDescribe aiModelDescribe, List messages,
+ CancellationToken cancellationToken);
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs
index ae9b8321..6b8a4c6b 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureChatService.cs
@@ -1,28 +1,24 @@
using System.Runtime.CompilerServices;
using Azure;
using Azure.AI.OpenAI;
-using Microsoft.Extensions.Options;
using OpenAI.Chat;
-using Yi.Framework.AiHub.Application.Contracts.Options;
+using Yi.Framework.AiHub.Domain.Shared.Dtos;
namespace Yi.Framework.AiHub.Domain.AiChat.Impl;
public class AzureChatService : IChatService
{
- private readonly AiChatModelOptions _options;
-
- public AzureChatService(IOptions options)
+ public AzureChatService()
{
- this._options = options.Value.Chats[nameof(AzureChatService)];
}
- public async IAsyncEnumerable CompleteChatAsync(string modelId, List messages,
+ public async IAsyncEnumerable CompleteChatAsync(AiModelDescribe aiModelDescribe, List messages,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
- var endpoint = new Uri(_options.Endpoint);
+ var endpoint = new Uri(aiModelDescribe.Endpoint);
- var deploymentName = modelId;
- var apiKey = _options.ApiKey;
+ var deploymentName = aiModelDescribe.ModelId;
+ var apiKey = aiModelDescribe.ApiKey;
AzureOpenAIClient azureClient = new(
endpoint,
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs
index 502eae48..c1419710 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/AiChat/Impl/AzureRestChatService.cs
@@ -1,28 +1,24 @@
using System.Runtime.CompilerServices;
using System.Text;
-using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OpenAI.Chat;
-using Yi.Framework.AiHub.Application.Contracts.Options;
using Yi.Framework.AiHub.Domain.Extensions;
+using Yi.Framework.AiHub.Domain.Shared.Dtos;
namespace Yi.Framework.AiHub.Domain.AiChat.Impl;
public class AzureRestChatService : IChatService
{
- private readonly AiChatModelOptions _options;
-
- public AzureRestChatService(IOptions options)
+ public AzureRestChatService()
{
- this._options = options.Value.Chats[nameof(AzureRestChatService)];
}
- public async IAsyncEnumerable CompleteChatAsync(string modelId, List messages,
+ public async IAsyncEnumerable CompleteChatAsync(AiModelDescribe aiModelDescribe, List messages,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
// 设置API URL
- var apiUrl = $"{_options.Endpoint}models/chat/completions";
+ var apiUrl = $"{aiModelDescribe.Endpoint}models/chat/completions";
var ss = messages.Select(x => new
@@ -45,7 +41,7 @@ public class AzureRestChatService : IChatService
top_p = 0.1,
presence_penalty = 0,
frequency_penalty = 0,
- model = modelId
+ model = aiModelDescribe.ModelId
};
// 序列化请求内容为JSON
@@ -53,24 +49,25 @@ public class AzureRestChatService : IChatService
using var httpClient = new HttpClient();
// 设置请求头
- httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_options.ApiKey}");
+ httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {aiModelDescribe.ApiKey}");
// 其他头信息如Content-Type在StringContent中设置
-
+
// 构造 POST 请求
var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
// 设置请求内容(示例)
- request.Content =new StringContent(jsonBody, Encoding.UTF8, "application/json");
-
+ request.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
+
// 发送POST请求
- HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
+ HttpResponseMessage response =
+ await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
// 确认响应成功
response.EnsureSuccessStatusCode();
// 读取响应内容
var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
// 从流中读取数据并输出到控制台
- using var streamReader = new System.IO.StreamReader(responseStream);
+ using var streamReader = new StreamReader(responseStream);
string line;
while ((line = await streamReader.ReadLineAsync(cancellationToken)) != null)
{
@@ -117,7 +114,5 @@ public class AzureRestChatService : IChatService
// 解析失败
return null;
}
-
- return null;
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AiBlacklistAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AiBlacklistAggregateRoot.cs
new file mode 100644
index 00000000..2063f6ee
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/AiBlacklistAggregateRoot.cs
@@ -0,0 +1,26 @@
+using SqlSugar;
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace Yi.Framework.AiHub.Domain.Entities;
+
+///
+/// ai黑名单
+///
+[SugarTable("Ai_Blacklist")]
+public class AiBlacklistAggregateRoot : FullAuditedAggregateRoot
+{
+ ///
+ /// 用户
+ ///
+ public Guid UserId { get; set; }
+
+ ///
+ /// 有效开始时间
+ ///
+ public DateTime StartTime { get; set; }
+
+ ///
+ /// 有效结束时间
+ ///
+ public DateTime EndTime { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/MessageAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/MessageAggregateRoot.cs
similarity index 100%
rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/MessageAggregateRoot.cs
rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/MessageAggregateRoot.cs
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/SessionAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/SessionAggregateRoot.cs
similarity index 100%
rename from Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/SessionAggregateRoot.cs
rename to Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Chat/SessionAggregateRoot.cs
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiAppAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiAppAggregateRoot.cs
new file mode 100644
index 00000000..cd7eced2
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiAppAggregateRoot.cs
@@ -0,0 +1,38 @@
+using SqlSugar;
+using Volo.Abp.Domain.Entities.Auditing;
+using Yi.Framework.Core.Data;
+
+namespace Yi.Framework.AiHub.Domain.Entities;
+
+///
+/// ai应用
+///
+[SugarTable("Ai_App")]
+public class AiAppAggregateRoot : FullAuditedAggregateRoot, IOrderNum
+{
+ ///
+ /// 应用名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 应用终结点
+ ///
+ public string Endpoint { get; set; }
+
+ ///
+ /// 应用key
+ ///
+ public string ApiKey { get; set; }
+
+ ///
+ /// 排序
+ ///
+ public int OrderNum { get; set; }
+
+ ///
+ /// ai模型
+ ///
+ [Navigate(NavigateType.OneToMany, nameof(AiModelEntity.AiAppId))]
+ public List AiModels { get; set; }
+}
\ 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
new file mode 100644
index 00000000..d221d8eb
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/Model/AiModelEntity.cs
@@ -0,0 +1,48 @@
+using SqlSugar;
+using Volo.Abp.Domain.Entities;
+using Volo.Abp.Domain.Entities.Auditing;
+using Yi.Framework.Core.Data;
+
+namespace Yi.Framework.AiHub.Domain.Entities;
+
+///
+/// ai模型定义
+///
+[SugarTable("Ai_Model")]
+public class AiModelEntity : Entity, IOrderNum,ISoftDelete
+{
+ ///
+ /// 处理名
+ ///
+ public string HandlerName { get; set; }
+
+ ///
+ /// 模型id
+ ///
+ public string ModelId { get; set; }
+
+ ///
+ /// 模型名称
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// 模型描述
+ ///
+ public string? Description { get; set; }
+
+ ///
+ /// 排序
+ ///
+ public int OrderNum { get; set; }
+
+ ///
+ /// 软删除
+ ///
+ public bool IsDeleted { get; set; }
+
+ ///
+ /// ai应用id
+ ///
+ public Guid AiAppId { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/UsageStatisticsAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/UsageStatisticsAggregateRoot.cs
new file mode 100644
index 00000000..be212d3e
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/UsageStatisticsAggregateRoot.cs
@@ -0,0 +1,31 @@
+using SqlSugar;
+using Volo.Abp.Domain.Entities.Auditing;
+
+namespace Yi.Framework.AiHub.Domain.Entities;
+
+///
+/// 用量统计
+///
+[SugarTable("Ai_UsageStatistics")]
+public class UsageStatisticsAggregateRoot : FullAuditedAggregateRoot
+{
+ ///
+ /// 用户id
+ ///
+ public Guid UserId { get; set; }
+
+ ///
+ /// 哪个模型
+ ///
+ public string ModelId { get; set; }
+
+ ///
+ /// 总token使用
+ ///
+ public decimal TotalTokens { get; set; }
+
+ ///
+ /// 对话次数
+ ///
+ public int Number { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiBlacklistManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiBlacklistManager.cs
new file mode 100644
index 00000000..a8191d3a
--- /dev/null
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/AiBlacklistManager.cs
@@ -0,0 +1,31 @@
+using Volo.Abp.Domain.Services;
+using Yi.Framework.AiHub.Domain.Entities;
+using Yi.Framework.SqlSugarCore.Abstractions;
+
+namespace Yi.Framework.AiHub.Domain.Managers;
+
+public class AiBlacklistManager : DomainService
+{
+ private readonly ISqlSugarRepository _aiBlacklistRepository;
+
+ public AiBlacklistManager(ISqlSugarRepository aiBlacklistRepository)
+ {
+ _aiBlacklistRepository = aiBlacklistRepository;
+ }
+
+ ///
+ /// 校验黑名单
+ ///
+ ///
+ ///
+ public async Task VerifiyAiBlacklist(Guid userId)
+ {
+ var now = DateTime.Now;
+ if (await _aiBlacklistRepository._DbQueryable
+ .Where(x => now >= x.StartTime && now <= x.EndTime)
+ .AnyAsync(x => x.UserId == userId))
+ {
+ throw new UserFriendlyException("当前用户已被加入黑名单,请联系管理员处理");
+ }
+ }
+}
\ 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 5d926496..6f4a5a57 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,35 +1,70 @@
-using Azure;
-using Azure.AI.OpenAI;
+using System.Runtime.CompilerServices;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Options;
using OpenAI.Chat;
using Volo.Abp.Domain.Services;
-using Yi.Framework.AiHub.Application.Contracts.Options;
using Yi.Framework.AiHub.Domain.AiChat;
+using Yi.Framework.AiHub.Domain.Entities;
+using Yi.Framework.AiHub.Domain.Shared.Dtos;
+using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.AiHub.Domain.Managers;
public class AiGateWayManager : DomainService
{
- private readonly AiGateWayOptions _options;
+ private readonly ISqlSugarRepository _aiAppRepository;
- public AiGateWayManager(IOptions options)
+ public AiGateWayManager(ISqlSugarRepository aiAppRepository)
{
- this._options = options.Value;
+ _aiAppRepository = aiAppRepository;
}
- public IAsyncEnumerable CompleteChatAsync(string modelId, List messages,
- CancellationToken cancellationToken)
+ ///
+ /// 获取模型
+ ///
+ ///
+ ///
+ private async Task GetModelAsync(string modelId)
{
- foreach (var chat in _options.Chats)
+ var allApp = await _aiAppRepository._DbQueryable.Includes(x => x.AiModels).ToListAsync();
+ foreach (var app in allApp)
{
- if (chat.Value.ModelIds.Contains(modelId))
+ var model = app.AiModels.FirstOrDefault(x => x.ModelId == modelId);
+ if (model is not null)
{
- var chatService = LazyServiceProvider.GetRequiredKeyedService(chat.Key);
- return chatService.CompleteChatAsync(modelId, messages, cancellationToken);
+ return new AiModelDescribe
+ {
+ AppId = app.Id,
+ AppName = app.Name,
+ Endpoint = app.Endpoint,
+ ApiKey = app.ApiKey,
+ OrderNum = model.OrderNum,
+ HandlerName = model.HandlerName,
+ ModelId = model.ModelId,
+ ModelName = model.Name,
+ Description = model.Description
+ };
}
}
- throw new UserFriendlyException($"当前暂不支持该模型-【{modelId}】");
+ throw new UserFriendlyException($"{modelId}模型当前版本不支持");
+ }
+
+
+ ///
+ /// 聊天完成
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async IAsyncEnumerable CompleteChatAsync(string modelId, List messages,
+ [EnumeratorCancellation] CancellationToken cancellationToken)
+ {
+ var modelDescribe = await GetModelAsync(modelId);
+ var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName);
+ await foreach (var result in chatService.CompleteChatAsync(modelDescribe, messages, cancellationToken))
+ {
+ yield return result;
+ }
}
}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs
index 71822c88..3c135ca5 100644
--- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs
+++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/YiFrameworkAiHubDomainModule.cs
@@ -1,11 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
-using OpenAI.Chat;
-using Volo.Abp.Caching;
using Volo.Abp.Domain;
-using Yi.Framework.AiHub.Application.Contracts.Options;
-using Yi.Framework.AiHub.Domain.AiChat;
-using Yi.Framework.AiHub.Domain.AiChat.Impl;
-using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.AiHub.Domain.Shared;
using Yi.Framework.Mapster;
@@ -23,11 +17,10 @@ namespace Yi.Framework.AiHub.Domain
var configuration = context.Services.GetConfiguration();
var services = context.Services;
- Configure(configuration.GetSection("AiGateWay"));
-
-
- services.AddKeyedTransient(nameof(AzureChatService));
- services.AddKeyedTransient(nameof(AzureRestChatService));
+ // Configure(configuration.GetSection("AiGateWay"));
+ //
+ // services.AddKeyedTransient(nameof(AzureChatService));
+ // services.AddKeyedTransient(nameof(AzureRestChatService));
}
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj b/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj
index 83941d49..5d8907c6 100644
--- a/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj
+++ b/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj
@@ -56,12 +56,22 @@
Always
+
Always
+
+
+
+
+
+
+
+
+