feat: 完成ai-hub第一期功能
This commit is contained in:
@@ -5,7 +5,7 @@ public class ModelGetListOutput
|
||||
/// <summary>
|
||||
/// 模型ID
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型分类
|
||||
@@ -20,7 +20,7 @@ public class ModelGetListOutput
|
||||
/// <summary>
|
||||
/// 模型描述
|
||||
/// </summary>
|
||||
public string ModelDescribe { get; set; }
|
||||
public string? ModelDescribe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型价格
|
||||
@@ -55,5 +55,5 @@ public class ModelGetListOutput
|
||||
/// <summary>
|
||||
/// 备注信息
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace Yi.Framework.AiHub.Application.Contracts.Options;
|
||||
|
||||
public class AiGateWayOptions
|
||||
{
|
||||
public AiChatOptionDic Chats { get; set; }
|
||||
}
|
||||
|
||||
public class AiChatOptionDic : Dictionary<string, AiChatModelOptions>
|
||||
{
|
||||
}
|
||||
|
||||
public class AiChatModelOptions
|
||||
{
|
||||
public List<string> ModelIds { get; set; }
|
||||
public string Endpoint { get; set; }
|
||||
public string ApiKey { get; set; }
|
||||
}
|
||||
@@ -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;
|
||||
/// </summary>
|
||||
public class AiChatService : ApplicationService
|
||||
{
|
||||
private readonly AiGateWayOptions _options;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly AiMessageManager _aiMessageManager;
|
||||
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
|
||||
private readonly AiBlacklistManager _aiBlacklistManager;
|
||||
|
||||
public AiChatService(IOptions<AiGateWayOptions> 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
|
||||
/// <returns></returns>
|
||||
public async Task<List<ModelGetListOutput>> 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
|
||||
/// <param name="cancellationToken"></param>
|
||||
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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
namespace Yi.Framework.AiHub.Domain.Shared.Dtos;
|
||||
|
||||
public class AiModelDescribe
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用id
|
||||
/// </summary>
|
||||
public Guid AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用名称
|
||||
/// </summary>
|
||||
public string AppName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用终结点
|
||||
/// </summary>
|
||||
public string Endpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用key
|
||||
/// </summary>
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int OrderNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 处理名
|
||||
/// </summary>
|
||||
public string HandlerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型id
|
||||
/// </summary>
|
||||
public string ModelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型名称
|
||||
/// </summary>
|
||||
public string ModelName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Consts\" />
|
||||
<Folder Include="Dtos\" />
|
||||
<Folder Include="Enums\" />
|
||||
<Folder Include="Etos\" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -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<string> CompleteChatAsync(string modelId, List<ChatMessage> messages,CancellationToken cancellationToken);
|
||||
public IAsyncEnumerable<string> CompleteChatAsync(AiModelDescribe aiModelDescribe, List<ChatMessage> messages,
|
||||
CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -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<AiGateWayOptions> options)
|
||||
public AzureChatService()
|
||||
{
|
||||
this._options = options.Value.Chats[nameof(AzureChatService)];
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<string> CompleteChatAsync(string modelId, List<ChatMessage> messages,
|
||||
public async IAsyncEnumerable<string> CompleteChatAsync(AiModelDescribe aiModelDescribe, List<ChatMessage> 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,
|
||||
|
||||
@@ -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<AiGateWayOptions> options)
|
||||
public AzureRestChatService()
|
||||
{
|
||||
this._options = options.Value.Chats[nameof(AzureRestChatService)];
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<string> CompleteChatAsync(string modelId, List<ChatMessage> messages,
|
||||
public async IAsyncEnumerable<string> CompleteChatAsync(AiModelDescribe aiModelDescribe, List<ChatMessage> 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// ai黑名单
|
||||
/// </summary>
|
||||
[SugarTable("Ai_Blacklist")]
|
||||
public class AiBlacklistAggregateRoot : FullAuditedAggregateRoot<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 有效开始时间
|
||||
/// </summary>
|
||||
public DateTime StartTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 有效结束时间
|
||||
/// </summary>
|
||||
public DateTime EndTime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
using Yi.Framework.Core.Data;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// ai应用
|
||||
/// </summary>
|
||||
[SugarTable("Ai_App")]
|
||||
public class AiAppAggregateRoot : FullAuditedAggregateRoot<Guid>, IOrderNum
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用终结点
|
||||
/// </summary>
|
||||
public string Endpoint { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用key
|
||||
/// </summary>
|
||||
public string ApiKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int OrderNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ai模型
|
||||
/// </summary>
|
||||
[Navigate(NavigateType.OneToMany, nameof(AiModelEntity.AiAppId))]
|
||||
public List<AiModelEntity> AiModels { get; set; }
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// ai模型定义
|
||||
/// </summary>
|
||||
[SugarTable("Ai_Model")]
|
||||
public class AiModelEntity : Entity<Guid>, IOrderNum,ISoftDelete
|
||||
{
|
||||
/// <summary>
|
||||
/// 处理名
|
||||
/// </summary>
|
||||
public string HandlerName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型id
|
||||
/// </summary>
|
||||
public string ModelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 模型描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int OrderNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 软删除
|
||||
/// </summary>
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ai应用id
|
||||
/// </summary>
|
||||
public Guid AiAppId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Domain.Entities.Auditing;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// 用量统计
|
||||
/// </summary>
|
||||
[SugarTable("Ai_UsageStatistics")]
|
||||
public class UsageStatisticsAggregateRoot : FullAuditedAggregateRoot<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户id
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 哪个模型
|
||||
/// </summary>
|
||||
public string ModelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总token使用
|
||||
/// </summary>
|
||||
public decimal TotalTokens { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 对话次数
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
}
|
||||
@@ -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<AiBlacklistAggregateRoot> _aiBlacklistRepository;
|
||||
|
||||
public AiBlacklistManager(ISqlSugarRepository<AiBlacklistAggregateRoot> aiBlacklistRepository)
|
||||
{
|
||||
_aiBlacklistRepository = aiBlacklistRepository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 校验黑名单
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <exception cref="UserFriendlyException"></exception>
|
||||
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("当前用户已被加入黑名单,请联系管理员处理");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<AiAppAggregateRoot> _aiAppRepository;
|
||||
|
||||
public AiGateWayManager(IOptions<AiGateWayOptions> options)
|
||||
public AiGateWayManager(ISqlSugarRepository<AiAppAggregateRoot> aiAppRepository)
|
||||
{
|
||||
this._options = options.Value;
|
||||
_aiAppRepository = aiAppRepository;
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<string> CompleteChatAsync(string modelId, List<ChatMessage> messages,
|
||||
CancellationToken cancellationToken)
|
||||
/// <summary>
|
||||
/// 获取模型
|
||||
/// </summary>
|
||||
/// <param name="modelId"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<AiModelDescribe> 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<IChatService>(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}模型当前版本不支持");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 聊天完成
|
||||
/// </summary>
|
||||
/// <param name="modelId"></param>
|
||||
/// <param name="messages"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public async IAsyncEnumerable<string> CompleteChatAsync(string modelId, List<ChatMessage> messages,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
var modelDescribe = await GetModelAsync(modelId);
|
||||
var chatService = LazyServiceProvider.GetRequiredKeyedService<IChatService>(modelDescribe.HandlerName);
|
||||
await foreach (var result in chatService.CompleteChatAsync(modelDescribe, messages, cancellationToken))
|
||||
{
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<AiGateWayOptions>(configuration.GetSection("AiGateWay"));
|
||||
|
||||
|
||||
services.AddKeyedTransient<IChatService, AzureChatService>(nameof(AzureChatService));
|
||||
services.AddKeyedTransient<IChatService, AzureRestChatService>(nameof(AzureRestChatService));
|
||||
// Configure<AiGateWayOptions>(configuration.GetSection("AiGateWay"));
|
||||
//
|
||||
// services.AddKeyedTransient<IChatService, AzureChatService>(nameof(AzureChatService));
|
||||
// services.AddKeyedTransient<IChatService, AzureRestChatService>(nameof(AzureRestChatService));
|
||||
}
|
||||
|
||||
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||
|
||||
@@ -56,12 +56,22 @@
|
||||
<Content Update="wwwroot\stock\**">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Remove="logs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="ip2region.db">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Remove="logs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="logs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Remove="logs\**" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user