diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs index eeb0171b..4c7c3bb8 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiTokenAuthorizationFilter.cs @@ -75,6 +75,7 @@ public class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, IT function sendToken() { // 获取输入的 token var token = document.getElementById("tokenInput").value; + token = token.replace('Bearer ',''); // 构建请求 URL var url = "/hangfire"; // 发送 GET 请求 @@ -107,7 +108,7 @@ public class YiTokenAuthorizationFilter : IDashboardAsyncAuthorizationFilter, IT

Yi-hangfire

输入您的Token,我们将验证您是否为管理员

- + diff --git a/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Application/Services/AiChatService.cs b/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Application/Services/AiChatService.cs index 8604ab46..cdac53ee 100644 --- a/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Application/Services/AiChatService.cs +++ b/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Application/Services/AiChatService.cs @@ -23,14 +23,13 @@ namespace Yi.Framework.ChatHub.Application.Services /// /// [Authorize] - [HttpPost] - - public async Task ChatAsync([FromBody] List chatContext) + [HttpPost("ai-chat/chat/{model}")] + public async Task ChatAsync([FromRoute]string model, [FromBody] List chatContext) { const int maxChar = 10; var contextId = Guid.NewGuid(); Queue stringQueue = new Queue(); - await foreach (var aiResult in _aiManager.ChatAsStreamAsync(chatContext)) + await foreach (var aiResult in _aiManager.ChatAsStreamAsync(model,chatContext)) { stringQueue.Enqueue(aiResult); @@ -42,7 +41,7 @@ namespace Yi.Framework.ChatHub.Application.Services var str = stringQueue.Dequeue(); currentStr.Append(str); } - await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentStr.ToString(), CurrentUser.Id!.Value, contextId)); + await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentStr.ToString(), CurrentUser.Id!.Value, contextId),model); } } @@ -52,9 +51,7 @@ namespace Yi.Framework.ChatHub.Application.Services var str = stringQueue.Dequeue(); currentEndStr.Append(str); } - await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentEndStr.ToString(), CurrentUser.Id!.Value, contextId)); - - //await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(null, CurrentUser.Id!.Value, contextId)); + await _userMessageManager.SendMessageAsync(MessageContext.CreateAi(currentEndStr.ToString(), CurrentUser.Id!.Value, contextId),model); } } } diff --git a/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/AiManager.cs b/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/AiManager.cs index ddc81fd3..a8571f2b 100644 --- a/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/AiManager.cs +++ b/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/AiManager.cs @@ -24,19 +24,8 @@ namespace Yi.Framework.ChatHub.Domain.Managers } private OpenAIService OpenAIService { get; } - public async IAsyncEnumerable ChatAsStreamAsync(List aiChatContextDtos) + public async IAsyncEnumerable ChatAsStreamAsync(string model, List aiChatContextDtos) { - //var temp = "站长正在接入ChatGpt,敬请期待~"; - - //for (var i = 0; i < temp.Length; i++) - //{ - // await Task.Delay(200); - // yield return temp[i].ToString(); - //} - - - - if (aiChatContextDtos.Count == 0) { yield return null; @@ -56,7 +45,7 @@ namespace Yi.Framework.ChatHub.Domain.Managers var completionResult = OpenAIService.ChatCompletion.CreateCompletionAsStream(new ChatCompletionCreateRequest { Messages = messages, - Model = Models.Gpt_4o_mini + Model =model }); HttpStatusCode? error = null; diff --git a/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/UserMessageManager.cs b/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/UserMessageManager.cs index 7bfc47dd..6810e9f4 100644 --- a/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/UserMessageManager.cs +++ b/Yi.Abp.Net8/module/chat-hub/Yi.Framework.ChatHub.Domain/Managers/UserMessageManager.cs @@ -31,7 +31,14 @@ namespace Yi.Framework.ChatHub.Domain.Managers private IRedisClient RedisClient => LazyServiceProvider.LazyGetRequiredService(); private string CacheKeyPrefix => LazyServiceProvider.LazyGetRequiredService>().Value.KeyPrefix; - public async Task SendMessageAsync(MessageContext context) + + /// + /// 发送消息 + /// + /// 消息内容 + /// 关联字符 + /// + public async Task SendMessageAsync(MessageContext context,string relStr=null) { switch (context.MessageType) { @@ -39,20 +46,20 @@ namespace Yi.Framework.ChatHub.Domain.Managers var userModel = await GetUserAsync(context.ReceiveId.Value); if (userModel is not null) { - await _hubContext.Clients.Client(userModel.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType, context); + await _hubContext.Clients.Client(userModel.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType,relStr, context); } break; case MessageTypeEnum.Group: throw new NotImplementedException(); break; case MessageTypeEnum.All: - await _hubContext.Clients.All.SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType, context); + await _hubContext.Clients.All.SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType,relStr, context); break; case MessageTypeEnum.Ai: var userModel2 = await GetUserAsync(context.ReceiveId.Value); if (userModel2 is not null) { - await _hubContext.Clients.Client(userModel2.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType, context); + await _hubContext.Clients.Client(userModel2.ClientId).SendAsync(ChatConst.ClientActionReceiveMsg, context.MessageType,relStr, context); } break; diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Role/UpdateDataScpoceInput.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Role/UpdateDataScopeInput.cs similarity index 87% rename from Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Role/UpdateDataScpoceInput.cs rename to Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Role/UpdateDataScopeInput.cs index 4ef0c9c1..3ce38966 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Role/UpdateDataScpoceInput.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application.Contracts/Dtos/Role/UpdateDataScopeInput.cs @@ -2,7 +2,7 @@ namespace Yi.Framework.Rbac.Application.Contracts.Dtos.Role { - public class UpdateDataScpoceInput + public class UpdateDataScopeInput { public Guid RoleId { get; set; } diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs index 7ea3f185..6188f0ce 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/System/RoleService.cs @@ -39,7 +39,7 @@ namespace Yi.Framework.Rbac.Application.Services.System private ISqlSugarRepository _userRoleRepository; - public async Task UpdateDataScpoceAsync(UpdateDataScpoceInput input) + public async Task UpdateDataScopeAsync(UpdateDataScopeInput input) { //只有自定义的需要特殊处理 if (input.DataScope == DataScopeEnum.CUSTOM) diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj index 734dc0a1..0680e58f 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/Yi.Framework.Rbac.Domain.csproj @@ -20,7 +20,10 @@ - + + + + diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs index a5a61d92..cb3d4bf5 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Domain/YiFrameworkRbacDomainModule.cs @@ -1,6 +1,10 @@ -using Microsoft.Extensions.DependencyInjection; +using Medallion.Threading; +using Medallion.Threading.Redis; +using Microsoft.Extensions.DependencyInjection; +using StackExchange.Redis; using Volo.Abp.AspNetCore.SignalR; using Volo.Abp.Caching; +using Volo.Abp.DistributedLocking; using Volo.Abp.Domain; using Volo.Abp.Imaging; using Volo.Abp.Modularity; @@ -20,7 +24,8 @@ namespace Yi.Framework.Rbac.Domain typeof(AbpAspNetCoreSignalRModule), typeof(AbpDddDomainModule), typeof(AbpCachingModule), - typeof(AbpImagingImageSharpModule) + typeof(AbpImagingImageSharpModule), + typeof(AbpDistributedLockingModule) )] public class YiFrameworkRbacDomainModule : AbpModule { @@ -36,6 +41,15 @@ namespace Yi.Framework.Rbac.Domain //配置阿里云短信 Configure(configuration.GetSection(nameof(AliyunOptions))); + + //分布式锁 + context.Services.AddSingleton(sp => + { + var connection = ConnectionMultiplexer + .Connect(configuration["Redis:Configuration"]); + return new + RedisDistributedSynchronizationProvider(connection.GetDatabase()); + }); } } } \ No newline at end of file diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs index f1714368..da686753 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Services/TestService.cs @@ -1,8 +1,10 @@ using System.Xml.Linq; using Mapster; +using Medallion.Threading; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; using Volo.Abp.Application.Services; +using Volo.Abp.DistributedLocking; using Volo.Abp.Settings; using Volo.Abp.Uow; using Yi.Framework.Bbs.Application.Contracts.Dtos.Banner; @@ -49,7 +51,7 @@ namespace Yi.Abp.Application.Services throw new UserFriendlyException("业务异常"); throw new Exception("系统异常"); } - + /// /// SqlSugar /// @@ -138,6 +140,7 @@ namespace Yi.Abp.Application.Services } private static int RequestNumber { get; set; } = 0; + /// /// 速率限制 /// @@ -154,6 +157,7 @@ namespace Yi.Abp.Application.Services public ISettingProvider _settingProvider { get; set; } public ISettingManager _settingManager { get; set; } + /// /// 系统配置模块 /// @@ -175,5 +179,41 @@ namespace Yi.Abp.Application.Services return result ?? string.Empty; } + + + /// + /// 分布式送abp版本:abp套了一层娃。但是纯粹鸡肋,不建议使用这个 + /// + public IAbpDistributedLock AbpDistributedLock { get; set; } + + /// + /// 分布式锁推荐使用版本:yyds,分布式锁永远的神! + /// + public IDistributedLockProvider DistributedLock { get; set; } + + /// + /// 分布式锁 + /// + /// 强烈吐槽一下abp,正如他们所说,abp的分布式锁单纯为了自己用,一切还是以DistributedLock为主> + /// + public async Task GetDistributedLockAsync() + { + var number = 0; + await Parallel.ForAsync(0, 100, async (i, cancellationToken) => + { + await using (await DistributedLock.AcquireLockAsync("MyLockName")) + { + //执行1秒 + number += 1; + } + }); + var number2 = 0; + await Parallel.ForAsync(0, 100, async (i, cancellationToken) => + { + //执行1秒 + number2 += 1; + }); + return $"加锁结果:{number},不加锁结果:{number2}"; + } } -} +} \ No newline at end of file diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/AddModuleCommand.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/AddModuleCommand.cs index d1e9b1dc..6540a976 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/AddModuleCommand.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/AddModuleCommand.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.CommandLineUtils; @@ -39,12 +40,11 @@ namespace Yi.Abp.Tool.Commands } CheckFirstSlnPath(slnPath); - var dotnetSlnCommandPart1 = $"dotnet sln \"{slnPath}\" add \"{modulePath}\\{moduleName}."; - var dotnetSlnCommandPart2 = new List() { "Application", "Application.Contracts", "Domain", "Domain.Shared", "SqlSugarCore" }; - var paths = dotnetSlnCommandPart2.Select(x => $@"{modulePath}\{moduleName}." + x).ToArray(); + var dotnetSlnCommandPart = new List() { "Application", "Application.Contracts", "Domain", "Domain.Shared", "SqlSugarCore" }; + var paths = dotnetSlnCommandPart.Select(x => Path.Combine(modulePath, $"{moduleName}.{x}")).ToArray(); CheckPathExist(paths); - - var cmdCommands = dotnetSlnCommandPart2.Select(x => dotnetSlnCommandPart1 + x+"\"").ToArray(); + + var cmdCommands = dotnetSlnCommandPart.Select(x => $"dotnet sln \"{slnPath}\" add \"{Path.Combine(modulePath, $"{moduleName}.{x}")}\"").ToArray(); StartCmd(cmdCommands); Console.WriteLine("恭喜~模块添加成功!"); @@ -81,15 +81,24 @@ namespace Yi.Abp.Tool.Commands { ProcessStartInfo psi = new ProcessStartInfo { - FileName = "cmd.exe", - Arguments = $"/c chcp 65001&{string.Join("&", cmdCommands)}", RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, UseShellExecute = false }; - + // 判断操作系统 + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + psi.FileName = "cmd.exe"; + psi.Arguments = $"/c chcp 65001&{string.Join("&", cmdCommands)}"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + psi.FileName = "/bin/bash"; + psi.Arguments = $"-c \"{string.Join("; ", cmdCommands)}\""; + } + Process proc = new Process { StartInfo = psi diff --git a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/CloneCommand.cs b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/CloneCommand.cs index 00802bc9..d959e170 100644 --- a/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/CloneCommand.cs +++ b/Yi.Abp.Net8/tool/Yi.Abp.Tool/Commands/CloneCommand.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.CommandLineUtils; @@ -35,15 +36,24 @@ namespace Yi.Abp.Tool.Commands { ProcessStartInfo psi = new ProcessStartInfo { - FileName = "cmd.exe", - Arguments = $"/c chcp 65001&{string.Join("&", cmdCommands)}", RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, CreateNoWindow = true, UseShellExecute = false }; - + // 判断操作系统 + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + psi.FileName = "cmd.exe"; + psi.Arguments = $"/c chcp 65001&{string.Join("&", cmdCommands)}"; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + psi.FileName = "/bin/bash"; + psi.Arguments = $"-c \"{string.Join("; ", cmdCommands)}\""; + } + Process proc = new Process { StartInfo = psi diff --git a/Yi.Bbs.Vue3/src/apis/chatMessageApi.js b/Yi.Bbs.Vue3/src/apis/chatMessageApi.js index 3ed0d791..5a262d3c 100644 --- a/Yi.Bbs.Vue3/src/apis/chatMessageApi.js +++ b/Yi.Bbs.Vue3/src/apis/chatMessageApi.js @@ -22,9 +22,9 @@ export function sendGroupMessage(data) { }); } - export function sendAiChat(data) { + export function sendAiChat(data,model) { return request({ - url: "/ai-chat/chat", + url: `/ai-chat/chat/${model}`, method: "post", data }); diff --git a/Yi.Bbs.Vue3/src/assets/chat_images/deepSeekAi.png b/Yi.Bbs.Vue3/src/assets/chat_images/deepSeekAi.png new file mode 100644 index 00000000..aa2fa513 Binary files /dev/null and b/Yi.Bbs.Vue3/src/assets/chat_images/deepSeekAi.png differ diff --git a/Yi.Bbs.Vue3/public/openAi.png b/Yi.Bbs.Vue3/src/assets/chat_images/openAi.png similarity index 100% rename from Yi.Bbs.Vue3/public/openAi.png rename to Yi.Bbs.Vue3/src/assets/chat_images/openAi.png diff --git a/Yi.Bbs.Vue3/src/hubs/chatHub.js b/Yi.Bbs.Vue3/src/hubs/chatHub.js index c2aaa819..3310a243 100644 --- a/Yi.Bbs.Vue3/src/hubs/chatHub.js +++ b/Yi.Bbs.Vue3/src/hubs/chatHub.js @@ -12,18 +12,16 @@ const receiveMsg = (connection) => { chatStore.delUser(userId); }); //接受其他用户消息 - connection.on("receiveMsg", (type, content) => { + connection.on("receiveMsg", (type,relStr, content) => { const letChatStore = useChatStore(); //如果是ai消息,还要进行流式显示 - // alert(type) - if (type == 3) { + if (type === 3) {//(ai消息,还需要支持动态类型) + content.messageType ='ai@'+ relStr; letChatStore.addOrUpdateMsg(content); } else { letChatStore.addMsg(content); } - - }); //用户状态-正在输入中,无 connection.on("userStatus", (type) => { diff --git a/Yi.Bbs.Vue3/src/stores/chat.js b/Yi.Bbs.Vue3/src/stores/chat.js index aa7682ed..ec6754f1 100644 --- a/Yi.Bbs.Vue3/src/stores/chat.js +++ b/Yi.Bbs.Vue3/src/stores/chat.js @@ -5,16 +5,20 @@ const chatStore = defineStore("chat", { msgList: [] }), getters: { - allMsgContext: (state) => state.msgList.filter(x => x.messageType == "All"), - personalMsgContext: (state) => state.msgList.filter(x => x.messageType == "Personal"), - aiMsgContext: (state) => state.msgList.filter(x => x.messageType == "Ai") + allMsgContext: (state) => state.msgList.filter(x => x.messageType === "All"), + personalMsgContext: (state) => state.msgList.filter(x => x.messageType === "Personal"), + // aiMsgContext: (state) => state.msgList.filter(x => x.messageType === "Ai"), + //获取msg,通过类型 + getMsgContextFunc: (state) => (messageType) => { + return state.msgList.filter(item => item.messageType === messageType); + }, }, actions: { addOrUpdateMsg(msg) { - var currentMsg = this.msgList.filter(x => x.id == msg.id)[0]; + var currentMsg = this.msgList.filter(x => x.id === msg.id)[0]; //当前没有包含,如果有相同的上下文id,只需要改变content即可 - if (currentMsg == undefined) { + if (currentMsg === undefined) { this.addMsg(msg); } else { @@ -22,9 +26,9 @@ const chatStore = defineStore("chat", { } }, - clearAiMsg() + clearTypeMsg(messageType) { - this.msgList=this.msgList.filter(x => x.messageType != "Ai") + this.msgList=this.msgList.filter(x => x.messageType !==messageType) }, setMsgList(value) { this.msgList = value; @@ -39,7 +43,7 @@ const chatStore = defineStore("chat", { this.userList.push(user); }, delUser(userId) { - this.userList = this.userList.filter(obj => obj.userId != userId); + this.userList = this.userList.filter(obj => obj.userId !== userId); } }, }); diff --git a/Yi.Bbs.Vue3/src/views/chathub/Index.vue b/Yi.Bbs.Vue3/src/views/chathub/Index.vue index 3a7d4d26..1db223c6 100644 --- a/Yi.Bbs.Vue3/src/views/chathub/Index.vue +++ b/Yi.Bbs.Vue3/src/views/chathub/Index.vue @@ -1,26 +1,32 @@