diff --git a/Constants/XAiModelsConstants.cs b/Constants/XAiModelsConstants.cs index 3ac296f..55f4425 100644 --- a/Constants/XAiModelsConstants.cs +++ b/Constants/XAiModelsConstants.cs @@ -49,5 +49,7 @@ namespace xAiModels.Constants public const string DefaultXAiProjectTitleResourceID = "XAiPrjT"; public const string DefaultXAiConversationTitleResourceID = "XAiCnvT"; public const string DefaultXAiProjectDescriptionResourceID = "XAiPrjD"; + + // } } \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index bd37bd2..5ccef03 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -431,6 +431,12 @@ namespace xAiModels.DI services.Add( new ServiceDescriptor(typeof(IXAiMessageRepositoryProvider), typeof(XAiMessageRepositoryProvider), lifeTime) ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiMessageEnricher), typeof(XAiMessageEnricher), lifeTime) + ); #endregion // @@ -454,6 +460,12 @@ namespace xAiModels.DI services.Add( new ServiceDescriptor(typeof(IXAiProjectDescriptionResourceProvider), typeof(XAiProjectDescriptionResourceProvider), lifeTime) ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectEnricher), typeof(XAiProjectEnricher), lifeTime) + ); #endregion // diff --git a/Interfaces/Enrichers/IXAiConversationEnricher.cs b/Interfaces/Enrichers/IXAiConversationEnricher.cs index 26b5836..584b629 100644 --- a/Interfaces/Enrichers/IXAiConversationEnricher.cs +++ b/Interfaces/Enrichers/IXAiConversationEnricher.cs @@ -1,22 +1,11 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; using xAiModels.Models.Dtos; +using xDataService.Interfaces; namespace xAiModels.Interfaces.Enrichers { - public interface IXAiConversationEnricher - { - Task EnrichAsync( - XAiConversationDto source, - XAiConversationDto destination, - CancellationToken cancellationToken = default - ); - - Task> EnrichRangeAsync( - IEnumerable sources, - IEnumerable destinations, - CancellationToken cancellationToken = default - ); - } + /// + /// Ai Conversation Enricher ... + /// + public interface IXAiConversationEnricher : IXBaseEnricher + { } } \ No newline at end of file diff --git a/Interfaces/Enrichers/IXAiMessageEnricher.cs b/Interfaces/Enrichers/IXAiMessageEnricher.cs new file mode 100644 index 0000000..2cb4d4d --- /dev/null +++ b/Interfaces/Enrichers/IXAiMessageEnricher.cs @@ -0,0 +1,8 @@ +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiMessageEnricher : IXBaseEnricher + { } +} \ No newline at end of file diff --git a/Interfaces/Enrichers/IXAiProjectEnricher.cs b/Interfaces/Enrichers/IXAiProjectEnricher.cs new file mode 100644 index 0000000..3ec7cbb --- /dev/null +++ b/Interfaces/Enrichers/IXAiProjectEnricher.cs @@ -0,0 +1,8 @@ +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiProjectEnricher : IXBaseEnricher + { } +} \ No newline at end of file diff --git a/Models/Dtos/XAiConversationDto.cs b/Models/Dtos/XAiConversationDto.cs index 633862d..480777f 100644 --- a/Models/Dtos/XAiConversationDto.cs +++ b/Models/Dtos/XAiConversationDto.cs @@ -28,7 +28,7 @@ namespace xAiModels.Models.Dtos /// /// All Exists Title Locale Resources ... /// - public virtual XLocaleResourceDto[] TitleLocales { get; set; } + public virtual XResourceDto TitleResource { get; set; } /// /// Created Time ... @@ -58,11 +58,11 @@ namespace xAiModels.Models.Dtos /// /// Project Title Locale Resources ... /// - public virtual XLocaleResourceDto[] ProjectTitleLocales { get; set; } + public virtual XResourceDto ProjectTitleResource { get; set; } /// /// Project Description Locale Resources ... /// - public virtual XLocaleResourceDto[] ProjectDescriptionLocales { get; set; } + public virtual XResourceDto ProjectDescriptionResource { get; set; } } } \ No newline at end of file diff --git a/Models/Dtos/XAiMessageDto.cs b/Models/Dtos/XAiMessageDto.cs index e3004e4..d04c9f0 100644 --- a/Models/Dtos/XAiMessageDto.cs +++ b/Models/Dtos/XAiMessageDto.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; using xAiModels.Constants; using xCommons.Extensions; using xModels.Base; @@ -48,7 +49,8 @@ namespace xAiModels.Models.Dtos /// /// Conversation Info ... /// - public virtual XAiConversationDto Conversation { get; set; } = null; + public virtual string ConversationTitle { get; set; } = null; + public virtual XResourceDto ConversationTitleResouce { get; set; } = null; // #region Meta Data Property ... @@ -57,6 +59,7 @@ namespace xAiModels.Models.Dtos /// /// Meta Data of Message ... /// + [NotMapped] public IDictionary Metadata { get; private set; } = null; /// diff --git a/Models/Dtos/XAiProjectDto.cs b/Models/Dtos/XAiProjectDto.cs index 6e14d98..c7dfba5 100644 --- a/Models/Dtos/XAiProjectDto.cs +++ b/Models/Dtos/XAiProjectDto.cs @@ -29,7 +29,7 @@ namespace xAiModels.Models.Dtos /// /// All Exists Title Locale Resources ... /// - public virtual XLocaleResourceDto[] TitleLocales { get; set; } + public virtual XResourceDto TitleResource { get; set; } /// /// Description of Project ... @@ -39,7 +39,7 @@ namespace xAiModels.Models.Dtos /// /// All Exists Description Locale Resources ... /// - public virtual XLocaleResourceDto[] DescriptionLocales { get; set; } + public virtual XResourceDto DescriptionResource { get; set; } /// /// a Prompt for Project Start ... diff --git a/Providers/Enrichers/XAiConversationEnricher.cs b/Providers/Enrichers/XAiConversationEnricher.cs index c3c7f66..18d80ae 100644 --- a/Providers/Enrichers/XAiConversationEnricher.cs +++ b/Providers/Enrichers/XAiConversationEnricher.cs @@ -6,7 +6,6 @@ using xAiModels.Interfaces; using xAiModels.Interfaces.Dtos; using xAiModels.Interfaces.Enrichers; using xAiModels.Models.Dtos; -using xAiModels.Models.Entities; using xCommons.Extensions; using xIdentityService.Interfaces; using xIdentityService.Extensions; @@ -58,14 +57,14 @@ namespace xAiModels.Providers.Enrichers // // Attached Resolved Info to Destination ... destination.Owner = ownerTask.Result; - destination.TitleLocales = titleLocalesTask.Result; + destination.TitleResource = titleLocalesTask.Result; var project = projectTask.Result; if (!project.IsNullOrDefault()) { destination.ProjectTitle = project.Title; destination.ProjectDescription = project.Description; - destination.ProjectTitleLocales = project.TitleLocales; - destination.ProjectDescriptionLocales = project.DescriptionLocales; + destination.ProjectTitleResource = project.TitleResource; + destination.ProjectDescriptionResource = project.DescriptionResource; } } @@ -76,7 +75,7 @@ namespace xAiModels.Providers.Enrichers /// /// /// - public async Task> EnrichRangeAsync( + public async Task EnrichRangeAsync( IEnumerable sources, IEnumerable destinations, CancellationToken cancellationToken = default @@ -90,9 +89,6 @@ namespace xAiModels.Providers.Enrichers // await Task.WhenAll(tasks); - - // - return destinations; } // @@ -137,24 +133,23 @@ namespace xAiModels.Providers.Enrichers /// /// /// - private async Task ResolveTitleLocalesAsync( + private async Task ResolveTitleLocalesAsync( string title, CancellationToken cancellationToken = default ) { // - XLocaleResourceDto[] result = []; + XResourceDto result = null; if (title.IsNullOrEmpty()) { return result; } // - var locales = await conversationTitleResourceProvider.GetLocales( + result = await conversationTitleResourceProvider.GetResource( identifier: title, cancellationToken: cancellationToken ); - result = [.. locales]; // return result; diff --git a/Providers/Enrichers/XAiMessageEnricher.cs b/Providers/Enrichers/XAiMessageEnricher.cs new file mode 100644 index 0000000..f5c4d5f --- /dev/null +++ b/Providers/Enrichers/XAiMessageEnricher.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Models.Dtos; +using xCommons.Extensions; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xModels.Dtos; +using System.Linq; +using xAiModels.Interfaces.Dtos; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiMessageEnricher : IXAiMessageEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + + public XAiMessageEnricher( + IXIdentityProvider identityProvider, + IXAiConversationRepositoryService conversationRepositoryService + ) + { + this.identityProvider = identityProvider; + this.conversationRepositoryService = conversationRepositoryService; + } + + public async Task EnrichAsync( + XAiMessageDto source, + XAiMessageDto destination, + CancellationToken cancellationToken = default + ) + { + // + // Run independent async operations concurrently + var ownerTask = ResolveOwnerAsync(source.OwnerId, cancellationToken); + var conversationTask = ResolveConversationAsync(source.ConversationId, cancellationToken); + // + // wait until All Tasks Resolved ... + await Task.WhenAll(ownerTask, conversationTask); + + // + // Attached Resolved Info to Destination ... + destination.Owner = ownerTask.Result; + if (!conversationTask.Result.IsNullOrDefault()) + { + // + destination.ConversationTitle = conversationTask.Result.Title; + destination.ConversationTitleResouce = conversationTask.Result.TitleResource; + } + } + + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + CancellationToken cancellationToken = default + ) + { + // + // Make Tasks Ready ... + var tasks = sources.Zip(destinations, (src, dst) => + EnrichAsync(src, dst, cancellationToken) + ); + + // + await Task.WhenAll(tasks); + } + + // + #region Private ... + /// + /// Reading Owner User Info ... + /// + /// + /// + /// + private async Task ResolveOwnerAsync( + string ownerId, + CancellationToken cancellationToken = default + ) + { + // + XPersonDto result = null; + + // + // Validate ... + if (ownerId.IsNullOrEmpty()) + { + return result; + } + + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: ownerId + ); + result = userInfo.ToXPersonDto(); + + // + return result; + } + + /// + /// Reading Conversation ... + /// + /// + /// + /// + private async Task ResolveConversationAsync( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + XAiConversationDto result = null; + + // + // Validate ... + if (conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + return result; + } + + // + result = await conversationRepositoryService.GetAsync( + id: conversationId, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + #endregion + } +} \ No newline at end of file diff --git a/Providers/Enrichers/XAiProjectEnricher.cs b/Providers/Enrichers/XAiProjectEnricher.cs new file mode 100644 index 0000000..a07bde7 --- /dev/null +++ b/Providers/Enrichers/XAiProjectEnricher.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Models.Dtos; +using xCommons.Extensions; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xModels.Dtos; +using xAiModels.Interfaces; +using xAiModels.Interfaces.Dtos; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiProjectEnricher : IXAiProjectEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectEnricher( + IXIdentityProvider identityProvider, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationRepositoryService conversationRepositoryService, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationRepositoryService = conversationRepositoryService; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + public Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + CancellationToken cancellationToken = default + ) + { + throw new NotImplementedException(); + } + + public Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + CancellationToken cancellationToken = default + ) + { + throw new NotImplementedException(); + } + + // + #region Private ... + /// + /// Reading Owner User Info ... + /// + /// + /// + /// + private async Task ResolveOwnerAsync( + string ownerId, + CancellationToken cancellationToken = default + ) + { + // + XPersonDto result = null; + + // + // Validate ... + if (ownerId.IsNullOrEmpty()) + { + return result; + } + + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: ownerId + ); + result = userInfo.ToXPersonDto(); + + // + return result; + } + + /// + /// Retrieve Title Resource ... + /// + /// + /// + /// + private async Task ResolveTitleAsync( + string identifier, + CancellationToken cancellationToken = default + ) + { + // + XResourceDto result = null; + + // + // Validate ... + if (identifier.IsNullOrEmpty()) + { + return result; + } + + // + result = await projectTitleResourceProvider.GetResource( + identifier: identifier, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Description Resource ... + /// + /// + /// + /// + private async Task ResolveDescriptionAsync( + string identifier, + CancellationToken cancellationToken = default + ) + { + // + XResourceDto result = null; + + // + // Validate ... + if (identifier.IsNullOrEmpty()) + { + return result; + } + + // + result = await projectDescriptionResourceProvider.GetResource( + identifier: identifier, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Project Conversations ... + /// + /// + /// + /// + private async Task> ResolveConversationsAsync( + Guid projectId, + CancellationToken cancellationToken = default + ) + { + // + List result = []; + + // + // Validate ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + return result; + } + + // + var items = await conversationRepositoryService.FindManyAsync( + orderBuilder: null, + includeBuilder: null, + ignoreSoftDeleteds: true, + predicate: x => x.Id == projectId, + cancellationToken: cancellationToken + ); + result = [.. items]; + + // + return result; + } + #endregion + } +} \ No newline at end of file diff --git a/Providers/XAiDataProvider.cs b/Providers/XAiDataProvider.cs index a169dbe..e0fee04 100644 --- a/Providers/XAiDataProvider.cs +++ b/Providers/XAiDataProvider.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using Microsoft.AspNetCore.SignalR; using xAiModels.Interfaces; using xAiModels.Interfaces.Entities; @@ -52,7 +53,26 @@ namespace xAiModels.Providers this.conversationTitleResourceProvider = conversationTitleResourceProvider; this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; } - - + + // + #region Actions ... + #endregion + + // + #region Private ... + /// + /// Handle Default Project for Specified Owner ... + /// + /// + /// + private async Task HandleDefaultProject(string ownerId) { } + + /// + /// Handle Default Project's Default Conversation for Specified Owner ... + /// + /// + /// + private async Task HandleDefaultConversation(string ownerId) { } + #endregion } } \ No newline at end of file