diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreInMemoryCache.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreInMemoryCache.cs index 478ededa9..3d7d0d142 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreInMemoryCache.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreInMemoryCache.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Localization; +using Volo.Abp.Security.Encryption; using Volo.Abp.SimpleStateChecking; namespace LINGYUN.Abp.AIManagement.Workspaces; @@ -13,6 +14,7 @@ public class DynamicWorkspaceDefinitionStoreInMemoryCache : IDynamicWorkspaceDef { public string CacheStamp { get; set; } protected IDictionary WorkspaceDefinitions { get; } + protected IStringEncryptionService StringEncryptionService { get; } protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } protected ILocalizableStringSerializer LocalizableStringSerializer { get; } @@ -21,9 +23,11 @@ public class DynamicWorkspaceDefinitionStoreInMemoryCache : IDynamicWorkspaceDef public DateTime? LastCheckTime { get; set; } public DynamicWorkspaceDefinitionStoreInMemoryCache( + IStringEncryptionService stringEncryptionService, ISimpleStateCheckerSerializer stateCheckerSerializer, ILocalizableStringSerializer localizableStringSerializer) { + StringEncryptionService = stringEncryptionService; StateCheckerSerializer = stateCheckerSerializer; LocalizableStringSerializer = localizableStringSerializer; @@ -51,7 +55,8 @@ public class DynamicWorkspaceDefinitionStoreInMemoryCache : IDynamicWorkspaceDef if (!workspace.ApiKey.IsNullOrWhiteSpace()) { - workspaceDef.WithApiKey(workspace.ApiKey); + var decryptApiKey = StringEncryptionService.Decrypt(workspace.ApiKey); + workspaceDef.WithApiKey(decryptApiKey!); } if (!workspace.ApiBaseUrl.IsNullOrWhiteSpace()) { diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/IWorkspaceDefinitionRecordRepository.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/IWorkspaceDefinitionRecordRepository.cs index e4b566cee..4c893dd04 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/IWorkspaceDefinitionRecordRepository.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/IWorkspaceDefinitionRecordRepository.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; namespace LINGYUN.Abp.AIManagement.Workspaces; -public interface IWorkspaceDefinitionRecordRepository : IBasicRepository +public interface IWorkspaceDefinitionRecordRepository : IRepository { Task FindByNameAsync( string name, diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs index 1e75cba0b..e93500b17 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionRecord.cs @@ -14,7 +14,7 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot public string DisplayName { get; private set; } - public string? Description { get; private set; } + public string? Description { get; set; } public string? ApiKey { get; private set; } @@ -49,8 +49,6 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot string modelName, string displayName, string? description = null, - string? apiKey = null, - string? apiBaseUrl = null, string? systemPrompt = null, string? instructions = null, float? temperature = null, @@ -65,8 +63,6 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot ModelName = Check.NotNullOrWhiteSpace(modelName, nameof(modelName), WorkspaceDefinitionRecordConsts.MaxModelNameLength); DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), WorkspaceDefinitionRecordConsts.MaxDisplayNameLength); Description = Check.Length(description, nameof(description), WorkspaceDefinitionRecordConsts.MaxDescriptionLength); - ApiKey = Check.Length(apiKey, nameof(apiKey), WorkspaceDefinitionRecordConsts.MaxApiKeyLength); - ApiBaseUrl = Check.Length(apiBaseUrl, nameof(apiBaseUrl), WorkspaceDefinitionRecordConsts.MaxApiBaseUrlLength); SystemPrompt = Check.Length(systemPrompt, nameof(systemPrompt), WorkspaceDefinitionRecordConsts.MaxSystemPromptLength); Instructions = Check.Length(instructions, nameof(instructions), WorkspaceDefinitionRecordConsts.MaxInstructionsLength); StateCheckers = Check.Length(stateCheckers, nameof(stateCheckers), WorkspaceDefinitionRecordConsts.MaxStateCheckersLength); @@ -80,6 +76,23 @@ public class WorkspaceDefinitionRecord : AuditedAggregateRoot this.SetDefaultsForExtraProperties(); } + public void SetDisplayName(string displayName) + { + DisplayName = Check.NotNullOrWhiteSpace(displayName, nameof(displayName), WorkspaceDefinitionRecordConsts.MaxDisplayNameLength); + } + + public void SetModel(string provider, string modelName) + { + Provider = Check.NotNullOrWhiteSpace(provider, nameof(provider), WorkspaceDefinitionRecordConsts.MaxProviderLength); + ModelName = Check.NotNullOrWhiteSpace(modelName, nameof(modelName), WorkspaceDefinitionRecordConsts.MaxModelNameLength); + } + + public void SetApiKey(string? apiKey = null, string? apiBaseUrl = null) + { + ApiKey = Check.Length(apiKey, nameof(apiKey), WorkspaceDefinitionRecordConsts.MaxApiKeyLength); + ApiBaseUrl = Check.Length(apiBaseUrl, nameof(apiBaseUrl), WorkspaceDefinitionRecordConsts.MaxApiBaseUrlLength); + } + public bool HasSameData(WorkspaceDefinitionRecord otherWorkspace) { if (Name != otherWorkspace.Name) diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs index 3c69f73fd..94096f797 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDefinitionSerializer.cs @@ -1,4 +1,5 @@ using LINGYUN.Abp.AI.Workspaces; +using System; using System.Collections.Generic; using System.Globalization; using System.Threading.Tasks; @@ -6,21 +7,25 @@ using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.Guids; using Volo.Abp.Localization; +using Volo.Abp.Security.Encryption; using Volo.Abp.SimpleStateChecking; namespace LINGYUN.Abp.AIManagement.Workspaces; public class WorkspaceDefinitionSerializer : IWorkspaceDefinitionSerializer, ITransientDependency { protected IGuidGenerator GuidGenerator { get; } + protected IStringEncryptionService StringEncryptionService { get; } protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; } protected ILocalizableStringSerializer LocalizableStringSerializer { get; } public WorkspaceDefinitionSerializer( IGuidGenerator guidGenerator, + IStringEncryptionService stringEncryptionService, ISimpleStateCheckerSerializer stateCheckerSerializer, ILocalizableStringSerializer localizableStringSerializer) { GuidGenerator = guidGenerator; + StringEncryptionService = stringEncryptionService; StateCheckerSerializer = stateCheckerSerializer; LocalizableStringSerializer = localizableStringSerializer; } @@ -47,8 +52,6 @@ public class WorkspaceDefinitionSerializer : IWorkspaceDefinitionSerializer, ITr definition.ModelName, LocalizableStringSerializer.Serialize(definition.DisplayName)!, definition.Description != null ? LocalizableStringSerializer.Serialize(definition.Description) : null, - definition.ApiKey, - definition.ApiBaseUrl, definition.SystemPrompt, definition.Instructions, definition.Temperature, @@ -57,6 +60,12 @@ public class WorkspaceDefinitionSerializer : IWorkspaceDefinitionSerializer, ITr definition.PresencePenalty, SerializeStateCheckers(definition.StateCheckers)); + if (!definition.ApiKey.IsNullOrWhiteSpace()) + { + var encryptApiKey = StringEncryptionService.Encrypt(definition.ApiKey); + workspace.SetApiKey(encryptApiKey, definition.ApiBaseUrl); + } + foreach (var property in definition.Properties) { workspace.SetProperty(property.Key, property.Value); diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDynamicInitializer.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDynamicInitializer.cs index 591535580..793814d3a 100644 --- a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDynamicInitializer.cs +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/WorkspaceDynamicInitializer.cs @@ -1,5 +1,4 @@ -using JetBrains.Annotations; -using LINGYUN.Abp.AI.Workspaces; +using LINGYUN.Abp.AI.Workspaces; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; @@ -18,33 +17,17 @@ public class WorkspaceDynamicInitializer : ITransientDependency public ILogger Logger { get; set; } protected IServiceProvider ServiceProvider { get; } - protected IOptions Options { get; } - [CanBeNull] - protected IHostApplicationLifetime ApplicationLifetime { get; } - protected ICancellationTokenProvider CancellationTokenProvider { get; } - protected IDynamicWorkspaceDefinitionStore DynamicWorkspaceDefinitionStore { get; } - protected IStaticWorkspaceSaver StaticWorkspaceSaver { get; } - - public WorkspaceDynamicInitializer( - IServiceProvider serviceProvider, - IOptions options, - ICancellationTokenProvider cancellationTokenProvider, - IDynamicWorkspaceDefinitionStore dynamicWorkspaceDefinitionStore, - IStaticWorkspaceSaver staticWorkspaceSaver) + + public WorkspaceDynamicInitializer(IServiceProvider serviceProvider) { Logger = NullLogger.Instance; ServiceProvider = serviceProvider; - Options = options; - CancellationTokenProvider = cancellationTokenProvider; - DynamicWorkspaceDefinitionStore = dynamicWorkspaceDefinitionStore; - StaticWorkspaceSaver = staticWorkspaceSaver; - ApplicationLifetime = ServiceProvider.GetRequiredService(); } public virtual Task InitializeAsync(bool runInBackground, CancellationToken cancellationToken = default) { - var options = Options.Value; + var options = ServiceProvider.GetRequiredService>().Value; if (!options.SaveStaticWorkspacesToDatabase && !options.IsDynamicWorkspaceStoreEnabled) { @@ -53,11 +36,12 @@ public class WorkspaceDynamicInitializer : ITransientDependency if (runInBackground) { + var applicationLifetime = ServiceProvider.GetService(); Task.Run(async () => { - if (cancellationToken == default && ApplicationLifetime?.ApplicationStopping != null) + if (cancellationToken == default && applicationLifetime?.ApplicationStopping != null) { - cancellationToken = ApplicationLifetime.ApplicationStopping; + cancellationToken = applicationLifetime.ApplicationStopping; } await ExecuteInitializationAsync(options, cancellationToken); }, cancellationToken); @@ -72,16 +56,17 @@ public class WorkspaceDynamicInitializer : ITransientDependency { try { - using (CancellationTokenProvider.Use(cancellationToken)) + var cancellationTokenProvider = ServiceProvider.GetRequiredService(); + using (cancellationTokenProvider.Use(cancellationToken)) { - if (CancellationTokenProvider.Token.IsCancellationRequested) + if (cancellationTokenProvider.Token.IsCancellationRequested) { return; } await SaveStaticWorkspacesToDatabaseAsync(options, cancellationToken); - if (CancellationTokenProvider.Token.IsCancellationRequested) + if (cancellationTokenProvider.Token.IsCancellationRequested) { return; } @@ -104,6 +89,8 @@ public class WorkspaceDynamicInitializer : ITransientDependency return; } + var staticWorkspaceSaver = ServiceProvider.GetRequiredService(); + await Policy .Handle(ex => ex is not OperationCanceledException) .WaitAndRetryAsync( @@ -118,7 +105,7 @@ public class WorkspaceDynamicInitializer : ITransientDependency { try { - await StaticWorkspaceSaver.SaveAsync(); + await staticWorkspaceSaver.SaveAsync(); } catch (Exception ex) { @@ -135,10 +122,12 @@ public class WorkspaceDynamicInitializer : ITransientDependency return; } + var dynamicWorkspaceDefinitionStore = ServiceProvider.GetRequiredService(); + try { // Pre-cache Workspaces, so first request doesn't wait - await DynamicWorkspaceDefinitionStore.GetAllAsync(); + await dynamicWorkspaceDefinitionStore.GetAllAsync(); } catch (Exception ex) {