diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Token/TokenGetListOutputDto.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Token/TokenGetListOutputDto.cs index 6358985b..bc694245 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Token/TokenGetListOutputDto.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application.Contracts/Dtos/Token/TokenGetListOutputDto.cs @@ -40,6 +40,11 @@ public class TokenGetListOutputDto /// public bool IsDisabled { get; set; } + /// + /// 是否启用请求日志记录 + /// + public bool IsEnableLog { get; set; } + /// /// 创建时间 /// diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/TokenService.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/TokenService.cs index 204fda55..26aec796 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/TokenService.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/Chat/TokenService.cs @@ -83,6 +83,7 @@ public class TokenService : ApplicationService PremiumQuotaLimit = t.PremiumQuotaLimit, PremiumUsedQuota = usedQuota, IsDisabled = t.IsDisabled, + IsEnableLog = t.IsEnableLog, CreationTime = t.CreationTime }; }).ToList(); @@ -158,6 +159,7 @@ public class TokenService : ApplicationService PremiumQuotaLimit = token.PremiumQuotaLimit, PremiumUsedQuota = 0, IsDisabled = token.IsDisabled, + IsEnableLog = token.IsEnableLog, CreationTime = token.CreationTime }; } 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 5e4b0cf9..92a06773 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 @@ -1,12 +1,15 @@ using System.Text.Json; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Volo.Abp.Application.Services; +using Volo.Abp.Uow; using Volo.Abp.Users; using Yi.Framework.AiHub.Domain.Entities; using Yi.Framework.AiHub.Domain.Entities.Chat; using Yi.Framework.AiHub.Domain.Entities.Model; +using Yi.Framework.AiHub.Domain.Entities.OpenApi; using Yi.Framework.AiHub.Domain.Extensions; using Yi.Framework.AiHub.Domain.Managers; using Yi.Framework.AiHub.Domain.Shared.Consts; @@ -33,10 +36,12 @@ public class OpenApiService : ApplicationService private readonly PremiumPackageManager _premiumPackageManager; private readonly ISqlSugarRepository _imageStoreRepository; private readonly ISqlSugarRepository _aiModelRepository; + private readonly IServiceScopeFactory _serviceScopeFactory; public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger logger, TokenManager tokenManager, AiGateWayManager aiGateWayManager, ModelManager modelManager, AiBlacklistManager aiBlacklistManager, - IAccountService accountService, PremiumPackageManager premiumPackageManager, ISqlSugarRepository imageStoreRepository, ISqlSugarRepository aiModelRepository) + IAccountService accountService, PremiumPackageManager premiumPackageManager, ISqlSugarRepository imageStoreRepository, ISqlSugarRepository aiModelRepository, + IServiceScopeFactory serviceScopeFactory) { _httpContextAccessor = httpContextAccessor; _logger = logger; @@ -48,6 +53,7 @@ public class OpenApiService : ApplicationService _premiumPackageManager = premiumPackageManager; _imageStoreRepository = imageStoreRepository; _aiModelRepository = aiModelRepository; + _serviceScopeFactory = serviceScopeFactory; } /// @@ -91,6 +97,12 @@ public class OpenApiService : ApplicationService null, tokenId, CancellationToken.None); } + + // 记录请求日志 + if (tokenValidation.IsEnableLog) + { + FireAndForgetMessageLog(JsonSerializer.Serialize(input), tokenValidation.Token, tokenValidation.TokenName, input.Model, ModelApiTypeEnum.Completions); + } } @@ -206,6 +218,12 @@ public class OpenApiService : ApplicationService null, tokenId, CancellationToken.None); } + + // 记录请求日志 + if (tokenValidation.IsEnableLog) + { + FireAndForgetMessageLog(JsonSerializer.Serialize(input), tokenValidation.Token, tokenValidation.TokenName, input.Model, ModelApiTypeEnum.Messages); + } } @@ -258,6 +276,12 @@ public class OpenApiService : ApplicationService null, tokenId, CancellationToken.None); } + + // 记录请求日志 + if (tokenValidation.IsEnableLog) + { + FireAndForgetMessageLog(JsonSerializer.Serialize(input), tokenValidation.Token, tokenValidation.TokenName, input.Model, ModelApiTypeEnum.Responses); + } } @@ -318,6 +342,12 @@ public class OpenApiService : ApplicationService null, tokenId, CancellationToken.None); } + + // 记录请求日志 + if (tokenValidation.IsEnableLog) + { + FireAndForgetMessageLog(input.GetRawText(), tokenValidation.Token, tokenValidation.TokenName, modelId, ModelApiTypeEnum.GenerateContent); + } } #region 私有 @@ -357,5 +387,25 @@ public class OpenApiService : ApplicationService } } + private void FireAndForgetMessageLog(string requestBody, string apiKey, string apiKeyName, string modelId, ModelApiTypeEnum apiType) + { + _ = Task.Run(async () => + { + try + { + using var scope = _serviceScopeFactory.CreateScope(); + var uowManager = scope.ServiceProvider.GetRequiredService(); + var manager = scope.ServiceProvider.GetRequiredService(); + using var uow = uowManager.Begin(requiresNew: true); + await manager.CreateAsync(requestBody, apiKey, apiKeyName, modelId, apiType); + await uow.CompleteAsync(); + } + catch (Exception ex) + { + _logger.LogError(ex, "记录消息日志失败, 请求体长度: {RequestBodyLength}", requestBody?.Length ?? 0); + } + }); + } + #endregion } \ No newline at end of file diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs index c1f3c416..7eea51dd 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/AiHubConst.cs @@ -3,4 +3,4 @@ public class AiHubConst { public const string VipRole = "YiXinAi-Vip"; -} \ No newline at end of file +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/ModelConst.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/ModelConst.cs new file mode 100644 index 00000000..c88d6749 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Consts/ModelConst.cs @@ -0,0 +1,47 @@ +namespace Yi.Framework.AiHub.Domain.Shared.Consts; + +public class ModelConst +{ + /// + /// 需要移除的模型前缀列表 + /// + private static readonly List ModelPrefixesToRemove = + [ + "yi-", + "ma-" + ]; + + /// + /// 获取模型ID的前缀(如果存在) + /// + private static string? GetModelPrefix(string? modelId) + { + if (string.IsNullOrEmpty(modelId)) return null; + + return ModelPrefixesToRemove.FirstOrDefault(prefix => + modelId!.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)); + } + + /// + /// 移除模型ID的前缀,返回标准模型ID + /// + public static string RemoveModelPrefix(string? modelId) + { + if (string.IsNullOrEmpty(modelId)) return string.Empty; + + var prefix = GetModelPrefix(modelId); + if (prefix != null) + { + return modelId[prefix.Length..]; + } + return modelId; + } + + /// + /// 处理模型ID,如有前缀则移除并返回新字符串 + /// + public static string ProcessModelId(string? modelId) + { + return RemoveModelPrefix(modelId); + } +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs index 0ec815b3..5a9700ff 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain.Shared/Enums/GoodsTypeEnum.cs @@ -99,8 +99,8 @@ public enum GoodsTypeEnum [Price(83.7, 3, 27.9)] [DisplayName("YiXinVip 3 month", "3个月", "短期体验")] [GoodsCategory(GoodsCategoryType.Vip)] YiXinVip3 = 3, - [Price(114.5, 5, 22.9)] [DisplayName("YiXinVip 5 month", "5个月", "年度热销")] [GoodsCategory(GoodsCategoryType.Vip)] - YiXinVip5 = 15, + [Price(91.6, 4, 22.9)] [DisplayName("YiXinVip 4 month", "4个月", "年度热销")] [GoodsCategory(GoodsCategoryType.Vip)] + YiXinVip5 = 14, // 尊享包服务 - 需要VIP资格才能购买 [Price(188.9, 0, 1750)] diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/MessageLogAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/MessageLogAggregateRoot.cs new file mode 100644 index 00000000..038e6316 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/MessageLogAggregateRoot.cs @@ -0,0 +1,49 @@ +using SqlSugar; +using Volo.Abp.Domain.Entities; +using Yi.Framework.AiHub.Domain.Shared.Enums; + +namespace Yi.Framework.AiHub.Domain.Entities.OpenApi; + +[SugarTable("Ai_Message_Log")] +public class MessageLogAggregateRoot : Entity +{ + /// + /// 请求内容(httpbody) + /// + [SugarColumn(ColumnDataType = "text")] + public string? RequestBody { get; set; } + + /// + /// 请求apikey + /// + [SugarColumn(Length = 255)] + public string ApiKey { get; set; } + + /// + /// 请求apikey名称 + /// + [SugarColumn(Length = 255)] + public string ApiKeyName { get; set; } + + /// + /// 创建时间 + /// + public DateTime CreationTime { get; set; } + + /// + /// 模型id + /// + [SugarColumn(Length = 64)] + public string ModelId { get; set; } + + /// + /// api类型 + /// + public ModelApiTypeEnum ApiType { get; set; } + + /// + /// api类型名称 + /// + [SugarColumn(Length = 16)] + public string ApiTypeName { get; set; } +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/TokenAggregateRoot.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/TokenAggregateRoot.cs index d5217ca9..6fbe3656 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/TokenAggregateRoot.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Entities/OpenApi/TokenAggregateRoot.cs @@ -51,6 +51,11 @@ public class TokenAggregateRoot : FullAuditedAggregateRoot /// public bool IsDisabled { get; set; } + /// + /// 是否启用请求日志记录(仅数据库手动修改) + /// + public bool IsEnableLog { get; set; } + /// /// 检查Token是否可用 /// 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 38938708..5e83745e 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 @@ -15,6 +15,7 @@ using Yi.Framework.AiHub.Domain.AiGateWay.Exceptions; using Yi.Framework.AiHub.Domain.Entities.Chat; using Yi.Framework.AiHub.Domain.Entities.Model; using Yi.Framework.AiHub.Domain.Shared.Consts; +using ModelConst = Yi.Framework.AiHub.Domain.Shared.Consts.ModelConst; using Yi.Framework.AiHub.Domain.Shared.Dtos; using Yi.Framework.AiHub.Domain.Shared.Dtos.Anthropic; using Yi.Framework.AiHub.Domain.Shared.Dtos.Gemini; @@ -97,12 +98,8 @@ public class AiGateWayManager : DomainService throw new UserFriendlyException($"【{modelId}】模型当前版本【{modelApiType}】格式不支持"); } - // ✅ 统一处理 yi- 后缀(网关层模型规范化) - if (!string.IsNullOrEmpty(aiModelDescribe.ModelId) && - aiModelDescribe.ModelId.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - aiModelDescribe.ModelId = aiModelDescribe.ModelId[3..]; - } + // ✅ 统一处理模型前缀(网关层模型规范化) + aiModelDescribe.ModelId = ModelConst.RemoveModelPrefix(aiModelDescribe.ModelId); return aiModelDescribe; } @@ -134,11 +131,7 @@ public class AiGateWayManager : DomainService LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var sourceModelId = request.Model; - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + request.Model = ModelConst.ProcessModelId(request.Model); var data = await chatService.CompleteChatAsync(modelDescribe, request, cancellationToken); data.SupplementalMultiplier(modelDescribe.Multiplier); @@ -208,11 +201,7 @@ public class AiGateWayManager : DomainService LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var sourceModelId = request.Model; - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + request.Model = ModelConst.ProcessModelId(request.Model); var completeChatResponse = chatService.CompleteChatStreamAsync(modelDescribe, request, cancellationToken); var tokenUsage = new ThorUsageResponse(); @@ -540,11 +529,7 @@ public class AiGateWayManager : DomainService var modelDescribe = await GetModelAsync(ModelApiTypeEnum.Messages, request.Model); var sourceModelId = request.Model; - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + request.Model = ModelConst.ProcessModelId(request.Model); var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); @@ -620,11 +605,7 @@ public class AiGateWayManager : DomainService LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var sourceModelId = request.Model; - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + request.Model = ModelConst.ProcessModelId(request.Model); var completeChatResponse = chatService.StreamChatCompletionsAsync(modelDescribe, request, cancellationToken); ThorUsageResponse? tokenUsage = new ThorUsageResponse(); @@ -744,11 +725,7 @@ public class AiGateWayManager : DomainService var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var sourceModelId = request.Model; - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + request.Model = ModelConst.ProcessModelId(request.Model); var data = await chatService.ResponsesAsync(modelDescribe, request, cancellationToken); @@ -820,11 +797,7 @@ public class AiGateWayManager : DomainService var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var sourceModelId = request.Model; - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + request.Model = ModelConst.ProcessModelId(request.Model); var completeChatResponse = chatService.ResponsesStreamAsync(modelDescribe, request, cancellationToken); ThorUsageResponse? tokenUsage = null; @@ -1164,12 +1137,8 @@ public class AiGateWayManager : DomainService response.Headers.TryAdd("Connection", "keep-alive"); var sourceModelId = modelId; - // 处理 yi- 前缀 - if (!string.IsNullOrEmpty(modelId) && - modelId.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - modelId = modelId[3..]; - } + // 处理模型前缀 + modelId = ModelConst.RemoveModelPrefix(modelId); var modelDescribe = await GetModelAsync(apiType, sourceModelId); @@ -1302,12 +1271,8 @@ public class AiGateWayManager : DomainService // 提取用户最后一条消息 var userContent = request.Messages?.LastOrDefault()?.MessagesStore ?? string.Empty; - // 处理 yi- 前缀 - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + // 处理模型前缀 + request.Model = ModelConst.ProcessModelId(request.Model); var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var completeChatResponse = chatService.CompleteChatStreamAsync(modelDescribe, request, cancellationToken); @@ -1391,12 +1356,8 @@ public class AiGateWayManager : DomainService userContent = textContent?.Text ?? System.Text.Json.JsonSerializer.Serialize(lastMessage.Contents); } - // 处理 yi- 前缀 - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + // 处理模型前缀 + request.Model = ModelConst.ProcessModelId(request.Model); var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var completeChatResponse = chatService.StreamChatCompletionsAsync(modelDescribe, request, cancellationToken); @@ -1509,12 +1470,8 @@ public class AiGateWayManager : DomainService } } - // 处理 yi- 前缀 - if (!string.IsNullOrEmpty(request.Model) && - request.Model.StartsWith("yi-", StringComparison.OrdinalIgnoreCase)) - { - request.Model = request.Model[3..]; - } + // 处理模型前缀 + request.Model = ModelConst.ProcessModelId(request.Model); var chatService = LazyServiceProvider.GetRequiredKeyedService(modelDescribe.HandlerName); var completeChatResponse = chatService.ResponsesStreamAsync(modelDescribe, request, cancellationToken); diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/MessageLogManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/MessageLogManager.cs new file mode 100644 index 00000000..4737be73 --- /dev/null +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/MessageLogManager.cs @@ -0,0 +1,34 @@ +using Volo.Abp.Domain.Services; +using Yi.Framework.AiHub.Domain.Entities.OpenApi; +using Yi.Framework.AiHub.Domain.Shared.Enums; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Framework.AiHub.Domain.Managers; + +public class MessageLogManager : DomainService +{ + private readonly ISqlSugarRepository _repository; + + public MessageLogManager(ISqlSugarRepository repository) + { + _repository = repository; + } + + /// + /// 创建消息日志 + /// + public async Task CreateAsync(string requestBody, string apiKey, string apiKeyName, string modelId, ModelApiTypeEnum apiType) + { + var entity = new MessageLogAggregateRoot + { + RequestBody = requestBody, + ApiKey = apiKey, + ApiKeyName = apiKeyName, + ModelId = modelId, + ApiType = apiType, + ApiTypeName = apiType.ToString(), + CreationTime = DateTime.Now + }; + await _repository.InsertAsync(entity); + } +} diff --git a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/TokenManager.cs b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/TokenManager.cs index 9dc1fad9..0145f671 100644 --- a/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/TokenManager.cs +++ b/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Domain/Managers/TokenManager.cs @@ -27,6 +27,16 @@ public class TokenValidationResult /// token /// public string Token { get; set; } + + /// + /// Token名称 + /// + public string TokenName { get; set; } + + /// + /// 是否启用请求日志记录 + /// + public bool IsEnableLog { get; set; } } public class TokenManager : DomainService @@ -117,7 +127,9 @@ public class TokenManager : DomainService { UserId = entity.UserId, TokenId = entity.Id, - Token = entity.Token + Token = entity.Token, + TokenName = entity.Name, + IsEnableLog = entity.IsEnableLog }; } diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs index 1e0d9e1e..768a61b9 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/Program.cs @@ -15,6 +15,10 @@ Log.Logger = new LoggerConfiguration() .MinimumLevel.Override("Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.AspNetCore.Cors.Infrastructure.CorsService", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.AspNetCore.Authorization.DefaultAuthorizationService", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.AspNetCore.Routing.EndpointMiddleware", LogEventLevel.Warning) + .MinimumLevel.Override("Hangfire.Server.ServerHeartbeatProcess", LogEventLevel.Warning) + .MinimumLevel.Override("Hangfire.Redis.StackExchange.FetchedJobsWatcher", LogEventLevel.Warning) + .MinimumLevel.Override("Hangfire.Processing.BackgroundExecution", LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.Async(c => c.File("logs/all/log-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug,outputTemplate:outputTemplate)) .WriteTo.Async(c => c.File("logs/error/errorlog-.txt", rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Error,outputTemplate:outputTemplate)) diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index afaa6969..e9f4e792 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -361,7 +361,7 @@ namespace Yi.Abp.Web var app = context.GetApplicationBuilder(); app.UseRouting(); - // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); + //app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); // app.ApplicationServices.GetRequiredService().SqlSugarClient.CodeFirst.InitTables(); diff --git a/Yi.Ai.Vue3/.claude/settings.local.json b/Yi.Ai.Vue3/.claude/settings.local.json index 89b03152..842aaa71 100644 --- a/Yi.Ai.Vue3/.claude/settings.local.json +++ b/Yi.Ai.Vue3/.claude/settings.local.json @@ -10,7 +10,9 @@ "Bash(npm install marked --save)", "Bash(pnpm add marked)", "Bash(pnpm lint:*)", - "Bash(pnpm list:*)" + "Bash(pnpm list:*)", + "Bash(pnpm vue-tsc:*)", + "Bash(pnpm build:*)" ], "deny": [], "ask": [] diff --git a/Yi.Ai.Vue3/src/components/MarkedMarkdown/index.vue b/Yi.Ai.Vue3/src/components/MarkedMarkdown/index.vue index 6609df93..f0954924 100644 --- a/Yi.Ai.Vue3/src/components/MarkedMarkdown/index.vue +++ b/Yi.Ai.Vue3/src/components/MarkedMarkdown/index.vue @@ -10,11 +10,13 @@ import { useDesignStore } from '@/stores'; interface Props { content: string; theme?: 'light' | 'dark' | 'auto'; + sanitize?: boolean; } const props = withDefaults(defineProps(), { content: '', theme: 'auto', + sanitize: true, }); const designStore = useDesignStore(); @@ -94,7 +96,12 @@ const renderer = { // 行内代码 codespan(token: { text: string }) { - return `${token.text}`; + // 转义 HTML 标签,防止