diff --git a/Documents/GeneratedContext/xDashboard-xAiApi-20260926_085146.txt b/Documents/GeneratedContext/xDashboard-xAiApi-20260926_085146.txt new file mode 100644 index 0000000..c755ae0 --- /dev/null +++ b/Documents/GeneratedContext/xDashboard-xAiApi-20260926_085146.txt @@ -0,0 +1,2599 @@ + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Program.cs + +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace xAiApi +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Startup.cs + +using System; +using System.IO; +using System.Linq; +using xTagService.DI; +using System.Net.Http; +using xAiApi.Database; +using xHttpService.DI; +using xPushService.DI; +using xFileService.DI; +using xDataService.DI; +using Newtonsoft.Json; +using System.Reflection; +using xAiApi.Extensions; +using xStringService.DI; +using xStorageService.DI; +using xIdentityService.DI; +using xDataService.Models; +using xCommons.Extensions; +using xCommons.Configurations; +using System.Collections.Generic; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json.Serialization; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using IdentityModel.AspNetCore.OAuth2Introspection; +using xPushService.Helpers; +using xAiApi.DI; +using xAiApi.Interfaces; +using xAiApi.Providers; +using xAiModels.DI; + +namespace xAiApi +{ + public class Startup + { + // + #region Props ... + public IConfiguration Configuration { get; } + private readonly List databases; + private readonly XAiApiDatabaseDescriptor apiDatabaseDescriptor; + #endregion + + // + #region Constructor(s) ... + public Startup(IConfiguration configuration) + { + // + Configuration = configuration; + + // + // Create an Api Descriptor Class Instance ... + apiDatabaseDescriptor = new XAiApiDatabaseDescriptor(); + databases = new List + { + apiDatabaseDescriptor + }; + } + #endregion + + public void ConfigureServices(IServiceCollection services) + { + // + // Register Validation Provider and all XCommons Module Services ... + services.AddXCommons(); + + // + // Register App Configuration ... + services.AddXAppConfiguration(Configuration); + var appConfiguration = services.GetRegisteredService(); + + // + // Register Allowed Origins ... + services.AddXCors(appConfiguration.AllowedOrigins); + + // + // Register Swagger ... + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + services.AddXSwagger(Configuration, xmlFilePath: xmlPath); + + // + // Register HttpService ... + services.AddXHttpService(Configuration); + + // + // Add Api V1 Versioning ... + services.AddXApiV1Versioning(); + + // + // OAuthIntrospectin Http Client Handler ... + // this is for handling SSLErrors ... + services.AddHttpClient(OAuth2IntrospectionDefaults.BackChannelHttpClientName) + .ConfigurePrimaryHttpMessageHandler(() => + { + return new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true + }; + }); + + // + // Register Authorizations ... + services.AddXAuthorization(); + + // + services.AddControllers() + .AddNewtonsoftJson(x => + { + x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; + x.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + }); + + // + var lifeTime = ServiceLifetime.Scoped; + var repositoryType = xDataService.Constants.XRepositoryType.EF; + + // + // Register XIdentity Service ... + services.AddXIdentityService( + lifeTime: lifeTime, + configuration: Configuration + ); + + // + // Storage Service ... + services.AddXStorageService(Configuration); + + // + // Push Service ... + services.AddXPushService( + lifeTime: lifeTime, + config: Configuration + ); + + // + // Preparing DataBases ... + if (databases.HasChild()) + { + // + databases + .ToList() + .ForEach(database => + { + // + // Register DataBase ... + services.AddXDatabase( + lifeTime: lifeTime, + descriptor: database, + configuration: Configuration + ); + }); + } + + // + // Register String Service ... + services.AddXStringService( + lifeTime: lifeTime, + repositoryType: repositoryType + ); + + // + // Register Tag Service ... + services.AddXTagService( + lifeTime: lifeTime, + repositoryType: repositoryType + ); + + // + // Register File Service ... + services.AddXFileService( + lifeTime: lifeTime, + repositoryType: repositoryType + ); + + // + // Register AiApi Data Service ... + services.AddXAiDataService( + lifeTime: lifeTime, + repositoryType: repositoryType + ); + + // + // Register XAiApi Configuration ... + services.AddXAiApiConfiguration(Configuration); + + // + // Register Default Ai Service ... + services.AddScoped(); + services.AddScoped(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + // + // Configure the HTTP request pipeline. + var isDevelopmentEnvironment = false; + if (env.IsDevelopment()) + { + isDevelopmentEnvironment = true; + app.UseDeveloperExceptionPage(); + } + + // + // Use Swagger Middleware ... + app.UseXSwagger(); + + // + // Force Https Redirection ... + app.UseHttpsRedirection(); + + // + // Using Cors ... + app.UseXCors(); + + // + // Using Routing ... + app.UseRouting(); + + // + // Use xIdentityService ... + app.UseXIdentityService(); + + // + // Use Authorization ... + app.UseAuthorization(); + + // + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + }); + + // + // Use Storage Service ... + app.UseXStorageService(); + + // + // Use PushService ... + var pushHelper = new XPushServiceHelper(); + app.UseXPushService(pushHelper); + + // + // Using DataBase ... + if (databases.HasChild()) + { + // + databases + .ToList() + .ForEach(database => + { + // + app.UseXDatabase( + descriptor: database, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + }); + } + + // + // Using String Service ... + app.UseXStringService( + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + + // + // Using XTag Service ... + app.UseXTagService( + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + + // + // Using File Service ... + app.UseXFileService( + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Configurations\XAiApiConfiguration.cs + +using xAiModels.Models; + +namespace xAiApi.Configurations +{ + public class XAiApiConfiguration + { + /// + /// Allowed Models to Use ... + /// + public XAiModelDescriptor[] Models { get; set; } = []; + + /// + /// Allowed Prompts to Use ... + /// + public XAiPromptDescriptor[] Prompts { get; set; } = []; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Constants\ConfigurationNodeNames.cs + +namespace xAiApi.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiApiConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Constants\XAiApiConstants.cs + +namespace xAiApi.Constants +{ + public struct XAiApiConstants + { + // + // Database Descriptor ... + public const string XAiApiDbIdentifier = "xAiApiDb"; + public const string XAiApiMigrationsAssemblyIdentifier = "xAiApi"; + + // + public const string XDILogTag = "XAiApi"; + public const string XAiApiIntroductionPromptName = "Introduction"; + + // + public const string XAiEmbeddingModelName = "Embed"; + public const string XAiEmbeddingPromptName = "Embedding"; + + // + public const string XOpenAINoKey = "no-key-required"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Controllers\DefaultAiController.cs + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xAiApi.Interfaces; +using xCommons.Configurations; +using xCommons.Providers; + +namespace xAiApi.Controllers +{ + [Authorize] + [Route ("[controller]")] + public class DefaultAiController : XAiServiceControllerBase + { + public DefaultAiController( + ILogger logger, + IXDefaultAiService aiService, + XAppConfiguration appConfiguration, + XValidationProvider validationProvider + ) : base( + logger, + aiService, + appConfiguration, + validationProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Controllers\DefaultEmbeddingController.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xAiApi.Interfaces; +using xCommons.Configurations; +using xCommons.Providers; + +namespace xAiApi.Controllers +{ + [Authorize] + [Route("[controller]")] + public class DefaultEmbeddingController : XAiEmbeddingServiceControllerBase + { + public DefaultEmbeddingController( + ILogger logger, + IXDefaultEmbeddingService aiService, + XAppConfiguration appConfiguration, + XValidationProvider validationProvider + ) : base( + logger, + aiService, + appConfiguration, + validationProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Controllers\StartupController.cs + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xCommons.Configurations; +using xCommons.Controllers; +using xCommons.Providers; + +namespace xAiApi.Controllers +{ + /// + /// Runing when application start ... + /// + [Route("")] + [AllowAnonymous] + public class StartupController : XBaseController + { + + public StartupController( + ILogger logger, + XAppConfiguration appConfiguration, + XValidationProvider validationProvider + ) : base( + logger, + appConfiguration, + validationProvider + ) + { } + + /// + /// Show Configured Welcome Message + /// + /// + [HttpGet("")] + [AllowAnonymous] + public virtual ActionResult Index() + { + // + var controllerName = GetControllerName(); + var message = $"{AppConfiguration.WelcomeMessage}"; + + // + return Ok(message); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Controllers\XAiEmbeddingServiceControllerBase.cs + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xAiApi.Interfaces; +using xCommons.Configurations; +using xCommons.Providers; + +namespace xAiApi.Controllers +{ + [Authorize] + [Route("[controller]")] + public abstract class XAiEmbeddingServiceControllerBase : XAiServiceControllerBase, IXAiEmbeddingServiceControllerBase + where TAiService : IXAiEmbeddingServiceBase + { + private readonly TAiService aiService; + + protected XAiEmbeddingServiceControllerBase( + ILogger logger, + TAiService aiService, + XAppConfiguration appConfiguration, + XValidationProvider validationProvider + ) : base( + logger, + aiService, + appConfiguration, + validationProvider + ) + { + this.aiService = aiService; + } + + /// + /// Request For Embedding Specified String ... + /// + /// + /// + /// + [AllowAnonymous] + [HttpGet("Embedding")] + public async Task> Embedding( + [FromQuery] string content, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + ValidationProvider.NotEmpty(content); + + // + var result = await aiService.Embedding( + content: content, + cancellationToken: cancellationToken + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Request For Embedding Specified Batch ... + /// + /// + /// + /// + [AllowAnonymous] + [HttpGet("Embeddings")] + public async Task>> Embeddings( + [FromQuery] string[] batch, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + ValidationProvider.NotZeroChilds(batch); + + // + var result = await aiService.Embeddings( + batch: batch, + cancellationToken: cancellationToken + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Controllers\XAiServiceControllerBase.cs + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using xAiApi.Interfaces; +using xCommons.Configurations; +using xCommons.Controllers; +using xCommons.Providers; + +namespace xAiApi.Controllers +{ + [Authorize] + [Route ("[controller]")] + public abstract class XAiServiceControllerBase : XBaseController, IXAiServiceControllerBase + where TAiService : IXAiServiceBase + { + private readonly TAiService aiService; + + protected XAiServiceControllerBase( + ILogger logger, + TAiService aiService, + XAppConfiguration appConfiguration, + XValidationProvider validationProvider + ) : base( + logger, + appConfiguration, + validationProvider + ) + { + this.aiService = aiService; + } + + /// + /// Ask Question and Get Response ... + /// + /// + /// + /// + [AllowAnonymous] + [HttpGet("Ask")] + public virtual async Task> Ask( + [FromQuery] string question, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + ValidationProvider.NotEmpty(question); + + // + var result = await aiService.AskAsync( + prompt: question, + cancellationToken: cancellationToken + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Database\XAiApiDatabaseDescriptor.cs + +using xAiApi.Constants; +using xDataService.Interfaces; +using xDataService.Models; + +namespace xAiApi.Database +{ + /// + /// Ai Api Database Descriptor ... + /// + public class XAiApiDatabaseDescriptor : XDatabaseDescriptor, IXDatabaseDescriptor + { + public XAiApiDatabaseDescriptor() : base( + name: XAiApiConstants.XAiApiDbIdentifier, + repositories: [] + ) + { + OptionsBuilder = b => b.MigrationsAssembly(XAiApiConstants.XAiApiMigrationsAssemblyIdentifier); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Database\XAiApiDbContext.cs + +using Microsoft.EntityFrameworkCore; +using xAiApi.Constants; +using xAiModels.Providers; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Providers; +using xFileService.Providers; +using xStringService.Providers; +using xTagService.Providers; + +namespace xAiApi.Database +{ + /// + /// Db Context of AiApi ... + /// + public class XAiApiDbContext : XDbContext + { + // + #region DbSets ... + #endregion + + // + #region Navigation Property Entities ... + #endregion + + // + #region Constructor ... + public XAiApiDbContext( + DbContextOptions options, + XDataServiceConfiguration config, + XEntityRegisterarHandlerService dynamicEntityHandlers + ) : base( + config: config, + options: options, + database: XAiApiConstants.XAiApiDbIdentifier, + dynamicEntityHandlers: dynamicEntityHandlers, + dynamicEntityRegisterarsNames: [ + nameof(XTagEntityRegisterar), + nameof(XFileEntityRegisterar), + nameof(XStringEntityRegisterar), + nameof(XAiMessageEntityRegisterar), + nameof(XAiProjectEntityRegisterar), + nameof(XAiConversationEntityRegisterar), + ] + ) + { } + #endregion + + // + #region Overrides ... + // + public override void OnXModelCreating(ModelBuilder modelBuilder) + { } + + // + public override void OnXConfiguring(DbContextOptionsBuilder optionsBuilder) + { } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\DI\XDIHelperExtension.cs + +using System; +using xAiApi.Constants; +using xAiApi.Extensions; +using xCommons.Extensions; +using xAiApi.Configurations; +using xExceptions.Constants; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace xAiApi.DI +{ + public static partial class XDIHelperExtension + { + /// + /// Extract AI Configuration ... + /// + /// + /// + public static XAiApiConfiguration GetXAiApiConfiguration(this IConfiguration source) + { + // + XAiApiConfiguration result = null; + + // + var section = source.GetSection(ConfigurationNodeNames.AI_API_NODE); + if (!section.IsNull()) + { + result = section.Get(); + } + + // + return result; + } + + /// + /// Register AiApi Configuration ... + /// + /// + /// + public static void AddXAiApiConfiguration( + this IServiceCollection source, + IConfiguration configuration + ) + { + // + var apiConfig = configuration.GetXAiApiConfiguration(); + source.AddXAiApiConfiguration(apiConfig); + } + + /// + /// Register AiApi Configuration ... + /// + /// + /// + public static void AddXAiApiConfiguration( + this IServiceCollection source, + XAiApiConfiguration configuration + ) + { + // + if (!configuration.IsValid()) + { + XException.InvalidConfiguration.Throw(); + } + + // + source.AddSingleton(configuration); + } + + // + #region Private ... + /// + /// a LogTag for Service ... + /// + private static string XLogTag = XAiApiConstants.XDILogTag; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Extensions\XModelsExtensions.cs + +using System.Linq; +using xAiApi.Constants; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Extensions; +using xAiApi.Configurations; +using System.Collections.Generic; + +namespace xAiApi.Extensions +{ + public static class XModelsExtensions + { + /// + /// Validate Configurations ... + /// + /// + /// + public static bool IsValid(this XAiApiConfiguration source) + { + // + var result = + !source.IsNullOrDefault() && + source.Models.HasChild() && + source.Models.All(m => m.IsValid()) && + source.Prompts.All(m => m.IsValid()) && + source.Prompts.Any(p => p.Name + .Equals( + XAiApiConstants.XAiApiIntroductionPromptName, + System.StringComparison.InvariantCultureIgnoreCase)); + + // + return result; + } + + /// + /// Extract Default Model Descriptor ... + /// + /// + /// + public static XAiModelDescriptor GetDefaultModel(this XAiApiConfiguration source) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + result = source.Models[0]; + } + + // + return result; + } + + /// + /// Retrieve Specified Model from Config ... + /// + /// + /// + /// + public static XAiModelDescriptor GetModel( + this XAiApiConfiguration source, + string name + ) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + // + if (name.IsNullOrEmpty()) + { + result = source.GetDefaultModel(); + } + else + { + result = source.Models + .FirstOrDefault(m => m.Name + .Equals(name, System.StringComparison.InvariantCultureIgnoreCase)); + } + } + + // + return result; + } + + /// + /// Retrieve Introduction Prompt ... + /// + /// + /// + public static XAiPromptDescriptor GetIntroductionPrompt(this XAiApiConfiguration source) + { + // + XAiPromptDescriptor result = null; + + // + if (source.IsValid()) + { + // + result = source.Prompts + .FirstOrDefault(p => p.Name + .Equals( + XAiApiConstants.XAiApiIntroductionPromptName, + System.StringComparison.InvariantCultureIgnoreCase)); + } + + // + return result; + } + + /// + /// Select Specified Prompts and Parse it's Template + /// and Generate Message ... + /// + /// + /// + /// + /// + public static string GetPrompt( + this XAiApiConfiguration source, + string name = null, + IDictionary @params = null + ) + { + // + var result = string.Empty; + + // + // Normalize ... + if (name.IsNullOrEmpty()) + { + name = XAiApiConstants.XAiApiIntroductionPromptName; + } + + // + if (source.IsValid()) + { + // + var prompt = source.Prompts + .FirstOrDefault(p => p.Name + .Equals( + name, + System.StringComparison.InvariantCultureIgnoreCase + ) + ); + if (!prompt.IsNullOrDefault()) + { + // + result = prompt.Template; + + // + // Handle Params ... + if (!@params.IsNullOrDefault() && @params.HasChild()) + { + // + // Select Params ... + var existsParams = prompt.Params + .Where(p => @params.Any(pr => pr.Key == p.Name)) + .Distinct() + .ToList(); + + // + // Replace Selected Params ... + existsParams + .ForEach(pk => + { + result = result.Replace(pk.Param, @params[pk.Name]); + }); + } + } + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Extensions\XProgramExtensions.cs + +using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.Extensions.DependencyInjection; +using xCommons.Authorization; +using xCommons.Extensions; +using xIdentityHelper; + +namespace xAiApi.Extensions +{ + public static class XProgramExtensions + { + /// + /// Register Authorization Policies + /// + /// + /// + public static void AddXAuthorization( + this IServiceCollection services, + IDictionary policies = null + ) + { + // + services.AddAuthorization(options => + { + // + if (!policies.IsNull()) + { + // + // Fill Policies ... + using (var policiesEnumerator = policies.GetEnumerator()) + { + while (policiesEnumerator.MoveNext()) + { + var policyDescriptor = policiesEnumerator.Current; + options.AddPolicy(policyDescriptor.Key, policyDescriptor.Value); + } + } + } + + // + var xPolicies = XAuthorizationHelper.GetXAuthorizationPolicies(); + if (!xPolicies.IsNull()) + { + // + // Fill Policies ... + using (var policiesEnumerator = xPolicies.GetEnumerator()) + { + while (policiesEnumerator.MoveNext()) + { + var policyDescriptor = policiesEnumerator.Current; + options.AddPolicy(policyDescriptor.Key, policyDescriptor.Value); + } + } + } + }); + + // + services.AddSingleton(); + } + + /// + /// Use Forward Headers Options for resolving behind a proxy issues ... + /// + /// + /// + public static void UseXForwardOptions(this IApplicationBuilder source) + { + // + var forwardOptions = new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto, + RequireHeaderSymmetry = false + }; + + // + forwardOptions.KnownNetworks.Clear(); + forwardOptions.KnownProxies.Clear(); + + // + // ref: https://github.com/aspnet/Docs/issues/2384 + source.UseForwardedHeaders(forwardOptions); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Interfaces\IXAiEmbeddingServiceBase.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using OllamaSharp; + +namespace xAiApi.Interfaces +{ + /// + /// Base Embedding Provider Service ... + /// + public interface IXAiEmbeddingServiceBase : IXAiServiceBase + { + /// + /// Embedding Specified String ... + /// + /// + /// + /// + Task Embedding( + string content, + CancellationToken cancellationToken = default + ); + + /// + /// Embedding Specified Batch ... + /// + /// + /// + /// + Task> Embeddings( + string[] batch, + CancellationToken cancellationToken = default + ); + + /// + /// Access Embedding Client ... + /// + /// + OllamaApiClient GetEmbeddingClient(); + + IEmbeddingGenerator> GetEmbeddingGenerator(); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Interfaces\IXAiEmbeddingServiceControllerBase.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace xAiApi.Interfaces +{ + public interface IXAiEmbeddingServiceControllerBase : IXAiServiceControllerBase + { + /// + /// Request For Embedding Specified String ... + /// + /// + /// + /// + [HttpGet("Embedding")] + Task> Embedding( + [FromQuery] string content, + CancellationToken cancellationToken = default + ); + + /// + /// Request For Embedding Specified Batch ... + /// + /// + /// + /// + [HttpGet("Embeddings")] + Task>> Embeddings( + [FromQuery] string[] batch, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Interfaces\IXAiServiceBase.cs + +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; + +namespace xAiApi.Interfaces +{ + /// + /// Describe a Base Service Actions of any Ai Based Services ... + /// + public interface IXAiServiceBase : IDisposable + { + /// + /// Base Method for Communicate with LLM ... + /// + /// + /// + /// + Task AskAsync( + string prompt, + CancellationToken cancellationToken = default + ); + + /// + /// Base Method for Communicate with LLM ... + /// + /// + /// + /// + IAsyncEnumerable AskAsEnumerable( + string prompt, + CancellationToken cancellationToken = default + ); + + /// + /// Get LLM Client instance for Communicating with LLM ... + /// + /// + /// + IChatClient GetClient(string llm = null); + + /// + /// Create Custom HttpClient for Communicating with LLM API ... + /// + /// + /// + HttpClient GetHttpClient(string url = null); + + /// + /// Prepare a Message History List for LLM Communication based on Prompt ... + /// + /// + /// + /// + IList GetHistory( + string prompt = null, + bool forcePrompt = true + ); + + /// + /// Prepare a Message History List for LLM Communication based on Prompt ... + /// + /// + /// + /// + IList GetHistory( + ChatMessage message = null, + bool forceMessage = true + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Interfaces\IXAiServiceControllerBase.cs + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace xAiApi.Interfaces +{ + public interface IXAiServiceControllerBase + { + /// + /// Ask Question and Get Response ... + /// + /// + /// + /// + [HttpGet("Ask")] + Task> Ask( + [FromQuery] string question, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Interfaces\IXDefaultAiService.cs + +namespace xAiApi.Interfaces +{ + public interface IXDefaultAiService : IXAiServiceBase + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Interfaces\IXDefaultEmbeddingService.cs + +namespace xAiApi.Interfaces +{ + public interface IXDefaultEmbeddingService : IXAiEmbeddingServiceBase + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Migrations\20260906032616_InitialMigrationAiApi.cs + +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace xAiApi.Migrations +{ + public partial class InitialMigrationAiApi : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AiConversations", + columns: table => new + { + Id = table.Column(nullable: false), + Deleted = table.Column(nullable: false), + OwnerId = table.Column(maxLength: 255, nullable: false), + Title = table.Column(maxLength: 255, nullable: false), + CreatedOn = table.Column(nullable: false), + UpdatedAt = table.Column(nullable: false), + ProjectId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AiConversations", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AiMessages", + columns: table => new + { + Id = table.Column(nullable: false), + Deleted = table.Column(nullable: false), + OwnerId = table.Column(maxLength: 255, nullable: false), + Content = table.Column(nullable: false), + Role = table.Column(nullable: false), + CreatedOn = table.Column(nullable: false), + UpdatedAt = table.Column(nullable: false), + ConversationId = table.Column(maxLength: 255, nullable: false), + MeatDatas = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AiMessages", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AiProjects", + columns: table => new + { + Id = table.Column(nullable: false), + Deleted = table.Column(nullable: false), + OwnerId = table.Column(maxLength: 255, nullable: false), + Title = table.Column(maxLength: 255, nullable: false), + Description = table.Column(maxLength: 1000, nullable: true), + Prompt = table.Column(nullable: true), + CreatedOn = table.Column(nullable: false), + UpdatedAt = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AiProjects", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Files", + columns: table => new + { + Id = table.Column(nullable: false), + Deleted = table.Column(nullable: false), + Type = table.Column(nullable: false), + OwnerId = table.Column(maxLength: 255, nullable: false), + Name = table.Column(maxLength: 255, nullable: false), + Path = table.Column(nullable: false), + Thumb = table.Column(nullable: true), + ThumbPath = table.Column(nullable: true), + UploadedOn = table.Column(nullable: false), + FileName = table.Column(nullable: true), + References = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Files", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Strings", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Deleted = table.Column(nullable: false), + Language = table.Column(maxLength: 10, nullable: false), + ResourceTitle = table.Column(maxLength: 255, nullable: false), + TranslatedValue = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_Strings", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "Tags", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Deleted = table.Column(nullable: false), + Tag = table.Column(maxLength: 255, nullable: false), + References = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Tags", x => x.Id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AiConversations"); + + migrationBuilder.DropTable( + name: "AiMessages"); + + migrationBuilder.DropTable( + name: "AiProjects"); + + migrationBuilder.DropTable( + name: "Files"); + + migrationBuilder.DropTable( + name: "Strings"); + + migrationBuilder.DropTable( + name: "Tags"); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Migrations\20260906032616_InitialMigrationAiApi.Designer.cs + +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using xAiApi.Database; + +namespace xAiApi.Migrations +{ + [DbContext(typeof(XAiApiDbContext))] + [Migration("20260906032616_InitialMigrationAiApi")] + partial class InitialMigrationAiApi + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.14"); + + modelBuilder.Entity("xAiModels.Models.Entities.XAiConversation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("ProjectId") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AiConversations"); + }); + + modelBuilder.Entity("xAiModels.Models.Entities.XAiMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Content") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ConversationId") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("MeatDatas") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AiMessages"); + }); + + modelBuilder.Entity("xAiModels.Models.Entities.XAiProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasColumnType("TEXT") + .HasMaxLength(1000); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("Prompt") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AiProjects"); + }); + + modelBuilder.Entity("xFileService.Models.Entities.XFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("References") + .HasColumnType("TEXT"); + + b.Property("Thumb") + .HasColumnType("TEXT"); + + b.Property("ThumbPath") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UploadedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Files"); + }); + + modelBuilder.Entity("xStringService.Models.Entities.XString", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("Language") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10); + + b.Property("ResourceTitle") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("TranslatedValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Strings"); + }); + + modelBuilder.Entity("xTagService.Models.Entities.XTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("References") + .HasColumnType("TEXT"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Tags"); + }); +#pragma warning restore 612, 618 + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Migrations\XAiApiDbContextModelSnapshot.cs + +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using xAiApi.Database; + +namespace xAiApi.Migrations +{ + [DbContext(typeof(XAiApiDbContext))] + partial class XAiApiDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "3.1.14"); + + modelBuilder.Entity("xAiModels.Models.Entities.XAiConversation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("ProjectId") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AiConversations"); + }); + + modelBuilder.Entity("xAiModels.Models.Entities.XAiMessage", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Content") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ConversationId") + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("MeatDatas") + .HasColumnType("TEXT"); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("Role") + .HasColumnType("INTEGER"); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AiMessages"); + }); + + modelBuilder.Entity("xAiModels.Models.Entities.XAiProject", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("CreatedOn") + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("Description") + .HasColumnType("TEXT") + .HasMaxLength(1000); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("Prompt") + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("UpdatedAt") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("AiProjects"); + }); + + modelBuilder.Entity("xFileService.Models.Entities.XFile", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("TEXT"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("FileName") + .HasColumnType("TEXT"); + + b.Property("Name") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("OwnerId") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("Path") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("References") + .HasColumnType("TEXT"); + + b.Property("Thumb") + .HasColumnType("TEXT"); + + b.Property("ThumbPath") + .HasColumnType("TEXT"); + + b.Property("Type") + .HasColumnType("INTEGER"); + + b.Property("UploadedOn") + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Files"); + }); + + modelBuilder.Entity("xStringService.Models.Entities.XString", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("Language") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(10); + + b.Property("ResourceTitle") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.Property("TranslatedValue") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Strings"); + }); + + modelBuilder.Entity("xTagService.Models.Entities.XTag", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Deleted") + .HasColumnType("INTEGER"); + + b.Property("References") + .HasColumnType("TEXT"); + + b.Property("Tag") + .IsRequired() + .HasColumnType("TEXT") + .HasMaxLength(255); + + b.HasKey("Id"); + + b.ToTable("Tags"); + }); +#pragma warning restore 612, 618 + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Providers\XAiEmbeddingServiceBase.cs + +using System; +using System.Linq; +using OllamaSharp; +using System.Threading; +using xAiApi.Constants; +using xAiModels.Models; +using xAiApi.Extensions; +using xAiApi.Interfaces; +using OllamaSharp.Models; +using xAiService.Helpers; +using xCommons.Extensions; +using xAiModels.Extensions; +using xAiModels.Interfaces; +using xAiApi.Configurations; +using xExceptions.Constants; +using System.Threading.Tasks; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.AI; +using xAiModels.Constants; +using OpenAI; +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace xAiApi.Providers +{ + /// + /// Base Embedding Provider Service ... + /// + public abstract class XAiEmbeddingServiceBase : XAIServiceBase, IXAiEmbeddingServiceBase + { + private readonly XAiModelDescriptor descriptor; + private readonly ILogger logger; + + protected XAiEmbeddingServiceBase( + IXAiDataProvider dataProvider, + XAiApiConfiguration configuration, + ILogger logger, + string embeddingModelName = XAiApiConstants.XAiEmbeddingModelName + ) : base( + dataProvider, + logger, + configuration + ) + { + // + // Prepare Embedding Model Descriptor ... + descriptor = configuration.GetModel(embeddingModelName); + if (!descriptor.IsValid()) + { + XException.InvalidConfiguration.Throw(); + } + + // + this.logger = logger; + } + + /// + /// Embedding Specified String ... + /// + /// + /// + /// + public virtual async Task Embedding( + string content, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + if (content.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + using var generator = GetEmbeddingGenerator(); + GeneratedEmbeddings> response = null; + try + { + response = await generator.GenerateAsync([content]); + } + catch (Exception ex) + { + logger.LogError(ex.Message); + } + + // + if (response.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + // Generae Result ... + var result = response + .First()? + .Vector + .ToArray() + ?? []; + if (result.Length == 0) + { + XException.ActionFailed.Throw(); + } + + // + // Retrieve Ollama Client ... + // using var client = GetEmbeddingClient(); + + // // + // // Create Embedding Request .... + // var request = new EmbedRequest + // { + // Input = [content], + // Model = descriptor.LLM, + // }; + + // // + // // Make Request and Recieve Response ... + // var response = await client.EmbedAsync( + // request: request, + // cancellationToken: cancellationToken + // ); + // if (response.IsNullOrDefault()) + // { + // XException.ActionFailed.Throw(); + // } + + // // + // // Generae Result ... + // var result = response? + // .Embeddings? + // .FirstOrDefault() + // ?? []; + // if (result.Length == 0) + // { + // XException.ActionFailed.Throw(); + // } + + // + // Normalize ... + VectorHelper.Normalize(result); + + // + return result; + } + + /// + /// Embedding Specified Batch ... + /// + /// + /// + /// + public virtual async Task> Embeddings( + string[] batch, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + if (!batch.HasChild() || + !batch.All(x => !x.IsNullOrEmpty()) + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Ollama Client ... + using var client = GetEmbeddingClient(); + + // + // Create Embedding Request .... + var request = new EmbedRequest + { + Input = [.. batch], + Model = descriptor.LLM, + }; + + // + // Make Request and Recieve Response ... + var response = await client.EmbedAsync( + request: request, + cancellationToken: cancellationToken + ); + if (response.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + // Generae Result ... + var result = response? + .Embeddings + .ToArray() + ?? []; + + // + // Validate Result ... + if (result.Length == 0) + { + XException.ActionFailed.Throw(); + } + + // + // Normalize ... + foreach (var vector in result) + { + VectorHelper.Normalize(vector); + } + + // + return result; + } + + /// + /// Access Embedding Client ... + /// + /// + public OllamaApiClient GetEmbeddingClient() + { + // + var result = new OllamaApiClient(new Uri(descriptor.Url)); + + // + return result; + } + + public IEmbeddingGenerator> GetEmbeddingGenerator() + { + // + IEmbeddingGenerator> result = null; + + // + if (!descriptor.IsValid()) + { + XException.InvalidData.Throw("Invalid Embedding Model ..."); + } + + // + switch (descriptor.Provider) + { + // + case XAiModelProviderType.OpenAI: + // + var openAiClient = new OpenAIClient( + new ApiKeyCredential(descriptor.ApiKey.IsNullOrEmpty() ? XAiApiConstants.XOpenAINoKey : descriptor.ApiKey), + new OpenAIClientOptions + { + Endpoint = new Uri(descriptor.Url), + Transport = new HttpClientPipelineTransport(GetHttpClient(descriptor.Url)) + } + ); + result = openAiClient + .GetEmbeddingClient(descriptor.LLM) + .AsIEmbeddingGenerator(); + break; + + // + case XAiModelProviderType.Ollama: + // + var ollamaClient = new OllamaApiClient(new Uri(descriptor.Url)); + result = ollamaClient; + break; + } + + // + if (result.IsNull()) + { + XException.InvalidData.Throw("Invalid Embedding Model ..."); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Providers\XAIServiceBase.cs + +using System; +using OpenAI; +using OllamaSharp; +using System.Net.Http; +using System.Threading; +using xAiApi.Constants; +using xAiApi.Interfaces; +using xAiApi.Extensions; +using System.ClientModel; +using xCommons.Extensions; +using xAiModels.Constants; +using xAiModels.Interfaces; +using xAiModels.Extensions; +using xAiApi.Configurations; +using xExceptions.Constants; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using System.Collections.Generic; +using Microsoft.Extensions.Logging; +using System.ClientModel.Primitives; +using System.Runtime.CompilerServices; + +namespace xAiApi.Providers +{ + public abstract class XAIServiceBase : IXAiServiceBase + { + private readonly IXAiDataProvider dataProvider; + private readonly ILogger logger; + private readonly XAiApiConfiguration configuration; + + protected XAIServiceBase( + IXAiDataProvider dataProvider, + ILogger logger, + XAiApiConfiguration configuration + ) + { + this.logger = logger; + this.dataProvider = dataProvider; + this.configuration = configuration; + } + + // + #region Actions ... + /// + /// Base Method for Communicate with LLM ... + /// + /// + /// + /// + public virtual async Task AskAsync( + string prompt, + CancellationToken cancellationToken = default + ) + { + // + // Check Prompt Exists ... + if (prompt.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + using var client = GetClient(); + var history = GetHistory(prompt); + var response = await client.GetResponseAsync( + messages: history, + cancellationToken: cancellationToken + ); + + // + // Validate Response ... + if (!response.IsValid()) + { + // + // Dispose Client ... + client.Dispose(); + XException.ActionFailed.Throw(); + } + + // + // Retrieve Response Text ... + var result = response.Text; + + // + // Dispose Client ... + client.Dispose(); + + // + return result; + } + + /// + /// Base Method for Communicate with LLM ... + /// + /// + /// + /// + public virtual async IAsyncEnumerable AskAsEnumerable( + string prompt, + [EnumeratorCancellation] + CancellationToken cancellationToken = default + ) + { + // + // Check Prompt Exists ... + if (prompt.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + using var client = GetClient(); + var history = GetHistory(prompt); + var enumerable = client.GetStreamingResponseAsync( + options: null, + messages: history + ); + + // + var result = ""; + await foreach (var res in enumerable) + { + // + // Cancellation Token ... + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + result += res.Text; + } + + // + // Dispose Client ... + client.Dispose(); + + // + yield return result; + } + + /// + /// Get LLM Client instance for Communicating with LLM ... + /// + /// + /// + public virtual IChatClient GetClient(string llm = null) + { + // + // Retrieve Model Descriptor ... + var modelDescriptor = configuration.GetModel(llm); + if (modelDescriptor.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Try to Initialize LLm ... + var model = modelDescriptor.LLM; + var apiKey = modelDescriptor.ApiKey; + var url = new Uri(modelDescriptor.Url); + var httpClient = GetHttpClient(modelDescriptor.Url); + + // + IChatClient result = null; + switch (modelDescriptor.Provider) + { + // + case XAiModelProviderType.Ollama: + // + // Instance Ollama Client using Custom HttpCLient ... + var ollamaClient = new OllamaApiClient(httpClient, model); + result = + new ChatClientBuilder(ollamaClient) + .Build(); + break; + + // + case XAiModelProviderType.OpenAI: + // + // Instance Ollama Client using Custom HttpCLient ... + var openAiClient = new OpenAIClient( + new ApiKeyCredential(apiKey.IsNullOrEmpty() ? XAiApiConstants.XOpenAINoKey : apiKey), + new OpenAIClientOptions + { + Endpoint = url, + Transport = new HttpClientPipelineTransport(httpClient) + } + ); + result = + openAiClient + .GetChatClient(model) + .AsIChatClient(); + break; + + // + case XAiModelProviderType.DeepSeek: + break; + + // + case XAiModelProviderType.HuggingFace: + break; + + // + default: + break; + } + + // // + // if (isOllamaBased) + // { + // } + // else if (isDeepSeekBased) + // { + // // + // if (apiKey is null || + // string.IsNullOrWhiteSpace(apiKey)) + // { + // throw new Exception("Inavlid Args ..."); + // } + + // // + // var deepseekClient = new DeepSeekChatClient(apiKey: apiKey); + // result = deepseekClient; + // } + // else + // { + // // + // // TODO: Implement this ... + // } + + // + if (result.IsNullOrDefault()) + { + XException.InvalidData.Throw(); + } + + // + return result; + } + + /// + /// Create Custom HttpClient for Communicating with LLM API ... + /// + /// + /// + public virtual HttpClient GetHttpClient(string url = null) + { + // + var result = new HttpClient + { + // + // Disable timeout completely (not recommended for production) + Timeout = Timeout.InfiniteTimeSpan, + + // + BaseAddress = url.IsNullOrEmpty() + ? null + : new Uri(url), + + // + // OR set a very long timeout (e.g., 30 minutes for large file uploads) + // Timeout = TimeSpan.FromMinutes(30) + }; + + // + return result; + } + + /// + /// Prepare a Message History List for LLM Communication based on Prompt ... + /// + /// + /// + /// + public virtual IList GetHistory( + string prompt = null, + bool forcePrompt = true + ) + { + // + // Validate Args ... + if (prompt.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // User Prompt ... + var promptMessage = new ChatMessage( + ChatRole.User, + prompt + ); + + // + // Preparing Introduction Prompt ... + var introductionPrompt = new ChatMessage( + ChatRole.System, + configuration.GetPrompt() + ); + + // + List result = + [ + introductionPrompt, + ]; + if (forcePrompt && + prompt is not null && + !string.IsNullOrWhiteSpace(prompt)) + { + result.Add(promptMessage); + } + + // + return result; + } + + /// + /// Prepare a Message History List for LLM Communication based on Prompt ... + /// + /// + /// + /// + public virtual IList GetHistory( + ChatMessage message = null, + bool forceMessage = true + ) + { + // + // Preparing Introduction Prompt ... + var introductionPrompt = new ChatMessage( + ChatRole.System, + configuration.GetPrompt() + ); + + // + List result = + [ + introductionPrompt, + ]; + if (forceMessage && + message is not null) + { + result.Add(message); + } + + // + return result; + } + #endregion + + /// + /// Base Dispose Action ... + /// + /// + public virtual void Dispose() + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Providers\XDefaultAiService.cs + +using Microsoft.Extensions.Logging; +using xAiApi.Configurations; +using xAiApi.Interfaces; +using xAiModels.Interfaces; + +namespace xAiApi.Providers +{ + public class XDefaultAiService : XAIServiceBase, IXDefaultAiService + { + public XDefaultAiService( + IXAiDataProvider dataProvider, + ILogger logger, + XAiApiConfiguration configuration + ) : base( + dataProvider, + logger, + configuration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\xAiApi\Providers\XDefaultEmbeddingService.cs + +using Microsoft.Extensions.Logging; +using xAiApi.Configurations; +using xAiApi.Interfaces; +using xAiModels.Interfaces; + +namespace xAiApi.Providers +{ + public class XDefaultEmbeddingService : XAiEmbeddingServiceBase, IXDefaultEmbeddingService + { + public XDefaultEmbeddingService( + IXAiDataProvider dataProvider, + XAiApiConfiguration configuration, + ILogger logger + ) : base( + dataProvider, + configuration, + logger + ) + { } + } +} diff --git a/Documents/GeneratedContext/xDashboard-xAiModels-20260926_085159.txt b/Documents/GeneratedContext/xDashboard-xAiModels-20260926_085159.txt new file mode 100644 index 0000000..b4bb10a --- /dev/null +++ b/Documents/GeneratedContext/xDashboard-xAiModels-20260926_085159.txt @@ -0,0 +1,7423 @@ + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\XAiApiConfiguration.cs + +using xAiModels.Models; +using xAiModels.Constants; + +namespace xAiModels.Configurations +{ + public class XAiApiConfiguration + { + /// + /// Model Providers ... + /// + public XAiModelDescriptor[] Models { get; set; } = []; + + /// + /// Each User must Has a Default Project, this is Title Resource Identifier ... + /// + public string DefaultProjectTitleResource { get; set; } = XAiModelsConstants.DefaultXAiProjectTitleResourceID; + + /// + /// Each User must Has a Default Project, this is Description Resource Identifier ... + /// + public string DefaultProjectDescriptionResource { get; set; } = XAiModelsConstants.DefaultXAiProjectDescriptionResourceID; + + /// + /// Each User must Has a Default Conversation, this is Title Resource Identifier ... ... + /// + public string DefaultConversationTitleResource { get; set; } = XAiModelsConstants.DefaultXAiConversationTitleResourceID; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\XAiModelMappersProfile.cs + +using AutoMapper; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Configurations +{ + public class XAiModelMappersProfile : Profile + { + public XAiModelMappersProfile() + { + // + // XAiMessage ... + CreateMap(); + + // + // XAiProject ... + CreateMap(); + + // + // XAiConversation ... + CreateMap(); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiConversationEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiConversationEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiConversationTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiMessageEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiMessageEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiMessageTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiProjectEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiProjectEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiProjectTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\ConfigurationNodeNames.cs + +namespace xAiModels.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiApiConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiChatRole.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiChatRoles + { + public const string None = "none"; + public const string User = "user"; + public const string Tool = "tool"; + public const string System = "system"; + public const string Assistant = "assistant"; + } + + public enum XAiChatRole + { + [StringValue(XAiChatRoles.None)] + None, + [StringValue(XAiChatRoles.User)] + User, + [StringValue(XAiChatRoles.Tool)] + Tool, + [StringValue(XAiChatRoles.System)] + System, + [StringValue(XAiChatRoles.Assistant)] + Assistant, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiDataProviderConstants.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiDataProviderConstants + { + public const string XDefaultAiProjectSuffix = "DefAiPrj"; + public const string XDefaultAiConversationSuffix = "DefAiCnv"; + } + + public enum XAiDataProviderHubActions + { + // + // Project ... + [StringValue("ProjectCreated")] + ProjectCreated, + + [StringValue("ProjectUpdated")] + ProjectUpdated, + + [StringValue("ProjectRemoved")] + ProjectRemoved, + + // + // Conversation ... + [StringValue("ConversationCreated")] + ConversationCreated, + + [StringValue("ConversationUpdated")] + ConversationUpdated, + + [StringValue("ConversationRemoved")] + ConversationRemoved, + + // + // Message ... + [StringValue("MessageCreated")] + MessageCreated, + + [StringValue("MessageUpdated")] + MessageUpdated, + + [StringValue("MessageRemoved")] + MessageRemoved, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiModelProviderType.cs + +namespace xAiModels.Constants +{ + /// + /// Specifiy Provider Type ... + /// + public enum XAiModelProviderType + { + None, + OpenAI, + Ollama, + DeepSeek, + HuggingFace + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiModelsConstants.cs + +namespace xAiModels.Constants +{ + public struct XAiModelsConstants + { + // + // Service Extensions Log Tag ... + public const string XAiModelsDILogTag = "XAiModels"; + + // + // Table Mapping Identifiers ... + public const string XAiMessageTable = "AiMessages"; + public const string XAiProjectTable = "AiProjects"; + public const string XAiConversationTable = "AiConversations"; + + // + // GraphQL Collection Mappings ... + public const string XAiMessageSingleName = "aiMessage"; + public const string XAiProjectSingleName = "aiProject"; + public const string XAiConversationSignleName = "aiConversation"; + + public const string XAiMessageCollectionName = "aiMessages"; + public const string XAiProjectCollectionName = "AiProjectsa"; + public const string XAiConversationCollectionName = "aiConversations"; + + // + // Hubs ... + public const string XAiMessageDtoHub = "aiMessageDto"; + public const string XAiMessageEntityHub = "aiMessageEntity"; + + public const string XAiProjectDtoHub = "aiProjectDto"; + public const string XAiProjectEntityHub = "aiProjectEntity"; + + public const string XAiConversationDtoHub = "aiConversationDto"; + public const string XAiConversationEntityHub = "aiConversationEntity"; + + // + // Resource Provider Identifiers ... + public const string XAiProjectTitleIdentifier = "AiPrjT"; + public const string XAiProjectDescriptionIdentifier = "AiPrjD"; + public const string XAiConversationTitleIdentifier = "AiCnvrT"; + + // + // EF Repositories Helper Extensions ... + public const string GetXAiMessageEFRepositoryDescriptor = "GetXAiMessageEFRepositoryDescriptor"; + public const string GetXAiProjectEFRepositoryDescriptor = "GetXAiProjectEFRepositoryDescriptor"; + public const string GetXAiConversationEFRepositoryDescriptor = "GetXAiConversationEFRepositoryDescriptor"; + + // + public const string DefaultXAiProjectTitleResourceID = "XAiPrjT"; + public const string DefaultXAiConversationTitleResourceID = "XAiCnvT"; + public const string DefaultXAiProjectDescriptionResourceID = "XAiPrjD"; + + // + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\DI\XDIHelperExtension.cs + +using System; +using xDataService.Db; +using xPushService.DI; +using xDataService.DI; +using xCommons.Helpers; +using xAiModels.Helpers; +using xDataService.Models; +using xAiModels.Providers; +using xAiModels.Constants; +using xCommons.Extensions; +using xPushService.Helpers; +using xAiModels.Interfaces; +using xExceptions.Constants; +using xDataService.Constants; +using xAiModels.Providers.Dtos; +using xAiModels.Interfaces.Dtos; +using Microsoft.AspNetCore.Builder; +using xAiModels.Providers.Entities; +using xAiModels.Interfaces.Entities; +using xAiModels.Providers.Enrichers; +using xAiModels.Interfaces.Enrichers; +using Microsoft.Extensions.DependencyInjection; + +namespace xAiModels.DI +{ + /// + /// Service Registration Extensions Classes ... + /// + public static class XDIHelperExtension + { + /// + /// Register Service ... + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + AddAiDataService( + contextType: null, + services: services, + lifeTime: lifeTime, + repositoryType: repositoryType + ); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + where TContext : XDbContext + { + AddAiDataService( + services: services, + lifeTime: lifeTime, + contextType: typeof(TContext), + repositoryType: repositoryType + ); + } + + /// + /// Use XSubCategoryService Middleware ... + /// + /// + /// + public static void UseXAiDataService( + this IApplicationBuilder app, + bool isDevelopmentEnvironment = false + ) + { + // + #region Using Hubs ... + // + var pushHelper = new XPushServiceHelper(); + + // + // XAiMessage ... + pushHelper.AddHub(XAiModelsConstants.XAiMessageDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiMessageEntityHub); + + // + // XAiProject ... + pushHelper.AddHub(XAiModelsConstants.XAiProjectDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiProjectEntityHub); + + // + // XAiConversation ... + pushHelper.AddHub(XAiModelsConstants.XAiConversationDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiConversationEntityHub); + + // + app.UseXPushService(pushHelper); + #endregion + + // + // Using XAiConversation Repository Descriptor ... + if (!aiConversationDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiConversationDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiMessage Repository Descriptor ... + if (!aiMessageDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiMessageDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiProject Repository Descriptor ... + if (!aiProjectDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiProjectDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Create an Scope for Services Acces ... + // Handle Seeding Category/SubCategory Resources ... + // TODO: Enable Seeding if Required ... + // using (var scope = app.ApplicationServices.CreateScope()) + // { + // // + // // Retrieve Configuratuions ... + // var aiMessageProvider = scope.ServiceProvider.GetService(); + // var aiProjectProvider = scope.ServiceProvider.GetService(); + // var aiConversationProvider = scope.ServiceProvider.GetService(); + // var configuration = scope.ServiceProvider.GetService(); + // if (!configuration.IsNullOrDefault() && + // !categoryProvider.IsNullOrDefault() && + // !subaiConversationDescriptor.IsNullOrDefault() + // ) + // { + // // + // // Logging ... + // Log("Start Seeding ..."); + + // // + // // Count Data in Category ... + // var hasCategory = (categoryProvider.Count().GetAwaiter().GetResult()) > 0; + // var hasSubCategory = (subCategoryProvider.Count().GetAwaiter().GetResult()) > 0; + + // // + // // Seed Category Resources ... + // var canSeed = + // !hasCategory && + // configuration.Categories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var cat in configuration.Categories) + // { + // // + // try + // { + // // + // Log($"Start Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // categoryProvider.Refresh( + // resource: cat, + // userInfo: null, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // // Seed SubCategory Resources ... + // canSeed = + // !hasSubCategory && + // configuration.SubCategories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var subcat in configuration.SubCategories) + // { + // // + // try + // { + // // + // Log($"Start Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // subCategoryProvider.Refresh( + // userInfo: null, + // resource: subcat, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // Log("Finish Seeding ..."); + // } + // } + } + + // + #region Private ... + private static XRepositoryDescriptor aiMessageDescriptor = null; + private static XRepositoryDescriptor aiProjectDescriptor = null; + private static XRepositoryDescriptor aiConversationDescriptor = null; + + /// + /// a LogTag for Service ... + /// + private static string XLogTag = XAiModelsConstants.XAiModelsDILogTag; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + private static void AddAiDataService( + IServiceCollection services, + XRepositoryType repositoryType, + Type contextType = null, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("Service Registration failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("Service Registration failed, lifetime not provided ..."); + throw exception; + } + + // + // Validate Repository Type ... + var isRepositoryTypeValid = + (repositoryType == XRepositoryType.EF && + !contextType.IsNull()) || + ((repositoryType == XRepositoryType.Mongo || + repositoryType == XRepositoryType.InMemory) && + contextType.IsNull()); + if (!isRepositoryTypeValid) + { + // + Log("Service Registration failed, Invalid Repository Type and Context Type ..."); + throw exception; + } + + // + // Maske Instance of Repository Descriptor + // Based on Provided Type ... + switch (repositoryType) + { + // + case XRepositoryType.EF: + // + // XAiMessage ... + aiMessageDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiMessageEFRepositoryDescriptor + ); + + // + // XAiProject ... + aiProjectDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiProjectEFRepositoryDescriptor + ); + + // + // XAiConversation ... + aiConversationDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiConversationEFRepositoryDescriptor + ); + break; + + // + case XRepositoryType.Mongo: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageMongoRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectMongoRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationMongoRepositoryDescriptor(); + break; + + // + case XRepositoryType.InMemory: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageInMemoryRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectInMemoryRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationInMemoryRepositoryDescriptor(); + break; + } + + // + #region Register Repository Descriptor ... + // + // XAiMessage ... + if (!aiMessageDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiMessageDescriptor + ); + } + + // + // XAiProject ... + if (!aiProjectDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiProjectDescriptor + ); + } + + // + // XAiConversation ... + if (!aiConversationDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiConversationDescriptor + ); + } + #endregion + + // + #region Register Services ... + // + #region AiMessage ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiMessageServiceProvider), typeof(XAiMessageServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryService), typeof(XAiMessageRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryProvider), typeof(XAiMessageRepositoryProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiMessageEnricher), typeof(XAiMessageEnricher), lifeTime) + ); + #endregion + + // + #region AiProject ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiProjectServiceProvider), typeof(XAiProjectServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryService), typeof(XAiProjectRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryProvider), typeof(XAiProjectRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectTitleResourceProvider), typeof(XAiProjectTitleResourceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectDescriptionResourceProvider), typeof(XAiProjectDescriptionResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectEnricher), typeof(XAiProjectEnricher), lifeTime) + ); + #endregion + + // + #region AiConversation ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiConversationServiceProvider), typeof(XAiConversationServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryService), typeof(XAiConversationRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryProvider), typeof(XAiConversationRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationTitleResourceProvider), typeof(XAiConversationTitleResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationEnricher), typeof(XAiConversationEnricher), lifeTime) + ); + #endregion + #endregion + + // + // Data Provider ... + services.Add( + new ServiceDescriptor(typeof(IXAiDataProvider), typeof(XAiDataProvider), lifeTime) + ); + + // + Log("Service Regitration Succeed ..."); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\ChatResponseExtensions.cs + +using xCommons.Extensions; +using Microsoft.Extensions.AI; + +namespace xAiModels.Extensions +{ + public static class ChatResponseExtensions + { + /// + /// Validate a Chat Response ... + /// + /// + /// + public static bool IsValid(this ChatResponse source) + { + // + var result = + source is not null && + !source.IsNullOrDefault() && + !string.IsNullOrWhiteSpace(source.Text) && + source.FinishReason == ChatFinishReason.Stop; + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\ChatRoleExtensions.cs + +using xAiModels.Constants; +using xCommons.Extensions; +using Microsoft.Extensions.AI; + +namespace xAiModels.Extensions +{ + /// + /// Extensions for ChatRole ... + /// + public static class ChatRoleExtensions + { + /// + /// Normalize an String to Propper Chat Role Value ... + /// > + /// + /// + /// + public static string GetChatRoleTitle(this string source) + { + // + var result = XAiChatRoles.None; + + // + if (source.ToNormalString() == XAiChatRoles.None.ToNormalString()) + { + result = XAiChatRoles.None; + } + else if (source.ToNormalString() == XAiChatRoles.User.ToNormalString()) + { + result = XAiChatRoles.User; + } + else if (source.ToNormalString() == XAiChatRoles.Tool.ToNormalString()) + { + result = XAiChatRoles.Tool; + } + else if (source.ToNormalString() == XAiChatRoles.System.ToNormalString()) + { + result = XAiChatRoles.System; + } + else if (source.ToNormalString() == XAiChatRoles.Assistant.ToNormalString()) + { + result = XAiChatRoles.Assistant; + } + + // + return result; + } + + /// + /// Get Chat Role Title from Chat Role Class ... + /// + /// + /// + /// + public static string GetRole(this ChatRole source) + { + // + var result = source.Value + .GetChatRoleTitle(); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this string source) + { + // + var role = source.GetChatRoleTitle(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this XAiChatRole source) + { + // + var role = source.GetStringValue(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Extract Chat Role Enum from Chat Role ... + /// + /// + /// + /// + /// + public static XAiChatRole ToChatRole(this ChatRole source) + { + // + var role = source + .GetRole() + .GetChatRoleTitle(); + + // + XAiChatRole result = XAiChatRole.User; + + // + if (role == XAiChatRoles.User) + { + result = XAiChatRole.User; + } + else if (role == XAiChatRoles.Tool) + { + result = XAiChatRole.Tool; + } + else if (role == XAiChatRoles.System) + { + result = XAiChatRole.System; + } + else if (role == XAiChatRoles.Assistant) + { + result = XAiChatRole.Assistant; + } + + // + return result; + } + + /// + /// Validate an String as Chat Role ... + /// + /// + /// + public static bool IsValid(this string source) + { + // + var result = + source != XAiChatRoles.None && + source.ToNormalString() != XAiChatRoles.None.ToNormalString(); + + // + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this XAiChatRole source) + { + // + var result = source != XAiChatRole.None; + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this ChatRole source) + { + // + var role = source.ToChatRole(); + var result = role.IsValid(); + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\XAiApiConfigurationExtensions.cs + +using System.Linq; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Configurations; + +namespace xAiModels.Extensions +{ + public static class XAiApiConfigurationExtensions + { + /// + /// Validate Api Configuration ... + /// + /// + /// + public static bool IsValid(this XAiApiConfiguration source) + { + return + !source.IsNullOrDefault() && + source.Models.HasChild(); + } + + /// + /// Retrieve Default Model Descriptor ... + /// + /// + /// + public static XAiModelDescriptor GetDefaultModel(this XAiApiConfiguration source) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + result = source.Models.First(); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\XAiModelsExtensions.cs + +using System.Linq; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Extensions +{ + /// + /// Extensions Methods for XAiModels ... + /// + public static class XAiModelsExtensions + { + /// + /// Validate a Project for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiProject source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiProjectDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Conversation for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiConversation source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiConversationDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + + /// + /// Validate a Message for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiMessage source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiMessageDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Model Descriptor ... + /// + /// + /// + public static bool IsValid(this XAiModelDescriptor source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Url.IsNullOrEmpty() && + source.Url.IsValidUrl() && + !source.LLM.IsNullOrEmpty() && + source.Provider != Constants.XAiModelProviderType.None; + + // + return result; + } + + /// + /// Validate Specified Param ... + /// + /// + /// + public static bool IsValid(this XAiPromptParam source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Param.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate Specified Prompt ... + /// + /// + /// + public static bool IsValid(this XAiPromptDescriptor source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Template.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + if (source.Params.HasChild()) + { + result = + result && + source.Params.All(x => x.IsValid()); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Helpers\XAiModelsHelper.cs + +using System; +using GraphQL.Types; +using xDataService.Db; +using xDataService.Models; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Providers.GraphQL; +using xAiModels.Providers.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Helpers +{ + public static class XAiModelsHelper + { + // + #region XAiConversation ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + > GetXAiConversationMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + > GetXAiConversationInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiMessage ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + > GetXAiMessageMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + > GetXAiMessageInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiProject ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + > GetXAiProjectMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + > GetXAiProjectInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiConversationTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiConversationTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiDataProvider.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace xAiModels.Interfaces +{ + /// + /// All Data Manipulation Requirements ... + /// + public interface IXAiDataProvider + { + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Creator/Adders ... + /// + /// Create Project ... + /// + /// + /// + /// + /// + /// + Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Create Conversation ... + /// + /// + /// + /// + /// + /// + Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Message ... + /// + /// + /// + /// + /// + /// + Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiProjectDescriptionResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectDescriptionResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiProjectTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiConversationEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + /// + /// Ai Conversation Enricher ... + /// + public interface IXAiConversationEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiMessageEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiMessageEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiProjectEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiProjectEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiDocumentEntityHub.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiDocumentEntityHub + { + + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\XAiModelDescriptor.cs + +using xAiModels.Constants; + +namespace xAiModels.Models +{ + /// + /// Describe a Provided Model ... + /// + public class XAiModelDescriptor + { + /// + /// Provider Name ... + /// + public string Name { get; set; } + + /// + /// LLM Provider Url ... + /// + public string Url { get; set; } + + /// + /// Model Name ... + /// + public string LLM { get; set; } + + /// + /// Api Key for Connection ... + /// + public string ApiKey { get; set; } + + /// + /// Specified Model Provider Type ... + /// + public XAiModelProviderType Provider { get; set; } = XAiModelProviderType.Ollama; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\XAiPromptDescriptor.cs + +namespace xAiModels.Models +{ + /// + /// Describe Specified Prompt ... + /// + public class XAiPromptDescriptor + { + /// + /// Prompt Name ... + /// + public string Name { get; set; } + + /// + /// Prompt Template ... + /// + public string Template { get; set; } + + /// + /// Prompt Description ... + /// + public string Description { get; set; } + + /// + /// Prompt Template Params ... + /// + public XAiPromptParam[] Params { get; set; } = []; + } + + /// + /// Specified a Prompt Param ... + /// + public class XAiPromptParam + { + /// + /// Param Name ... + /// + public string Name { get; set; } + + /// + /// Param Identifier ... + /// + public string Param { get; set; } + + /// + /// Parma Description ... + /// + public string Description { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiConversationDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using System.Collections.Generic; + +namespace xAiModels.Models.Dtos +{ + /// + /// Conversation Describe ... + /// + public class XAiConversationDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Conversation Title Resource ID ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Messages ... + /// + public virtual IEnumerable Messages { get; set; } = []; + + /// + /// Project ID ... + /// + public Guid ProjectId { get; set; } + + /// + /// Project Title Resource ID ... + /// + public virtual string ProjectTitle { get; set; } = null; + + /// + /// Project Description Resource ID ... + /// + public virtual string ProjectDescription { get; set; } = null; + + /// + /// Project Title Locale Resources ... + /// + public virtual XResourceDto ProjectTitleResource { get; set; } + + /// + /// Project Description Locale Resources ... + /// + public virtual XResourceDto ProjectDescriptionResource { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiMessageDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using xAiModels.Constants; +using xCommons.Extensions; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace xAiModels.Models.Dtos +{ + public class XAiMessageDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Message of Chat ... + /// + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + public Guid ConversationId { get; set; } + + /// + /// Conversation Info ... + /// + public virtual string ConversationTitle { get; set; } = null; + public virtual XResourceDto ConversationTitleResouce { get; set; } = null; + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MetaDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiProjectDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using System.Collections.Generic; + +namespace xAiModels.Models.Dtos +{ + /// + /// Describe a Project ... + /// + public class XAiProjectDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Title of Project ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Description of Project ... + /// + public string Description { get; set; } + + /// + /// All Exists Description Locale Resources ... + /// + public virtual XResourceDto DescriptionResource { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversations ... + /// + public virtual IList Conversations { get; set; } = []; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiConversation.cs + +using System; +using xModels.Base; +using System.ComponentModel.DataAnnotations; + +namespace xAiModels.Models.Entities +{ + /// + /// Conversation Describe ... + /// + public class XAiConversation : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Conversation ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Project ID ... + /// + [Required] + public Guid ProjectId { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiDocument.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Represents an embedd document in the AI system. + /// + public class XAiDocument : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Document ... + /// + [StringLength(255)] + public string Title { get; set; } + + /// + /// Content of Document ... + /// + public string Content { get; set; } + + /// + /// Hash of the Document Content ... + /// + public string ContentHash { get; set; } = string.Empty; + + /// + /// Embedding Model Identifier ... + /// + public string EmbeddingModel { get; set; } = string.Empty; + + /// + /// Dimensions of the Embedding ... + /// + public int Dimensions { get; set; } + + /// + /// Vector representation of the Document ... + /// + public byte[] Vector { get; set; } = []; + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiMessage.cs + +using System; +using xModels.Base; +using xAiModels.Constants; +using xCommons.Extensions; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace xAiModels.Models.Entities +{ + /// + /// Message Model of Ai ... + /// + public class XAiMessage : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Message of Chat ... + /// + [Required] + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + [StringLength(255)] + public Guid ConversationId { get; set; } + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MetaDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiProject.cs + +using System; +using xModels.Base; +using System.ComponentModel.DataAnnotations; + +namespace xAiModels.Models.Entities +{ + /// + /// Describe a Project ... + /// + public class XAiProject : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Project ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Description of Project ... + /// + [StringLength(1000)] + public string Description { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiConversationEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiConversationEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiConversationEntityRegisterar() + : base(nameof(XAiConversationEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiConversationEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiConversationTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiConversationTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiConversationTitleResourceProvider + { + public XAiConversationTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiConversationTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiDataProvider.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xAiModels.Constants; +using xCommons.Extensions; +using xAiModels.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using xExceptions.Constants; +using System.Threading.Tasks; +using xCommons.Configurations; +using xAiModels.Providers.Hubs; +using xAiModels.Interfaces.Dtos; +using xStringService.Interfaces; +using System.Collections.Generic; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers +{ + /// + /// All Data Manipulation Requirements ... + /// + public class XAiDataProvider : IXAiDataProvider + { + // + #region Properties ... + private readonly IXStringProvider stringProvider; + private readonly XAppConfiguration appConfiguration; + private readonly IHubContext hub; + private readonly IXAiMessageRepositoryService messageRepositoryService; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + #endregion + + public XAiDataProvider( + IXStringProvider stringProvider, + XAppConfiguration appConfiguration, + IHubContext hub, + IXAiMessageRepositoryService messageRepositoryService, + IXAiProjectRepositoryService projectRepositoryService, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationRepositoryService conversationRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + this.hub = hub; + this.stringProvider = stringProvider; + this.appConfiguration = appConfiguration; + this.messageRepositoryService = messageRepositoryService; + this.projectRepositoryService = projectRepositoryService; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationRepositoryService = conversationRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + public async Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Default Project and Conversation ... + bool hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (!hasDefault) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: null, + cancellationToken: cancellationToken + ); + } + + // + // Retrieve Project List ... + var result = await projectRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: fillConversations, + predicate: x => x.OwnerId == ownerId, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + // fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + public async Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Conversation's List ... + var result = await conversationRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: false, + // fillMessages: fillMessages, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == projectId, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + return result; + } + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + public async Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Message Lists of Specified Conversation ... + var result = await messageRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversationId + ); + + // + return result; + } + #endregion + + // + #region Creator/Adders ... + public async Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Project Provided or not ... + var hasProject = !item.IsNullOrDefault(); + + // + // Normalize Provided Project ... + if (hasProject) + { + // + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiProjectDto result = null; + + // + // Create Provided Project ... + if (hasProject) + { + // + result = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + // + // Check Default Project ... + else + { + // + // Check Default Project Exists or not ... + var hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Project ... + result = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Proejct ... + XAiProjectDto project = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Conversation Provided or not ... + var hasConversation = !item.IsNullOrDefault(); + + // + // Normalize Conversation if Provided ... + if (hasConversation) + { + // + item.ProjectId = project.Id; + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiConversationDto result = null; + + // + // Create Provided Conversation ... + if (hasConversation) + { + // + result = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + // fillMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + // + // Check Default Conversation ... + else + { + // + // Check Default Conversation Exists or not ... + var hasDefault = await HasDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Conversation ... + result = await GetDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (item.IsNullOrDefault() || + conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + item.CreatedOn = DateTime.UtcNow; + item.ConversationId = conversationId; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + + // + var result = await messageRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.MessageCreated.GetStringValue() + ); + } + + // + return result; + } + #endregion + + // + #region Updaters ... + #endregion + + // + #region Private ... + /// + /// Check Default Project Exists or not ... + /// + /// + /// + /// + /// + private async Task HasDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Default Owner Exists or not ... + result = !(await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + )) + .IsNullOrDefault(); + return result; + } + + /// + /// Retrieve Default Project of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + private async Task GetDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Default Project Exists or noit ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var result = await projectRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Create Default Project for Specified Owner ... + /// + /// + /// + /// + /// + private async Task CreateDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + if (ownerId.IsNullOrEmpty()) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Check Default Owner Exists or not ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (isExists) + { + return; + } + + // + // Create Default ... + var item = new XAiProjectDto() + { + OwnerId = ownerId, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString(), + Description = Guid.NewGuid().ToString(), + }; + item = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Tile and Description Resource Ids ... + var titleResource = await projectTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + var descriptionResource = await projectDescriptionResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault() || + descriptionResource.IsNullOrDefault() + ) + { + return; + } + + // + // Update Project Resources ... + item.Title = titleResource.Resource; + item.Description = descriptionResource.Resource; + item = await projectRepositoryService.UpdateAsync( + id: item.Id, + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task HasDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiConversationTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiConversationSuffix) + ); + result = !resource.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + result = !(await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => + x.ProjectId == projectId && + x.Title == resource.ResourceTitle + )) + .IsNullOrDefault(); + + // + return result; + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task CreateDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var isValid = !ownerId.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + isValid = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + cancellationToken: cancellationToken + ); + if (isValid) + { + return; + } + + // + // Create Default Conversation ... + var item = new XAiConversationDto + { + OwnerId = ownerId, + ProjectId = project.Id, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString() + }; + item = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Title Resource Ids ... + var titleResource = await conversationTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiConversationSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault()) + { + return; + } + + // + // Update Conversation Resources ... + item.Title = titleResource.Resource; + item = await conversationRepositoryService.UpdateAsync( + item: item, + id: item.Id, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + + /// + /// Retrieve Default Conversation of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + /// + private async Task GetDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Conversation Exists or noit ... + var isExists = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Detect Conversation Resource ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Find Default Conversation ... + var result = await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) && + x.ProjectId == project.Id + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Normalize and Validate Language ... + /// + /// + /// + private string NormalizeAndValidateLanguage(string language) + { + // + if (language.IsNullOrEmpty()) + { + language = appConfiguration.DefaultLanguage; + } + + // + if (language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + return language; + } + + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + public async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Collect Allowed Actions ... + var actions = new List + { + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + }; + + // + // Validate Args ... + var isValid = + !action.IsNullOrEmpty() && + actions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve Connection Id ... + var clients = hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = hub.Clients.AllExcept(connectionId); + } + + // + await clients.SendAsync( + action, + payLoad, + connectionId, + cancellationToken + ); + } + catch { } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiMessageEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiMessageEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiMessageEntityRegisterar() + : base(nameof(XAiMessageEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiMessageEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectDescriptionResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiProjectDescriptionResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectDescriptionResourceProvider + { + public XAiProjectDescriptionResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectDescriptionIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiProjectEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiProjectEntityRegisterar() + : base(nameof(XAiProjectEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiProjectEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiProjectTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectTitleResourceProvider + { + public XAiProjectTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationDtoHub : XBaseDtoHub, IXAiConversationDtoHub + { + public XAiConversationDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationRepositoryService : XBaseRepositoryService, IXAiConversationRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepository repository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiConversationRepositoryService( + IXIdentityProvider identityProvider, + IXAiConversationRepository repository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.repository = repository; + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title Resource ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + XResourceDto projectTitleResource = null; + XResourceDto projectDescriptionResource = null; + if (!source.ProjectId.IsDefaultGuid()) + { + // + projectTitleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + + // + projectDescriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.ProjectTitleResource)] = projectTitleResource; + options.Items[nameof(source.ProjectDescriptionResource)] = projectDescriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationServiceProvider : XBaseDtoProvider, IXAiConversationServiceProvider + { + public XAiConversationServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiConversationRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageDtoHub : XBaseDtoHub, IXAiMessageDtoHub + { + public XAiMessageDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageRepositoryService : XBaseRepositoryService, IXAiMessageRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiMessageRepositoryService( + IXAiMessageRepository repository, + IXIdentityProvider identityProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.identityProvider = identityProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Conversation Title ... + string conversationTitle = string.Empty; + XResourceDto conversationTitleResource = null; + if (!source.ConversationId.IsDefaultGuid()) + { + // + conversationTitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ConversationId, + cancellationToken: cancellationToken + ); + if (!conversationTitleResource.IsNullOrDefault()) + { + conversationTitle = conversationTitleResource.Resource; + } + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.ConversationTitle)] = conversationTitle; + options.Items[nameof(source.ConversationTitleResouce)] = conversationTitleResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageServiceProvider : XBaseDtoProvider, IXAiMessageServiceProvider + { + public XAiMessageServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiMessageRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectDtoHub : XBaseDtoHub, IXAiProjectDtoHub + { + public XAiProjectDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectRepositoryService : XBaseRepositoryService, IXAiProjectRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiMessageRepository messageRepository; + private readonly IXAiConversationRepository conversationRepository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectRepositoryService( + IXAiProjectRepository repository, + IXIdentityProvider identityProvider, + IXAiMessageRepository messageRepository, + IXAiConversationRepository conversationRepository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + // + this.identityProvider = identityProvider; + this.messageRepository = messageRepository; + this.conversationRepository = conversationRepository; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Description ... + XResourceDto descriptionResource = null; + if (!source.Description.IsNullOrEmpty()) + { + // + descriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Conversations ... + IEnumerable conversations = []; + if (fillConversations) + { + // + // Reading Entities ... + var entitiies = await conversationRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == source.Id, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + // Converts to Dto Enumerable ... + conversations = entitiies + .MapConvert(); + + // + // Handle Conversation Enrichment ... + foreach (var conversation in conversations) + { + // + // Handle Owner ... + if (!conversation.OwnerId.IsNullOrEmpty()) + { + conversation.Owner = owner; + } + + // + // Handle Title Resource ... + if (!conversation.Title.IsNullOrEmpty()) + { + // + conversation.TitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: conversation.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + if (!conversation.ProjectId.IsDefaultGuid()) + { + conversation.ProjectTitle = source.Title; + conversation.ProjectTitleResource = titleResource; + conversation.ProjectDescription = source.Description; + conversation.ProjectDescriptionResource = descriptionResource; + } + } + + // + // Handle Fill Messages ... + if (fillConversationMessages) + { + // + foreach (var conversation in conversations) + { + // + IEnumerable messages = []; + + // + // Retrieve Message Entities ... + var messageEntities = await messageRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversation.Id + ); + if (messageEntities.HasChild()) + { + // + // Converts to Message ... + messages = messageEntities + .MapConvert(); + + // + // Ennrich Messages ... + foreach (var message in messages) + { + // + // Handle Owner ... + if (!message.OwnerId.IsNullOrEmpty()) + { + message.Owner = owner; + } + + // + // Handle Conversation ... + if (!message.ConversationId.IsDefaultGuid()) + { + message.ConversationTitle = conversation.Title; + message.ConversationTitleResouce = conversation.TitleResource; + } + } + } + + // + conversation.Messages = [.. messages]; + } + } + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.Conversations)] = conversations; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.DescriptionResource)] = descriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectServiceProvider : XBaseDtoProvider, IXAiProjectServiceProvider + { + public XAiProjectServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiProjectRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiConversationEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiConversationEnricher : IXAiConversationEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepository repository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiConversationEnricher( + IXIdentityProvider identityProvider, + IXAiConversationRepository repository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + // + this.repository = repository; + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title Resource ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + XResourceDto projectTitleResource = null; + XResourceDto projectDescriptionResource = null; + if (!source.ProjectId.IsDefaultGuid()) + { + // + projectTitleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + + // + projectDescriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.TitleResource = titleResource; + result.ProjectTitleResource = projectTitleResource; + result.ProjectDescriptionResource = projectDescriptionResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiMessageEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiMessageEnricher : IXAiMessageEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiMessageEnricher( + IXIdentityProvider identityProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) + { + this.identityProvider = identityProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Conversation Title ... + string conversationTitle = string.Empty; + XResourceDto conversationTitleResource = null; + if (!source.ConversationId.IsDefaultGuid()) + { + // + conversationTitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ConversationId, + cancellationToken: cancellationToken + ); + if (!conversationTitleResource.IsNullOrDefault()) + { + conversationTitle = conversationTitleResource.Resource; + } + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.ConversationTitle = conversationTitle; + result.ConversationTitleResouce = conversationTitleResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiProjectEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiProjectEnricher : IXAiProjectEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiMessageRepository messageRepository; + private readonly IXAiConversationRepository conversationRepository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectEnricher( + IXIdentityProvider identityProvider, + IXAiMessageRepository messageRepository, + IXAiConversationRepository conversationRepository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + // + this.identityProvider = identityProvider; + this.messageRepository = messageRepository; + this.conversationRepository = conversationRepository; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Description ... + XResourceDto descriptionResource = null; + if (!source.Description.IsNullOrEmpty()) + { + // + descriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Conversations ... + IEnumerable conversations = []; + if (fillConversations) + { + // + // Reading Entities ... + var entitiies = await conversationRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == source.Id, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + // Converts to Dto Enumerable ... + conversations = entitiies + .MapConvert(); + + // + // Handle Conversation Enrichment ... + foreach (var conversation in conversations) + { + // + // Handle Owner ... + if (!conversation.OwnerId.IsNullOrEmpty()) + { + conversation.Owner = owner; + } + + // + // Handle Title Resource ... + if (!conversation.Title.IsNullOrEmpty()) + { + // + conversation.TitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: conversation.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + if (!conversation.ProjectId.IsDefaultGuid()) + { + conversation.ProjectTitle = source.Title; + conversation.ProjectTitleResource = titleResource; + conversation.ProjectDescription = source.Description; + conversation.ProjectDescriptionResource = descriptionResource; + } + } + + // + // Handle Fill Messages ... + if (fillConversationMessages) + { + // + foreach (var conversation in conversations) + { + // + IEnumerable messages = []; + + // + // Retrieve Message Entities ... + var messageEntities = await messageRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversation.Id + ); + if (messageEntities.HasChild()) + { + // + // Converts to Message ... + messages = messageEntities + .MapConvert(); + + // + // Ennrich Messages ... + foreach (var message in messages) + { + // + // Handle Owner ... + if (!message.OwnerId.IsNullOrEmpty()) + { + message.Owner = owner; + } + + // + // Handle Conversation ... + if (!message.ConversationId.IsDefaultGuid()) + { + message.ConversationTitle = conversation.Title; + message.ConversationTitleResouce = conversation.TitleResource; + } + } + } + + // + conversation.Messages = [.. messages]; + } + } + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.TitleResource = titleResource; + result.Conversations = [.. conversations]; + result.DescriptionResource = descriptionResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEFRepository : XBaseEFRepository, IXAiConversationRepository + where TContext : XDbContext + { + public XAiConversationEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEntityHub : XBaseEntityHub, IXAiConversationEntityHub + { + public XAiConversationEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationInMemoryRepository : XBaseInMemoryRepository, IXAiConversationRepository + { + public XAiConversationInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationKeyGenerator : XGuidKeyGenerator, IXAiConversationKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationMongoRepository : XBaseMongoRepository, IXAiConversationRepository + { + public XAiConversationMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryEvents : XBaseRepositoryEvents, IXAiConversationRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryProvider : XBaseEntityProvider, IXAiConversationRepositoryProvider + { + public XAiConversationRepositoryProvider( + IHubContext hub, + IXAiConversationRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiConversationSeederBase : XBaseDbSeeder, IXAiConversationSeeder + { + protected XAiConversationSeederBase( + string entity, + string database, + IXAiConversationRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEFRepository : XBaseEFRepository, IXAiMessageRepository + where TContext : XDbContext + { + public XAiMessageEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEntityHub : XBaseEntityHub, IXAiMessageEntityHub + { + public XAiMessageEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageInMemoryRepository : XBaseInMemoryRepository, IXAiMessageRepository + { + public XAiMessageInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageKeyGenerator : XGuidKeyGenerator, IXAiMessageKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageMongoRepository : XBaseMongoRepository, IXAiMessageRepository + { + public XAiMessageMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryEvents : XBaseRepositoryEvents, IXAiMessageRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryProvider : XBaseEntityProvider, IXAiMessageRepositoryProvider + { + public XAiMessageRepositoryProvider( + IHubContext hub, + IXAiMessageRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiMessageSeederBase : XBaseDbSeeder, IXAiMessageSeeder + { + protected XAiMessageSeederBase( + string entity, + string database, + IXAiMessageRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEFRepository : XBaseEFRepository, IXAiProjectRepository + where TContext : XDbContext + { + public XAiProjectEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEntityHub : XBaseEntityHub, IXAiProjectEntityHub + { + public XAiProjectEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectInMemoryRepository : XBaseInMemoryRepository, IXAiProjectRepository + { + public XAiProjectInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectKeyGenerator : XGuidKeyGenerator, IXAiProjectKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectMongoRepository : XBaseMongoRepository, IXAiProjectRepository + { + public XAiProjectMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryEvents : XBaseRepositoryEvents, IXAiProjectRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryProvider : XBaseEntityProvider, IXAiProjectRepositoryProvider + { + public XAiProjectRepositoryProvider( + IHubContext hub, + IXAiProjectRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiProjectSeederBase : XBaseDbSeeder, IXAiProjectSeeder + { + protected XAiProjectSeederBase( + string entity, + string database, + IXAiProjectRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiConversationGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiConversationCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiConversationSignleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQuery : XBaseGraphQLQuery + { + public XAiConversationGraphQuery( + XDataServiceConfiguration configuration, + IXAiConversationRepository repository, + IXAiConversationGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphSchema : Schema + { + public XAiConversationGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiConversationGraphQuery)services.GetService(typeof(XAiConversationGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphType : XBaseGraphObjectType + { + public XAiConversationGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ProjectId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiMessageGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiMessageCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiMessageSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQuery : XBaseGraphQLQuery + { + public XAiMessageGraphQuery( + XDataServiceConfiguration configuration, + IXAiMessageRepository repository, + IXAiMessageGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphSchema : Schema + { + public XAiMessageGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiMessageGraphQuery)services.GetService(typeof(XAiMessageGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphType: XBaseGraphObjectType + { + public XAiMessageGraphType() : base() + { + Field(x => x.Role); + Field(x => x.OwnerId); + Field(x => x.Content); + Field(x => x.Metadata); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ConversationId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiProjectGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiProjectCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiProjectSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQuery : XBaseGraphQLQuery + { + public XAiProjectGraphQuery( + XDataServiceConfiguration configuration, + IXAiProjectRepository repository, + IXAiProjectGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphSchema : Schema + { + public XAiProjectGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiProjectGraphQuery)services.GetService(typeof(XAiProjectGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphType : XBaseGraphObjectType + { + public XAiProjectGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.Prompt); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.Description); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Hubs\XAiDataProviderHub.cs + +using System.Threading; +using xPushService.Base; +using xAiModels.Constants; +using xCommons.Extensions; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Hubs +{ + public class XAiDataProviderHub : XBaseHub + { + public XAiDataProviderHub( + ILogger logger + ) : base(logger) + { } + + // + #region XAiProject ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ProjectCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ProjectRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ProjectUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiConversation ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ConversationCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ConversationRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ConversationUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiMessage ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task MessageCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task MessageRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task MessageUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + } +} diff --git a/Documents/GeneratedContext/xDashboard-xAiService-20260926_085204.txt b/Documents/GeneratedContext/xDashboard-xAiService-20260926_085204.txt new file mode 100644 index 0000000..7891ba5 --- /dev/null +++ b/Documents/GeneratedContext/xDashboard-xAiService-20260926_085204.txt @@ -0,0 +1,107 @@ + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\Constants\ConfigurationNodeNames.cs + +namespace xAiService.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_SERVICE_NODE = "AIServiceConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\DI\XDIHelperExtension.cs + +namespace xAiService.DI +{ + public static partial class XDIHelperExtension + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\Helpers\VectorHelper.cs + +using System; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class VectorHelper + { + /// + /// Normalize a Vector ... + /// + /// + public static void Normalize(float[] vector) + { + // + // Validate ... + if (vector.IsNull() || !vector.HasChild()) + { + return; + } + + // + float sum = 0f; + foreach (var value in vector) + { + sum += value * value; + } + + // + float norm = MathF.Sqrt(sum); + if (norm <= 1e-9f) + { + return; + } + + // + for (int i = 0; i < vector.Length; i++) + { + vector[i] /= norm; + } + } + + /// + /// Similarity Check ... + /// + /// + /// + /// + public static float CosineSimilarity(float[] a, float[] b) + { + // + if (a.IsNull() || b.IsNull()) + { + return 0f; + } + + // + if (a.Length != b.Length) + { + return 0f; + } + + // + float dot = 0f; + float normA = 0f; + float normB = 0f; + for (int i = 0; i < a.Length; i++) + { + // + dot += a[i] * b[i]; + normA += a[i] * a[i]; + normB += b[i] * b[i]; + } + + // + float denominator = MathF.Sqrt(normA) * MathF.Sqrt(normB); + if (denominator <= 1e-9f) + { + return 0f; + } + + // + var result = dot / denominator; + return result; + } + } +} diff --git a/Documents/GeneratedContext/xDashboard-xSaherelmWorkspace-20260926_085134.txt b/Documents/GeneratedContext/xDashboard-xSaherelmWorkspace-20260926_085134.txt new file mode 100644 index 0000000..85dac1e --- /dev/null +++ b/Documents/GeneratedContext/xDashboard-xSaherelmWorkspace-20260926_085134.txt @@ -0,0 +1,44469 @@ + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Codes\XContentRepositoryService.cs + +using System; +using AutoMapper; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xDataService.Providers; +using System.Threading.Tasks; +using System.Collections.Generic; +using xContentService.Interfaces; +using xContentService.Models.Dtos; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xContentService.Interfaces.Dtos; +using xContentService.Models.Entities; +using xContentService.Interfaces.Entities; + +namespace xContentService.Providers.Dtos +{ + public class XContentRepositoryService : XBaseRepositoryService, IXContentRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXContentTitleResourceProvider titleResourceProvider; + private readonly IXContentDescriptionResourceProvider descriptionResourceProvider; + + public XContentRepositoryService( + IXContentRepository repository, + IXIdentityProvider identityProvider, + IXContentTitleResourceProvider titleResourceProvider, + IXContentDescriptionResourceProvider descriptionResourceProvider, + IEnumerable mapperProfiles = null + ) : base( + repository, + mapperProfiles + ) + { + this.identityProvider = identityProvider; + this.titleResourceProvider = titleResourceProvider; + this.descriptionResourceProvider = descriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public async Task Enrich( + XContent source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public async Task Enrich( + XContentDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Content Title ... + string contentTitle = string.Empty; + XResourceDto titleResource = await titleResourceProvider.GetResource( + identifier: source.Id, + cancellationToken: cancellationToken + ); + if (!titleResource.IsNullOrDefault()) + { + contentTitle = titleResource.Resource; + } + + // + // Hanlde Content Description ... + string contentDescription = string.Empty; + XResourceDto descriptionResource = await descriptionResourceProvider.GetResource( + identifier: source.Id, + cancellationToken: cancellationToken + ); + if (!descriptionResource.IsNullOrDefault()) + { + contentDescription = descriptionResource.Resource; + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.Title)] = contentTitle; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.Description)] = contentDescription; + options.Items[nameof(source.DescriptionResource)] = descriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Markdown\AppexChartOptionsDocumentation.html + + + + + + + مستند جامع تحلیل ApexOptions در ApexCharts + + + + + + + +
+ +
+
+

مستند جامع تحلیل ApexOptions در ApexCharts

+

📅 تاریخ تهیه: دوشنبه ۱۱ شهریور ۱۴۰۴

+

📌 موضوع: بررسی تفصیلی فیلدهای ApexOptions

+
+
+ شرکت فن آوران ساحر علم
+ https://saherelm.ir
+ توسعه‌دهنده: هادی خزاعی اصل +
+
+ + +

۱. مقدمه

+

+ مدل ApexOptions قلب تپنده کتابخانه ApexCharts است و تمام تنظیمات نمودار را در بر می‌گیرد. این مدل شامل ۲۵ فیلد اصلی است که هر کدام بخش خاصی از نمودار را کنترل می‌کنند. در این سند، هر فیلد به همراه زیرفیلدها، توضیحات و مثال‌های کاربردی بررسی شده است. +

+ +
+ 📌 نکته: تمام فیلدها اختیاری هستند و در صورت عدم تعریف، از مقادیر پیش‌فرض ApexCharts استفاده می‌شود. +
+ + +

۲. جدول کلی فیلدهای ApexOptions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفنام فیلدتوضیح
۱annotationsحاشیه‌نویسی‌ها (خطوط، نقاط، متن‌ها)
۲chartتنظیمات اصلی نمودار (نوع، ابعاد، انیمیشن)
۳colorsرنگ‌های سری‌های داده
۴dataLabelsبرچسب‌های داده روی نقاط
۵drilldownناوبری عمیق (Drilldown)
۶fillپرکننده (رنگ، گرادیانت، الگو)
۷forecastDataPointsنقاط داده پیش‌بینی
۸gridشبکه‌بندی نمودار
۹labelsبرچسب‌های نمودار
۱۰legendراهنمای نمودار
۱۱markersنشانگرهای نقاط
۱۲noDataپیام عدم وجود داده
۱۳pluginsافزونه‌ها (Weave)
۱۴plotOptionsگزینه‌های خاص هر نوع نمودار
۱۵responsiveتنظیمات واکنش‌گرا
۱۶seriesسری‌های داده
۱۷statesحالت‌های مختلف (hover, active)
۱۸strokeخطوط نمودار
۱۹subtitleزیرعنوان
۲۰themeتم (روشن/تاریک)
۲۱titleعنوان نمودار
۲۲tooltipTooltip (راهنمای شناور)
۲۳xaxisمحور X
۲۴yaxisمحور Y
+ + +

۳. بررسی تفصیلی فیلدها

+ + +

۳.۱. فیلد annotations - حاشیه‌نویسی‌ها

+

این فیلد برای اضافه کردن حاشیه‌نویسی‌های سفارشی (خطوط، نقاط، متن‌ها) به نمودار استفاده می‌شود.

+ +

زیرفیلدها:

+
    +
  • xaxis: حاشیه‌نویسی‌های محور X (خطوط عمودی)
  • +
  • yaxis: حاشیه‌نویسی‌های محور Y (خطوط افقی)
  • +
  • points: حاشیه‌نویسی‌های نقطه‌ای
  • +
  • texts: متن‌های سفارشی
  • +
  • images: تصاویر سفارشی
  • +
+ +

ساختار XAxisAnnotations:

+
xaxis?: [
+  {
+    id?: number | string;
+    x?: null | number | string;
+    x2?: null | number | string;
+    strokeDashArray?: number;
+    fillColor?: string;
+    borderColor?: string;
+    borderWidth?: number;
+    opacity?: number;
+    offsetX?: number;
+    offsetY?: number;
+    label?: {
+      text?: string | string[];
+      textAnchor?: string;
+      offsetX?: number;
+      offsetY?: number;
+      style?: {
+        background?: string;
+        color?: string;
+        fontSize?: string;
+        fontFamily?: string;
+        fontWeight?: string | number;
+        padding?: { left?: number; right?: number; top?: number; bottom?: number; };
+      };
+    };
+  }
+]
+ +

مثال کاربردی:

+
annotations: {
+  xaxis: [{
+    x: new Date('2024-06-01').getTime(),
+    borderColor: '#FF0000',
+    label: {
+      borderColor: '#FF0000',
+      style: { color: '#fff', background: '#FF0000' },
+      text: 'تاریخ مهم'
+    }
+  }],
+  yaxis: [{
+    y: 50,
+    borderColor: '#00FF00',
+    label: { text: 'خط هدف', style: { color: '#00FF00' } }
+  }],
+  points: [{
+    x: 'فروردین',
+    y: 50,
+    marker: { size: 8, fillColor: '#FF0000' },
+    label: { text: 'نقطه مهم' }
+  }]
+}
+ + +

۳.۲. فیلد chart - تنظیمات اصلی نمودار

+

این فیلد مهم‌ترین بخش تنظیمات است و رفتار کلی نمودار را کنترل می‌کند.

+ +

زیرفیلدهای اصلی:

+
    +
  • width: عرض نمودار (عدد یا درصد)
  • +
  • height: ارتفاع نمودار (عدد یا درصد)
  • +
  • type: نوع نمودار (line, area, bar, pie, donut, radialBar, scatter, bubble, heatmap, candlestick, boxPlot, violin, histogram, radar, polarArea, rangeBar, rangeArea, treemap, waffle, sunburst, funnel, pyramid, gauge)
  • +
  • foreColor: رنگ متن پیش‌زمینه
  • +
  • fontFamily: فونت متن
  • +
  • background: رنگ پس‌زمینه
  • +
  • animations: تنظیمات انیمیشن
  • +
  • events: رویدادهای نمودار
  • +
  • toolbar: نوار ابزار
  • +
  • zoom: تنظیمات زوم
  • +
  • selection: تنظیمات انتخاب
  • +
  • stacked: نمودار پشته‌ای
  • +
  • stackType: نوع پشته (normal, 100%)
  • +
+ +

ساختار chart:

+
chart: {
+  width?: string | number;
+  height?: string | number;
+  type?: 'line' | 'area' | 'bar' | 'pie' | 'donut' | 'radialBar' | 
+         'scatter' | 'bubble' | 'heatmap' | 'candlestick' | 
+         'boxPlot' | 'violin' | 'histogram' | 'radar' | 
+         'polarArea' | 'rangeBar' | 'rangeArea' | 'treemap' | 
+         'waffle' | 'sunburst' | 'funnel' | 'pyramid' | 'gauge';
+  foreColor?: string;
+  fontFamily?: string;
+  background?: string;
+  offsetX?: number;
+  offsetY?: number;
+  dropShadow?: {
+    enabled?: boolean;
+    top?: number;
+    left?: number;
+    blur?: number;
+    opacity?: number;
+    color?: string | string[];
+  };
+  events?: {
+    animationEnd?(chart: ApexCharts, options?: any): void;
+    beforeMount?(chart: ApexCharts, options?: any): void;
+    mounted?(chart: ApexCharts, options?: any): void;
+    updated?(chart: ApexCharts, options?: any): void;
+    mouseMove?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    mouseLeave?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    click?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    legendClick?(chart: ApexCharts, seriesIndex?: number, options?: any): void;
+    markerClick?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    selection?(chart: ApexCharts, options?: any): void;
+    dataPointSelection?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    dataPointMouseEnter?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    dataPointMouseLeave?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    beforeZoom?(chart: ApexCharts, options?: any): boolean | void;
+    beforeResetZoom?(chart: ApexCharts, options?: any): boolean | void;
+    zoomed?(chart: ApexCharts, options?: any): void;
+    scrolled?(chart: ApexCharts, options?: any): void;
+    brushScrolled?(chart: ApexCharts, options?: any): void;
+  };
+  animations?: {
+    enabled?: boolean;
+    easing?: 'linear' | 'easeInSine' | 'easeOutSine' | 'easeInOutSine' | 
+             'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 
+             'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | string | 
+             [number, number, number, number] | ((t: number) => number);
+    speed?: number;
+    animateGradually?: { enabled?: boolean; delay?: number; };
+    dynamicAnimation?: { enabled?: boolean; speed?: number; easing?: string; };
+  };
+  toolbar?: {
+    show?: boolean;
+    offsetX?: number;
+    offsetY?: number;
+    tools?: {
+      download?: boolean | string;
+      selection?: boolean | string;
+      zoom?: boolean | string;
+      zoomin?: boolean | string;
+      zoomout?: boolean | string;
+      pan?: boolean | string;
+      reset?: boolean | string;
+      measure?: boolean | string;
+      customIcons?: Array<{
+        icon?: string;
+        title?: string;
+        index?: number;
+        class?: string;
+        click?(chart: ApexCharts, options?: any, e?: MouseEvent): void;
+      }>;
+    };
+    export?: {
+      csv?: { filename?: string; columnDelimiter?: string; headerCategory?: string; headerValue?: string; };
+      svg?: { filename?: string; };
+      png?: { filename?: string; };
+    };
+    autoSelected?: 'zoom' | 'selection' | 'pan' | 'measure';
+  };
+  zoom?: {
+    enabled?: boolean;
+    type?: 'x' | 'y' | 'xy';
+    autoScaleYaxis?: boolean;
+    allowMouseWheelZoom?: boolean | 'auto';
+    pinch?: boolean | 'auto';
+    zoomedArea?: {
+      fill?: { color?: string; opacity?: number; };
+      stroke?: { color?: string; opacity?: number; width?: number; };
+    };
+  };
+  selection?: {
+    enabled?: boolean;
+    type?: string;
+    fill?: { color?: string; opacity?: number; };
+    stroke?: { width?: number; color?: string; opacity?: number; dashArray?: number; };
+    xaxis?: { min?: number; max?: number; };
+    yaxis?: { min?: number; max?: number; };
+  };
+  stacked?: boolean;
+  stackType?: 'normal' | '100%';
+  id?: string;
+  group?: string;
+  locales?: Array<{ name?: string; options?: any; }>;
+  defaultLocale?: string;
+  parentHeightOffset?: number;
+  redrawOnParentResize?: boolean;
+  redrawOnWindowResize?: boolean | ((...args: any[]) => boolean);
+  sparkline?: { enabled?: boolean; };
+}
+ +

مثال کاربردی:

+
chart: {
+  type: 'line',
+  height: 350,
+  foreColor: '#333',
+  fontFamily: 'Vazirmatn, sans-serif',
+  animations: {
+    enabled: true,
+    easing: 'easeInOutCubic',
+    speed: 800,
+    animateGradually: { enabled: true, delay: 150 },
+    dynamicAnimation: { enabled: true, speed: 350 }
+  },
+  toolbar: {
+    show: true,
+    tools: {
+      download: true,
+      zoom: true,
+      zoomin: true,
+      zoomout: true,
+      reset: true,
+      customIcons: [{
+        icon: '<svg>...</svg>',
+        title: 'دکمه سفارشی',
+        index: 0,
+        click: (chart, options, e) => { console.log('کلیک شد'); }
+      }]
+    }
+  },
+  zoom: {
+    enabled: true,
+    type: 'x',
+    autoScaleYaxis: false
+  },
+  events: {
+    mounted: (chart, options) => { console.log('نمودار نصب شد'); },
+    dataPointSelection: (e, chart, options) => { console.log('نقطه انتخاب شد'); }
+  }
+}
+ + +

۳.۳. فیلد colors - رنگ‌های سری‌های داده

+

آرایه‌ای از رنگ‌ها برای سری‌های داده. هر سری با یک رنگ متفاوت نمایش داده می‌شود.

+ +

ساختار:

+
colors?: Array<string | ((opts: {
+  value: number;
+  seriesIndex: number;
+  dataPointIndex: number;
+  w: any;
+}) => string)>
+ +

مثال کاربردی:

+
// رنگ‌های ثابت
+colors: ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0']
+
+// رنگ‌های داینامیک بر اساس مقدار
+colors: [
+  function({ value, seriesIndex, dataPointIndex }) {
+    return value > 50 ? '#00E396' : '#FF4560';
+  }
+]
+ + +

۳.۴. فیلد dataLabels - برچسب‌های داده

+

برچسب‌هایی که روی نقاط داده نمایش داده می‌شوند.

+ +

ساختار:

+
dataLabels?: {
+  enabled?: boolean;
+  enabledOnSeries?: number[];
+  formatter?(val: string | number | number[], opts?: any): string | number | (string | number)[];
+  textAnchor?: 'start' | 'middle' | 'end';
+  distributed?: boolean;
+  offsetX?: number;
+  offsetY?: number;
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+    fontWeight?: string | number;
+    colors?: string[];
+  };
+  background?: {
+    enabled?: boolean;
+    foreColor?: string;
+    borderRadius?: number;
+    padding?: number;
+    opacity?: number;
+    borderWidth?: number;
+    borderColor?: string;
+    dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+  };
+  dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+}
+ +

مثال کاربردی:

+
dataLabels: {
+  enabled: true,
+  formatter: (val) => val + '%',
+  style: {
+    fontSize: '12px',
+    fontFamily: 'Vazirmatn',
+    colors: ['#fff']
+  },
+  background: {
+    enabled: true,
+    foreColor: '#fff',
+    borderRadius: 4,
+    padding: 4,
+    borderColor: '#000',
+    borderWidth: 1
+  }
+}
+ + +

۳.۵. فیلد fill - پرکننده

+

تنظیمات پرکننده (رنگ، گرادیانت، الگو، تصویر).

+ +

ساختار:

+
fill?: {
+  colors?: string[];
+  opacity?: number | number[];
+  type?: string | string[];
+  gradient?: {
+    shade?: string;
+    type?: string;
+    shadeIntensity?: number;
+    gradientToColors?: string[];
+    inverseColors?: boolean;
+    opacityFrom?: number | number[];
+    opacityTo?: number | number[];
+    stops?: number[];
+    colorStops?: Array<{ offset: number; color: string; opacity: number; }> | Array<Array<{ offset: number; color: string; opacity: number; }>>;
+  };
+  image?: {
+    src?: string | string[];
+    width?: number;
+    height?: number;
+  };
+  pattern?: {
+    style?: string | string[];
+    width?: number;
+    height?: number;
+    strokeWidth?: number;
+  };
+}
+ +

مثال کاربردی:

+
fill: {
+  type: 'gradient',
+  gradient: {
+    shade: 'light',
+    type: 'vertical',
+    shadeIntensity: 0.5,
+    gradientToColors: ['#008FFB', '#00E396'],
+    opacityFrom: 1,
+    opacityTo: 0.5,
+    stops: [0, 50, 100]
+  }
+}
+ + +

۳.۶. فیلد grid - شبکه‌بندی

+

تنظیمات شبکه‌بندی نمودار.

+ +

ساختار:

+
grid?: {
+  show?: boolean;
+  borderColor?: string;
+  strokeDashArray?: number;
+  position?: 'front' | 'back';
+  xaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; };
+  yaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; };
+  row?: { colors?: string[]; opacity?: number; };
+  column?: { colors?: string[]; opacity?: number; };
+  padding?: { top?: number; right?: number; bottom?: number; left?: number; };
+}
+ +

مثال کاربردی:

+
grid: {
+  show: true,
+  borderColor: '#e0e0e0',
+  strokeDashArray: 4,
+  position: 'back',
+  row: { colors: ['#f3f3f3', 'transparent'], opacity: 0.5 },
+  padding: { top: 0, right: 10, bottom: 0, left: 10 }
+}
+ + +

۳.۷. فیلد legend - راهنمای نمودار

+

تنظیمات راهنمای نمودار (Legend).

+ +

ساختار:

+
legend?: {
+  show?: boolean;
+  showForSingleSeries?: boolean;
+  showForNullSeries?: boolean;
+  showForZeroSeries?: boolean;
+  floating?: boolean;
+  inverseOrder?: boolean;
+  position?: 'top' | 'right' | 'bottom' | 'left';
+  horizontalAlign?: 'left' | 'center' | 'right';
+  fontSize?: string;
+  fontFamily?: string;
+  fontWeight?: string | number;
+  width?: number;
+  height?: number;
+  formatter?(legendName: string, opts?: { seriesIndex: number; w: any; }): string;
+  tooltipHoverFormatter?(legendName: string, opts?: { seriesIndex: number; w: any; }): string;
+  customLegendItems?: string[];
+  labels?: { colors?: string | string[]; useSeriesColors?: boolean; };
+  markers?: {
+    width?: number;
+    height?: number;
+    strokeColor?: string;
+    strokeWidth?: number;
+    radius?: number;
+    customHTML?(): any;
+    onClick?(): void;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  itemMargin?: { horizontal?: number; vertical?: number; };
+  onItemClick?: { toggleDataSeries?: boolean; };
+  onItemHover?: { highlightDataSeries?: boolean; };
+}
+ +

مثال کاربردی:

+
legend: {
+  show: true,
+  position: 'top',
+  horizontalAlign: 'center',
+  fontSize: '14px',
+  fontFamily: 'Vazirmatn',
+  markers: { width: 12, height: 12, radius: 6 },
+  onItemClick: { toggleDataSeries: true },
+  onItemHover: { highlightDataSeries: true }
+}
+ + +

۳.۸. فیلد markers - نشانگرها

+

تنظیمات نشانگرهای نقاط داده.

+ +

ساختار:

+
markers?: {
+  size?: number | number[];
+  colors?: string | string[];
+  strokeColors?: string | string[];
+  strokeWidth?: number | number[];
+  strokeOpacity?: number | number[];
+  strokeDashArray?: number | number[];
+  fillOpacity?: number | number[];
+  discrete?: Array<{
+    seriesIndex?: number;
+    dataPointIndex?: number;
+    fillColor?: string;
+    strokeColor?: string;
+    size?: number;
+  }>;
+  shape?: 'circle' | 'square' | 'rect';
+  offsetX?: number;
+  offsetY?: number;
+  hover?: { size?: number; sizeOffset?: number; };
+  onClick?(e?: any): void;
+  onDblClick?(e?: any): void;
+  showNullDataPoints?: boolean;
+}
+ +

مثال کاربردی:

+
markers: {
+  size: 6,
+  colors: ['#008FFB'],
+  strokeColors: '#fff',
+  strokeWidth: 2,
+  hover: { size: 8, sizeOffset: 3 },
+  discrete: [{
+    seriesIndex: 0,
+    dataPointIndex: 3,
+    fillColor: '#FF0000',
+    size: 10
+  }]
+}
+ + +

۳.۹. فیلد plotOptions - گزینه‌های خاص هر نوع نمودار

+

این فیلد تنظیمات خاص هر نوع نمودار را شامل می‌شود.

+ +

ساختار (خلاصه):

+
plotOptions?: {
+  bar?: {
+    horizontal?: boolean;
+    columnWidth?: string | number;
+    barHeight?: string | number;
+    distributed?: boolean;
+    borderRadius?: number;
+    borderRadiusApplication?: 'around' | 'end';
+    borderRadiusWhenStacked?: 'all' | 'last';
+    hideZeroBarsWhenGrouped?: boolean;
+    rangeBarOverlap?: boolean;
+    rangeBarGroupRows?: boolean;
+    isDumbbell?: boolean;
+    dumbbellColors?: string[][];
+    colors?: {
+      ranges?: Array<{ from?: number; to?: number; color?: string; }>;
+      backgroundBarColors?: string[];
+      backgroundBarOpacity?: number;
+      backgroundBarRadius?: number;
+    };
+    dataLabels?: {
+      maxItems?: number;
+      hideOverflowingLabels?: boolean;
+      position?: string;
+      orientation?: 'horizontal' | 'vertical';
+      total?: {
+        enabled?: boolean;
+        formatter?(val?: string, opts?: any): string;
+        offsetX?: number;
+        offsetY?: number;
+        style?: { color?: string; fontSize?: string; fontFamily?: string; fontWeight?: string | number; };
+      };
+    };
+  };
+  bubble?: { minBubbleRadius?: number; maxBubbleRadius?: number; };
+  candlestick?: {
+    colors?: { upward?: string | string[]; downward?: string | string[]; };
+    wick?: { useFillColor?: boolean; };
+  };
+  boxPlot?: {
+    colors?: { upper?: string | string[]; lower?: string | string[]; };
+  };
+  heatmap?: {
+    radius?: number;
+    enableShades?: boolean;
+    shadeIntensity?: number;
+    reverseNegativeShade?: boolean;
+    distributed?: boolean;
+    useFillColorAsStroke?: boolean;
+    colorScale?: {
+      ranges?: Array<{ from?: number; to?: number; color?: string; foreColor?: string; name?: string; }>;
+      inverse?: boolean;
+      min?: number;
+      max?: number;
+    };
+  };
+  treemap?: {
+    enableShades?: boolean;
+    shadeIntensity?: number;
+    distributed?: boolean;
+    reverseNegativeShade?: boolean;
+    useFillColorAsStroke?: boolean;
+    dataLabels?: { format?: 'scale' | 'truncate'; };
+    borderRadius?: number;
+    colorScale?: {
+      inverse?: boolean;
+      ranges?: Array<{ from?: number; to?: number; color?: string; foreColor?: string; name?: string; }>;
+      min?: number;
+      max?: number;
+    };
+  };
+  pie?: {
+    startAngle?: number;
+    endAngle?: number;
+    customScale?: number;
+    offsetX?: number;
+    offsetY?: number;
+    expandOnClick?: boolean;
+    expandOffset?: number;
+    dataLabels?: { offset?: number; };
+  };
+  donut?: {
+    size?: string;
+    background?: string;
+    labels?: {
+      show?: boolean;
+      name?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; formatter?(val: string): string; };
+      value?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; formatter?(val: number | string): string; };
+      total?: { show?: boolean; showAlways?: boolean; label?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?(w: any): string; };
+    };
+  };
+  radialBar?: {
+    inverseOrder?: boolean;
+    startAngle?: number;
+    endAngle?: number;
+    offsetX?: number;
+    offsetY?: number;
+    hollow?: {
+      margin?: number;
+      size?: string;
+      background?: string;
+      image?: string;
+      imageWidth?: number;
+      imageHeight?: number;
+      imageOffsetX?: number;
+      imageOffsetY?: number;
+      imageClipped?: boolean;
+      position?: 'front' | 'back';
+      dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+    };
+    track?: {
+      show?: boolean;
+      startAngle?: number;
+      endAngle?: number;
+      background?: string | string[];
+      strokeWidth?: string;
+      opacity?: number;
+      margin?: number;
+      dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+    };
+    dataLabels?: {
+      show?: boolean;
+      name?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; };
+      value?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; formatter?(val: number): string; };
+      total?: { show?: boolean; label?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?(w: any): string; };
+    };
+  };
+  radar?: {
+    size?: number;
+    offsetX?: number;
+    offsetY?: number;
+    polygons?: {
+      strokeColors?: string | string[];
+      strokeWidth?: string | number[];
+      connectorColors?: string | string[];
+      fill?: { colors?: string[]; };
+    };
+  };
+  polarArea?: {
+    rings?: { strokeColor?: string; strokeWidth?: number; };
+    spokes?: { connectorColors?: string | string[]; strokeWidth?: number; };
+  };
+}
+ +

مثال کاربردی (Bar):

+
plotOptions: {
+  bar: {
+    horizontal: false,
+    columnWidth: '70%',
+    borderRadius: 4,
+    borderRadiusApplication: 'end',
+    distributed: false,
+    dataLabels: {
+      position: 'top',
+      maxItems: 100,
+      hideOverflowingLabels: true
+    }
+  }
+}
+ +

مثال کاربردی (Pie):

+
plotOptions: {
+  pie: {
+    startAngle: 0,
+    endAngle: 360,
+    expandOnClick: true,
+    expandOffset: 10,
+    dataLabels: { offset: 0 }
+  }
+}
+ + +

۳.۱۰. فیلد responsive - تنظیمات واکنش‌گرا

+

تنظیمات واکنش‌گرا برای اندازه‌های مختلف صفحه.

+ +

ساختار:

+
responsive?: Array<{
+  breakpoint?: number;
+  options?: ApexOptions;
+}>
+ +

مثال کاربردی:

+
responsive: [
+  {
+    breakpoint: 480,
+    options: {
+      chart: { width: '100%', height: 250 },
+      legend: { position: 'bottom' }
+    }
+  },
+  {
+    breakpoint: 768,
+    options: {
+      chart: { width: '100%', height: 300 },
+      legend: { position: 'bottom' }
+    }
+  }
+]
+ + +

۳.۱۱. فیلد states - حالت‌های مختلف

+

تنظیمات حالت‌های مختلف (hover, active).

+ +

ساختار:

+
states?: {
+  hover?: {
+    filter?: {
+      type?: 'none' | 'lighten' | 'darken';
+      value?: number;
+    };
+  };
+  active?: {
+    allowMultipleDataPointsSelection?: boolean;
+    filter?: {
+      type?: 'none' | 'lighten' | 'darken';
+      value?: number;
+    };
+  };
+}
+ +

مثال کاربردی:

+
states: {
+  hover: {
+    filter: { type: 'darken', value: 0.15 }
+  },
+  active: {
+    allowMultipleDataPointsSelection: false,
+    filter: { type: 'darken', value: 0.35 }
+  }
+}
+ + +

۳.۱۲. فیلد stroke - خطوط نمودار

+

تنظیمات خطوط نمودار.

+ +

ساختار:

+
stroke?: {
+  show?: boolean;
+  curve?: 'smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic' | 
+          ('smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic')[];
+  lineCap?: 'butt' | 'square' | 'round';
+  colors?: string[];
+  width?: number | number[];
+  dashArray?: number | number[];
+}
+ +

مثال کاربردی:

+
stroke: {
+  show: true,
+  curve: 'smooth',
+  lineCap: 'round',
+  colors: ['#008FFB'],
+  width: 3,
+  dashArray: 0
+}
+ + +

۳.۱۳. فیلد theme - تم

+

تنظیمات تم (روشن/تاریک).

+ +

ساختار:

+
theme?: {
+  mode?: 'light' | 'dark' | '';
+  palette?: string;
+  monochrome?: {
+    enabled?: boolean;
+    color?: string;
+    shadeTo?: 'light' | 'dark';
+    shadeIntensity?: number;
+  };
+}
+ +

مثال کاربردی:

+
theme: {
+  mode: 'light',
+  palette: 'palette1',
+  monochrome: {
+    enabled: false,
+    color: '#008FFB',
+    shadeTo: 'light',
+    shadeIntensity: 0.65
+  }
+}
+ + +

۳.۱۴. فیلدهای title و subtitle - عنوان و زیرعنوان

+

تنظیمات عنوان و زیرعنوان نمودار.

+ +

ساختار:

+
title?: {
+  text?: string;
+  align?: 'left' | 'center' | 'right';
+  margin?: number;
+  offsetX?: number;
+  offsetY?: number;
+  floating?: boolean;
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+    fontWeight?: string | number;
+    color?: string;
+  };
+}
+
+subtitle?: {
+  text?: string;
+  align?: 'left' | 'center' | 'right';
+  margin?: number;
+  offsetX?: number;
+  offsetY?: number;
+  floating?: boolean;
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+    fontWeight?: string | number;
+    color?: string;
+  };
+}
+ +

مثال کاربردی:

+
title: {
+  text: 'نمودار فروش ماهانه',
+  align: 'center',
+  margin: 10,
+  style: {
+    fontSize: '18px',
+    fontFamily: 'Vazirmatn',
+    fontWeight: 'bold',
+    color: '#333'
+  }
+},
+subtitle: {
+  text: 'آمار فروش سال ۱۴۰۳',
+  align: 'center',
+  style: {
+    fontSize: '14px',
+    color: '#666'
+  }
+}
+ + +

۳.۱۵. فیلد tooltip - Tooltip

+

تنظیمات Tooltip (راهنمای شناور).

+ +

ساختار:

+
tooltip?: {
+  enabled?: boolean;
+  enabledOnSeries?: number[];
+  shared?: boolean;
+  followCursor?: boolean;
+  intersect?: boolean;
+  inverseOrder?: boolean;
+  arrow?: boolean;
+  custom?: Array<(opts: {
+    series: number[][];
+    seriesIndex: number;
+    dataPointIndex: number;
+    y1?: number;
+    y2?: number;
+    w: any;
+  }) => string>;
+  fillSeriesColor?: boolean;
+  theme?: 'light' | 'dark';
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+  };
+  onDatasetHover?: { highlightDataSeries?: boolean; };
+  x?: {
+    show?: boolean;
+    format?: string;
+    formatter?(value: string | number, opts?: any): string;
+  };
+  y?: Array<{
+    title?: { title?: string; formatter?(seriesName: string, opts?: any): string; };
+    formatter?(value: number, opts?: any): string;
+  }>;
+  marker?: { show?: boolean; fillColors?: string[]; };
+  items?: { display?: string; };
+  fixed?: {
+    enabled?: boolean;
+    position?: string;
+    offsetX?: number;
+    offsetY?: number;
+  };
+}
+ +

مثال کاربردی:

+
tooltip: {
+  enabled: true,
+  shared: true,
+  followCursor: false,
+  intersect: false,
+  theme: 'light',
+  style: { fontSize: '12px', fontFamily: 'Vazirmatn' },
+  x: { show: true, format: 'dd MMM' },
+  y: [{
+    title: { title: 'فروش: ' },
+    formatter: (val) => val.toLocaleString('fa-IR') + ' تومان'
+  }],
+  marker: { show: true }
+}
+ + +

۳.۱۶. فیلد xaxis - محور X

+

تنظیمات محور X.

+ +

ساختار:

+
xaxis?: {
+  type?: 'category' | 'datetime' | 'numeric';
+  categories?: Array<string | number> | Array<Array<string | number>>;
+  overwriteCategories?: number[] | string[];
+  offsetX?: number;
+  offsetY?: number;
+  sorted?: boolean;
+  labels?: {
+    show?: boolean;
+    rotate?: number;
+    rotateAlways?: boolean;
+    hideOverlappingLabels?: boolean;
+    showDuplicates?: boolean;
+    trim?: boolean;
+    minHeight?: number;
+    maxHeight?: number;
+    style?: {
+      colors?: string | string[];
+      fontSize?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      cssClass?: string;
+    };
+    offsetX?: number;
+    offsetY?: number;
+    format?: string;
+    formatter?(value: string | number, timestamp?: number, opts?: any): string | string[];
+    datetimeUTC?: boolean;
+    datetimeFormatter?: {
+      year?: string;
+      month?: string;
+      day?: string;
+      hour?: string;
+      minute?: string;
+      second?: string;
+    };
+  };
+  group?: {
+    groups?: Array<{ title: string; cols: number }>;
+    style?: {
+      colors?: string | string[];
+      fontSize?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      cssClass?: string;
+    };
+  };
+  axisBorder?: {
+    show?: boolean;
+    color?: string;
+    width?: string | number;
+    height?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  axisTicks?: {
+    show?: boolean;
+    borderType?: 'solid' | 'dotted';
+    color?: string;
+    width?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  tickPlacement?: string;
+  tickAmount?: number | 'dataPoints';
+  stepSize?: number;
+  min?: number;
+  max?: number;
+  range?: number;
+  floating?: boolean;
+  position?: string;
+  title?: {
+    text?: string;
+    offsetX?: number;
+    offsetY?: number;
+    style?: {
+      color?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      fontSize?: string;
+      cssClass?: string;
+    };
+  };
+  crosshairs?: {
+    show?: boolean;
+    width?: number | string;
+    position?: string;
+    opacity?: number;
+    stroke?: { color?: string; width?: number; dashArray?: number; };
+    fill?: {
+      type?: string;
+      color?: string;
+      gradient?: {
+        colorFrom?: string;
+        colorTo?: string;
+        stops?: number[];
+        opacityFrom?: number;
+        opacityTo?: number;
+      };
+    };
+    dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+  };
+  tooltip?: {
+    enabled?: boolean;
+    offsetY?: number;
+    formatter?(value: string | number, opts?: any): string;
+    style?: { fontSize?: string; fontFamily?: string; };
+  };
+}
+ +

مثال کاربردی:

+
xaxis: {
+  type: 'category',
+  categories: ['فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر'],
+  labels: {
+    show: true,
+    rotate: -45,
+    style: {
+      fontSize: '12px',
+      fontFamily: 'Vazirmatn',
+      colors: ['#333']
+    }
+  },
+  title: {
+    text: 'ماه',
+    style: { fontSize: '14px', fontWeight: 'bold' }
+  },
+  crosshairs: {
+    show: true,
+    stroke: { color: '#000', width: 1, dashArray: 0 }
+  }
+}
+ + +

۳.۱۷. فیلد yaxis - محور Y

+

تنظیمات محور Y.

+ +

ساختار:

+
yaxis?: {
+  show?: boolean;
+  showAlways?: boolean;
+  showForNullSeries?: boolean;
+  seriesName?: string | string[];
+  opposite?: boolean;
+  reversed?: boolean;
+  logarithmic?: boolean;
+  logBase?: number;
+  tickAmount?: number;
+  stepSize?: number;
+  forceNiceScale?: boolean;
+  min?: number | ((min: number) => number);
+  max?: number | ((max: number) => number);
+  floating?: boolean;
+  decimalsInFloat?: number;
+  labels?: {
+    show?: boolean;
+    showDuplicates?: boolean;
+    minWidth?: number;
+    maxWidth?: number;
+    style?: {
+      colors?: string | string[];
+      fontSize?: string;
+      fontWeight?: string | number;
+      fontFamily?: string;
+      cssClass?: string;
+    };
+    offsetX?: number;
+    offsetY?: number;
+    rotate?: number;
+    align?: 'left' | 'center' | 'right';
+    padding?: number;
+    formatter?(value: number, opts?: any): string | string[];
+  };
+  axisBorder?: {
+    show?: boolean;
+    color?: string;
+    width?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  axisTicks?: {
+    show?: boolean;
+    borderType?: 'solid' | 'dotted';
+    color?: string;
+    width?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  title?: {
+    text?: string;
+    rotate?: number;
+    offsetX?: number;
+    offsetY?: number;
+    style?: {
+      color?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      fontSize?: string;
+      cssClass?: string;
+    };
+  };
+  crosshairs?: {
+    show?: boolean;
+    position?: string;
+    stroke?: { color?: string; width?: number; dashArray?: number; };
+  };
+  tooltip?: {
+    enabled?: boolean;
+    offsetX?: number;
+  };
+}
+ +

مثال کاربردی:

+
yaxis: {
+  show: true,
+  title: {
+    text: 'مبلغ (تومان)',
+    style: { fontSize: '14px', fontWeight: 'bold' }
+  },
+  labels: {
+    show: true,
+    formatter: (val) => val.toLocaleString('fa-IR'),
+    style: { fontSize: '12px', fontFamily: 'Vazirmatn' }
+  },
+  min: 0,
+  max: 100,
+  tickAmount: 5
+}
+ + +

۳.۱۸. فیلد noData - پیام عدم وجود داده

+

تنظیمات پیام نمایش داده شده در صورت عدم وجود داده.

+ +

ساختار:

+
noData?: {
+  text?: string;
+  align?: 'left' | 'center' | 'right';
+  verticalAlign?: 'top' | 'middle' | 'bottom';
+  offsetX?: number;
+  offsetY?: number;
+  style?: {
+    color?: string;
+    fontSize?: string;
+    fontFamily?: string;
+  };
+}
+ +

مثال کاربردی:

+
noData: {
+  text: 'داده‌ای برای نمایش وجود ندارد',
+  align: 'center',
+  verticalAlign: 'middle',
+  style: {
+    color: '#999',
+    fontSize: '16px',
+    fontFamily: 'Vazirmatn'
+  }
+}
+ + +

۴. خلاصه و جمع‌بندی

+

+ مدل ApexOptions با ۲۵ فیلد اصلی، کنترل کاملی بر تمام جنبه‌های نمودار ارائه می‌دهد. با استفاده از این فیلدها می‌توانید نمودارهای کاملاً سفارشی و حرفه‌ای ایجاد کنید. +

+ +
+ 💡 نکته مهم: برای استفاده بهینه، همیشه از مستندات رسمی ApexCharts (apexcharts.com/docs/options) استفاده کنید و مقادیر پیش‌فرض را بررسی کنید. +
+ +
+ ⚠️ هشدار: برخی فیلدها فقط برای انواع خاصی از نمودار کاربرد دارند. قبل از استفاده، مطمئن شوید که فیلد مورد نظر با نوع نمودار شما سازگار است. +
+ + +
+

© کلیه حقوق این مستند متعلق به شرکت فن آوران ساحر علم می‌باشد.

+

طراحی و توسعه: هادی خزاعی اصل | وب‌سایت: https://saherelm.ir

+

📅 تاریخ تهیه: دوشنبه ۱۱ شهریور ۱۴۰۴

+
+
+ + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\غالب پروژه ها.html + + + + + + + پروژه نمونه + + + + +
+
+ +
+
پروژه نمونه
+
توضیحات پروژه
+
+
+
+ + +
+ + +
+ + +
+ + + + +
+
+
📋
+

ناحیه اصلی

+

محتوای اصلی برنامه در این ناحیه نمایش داده می‌شود

+
+
+
+ + +
+
+ طراح و توسعه‌دهنده: هادی خزاعی اصل + | + شرکت: رایان پرداز کاوش +
+
+ نسخه: 1.0.0 +
+
+ + + + + +
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Themes\Generator\xFrameworkThemeGenerator.html + + + + + + + xFramework Theme Generator + + + +
+

🎨 تولیدکننده پوسته xFramework

+

+ مدیریت و ویرایش پوسته‌های رنگی برای برنامه‌های کاربردی مبتنی بر + xFramework +

+
+ توسعه‌دهنده: هادی خزاعی اصل | شرکت: فن آوران ساحر علم | تاریخ: ۱ شهریور + ۱۴۰۵ +
+
+ +
+
+

✏️ ویرایش پوسته

+ +
+ + +
+ +
+
+ 📚 پوسته‌های از پیش تعریف‌شده (۵۰ مورد) +
+
+ 📁 بارگذاری فایل JSON +
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+
+ +
+
+ +
+
+
+ ☀️ Light +
+
+ 🌙 Dark +
+
+
+
+ + +
+
+
+ پیش‌نمایش زنده +
+
+
+
+
+
+
+ +
+
+
+ 📄 JSON (Light) +
+
+ 📄 JSON (Dark) +
+
+ 📄 Full JSON +
+
+

+          
+ +
+ + + +
+
+
+
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\xKanban.html + + + + + + +xKanban | ابزار مدیریت بردهای کانبان + + + + + + + + + + + +
+ + + + +
+ + + + +
+
+ 📋 + کل کارت‌ها: + 0 +
+
+ ✅ + تکمیل‌شده: + 0 +
+
+ ⏰ + نزدیک به موعد: + 0 +
+
+ ⚠️ + عقب‌افتاده: + 0 +
+
+ 📊 + پیشرفت: + 0% +
+
+ + +
+
+
📋
+

هیچ بردی وجود ندارد

+

برای شروع، یک برد جدید ایجاد کنید

+ +
+ +
+
+
+ + +
+
طراحی و توسعه: هادی خزاعی اصل | معمار و توسعه‌دهنده ارشد نرم‌افزار
+
نسخه ۱.۰.۰ |
+
+ + +
+
+ ذخیره خودکار فعال +
+ + +
+
+ در حال ارسال... +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\xToolTemplate.html + + + + + + + پروژه نمونه + + + + +
+
+ +
+
پروژه نمونه
+
توضیحات پروژه
+
+
+
+ + +
+ + +
+ + +
+ + + + +
+
+
📋
+

ناحیه اصلی

+

محتوای اصلی برنامه در این ناحیه نمایش داده می‌شود

+
+
+
+ + +
+
+ طراح و توسعه‌دهنده: هادی خزاعی اصل + | + شرکت: رایان پرداز کاوش +
+
+ نسخه: 1.0.0 +
+
+ + + + + +
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\xUMLDrawer.html + + + + + + +ابزار رسم نمودارهای UML + + + + + +
+
+
+
+
+

🎯 ابزار رسم نمودارهای UML

+

مدیریت چند نمودار با قابلیت ذخیره و بازیابی

+
+
طراح: هادی خزاعی اصل
+
+
+
+ +
+ + + +
+ + +
+ +
100%
+ +
+
+
+ +
+ + +
+
+ +
+
+ +
+
آماده
دیاگرام‌ها: 0
+
+
+ + + + + +
+
+
+
+
+

⚙️ ویژگی‌های المان

+ +
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Case_Study_1.html + + + + + + +xKanban | مستند جامع معرفی محصول و معماری فنی + + + +
+ + +
+
+
+ +
+
+
شماره مستند: PROD-XKN-1405-002
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۰:۳۰
+
طبقه‌بندی: عمومی - معرفی محصول
+
+
+
+PRODUCT DOCUMENTATION +

xKanban | ابزار مدیریت بردهای کانبان

+

معرفی محصول، تحلیل ارزش سازمانی و معماری فنی

+
+
+ + +
+ +
+مخاطبان مستند: مدیران فناوری اطلاعات، مدیران پروژه، سرپرستان تیم‌های توسعه، معماران نرم‌افزار و تصمیم‌گیرندگان سازمانی
+این مستند به معرفی جامع ابزار xKanban می‌پردازد؛ ابزاری که از دل نیازهای واقعی تیم‌های چابک متولد شده و با هدف حذف پیچیدگی‌های غیرضروری ابزارهای مدیریت پروژه طراحی شده است. در این مستند، از چرایی شکل‌گیری محصول تا معماری فنی و ارزش‌های سازمانی آن، همه‌چیز تشریح شده است. +
+ + +
+

📑 فهرست مطالب

+
    +
  1. شرح مسئله و چرایی خلق xKanban
  2. +
  3. مزایای کلیدی محصول
  4. +
  5. ارزش‌های سازمانی خلق‌شده
  6. +
  7. معماری فنی پروژه
  8. +
  9. مناسب برای چه سازمان‌ها و تیم‌هایی؟
  10. +
  11. جمع‌بندی و گام‌های بعدی
  12. +
+
+ + +
+
+
۱
+
+

شرح مسئله و چرایی خلق xKanban

+
Problem Statement & Product Genesis
+
+
+
+ +

در دنیای امروز، تقریباً هر تیمی — از توسعه نرم‌افزار گرفته تا بازاریابی، منابع انسانی و عملیات — با یک چالش مشترک دست‌وپنجه نرم می‌کند: چگونه کارها را به‌صورت شفاف، منظم و قابل ردیابی مدیریت کنیم؟ متدولوژی کانبان به‌عنوان یکی از مؤثرترین رویکردهای مدیریت بصری کار، سال‌هاست که پاسخ این سؤال را ارائه داده است؛ اما ابزارهای موجود برای پیاده‌سازی این متدولوژی، خود به منبع جدیدی از پیچیدگی تبدیل شده‌اند.

+ +

معضلات رایج در اکوسیستم ابزارهای فعلی:

+ +
+⚠️ چالش‌هایی که تیم‌ها هر روز با آن‌ها مواجه‌اند: +
    +
  • وابستگی به اینترنت و سرور: بسیاری از ابزارها نیازمند اتصال دائمی به اینترنت و سرورهای ابری هستند. در محیط‌هایی با محدودیت شبکه یا الزامات امنیتی بالا، این وابستگی یک مانع جدی است.
  • +
  • هزینه‌های اشتراک ماهانه: ابزارهای تجاری برای هر کاربر هزینه اشتراک دریافت می‌کنند. برای تیم‌های بزرگ، این هزینه به‌سرعت به رقم قابل‌توجهی تبدیل می‌شود.
  • +
  • پیچیدگی بیش‌ازحد: ابزارهایی مانند Jira یا Azure DevOps صدها قابلیت دارند که اکثر تیم‌ها از کمتر از ۲۰ درصد آن‌ها استفاده می‌کنند. این پیچیدگی، منحنی یادگیری را بالا برده و بهره‌وری را کاهش می‌دهد.
  • +
  • فرآیند نصب و راه‌اندازی سنگین: برخی ابزارها نیازمند نصب سرور، پیکربندی دیتابیس و مدیریت زیرساخت هستند که زمان و تخصص قابل‌توجهی می‌طلبد.
  • +
  • قفل‌شدگی داده‌ها (Vendor Lock-in): داده‌های پروژه در سرورهای ارائه‌دهنده سرویس ذخیره می‌شوند و خروج از آن اکوسیستم، پرهزینه و دشوار است.
  • +
  • عدم قابلیت حمل: انتقال پروژه از یک محیط به محیط دیگر (مثلاً از لپ‌تاپ شخصی به سیستم شرکت) در بسیاری از ابزارها فرآیندی پیچیده است.
  • +
+
+ +

این معضلات، یک شکاف آشکار در بازار ابزارهای مدیریت پروژه ایجاد کرده بود: جای خالی ابزاری ساده، مستقل، رایگان و در عین حال حرفه‌ای که بدون هیچ پیش‌نیازی قابل استفاده باشد و در عین حال، قابلیت‌های پیشرفته‌ای مانند فیلتر چندبعدی، تاریخچه تغییرات، وابستگی بین کارت‌ها و یکپارچگی با سیستم‌های خارجی را ارائه دهد.

+ +
+🎯 نقطه عطف: xKanban دقیقاً از همین شکاف متولد شد. هدف، خلق ابزاری بود که «صفر تا صد» مدیریت کانبان را بدون هیچ وابستگی خارجی، در یک فایل واحد و قابل حمل ارائه دهد — ابزاری که در کمتر از ۳ ثانیه باز شود و از همان لحظه اول قابل استفاده باشد. +
+ +

نیازمندی‌های کلیدی که xKanban برای پاسخ به آن‌ها طراحی شد:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفنیازمندیوضعیت در ابزارهای موجودپاسخ xKanban
۱اجرای آفلاین و بدون سروراکثراً ناممکن✓ کاملاً آفلاین
۲بدون هزینه اشتراکاشتراک ماهانه/سالانه✓ کاملاً رایگان
۳راه‌اندازی فورینیاز به نصب و پیکربندی✓ یک کلیک
۴قابلیت حمل داده‌هامحدود و پیچیده✓ فایل JSON
۵سادگی همراه با قدرتیا ساده یا پیچیده✓ تعادل بهینه
۶مالکیت کامل داده‌هاذخیره در سرور ثالث✓ کاملاً محلی
+ +
+
+ + +
+
+
۲
+
+

مزایای کلیدی محصول

+
Key Product Advantages
+
+
+
+ +

xKanban مجموعه‌ای از مزایای منحصربه‌فرد را ارائه می‌دهد که آن را از تمامی ابزارهای موجود در بازار متمایز می‌سازد. این مزایا نه صرفاً ویژگی‌های فنی، بلکه تصمیمات استراتژیک طراحی هستند که هر کدام پاسخی مستقیم به یکی از معضلات مطرح‌شده در بخش قبل می‌باشند.

+ +
+
+
۰ ثانیه
نصب
+
بدون نیاز به هیچ فرآیند نصب یا پیکربندی
+
+
+
۱۰۰٪
آفلاین
+
اجرای کامل بدون نیاز به اینترنت یا سرور
+
+
+
۱ فایل
واحد
+
تمام محصول در یک فایل HTML مستقل
+
+
+ +
+
+
🚀
+
راه‌اندازی آنی
+

فایل HTML را در مرورگر باز کنید. تمام. هیچ سروری، هیچ دیتابیسی، هیچ اکانتی لازم نیست. در کمتر از ۳ ثانیه آماده استفاده هستید.

+
+
+
🔒
+
حریم خصوصی مطلق
+

تمام داده‌ها در مرورگر شما باقی می‌مانند. هیچ اطلاعاتی به هیچ سرور خارجی ارسال نمی‌شود. مالکیت داده‌ها ۱۰۰٪ در اختیار شماست.

+
+
+
📦
+
قابلیت حمل بی‌نظیر
+

پروژه خود را به‌صورت فایل JSON ذخیره کنید و روی فلش، ایمیل یا هر فضای ابری منتقل کنید. در هر سیستمی قابل بارگذاری است.

+
+
+
🎨
+
رابط کاربری مدرن و حرفه‌ای
+

طراحی بصری جذاب با پشتیبانی از حالت تاریک/روشن، رنگ‌بندی سفارشی برای بردها، ستون‌ها و کارت‌ها و انیمیشن‌های روان.

+
+
+
🔍
+
فیلتر چندبعدی پیشرفته
+

فیلتر هم‌زمان بر اساس تگ، مسئول، وضعیت سررسید و جستجوی متنی. یافتن هر کارت در کمتر از یک ثانیه حتی در پروژه‌های بزرگ.

+
+
+
📡
+
یکپارچگی با Webhook
+

ارسال خودکار رویدادهای پروژه به Slack، Teams یا هر سیستم خارجی. ساختار JSON استاندارد با eventId و timestamp.

+
+
+
⌨️
+
میانبرهای کیبورد حرفه‌ای
+

بیش از ۸ میانبر کیبورد برای کاربران حرفه‌ای. از Ctrl+S برای ذخیره تا Alt+Arrow برای جابجایی سریع کارت‌ها بین ستون‌ها.

+
+
+
📊
+
آمار بلادرنگ پروژه
+

مشاهده آنی تعداد کارت‌ها، درصد پیشرفت، کارت‌های عقب‌افتاده و نزدیک به موعد در نوار وضعیت پایین صفحه.

+
+
+ +
+💎 مزیت رقابتی اصلی: xKanban تنها ابزاری است که ترکیب «سادگی یک فایل HTML» و «قدرت یک سیستم مدیریت پروژه حرفه‌ای» را به‌صورت هم‌زمان ارائه می‌دهد. هیچ ابزار دیگری در بازار این تعادل را برقرار نکرده است. +
+ +

مقایسه با ابزارهای رایج بازار:

+
+
+

ابزارهای تجاری (Jira, Trello, Asana)

+
    +
  • هزینه اشتراک ماهانه بالا
  • +
  • نیاز به اینترنت الزامی
  • +
  • نصب و راه‌اندازی ثبت‌نام + پیکربندی
  • +
  • مالکیت داده سرور ثالث
  • +
  • پیچیدگی بسیار بالا
  • +
  • آفلاین ناممکن
  • +
+
+ +
+ +
+
+ + +
+
+
۳
+
+

ارزش‌های سازمانی خلق‌شده

+
Organizational Value Proposition
+
+
+
+ +

استفاده از xKanban در یک سازمان، فراتر از صرفاً «مدیریت کارها» است. این ابزار، ارزش‌های استراتژیک و عملیاتی ملموسی را در سطوح مختلف سازمان خلق می‌کند که در ادامه به تفصیل تشریح شده‌اند:

+ +
+
💰
+
+
حذف کامل هزینه‌های لایسنس و اشتراک
+

سازمان‌هایی که از ابزارهایی مانند Jira یا Azure DevOps استفاده می‌کنند، سالانه مبالغ قابل‌توجهی بابت لایسنس هر کاربر پرداخت می‌کنند. xKanban این هزینه را به صفر می‌رساند و بودجه آزادشده را برای سرمایه‌گذاری در حوزه‌های ارزشمندتر آزاد می‌کند.

+
+
+ +
+
🔐
+
+
تطبیق با الزامات امنیتی و حریم خصوصی
+

در سازمان‌هایی با حساسیت امنیتی بالا (نظامی، بانکی، بهداشتی)، ارسال داده‌های پروژه به سرورهای ابری خارجی ممنوع یا محدود است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را به‌صورت ذاتی رعایت می‌کند.

+
+
+ +
+
⚡
+
+
کاهش زمان Onboarding اعضای جدید
+

برخلاف ابزارهای پیچیده که آموزش آن‌ها هفته‌ها زمان می‌برد، xKanban به‌قدری ساده و شهودی است که یک عضو جدید تیم در کمتر از ۱۰ دقیقه با آن آشنا شده و شروع به کار می‌کند.

+
+
+ +
+
📈
+
+
افزایش شفافیت و پاسخگویی در تیم
+

با نمایش بصری وضعیت تمام کارها، تاریخچه جابجایی کارت‌ها و آمار بلادرنگ پیشرفت، هر عضو تیم و هر مدیری در هر لحظه دید کاملی از وضعیت پروژه دارد. این شفافیت، فرهنگ پاسخگویی را تقویت می‌کند.

+
+
+ +
+
🔄
+
+
استانداردسازی فرآیندهای مدیریت پروژه
+

xKanban تیم‌ها را به استفاده از یک متدولوژی استاندارد (کانبان) هدایت می‌کند. ستون‌های مشخص، جریان کار تعریف‌شده و تاریخچه تغییرات، همگی به ایجاد یک فرآیند تکرارپذیر و قابل اندازه‌گیری کمک می‌کنند.

+
+
+ +
+
🛡️
+
+
حذف ریسک Vendor Lock-in
+

داده‌های پروژه در فرمت استاندارد JSON ذخیره می‌شوند. این یعنی سازمان هیچ‌گاه در اکوسیستم یک ارائه‌دهنده خاص قفل نمی‌شود و در هر زمان می‌تواند داده‌های خود را به هر سیستم دیگری منتقل کند.

+
+
+ +
+
🌐
+
+
یکپارچگی با اکوسیستم موجود سازمان
+

از طریق مکانیزم Webhook، xKanban می‌تواند رویدادهای پروژه را به Slack، Microsoft Teams، سیستم‌های CI/CD یا هر API سفارشی ارسال کند. این یعنی xKanban به‌جای جایگزینی ابزارهای موجود، آن‌ها را تکمیل می‌کند.

+
+
+ +
+
📉
+
+
کاهش سربار مدیریت زیرساخت
+

بدون نیاز به سرور، دیتابیس، به‌روزرسانی‌های امنیتی و مانیتورینگ، تیم IT سازمان از بار مدیریت یک ابزار اضافی رها می‌شود. این صرفه‌جویی در زمان و منابع انسانی، ارزش پنهان اما بسیار قابل‌توجهی است.

+
+
+ +
+📊 خلاصه ارزش‌آفرینی: xKanban در چهار بُعد اصلی برای سازمان ارزش خلق می‌کند: کاهش هزینه‌ها (حذف لایسنس و زیرساخت)، افزایش بهره‌وری (Onboarding سریع و رابط شهودی)، کاهش ریسک (امنیت داده و عدم وابستگی) و بهبود کیفیت فرآیندها (استانداردسازی و شفافیت). +
+ +
+
+ + +
+
+
۴
+
+

معماری فنی پروژه

+
Technical Architecture & Code Structure
+
+
+
+ +

xKanban به‌عنوان یک Single-Page Application (SPA) تک‌فایلی طراحی شده است که تمامی لایه‌های نمایش، منطق و داده را در یک فایل HTML واحد encapsulate می‌کند. این تصمیم معماری، اگرچه در نگاه اول غیرمعمول به نظر می‌رسد، اما با توجه به اهداف محصول (آفلاین بودن، قابلیت حمل و عدم وابستگی) منطقی‌ترین انتخاب ممکن بوده است.

+ +

الف) نمودار معماری لایه‌ای

+ +
+
+
🎨 Presentation Layer
+
+Toolbar UI +Board Renderer +Column Renderer +Card Renderer +Modal System +Filter Panel +Stats Bar +Theme Engine +
+
+
▼ Event Binding & State Observation ▼
+
+
⚙️ Application Logic Layer
+
+ProjectManager +BoardManager +ColumnManager +CardManager +TagManager +FilterEngine +WebhookService +ShortcutHandler +HistoryTracker +
+
+
▼ Read / Write / Sync ▼
+
+
💾 Data & Persistence Layer
+
+AppState (In-Memory) +LocalStorage Adapter +AutoSave Engine +JSON Serializer +Export/Import Service +Recovery Manager +
+
+
+ +

ب) مدل داده‌ای (Data Schema)

+

ساختار داده‌ای پروژه از یک سلسله‌مراتب چهارسطحی پیروی می‌کند:

+ +
+// ساختار سلسله‌مراتبی داده‌ها
+Project
+  ├── id: UUID
+  ├── title: string
+  ├── description: string
+  ├── createdAt: ISO8601
+  ├── webhook: { enabled, url }
+  ├── globalTags: [Tag]
+  └── boards: [
+        Board
+          ├── id, title, backgroundColor
+          └── columns: [
+              Column
+                ├── id, title, order
+                └── cards: [
+                    Card
+                      ├── id, title, description
+                      ├── dueDate, assignees, tags
+                      ├── dependencies, checklist
+                      └── history: [HistoryEntry]
+                  ]
+            ]
+      ]
+
+ +

ج) ماژول‌های اصلی و متدهای کلیدی

+

در ادامه، مهم‌ترین ماژول‌های سیستم به همراه متدهای کلیدی هر کدام تشریح شده‌اند. برای حفظ خوانایی، بدنه متدها خلاصه شده و تنها امضای آن‌ها نمایش داده شده است:

+ +
📁 ماژول ProjectManager
+
    +
  • +initProject() +مقداردهی اولیه پروژه +
  • +
  • +loadProject(data) +بارگذاری پروژه از فایل JSON +
  • +
  • +saveProject(filename) +ذخیره پروژه به‌صورت فایل JSON +
  • +
  • +updateProjectSettings(title, desc, webhook) +به‌روزرسانی تنظیمات پروژه +
  • +
  • +getProjectStats() +محاسبه آمار کلی پروژه +
  • +
+ +
📊 ماژول BoardManager
+
    +
  • +createBoard(title, description, bgColor) +ایجاد برد جدید +
  • +
  • +editBoard(boardId, data) +ویرایش برد موجود +
  • +
  • +deleteBoard(boardId) +حذف برد با تأیید کاربر +
  • +
  • +switchBoard(boardId) +تغییر برد فعال +
  • +
  • +renderBoardList() +رندر لیست بردها در منو +
  • +
+ +
📑 ماژول ColumnManager
+
    +
  • +addColumn(boardId, title, bgColor, textColor) +افزودن ستون جدید به برد +
  • +
  • +editColumn(columnId, data) +ویرایش ویژگی‌های ستون +
  • +
  • +deleteColumn(columnId) +حذف ستون و کارت‌های آن +
  • +
  • +reorderColumns(draggedId, targetId) +تغییر ترتیب ستون‌ها با Drag & Drop +
  • +
  • +renderColumns(boardId) +رندر ستون‌های برد فعال +
  • +
+ +
📝 ماژول CardManager
+
    +
  • +createCard(columnId, cardData) +ایجاد کارت جدید در ستون +
  • +
  • +updateCard(cardId, updates) +به‌روزرسانی اطلاعات کارت +
  • +
  • +deleteCard(cardId) +حذف کارت از ستون +
  • +
  • +moveCard(cardId, fromColumnId, toColumnId) +جابجایی کارت بین ستون‌ها +
  • +
  • +addChecklistItem(cardId, text) +افزودن آیتم به چک‌لیست +
  • +
  • +toggleChecklistItem(cardId, itemId) +تغییر وضعیت آیتم چک‌لیست +
  • +
  • +addDependency(cardId, dependOnCardId) +ایجاد وابستگی بین کارت‌ها +
  • +
  • +assignMember(cardId, memberName) +تخصیص مسئول به کارت +
  • +
  • +getCardDueStatus(card) +تعیین وضعیت سررسید کارت +
  • +
  • +openCardModal(cardId) +باز کردن پنجره ویرایش کارت +
  • +
+ +
🏷️ ماژول TagManager
+
    +
  • +createTag(name, color) +ایجاد تگ عمومی جدید +
  • +
  • +deleteTag(tagId) +حذف تگ و حذف از کارت‌ها +
  • +
  • +assignTagToCard(cardId, tagId) +تخصیص تگ به کارت +
  • +
  • +removeTagFromCard(cardId, tagId) +حذف تگ از کارت +
  • +
  • +renderTagManager() +رندر پنل مدیریت تگ‌ها +
  • +
+ +
🔍 ماژول FilterEngine
+
    +
  • +applyFilters(criteria) +اعمال فیلترهای چندبعدی +
  • +
  • +filterByTags(selectedTags) +فیلتر بر اساس تگ‌ها +
  • +
  • +filterByAssignees(selectedAssignees) +فیلتر بر اساس مسئولین +
  • +
  • +filterByDueStatus(status) +فیلتر بر اساس وضعیت سررسید +
  • +
  • +searchCards(query) +جستجوی متنی در کارت‌ها +
  • +
  • +clearAllFilters() +پاک‌سازی تمام فیلترها +
  • +
+ +
📡 ماژول WebhookService
+
    +
  • +sendEvent(eventType, payload) +ارسال رویداد به URL پیکربندی‌شده +
  • +
  • +testWebhook(url) +تست اتصال Webhook +
  • +
  • +buildEventPayload(eventType, data) +ساخت ساختار JSON استاندارد رویداد +
  • +
+ +
💾 ماژول PersistenceEngine
+
    +
  • +autoSave() +ذخیره خودکار در LocalStorage +
  • +
  • +loadAutoSave() +بارگذاری داده‌های ذخیره‌شده خودکار +
  • +
  • +scheduleAutoSave() +زمان‌بندی ذخیره با Debounce +
  • +
  • +exportToJSON() +خروجی فایل JSON +
  • +
  • +importFromJSON(file) +بارگذاری از فایل JSON +
  • +
  • +exportToMarkdown(boardId) +خروجی فرمت Markdown +
  • +
  • +exportToCSV(boardId) +خروجی فرمت CSV +
  • +
  • +checkRecovery() +بررسی وجود داده‌های بازیابی +
  • +
+ +
⌨️ ماژول ShortcutHandler
+
    +
  • +registerShortcuts() +ثبت تمام میانبرهای کیبورد +
  • +
  • +handleKeyDown(event) +پردازش رویدادهای کیبورد +
  • +
  • +navigateCards(direction) +پیمایش بین کارت‌ها با Tab +
  • +
  • +moveCardWithKeyboard(direction) +جابجایی کارت با Alt+Arrow +
  • +
+ +

د) الگوهای طراحی به‌کاررفته

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل استفادههدف
State-Driven Renderingکل رابط کاربریرندر UI بر اساس وضعیت مرکزی AppState
Observer / Pub-Subارتباط ماژول‌هااطلاع‌رسانی تغییرات وضعیت به ماژول‌های وابسته
DebouncingAutoSave Engineجلوگیری از نوشتن مکرر در LocalStorage
Factoryایجاد موجودیت‌هاتولید اشیاء Card، Column، Board با UUID
CommandUndo/Redoذخیره عملیات برای امکان بازگشت
SingletonAppStateیک منبع واحد حقیقت برای کل برنامه
+ +

ه) جریان داده (Data Flow)

+
+🔄 چرخه حیات یک عملیات کاربر:

+۱. User Action: کاربر یک کارت را از ستون «در حال انجام» به ستون «تکمیل‌شده» می‌کشد.
+۲. Event Capture: رویداد Drag & Drop توسط ColumnManager دریافت می‌شود.
+۳. State Update: متد moveCard() از CardManager فراخوانی شده و AppState به‌روزرسانی می‌شود.
+۴. History Log: متد HistoryTracker.log() جابجایی را با timestamp ثبت می‌کند.
+۵. Re-Render: متد renderColumns() رابط کاربری را با وضعیت جدید به‌روزرسانی می‌کند.
+۶. AutoSave: متد scheduleAutoSave() با تأخیر ۱ ثانیه، وضعیت را در LocalStorage ذخیره می‌کند.
+۷. Webhook: در صورت فعال بودن، متد sendEvent('card.moved', payload) رویداد را ارسال می‌کند.
+۸. Stats Update: متد getProjectStats() آمار نوار وضعیت را به‌روزرسانی می‌کند. +
+ +
+
+ + +
+
+
۵
+
+

مناسب برای چه سازمان‌ها و تیم‌هایی؟

+
Target Audience & Ideal Use Cases
+
+
+
+ +

xKanban به‌گونه‌ای طراحی شده که طیف وسیعی از سازمان‌ها و تیم‌ها بتوانند از آن بهره‌مند شوند. با این حال، برخی محیط‌ها بیشترین ارزش را از این ابزار دریافت خواهند کرد:

+ +

الف) سازمان‌های هدف

+ +
+
+
🏢
+
استارتاپ‌ها و شرکت‌های کوچک
+

تیم‌هایی که بودجه محدود دارند و به ابزاری رایگان، سریع و بدون سربار نیاز دارند. xKanban جایگزین ایده‌آل Trello و Asana برای این تیم‌هاست.

+
+
+
🏛️
+
سازمان‌های دولتی و نظامی
+

محیط‌هایی با محدودیت‌های امنیتی شدید که استفاده از سرویس‌های ابری خارجی ممنوع است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را رعایت می‌کند.

+
+
+
🏥
+
مراکز بهداشتی و درمانی
+

بیمارستان‌ها و مراکز تحقیقاتی که داده‌های حساس بیماران و پروژه‌ها نباید از شبکه داخلی خارج شود.

+
+
+
🏦
+
مؤسسات مالی و بانکی
+

سازمان‌هایی که تحت مقررات سخت‌گیرانه حفاظت از داده (مانند PCI-DSS) فعالیت می‌کنند و نمی‌توانند اطلاعات پروژه‌ها را در سرورهای ثالث ذخیره کنند.

+
+
+
🎓
+
دانشگاه‌ها و مراکز آموزشی
+

اساتید و دانشجویانی که برای مدیریت پروژه‌های تحقیقاتی، پایان‌نامه‌ها و کارهای گروهی به ابزاری ساده و رایگان نیاز دارند.

+
+
+
🌍
+
تیم‌های دورکار و فریلنسرها
+

افرادی که در محیط‌های مختلف کار می‌کنند و نیاز دارند پروژه خود را روی فلش یا فضای ابری شخصی حمل کنند.

+
+
+ +

ب) تیم‌های هدف

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع تیمنحوه استفاده از xKanbanارزش اصلی
تیم‌های توسعه نرم‌افزارمدیریت Sprint، باگ‌ها و Featureهایکپارچگی با CI/CD از طریق Webhook
تیم‌های DevOpsردیابی Incidentها و Change Requestهااجرای آفلاین در محیط‌های ایزوله
تیم‌های بازاریابیمدیریت کمپین‌ها و محتوای تولیدیسادگی و سرعت راه‌اندازی
تیم‌های منابع انسانیردیابی فرآیند استخدام و Onboardingحریم خصوصی داده‌های پرسنلی
تیم‌های طراحیمدیریت پروژه‌های طراحی و بازخوردرابط بصری جذاب و رنگ‌بندی سفارشی
تیم‌های پشتیبانیمدیریت تیکت‌ها و درخواست‌های مشتریانآمار بلادرنگ و فیلتر پیشرفته
مدیران محصولنقشه راه محصول و اولویت‌بندی ویژگی‌هاوابستگی بین کارت‌ها و چک‌لیست
+ +
+🎯 قانون کلی: هر تیمی که با سؤال «الان هر کس دارد روی چه چیزی کار می‌کند و وضعیتش چیست؟» مواجه است، یک کاندیدای ایده‌آل برای استفاده از xKanban محسوب می‌شود. +
+ +

ج) چه زمانی xKanban بهترین انتخاب نیست؟

+
+💡 شفافیت کامل: xKanban برای سناریوهای زیر طراحی نشده و در این موارد، ابزارهای تخصصی‌تر توصیه می‌شوند: +
    +
  • تیم‌های بسیار بزرگ (بیش از ۵۰ نفر) که نیاز به مدیریت دسترسی سطحی و نقش‌های پیچیده دارند
  • +
  • سازمان‌هایی که نیاز به هم‌زمانی بلادرنگ (Real-time Collaboration) بین چندین کاربر دارند
  • +
  • محیط‌هایی که نیاز به یکپارچگی عمیق با اکوسیستم‌های خاص (مانند SAP یا Salesforce) دارند
  • +
+
+ +
+
+ + +
+
+
۶
+
+

جمع‌بندی و گام‌های بعدی

+
Summary & Next Steps
+
+
+
+ +

xKanban پاسخی عملی و مهندسی‌شده به یکی از رایج‌ترین چالش‌های تیم‌های مدرن است: مدیریت بصری کارها بدون پیچیدگی، بدون هزینه و بدون وابستگی. این ابزار از دل تجربه واقعی در مدیریت پروژه‌های نرم‌افزاری متولد شده و هر ویژگی آن، پاسخی مستقیم به یک نیاز واقعی است.

+ +
+

🎯 چرا xKanban؟

+

زیرا مدیریت پروژه نباید خودش یک پروژه باشد.

+

xKanban با ترکیب سادگی، قدرت و استقلال، ابزاری را ارائه می‌دهد که از لحظه اول قابل استفاده است، داده‌های شما را در اختیار خودتان نگه می‌دارد و هیچ هزینه‌ای بر دوش سازمان نمی‌گذارد.

+
+💎 ارزش نهایی:
+صفر هزینه + صفر وابستگی + صفر پیچیدگی = ۱۰۰٪ بهره‌وری +
+
+ +

گام‌های پیشنهادی برای شروع:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
گاماقدامزمان تخمینی
۱فایل xKanban.html را در مرورگر باز کنید۳ ثانیه
۲یک پروژه و برد آزمایشی ایجاد کنید۲ دقیقه
۳ستون‌ها و کارت‌های واقعی تیم خود را وارد کنید۱۰ دقیقه
۴تگ‌ها و مسئولین را تعریف کنید۵ دقیقه
۵پروژه را به‌صورت فایل JSON ذخیره کنید۱ دقیقه
۶از xKanban لذت ببرید! 🎉همیشگی
+ +
+📞 تماس و پشتیبانی: برای دریافت مشاوره فنی، سفارشی‌سازی xKanban بر اساس نیازهای خاص سازمانی یا یکپارچگی با سیستم‌های موجود، آماده برگزاری جلسه فنی هستیم. طراحی، تحلیل و توسعه توسط هادی خزاعی اصل، معمار و توسعه‌دهنده ارشد نرم‌افزار. +
+ +
+
+ +
+این مستند جهت معرفی محصول و تحلیل فنی تهیه شده است. هرگونه استفاده تجاری از محتوای این مستند بدون اجازه کتبی ممنوع است. +
+ +
+ + +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۰:۳۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: عمومی
+
+ +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Case_Study_2.html + + + + + + +مستند جامع محصول xKanban | تحلیل مسئله، مزایا، معماری و مخاطبان هدف + + + +
+
+
+
+ +
+
+
شماره مستند: PROD-XKN-1405-002
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۱:۳۰
+
طبقه‌بندی: داخلی - محصولی
+
+
+
+PRODUCT DOCUMENTATION +

مستند جامع محصول xKanban

+

تحلیل مسئله، مزایا، ارزش‌های سازمانی، معماری فنی و مخاطبان هدف

+
+
+ +
+
+تهیه‌کننده: هادی خزاعی اصل | معمار و توسعه‌دهنده ارشد نرم‌افزار
+مخاطبان مستند: مدیران فنی، تصمیم‌گیرندگان سازمانی، رهبران تیم و معماران نرم‌افزار
+این مستند با هدف ارائه تصویری جامع از چرایی خلق محصول xKanban، مزایای رقابتی آن، ارزش‌های قابل‌خلق در سازمان، معماری فنی دقیق و شناسایی مخاطبان هدف تهیه شده است. +
+ + + + +
+
+
۱
+
+

شرح مسئله و ضرورت خلق ابزار

+
Problem Statement & Motivation
+
+
+
+

در دنیای توسعه نرم‌افزار و مدیریت پروژه، تیم‌ها با چالش‌های مشترکی در زمینه پیگیری وظایف، شفافیت وضعیت کارها و هماهنگی بین اعضا مواجه هستند. این چالش‌ها مختص سازمان خاصی نیستند، بلکه الگویی تکرارشونده در سراسر صنعت محسوب می‌شوند.

+ +

معضلات رایج در مدیریت وظایف:

+ +
+⚠️ وابستگی اجباری به زیرساخت سرور: +
    +
  • بخش عمده‌ای از ابزارهای مدیریت پروژه، نیازمند راه‌اندازی سرور، پایگاه داده، پیکربندی شبکه و نگهداری مداوم هستند
  • +
  • تیم‌های کوچک و فریلنسرها اغلب فاقد زیرساخت و دانش فنی لازم برای استقرار این ابزارها هستند
  • +
  • هزینه‌های سرور و نگهداری، بار مالی اضافی بر پروژه‌های کوچک تحمیل می‌کند
  • +
+
+ +
+⚠️ قفل‌شدگی در اکوسیستم ابری: +
    +
  • ابزارهای SaaS، داده‌های سازمان را روی سرورهای شخص ثالث ذخیره می‌کنند که نگرانی‌های امنیتی و حریم خصوصی ایجاد می‌کند
  • +
  • وابستگی به اتصال اینترنت پایدار، کار در محیط‌های آفلاین یا با پهنای باند محدود را غیرممکن می‌سازد
  • +
  • تغییر قیمت‌گذاری یا تعطیلی سرویس‌دهنده، ریسک از دست رفتن داده‌ها را به همراه دارد
  • +
+
+ +
+⚠️ پیچیدگی بیش از حد ابزارهای موجود: +
    +
  • بسیاری از ابزارها با انبوهی از ویژگی‌های غیرضروری، منحنی یادگیری بالایی دارند
  • +
  • تیم‌ها زمان قابل‌توجهی را صرف یادگیری ابزار می‌کنند به جای تمرکز بر کار اصلی
  • +
  • سفارشی‌سازی فرآیندها اغلب نیازمند پیکربندی‌های پیچیده و دانش تخصصی است
  • +
+
+ +
+⚠️ عدم قابلیت حمل و انتقال داده‌ها: +
    +
  • خروجی گرفتن از داده‌ها و انتقال آن‌ها بین ابزارها، فرآیندی دشوار و زمان‌بر است
  • +
  • فرمت‌های اختصاصی، امکان استفاده آفلاین یا اشتراک‌گذاری ساده پروژه را محدود می‌کنند
  • +
  • عدم امکان آرشیو کردن پروژه به صورت فایل مستقل، مدیریت بلندمدت را مختل می‌کند
  • +
+
+ +
+🎯 نتیجه‌گیری از تحلیل مسئله: نیاز به ابزاری احساس می‌شد که بدون نیاز به سرور، بدون وابستگی به اینترنت، بدون پیچیدگی غیرضروری و با قابلیت حمل کامل، امکان مدیریت حرفه‌ای پروژه‌ها را بر اساس متدولوژی کانبان فراهم آورد. xKanban پاسخی مستقیم به این نیاز است. +
+
+
+ + + + +
+
+
۲
+
+

مزایای کلیدی محصول

+
Key Product Advantages
+
+
+
+

xKanban با رویکردی متفاوت از ابزارهای رایج بازار طراحی شده و مزایایی را ارائه می‌دهد که هر یک به تنهایی می‌تواند دلیلی قانع‌کننده برای انتخاب این ابزار باشد:

+ +
+
+
صفر
سرور
+
بدون نیاز به هیچ زیرساخت سروری
+
+
+
یک
فایل
+
توزیع و اجرا با یک فایل HTML
+
+
+
۱۰۰٪
آفلاین
+
کارکرد کامل بدون اتصال اینترنت
+
+
+ +

مزیت ۱: استقلال مطلق از زیرساخت

+

xKanban به صورت کامل در مرورگر کاربر اجرا می‌شود. هیچ سروری نیاز نیست، هیچ پایگاه داده‌ای پیکربندی نمی‌شود، هیچ وابستگی به سرویس خارجی وجود ندارد. کاربر فقط یک فایل HTML را باز می‌کند و بلافاصله شروع به کار می‌کند. این یعنی زمان راه‌اندازی: صفر ثانیه.

+ +

مزیت ۲: مالکیت کامل داده‌ها

+

تمامی داده‌ها در مرورگر محلی کاربر و در فایل‌های JSON خروجی ذخیره می‌شوند. هیچ بایتی از اطلاعات پروژه به سرور خارجی ارسال نمی‌شود. این ویژگی برای سازمان‌هایی که با داده‌های حساس کار می‌کنند، یک مزیت حیاتی و غیرقابل‌مذاکره است.

+ +

مزیت ۳: قابلیت حمل بی‌نظیر

+

کل پروژه شامل بردها، ستون‌ها، کارت‌ها، تگ‌ها و تنظیمات در یک فایل JSON قابل‌صدور است. این فایل را می‌توان از طریق ایمیل ارسال کرد، روی فلش ذخیره کرد، در فضای ابری شخصی نگه داشت یا حتی پرینت گرفت. پروژه شما، همیشه در جیب شماست.

+ +

مزیت ۴: غنای عملکردی در عین سادگی

+

برخلاف تصور رایج که ابزارهای ساده فاقد قابلیت‌های پیشرفته هستند، xKanban مجموعه‌ای غنی از ویژگی‌ها را ارائه می‌دهد:

+ +
+
+
📊
+
بردهای چندگانه
+

مدیریت همزمان چندین برد مستقل در یک پروژه با جابجایی آنی

+
+
+
🎨
+
شخصی‌سازی بصری کامل
+

رنگ‌بندی مستقل برای بردها، ستون‌ها و کارت‌ها جهت شناسایی سریع

+
+
+
👥
+
تخصیص چندمسئوله
+

امکان اختصاص چندین نفر به هر کارت برای کارهای تیمی

+
+
+
🔗
+
مدیریت وابستگی‌ها
+

تعریف روابط پیش‌نیازی بین کارت‌ها برای درک زنجیره کار

+
+
+
✅
+
چک‌لیست ریزوظایف
+

شکستن کارت‌ها به وظایف کوچکتر با قابلیت پیگیری پیشرفت

+
+
+
📜
+
تاریخچه جابجایی
+

ثبت خودکار تمام جابجایی‌های کارت بین ستون‌ها با زمان دقیق

+
+
+
📡
+
یکپارچگی Webhook
+

ارسال رویدادها به سیستم‌های خارجی با ساختار استاندارد JSON

+
+
+
⌨️
+
میانبرهای کیبورد
+

پشتیبانی کامل از کیبورد برای کاربران حرفه‌ای و افزایش سرعت

+
+
+ +

مزیت ۵: خروجی چندفرمتی

+

xKanban علاوه بر فرمت JSON برای پشتیبان‌گیری کامل، امکان خروجی گرفتن به فرمت‌های Markdown و CSV را نیز فراهم می‌آورد. این یعنی داده‌های شما هرگز در یک فرمت اختصاصی قفل نمی‌شوند و همیشه قابل استفاده در ابزارهای دیگر هستند.

+ +

مزیت ۶: بازیابی خودکار هوشمند

+

سیستم AutoSave به صورت خودکار تغییرات را در مرورگر ذخیره می‌کند. در صورت بسته شدن ناگهانی مرورگر یا قطع برق، در جلسه بعدی سیستم به صورت خودکار داده‌های ذخیره‌شده را شناسایی کرده و گزینه بازیابی را ارائه می‌دهد.

+ +
+✨ مزیت رقابتی نهایی: xKanban تنها ابزاری است که همزمان تمامی ویژگی‌های «بدون سرور»، «آفلاین کامل»، «مالکیت داده»، «قابلیت حمل»، «غنای عملکردی» و «خروجی چندفرمتی» را در یک بسته واحد ارائه می‌دهد. هیچ ابزار دیگری در بازار این ترکیب منحصربه‌فرد را فراهم نمی‌آورد. +
+
+
+ + + + +
+
+
۳
+
+

ارزش‌های قابل‌خلق در سازمان

+
Organizational Value Proposition
+
+
+
+

استفاده از xKanban فراتر از یک ابزار مدیریت وظایف ساده است. این محصول می‌تواند ارزش‌های استراتژیک و عملیاتی ملموسی را در سازمان ایجاد کند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
حوزه ارزشارزش ایجادشدهتأثیر عملی
💰 کاهش هزینه‌هاحذف هزینه لایسنس ابزارهای SaaS، سرور، پایگاه داده و نگهداریصرفه‌جویی سالانه قابل‌توجه در بودجه فناوری اطلاعات
⚡ افزایش سرعتراه‌اندازی آنی بدون فرآیند خرید، نصب و پیکربندیتیم‌ها در کمتر از یک دقیقه شروع به کار می‌کنند
🔒 امنیت داده‌هاعدم خروج داده‌ها از محیط محلی سازمانانطباق با الزامات حریم خصوصی و مقررات حفاظت از داده
🔄 تداوم کسب‌وکارکارکرد مستقل از اینترنت و سرویس‌های خارجیعدم توقف کار تیم در صورت قطعی اینترنت یا اختلال سرویس
📈 شفافیت فرآیندهادید بلادرنگ به وضعیت تمام کارها و گلوگاه‌هاتصمیم‌گیری مبتنی بر داده و شناسایی سریع موانع
🤝 بهبود همکاری تیمیاشتراک‌گذاری آسان پروژه از طریق فایل JSONهماهنگی بهتر بین اعضا حتی در محیط‌های توزیع‌شده
📚 انباشت دانشتاریخچه کامل جابجایی‌ها و آرشیو پروژه‌هاامکان بازنگری فرآیندها و یادگیری از تجربیات گذشته
🎯 استانداردسازیاجرای دقیق متدولوژی کانبان با ساختار یکپارچهایجاد زبان مشترک و فرآیند یکنواخت در تمام تیم‌ها
🔌 یکپارچگی سیستمیارتباط با ابزارهای خارجی از طریق Webhookخودکارسازی اعلان‌ها و اتصال به اکوسیستم موجود سازمان
🧠 کاهش بار شناختیرابط کاربری ساده و متمرکز بدون ویژگی‌های اضافیکاهش زمان آموزش و افزایش تمرکز تیم بر کار اصلی
+ +
+

ابزاری که تیم واقعاً از آن استفاده کند، ارزشمندتر از ابزاری است که فقط خریداری شده ولی کسی سراغش نمی‌رود. سادگی xKanban تضمین می‌کند که نرخ پذیرش در تیم به حداکثر می‌رسد.

+
— اصل پذیرش فناوری در مهندسی نرم‌افزار
+
+ +
+📊 ارزش تجمعی: هر یک از ارزش‌های فوق به تنهایی مفید است، اما ترکیب آن‌ها یک اثر هم‌افزایی (Synergy) ایجاد می‌کند: تیمی که سریع شروع می‌کند، امن کار می‌کند، شفافیت دارد و داده‌هایش قابل حمل است، به مراتب چابک‌تر و تاب‌آورتر از تیمی است که هر یک از این مزایا را از ابزارهای جداگانه تأمین می‌کند. +
+
+
+ + + + +
+
+
۴
+
+

معماری فنی پروژه

+
Technical Architecture Deep Dive
+
+
+
+

xKanban بر پایه معماری Single-Page Application (SPA) با الگوی State-Driven Rendering پیاده‌سازی شده است. تمامی منطق در سمت کلاینت اجرا می‌شود و از معماری لایه‌ای سه‌تایی Presentation / Application / Data استفاده شده است.

+ +
+
+
🎨 Presentation Layer
+
+Toolbar Renderer +Board View +Column Renderer +Card Renderer +Modal System +Filter Panel +Toast Notifications +
+
+
▼
+
+
⚙️ Application Layer
+
+Project Manager +Board Manager +Column Manager +Card Manager +Tag Manager +Filter Engine +Webhook Service +Shortcut Handler +Export Engine +
+
+
▼
+
+
💾 Data Layer
+
+State Container +LocalStorage Adapter +AutoSave Engine +JSON Serializer +UUID Generator +
+
+
+ +

الف) متدهای راه‌اندازی و چرخه حیات

+
+// ── راه‌اندازی اولیه برنامه ──
+function init() { ... }

+// ── رندر کامل رابط کاربری ──
+function render() { ... }

+// ── رندر نوار ابزار بالا ──
+function renderToolbar() { ... }

+// ── رندر برد فعال ──
+function renderBoard() { ... } +
+ +

ب) متدهای مدیریت پروژه و پایداری

+
+// ── ذخیره پروژه در LocalStorage ──
+function saveProject() { ... }

+// ── بارگذاری پروژه از LocalStorage ──
+function loadProject() { ... }

+// ── ذخیره خودکار با Debounce ──
+function scheduleAutoSave() { ... }

+// ── بازیابی داده‌های ذخیره خودکار ──
+function recoverAutoSave() { ... }

+// ── تنظیمات پروژه (عنوان، توضیحات، وب‌هوک) ──
+function openProjectSettings() { ... }
+function saveProjectSettings() { ... } +
+ +

ج) متدهای مدیریت بردها

+
+// ── ایجاد برد جدید ──
+function createBoard() { ... }

+// ── ویرایش برد موجود ──
+function editBoard(boardId) { ... }

+// ── حذف برد ──
+function deleteBoard(boardId) { ... }

+// ── جابجایی بین بردها ──
+function switchBoard(boardId) { ... } +
+ +

د) متدهای مدیریت ستون‌ها

+
+// ── ایجاد ستون جدید ──
+function createColumn() { ... }

+// ── ویرایش ستون ──
+function editColumn(columnId) { ... }

+// ── حذف ستون ──
+function deleteColumn(columnId) { ... }

+// ── جابجایی ستون با Drag & Drop ──
+function moveColumn(fromIndex, toIndex) { ... } +
+ +

هـ) متدهای مدیریت کارت‌ها (غنی‌ترین ماژول)

+
+// ── ایجاد کارت جدید ──
+function createCard(columnId) { ... }

+// ── ویرایش کارت (Modal کامل) ──
+function editCard(cardId) { ... }

+// ── حذف کارت ──
+function deleteCard(cardId) { ... }

+// ── جابجایی کارت بین ستون‌ها ──
+function moveCard(cardId, targetColumnId) { ... }

+// ── افزودن/حذف مسئول ──
+function addAssignee(cardId, name) { ... }
+function removeAssignee(cardId, name) { ... }

+// ── مدیریت چک‌لیست ──
+function addChecklistItem(cardId, text) { ... }
+function toggleChecklistItem(cardId, itemIndex) { ... }
+function removeChecklistItem(cardId, itemIndex) { ... }

+// ── مدیریت وابستگی‌ها ──
+function addDependency(cardId, dependencyId) { ... }
+function removeDependency(cardId, dependencyId) { ... }

+// ── ثبت تاریخچه جابجایی ──
+function addHistoryEntry(cardId, fromColumn, toColumn) { ... } +
+ +

و) متدهای مدیریت تگ‌ها

+
+// ── مدیریت تگ‌های عمومی پروژه ──
+function openTagManager() { ... }
+function addTag(name, color) { ... }
+function removeTag(tagId) { ... }

+// ── تخصیص/حذف تگ به کارت ──
+function assignTagToCard(cardId, tagId) { ... }
+function removeTagFromCard(cardId, tagId) { ... } +
+ +

ز) متدهای فیلتر و جستجو

+
+// ── فیلتر چندبعدی کارت‌ها ──
+function filterCards() { ... }

+// ── جستجوی متنی در کارت‌ها ──
+function searchCards(query) { ... }

+// ── پاک‌سازی فیلترها ──
+function clearFilters() { ... } +
+ +

ح) متدهای صادرات و واردات

+
+// ── صادرات پروژه به فایل JSON ──
+function exportJSON() { ... }

+// ── واردات پروژه از فایل JSON ──
+function importJSON(file) { ... }

+// ── خروجی Markdown ──
+function exportMarkdown(boardFilter) { ... }

+// ── خروجی CSV ──
+function exportCSV(boardFilter) { ... } +
+ +

ط) متدهای یکپارچگی و Webhook

+
+// ── ارسال رویداد به Webhook ──
+function sendWebhook(eventType, data) { ... }

+// ── تست اتصال Webhook ──
+function testWebhook() { ... } +
+ +

ی) متدهای رابط کاربری و تعامل

+
+// ── سیستم Modal ──
+function openModal(modalId) { ... }
+function closeModal(modalId) { ... }

+// ── اعلان‌های Toast ──
+function showToast(message, type) { ... }

+// ── تغییر حالت تاریک/روشن ──
+function toggleDarkMode() { ... }

+// ── مدیریت میانبرهای کیبورد ──
+function handleKeyboardShortcuts(event) { ... } +
+ +

ک) متدهای کمکی

+
+// ── تولید شناسه یکتا ──
+function generateUUID() { ... }

+// ── محاسبه وضعیت سررسید کارت ──
+function getCardDueStatus(card) { ... }

+// ── محاسبه آمار برد ──
+function calculateBoardStats() { ... }

+// ── دانلود فایل ──
+function downloadFile(content, filename, mimeType) { ... } +
+ +
+💡 اصل طراحی کدها: تمامی متدها بر اساس اصل Single Responsibility طراحی شده‌اند. هر متد دقیقاً یک وظیفه مشخص دارد و از ترکیب آن‌ها، رفتارهای پیچیده‌تر ساخته می‌شود. بدنه متدها در این مستند با ... خلاصه شده تا تمرکز بر ساختار و معماری باقی بماند. +
+ +

جریان داده در سیستم:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
مرحلهعملیاتمتد درگیر
۱کاربر عملیاتی انجام می‌دهد (مثلاً ایجاد کارت)createCard()
۲وضعیت State به‌روزرسانی می‌شودمستقیم روی State Container
۳رابط کاربری مجدداً رندر می‌شودrender()
۴ذخیره خودکار زمان‌بندی می‌شودscheduleAutoSave()
۵در صورت فعال بودن، Webhook ارسال می‌شودsendWebhook()
۶اعلان تأیید به کاربر نمایش داده می‌شودshowToast()
+
+
+ + + + +
+
+
۵
+
+

مخاطبان هدف: سازمان‌ها و تیم‌های مناسب

+
Target Audience & Ideal Use Cases
+
+
+
+

xKanban برای طیف گسترده‌ای از سازمان‌ها و تیم‌ها مناسب است. در ادامه، مخاطبان ایده‌آل این ابزار بر اساس ویژگی‌ها و نیازمندی‌هایشان دسته‌بندی شده‌اند:

+ +

الف) بر اساس نوع سازمان:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع سازمانچرا xKanban مناسب است؟
استارتاپ‌هابودجه محدود، نیاز به شروع سریع، عدم تمایل به وابستگی به ابزارهای گران‌قیمت SaaS
شرکت‌های کوچک و متوسطفقدان تیم IT اختصاصی برای نگهداری سرور، نیاز به ابزار ساده ولی حرفه‌ای
سازمان‌های دولتی و نظامیالزامات سخت‌گیرانه امنیتی، ممنوعیت ارسال داده به سرورهای خارجی، نیاز به کارکرد آفلاین
مراکز تحقیقاتی و دانشگاهیمدیریت پروژه‌های پژوهشی، کار در محیط‌های ایزوله شبکه‌ای، بودجه محدود
شرکت‌های مشاوره‌ایمدیریت همزمان چندین پروژه مشتری، نیاز به قابلیت حمل و ارائه گزارش
تیم‌های توزیع‌شده و ریموتاشتراک‌گذاری آسان پروژه از طریق فایل، عدم وابستگی به اتصال اینترنت پایدار
+ +

ب) بر اساس نوع تیم:

+ +
+
+
💻
+
تیم‌های توسعه نرم‌افزار
+

مدیریت اسپرینت‌ها، پیگیری باگ‌ها، مدیریت وابستگی‌های فنی و یکپارچگی با ابزارهای CI/CD از طریق Webhook

+
+
+
🎨
+
تیم‌های طراحی و خلاقیت
+

پیگیری مراحل طراحی، مدیریت بازخوردها، رنگ‌بندی بصری برای دسته‌بندی پروژه‌ها

+
+
+
📢
+
تیم‌های بازاریابی و محتوا
+

مدیریت تقویم محتوایی، پیگیری کمپین‌ها، تخصیص وظایف به نویسندگان و طراحان

+
+
+
🏗️
+
تیم‌های عملیات و زیرساخت
+

مدیریت تیکت‌ها، پیگیری حوادث، ثبت تاریخچه جابجایی برای گزارش‌گیری

+
+
+
🎓
+
تیم‌های آموزشی و آکادمیک
+

مدیریت پروژه‌های دانشجویی، پیگیری تکالیف، کار در محیط‌های بدون اینترنت

+
+
+
🧑‍💼
+
فریلنسرها و مشاوران مستقل
+

مدیریت چندین پروژه مشتری، قابلیت حمل، عدم هزینه اشتراک ماهیانه

+
+
+ +

ج) سناریوهای ایده‌آل استفاده:

+ +
+ + +
+ +
+💡 نکته مهم: xKanban در حال حاضر برای استفاده فردی یا تیم‌های کوچک تا متوسط طراحی شده است. برای سازمان‌های بزرگ با نیاز به همزمانی چندکاربره بلادرنگ، نسخه فعلی به عنوان ابزار مکمل در کنار سیستم‌های سازمانی قابل استفاده است و نسخه چندکاربره در نقشه راه آینده قرار دارد. +
+
+
+ + + + +
+
+
۶
+
+

جمع‌بندی نهایی

+
Final Summary
+
+
+
+

xKanban پاسخی مهندسی‌شده به معضلات واقعی مدیریت پروژه در دنیای مدرن است. این ابزار با حذف وابستگی به سرور، تضمین مالکیت داده‌ها، ارائه قابلیت حمل بی‌نظیر و حفظ غنای عملکردی، جایگاه منحصربه‌فردی در اکوسیستم ابزارهای مدیریت پروژه دارد.

+ +
+

🎯 ارزش پیشنهادی xKanban در یک نگاه

+

ابزاری حرفه‌ای، مستقل، امن و قابل حمل برای مدیریت پروژه‌های کانبان که بدون هیچ هزینه‌ای، بدون نیاز به سرور و بدون وابستگی به اینترنت، در اختیار تیم شما قرار می‌گیرد.

+
+💎 فرمول ارزش xKanban:
+استقلال از زیرساخت + مالکیت کامل داده + قابلیت حمل + غنای عملکردی + سادگی = آزادی عمل مطلق تیم +
+
+ +
+📞 گام بعدی: برای ارزیابی عملی xKanban در محیط سازمان خود، می‌توانید فایل HTML را مستقیماً در مرورگر باز کرده و بدون هیچ پیکربندی، تجربه کاربری واقعی را لمس کنید. جهت سفارشی‌سازی یا توسعه ویژگی‌های اختصاصی، آماده برگزاری جلسه فنی هستیم. +
+
+
+ +
+این مستند محرمانه بوده و صرفاً جهت استفاده داخلی و ارائه به ذی‌نفعان تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+ +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۱:۳۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: داخلی - محصولی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Case_Study.html + + + + + + +xKanban | مستند جامع معرفی محصول و معماری فنی + + + +
+ + +
+
+
+ +
+
+
شماره مستند: PROD-XKN-1405-002
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۰:۳۰
+
طبقه‌بندی: عمومی - معرفی محصول
+
+
+
+PRODUCT DOCUMENTATION +

xKanban | ابزار مدیریت بردهای کانبان

+

معرفی محصول، تحلیل ارزش سازمانی و معماری فنی

+
+
+ + +
+ +
+مخاطبان مستند: مدیران فناوری اطلاعات، مدیران پروژه، سرپرستان تیم‌های توسعه، معماران نرم‌افزار و تصمیم‌گیرندگان سازمانی
+این مستند به معرفی جامع ابزار xKanban می‌پردازد؛ ابزاری که از دل نیازهای واقعی تیم‌های چابک متولد شده و با هدف حذف پیچیدگی‌های غیرضروری ابزارهای مدیریت پروژه طراحی شده است. در این مستند، از چرایی شکل‌گیری محصول تا معماری فنی و ارزش‌های سازمانی آن، همه‌چیز تشریح شده است. +
+ + +
+

📑 فهرست مطالب

+
    +
  1. شرح مسئله و چرایی خلق xKanban
  2. +
  3. مزایای کلیدی محصول
  4. +
  5. ارزش‌های سازمانی خلق‌شده
  6. +
  7. معماری فنی پروژه
  8. +
  9. مناسب برای چه سازمان‌ها و تیم‌هایی؟
  10. +
  11. جمع‌بندی و گام‌های بعدی
  12. +
+
+ + +
+
+
۱
+
+

شرح مسئله و چرایی خلق xKanban

+
Problem Statement & Product Genesis
+
+
+
+ +

در دنیای امروز، تقریباً هر تیمی — از توسعه نرم‌افزار گرفته تا بازاریابی، منابع انسانی و عملیات — با یک چالش مشترک دست‌وپنجه نرم می‌کند: چگونه کارها را به‌صورت شفاف، منظم و قابل ردیابی مدیریت کنیم؟ متدولوژی کانبان به‌عنوان یکی از مؤثرترین رویکردهای مدیریت بصری کار، سال‌هاست که پاسخ این سؤال را ارائه داده است؛ اما ابزارهای موجود برای پیاده‌سازی این متدولوژی، خود به منبع جدیدی از پیچیدگی تبدیل شده‌اند.

+ +

معضلات رایج در اکوسیستم ابزارهای فعلی:

+ +
+⚠️ چالش‌هایی که تیم‌ها هر روز با آن‌ها مواجه‌اند: +
    +
  • وابستگی به اینترنت و سرور: بسیاری از ابزارها نیازمند اتصال دائمی به اینترنت و سرورهای ابری هستند. در محیط‌هایی با محدودیت شبکه یا الزامات امنیتی بالا، این وابستگی یک مانع جدی است.
  • +
  • هزینه‌های اشتراک ماهانه: ابزارهای تجاری برای هر کاربر هزینه اشتراک دریافت می‌کنند. برای تیم‌های بزرگ، این هزینه به‌سرعت به رقم قابل‌توجهی تبدیل می‌شود.
  • +
  • پیچیدگی بیش‌ازحد: ابزارهایی مانند Jira یا Azure DevOps صدها قابلیت دارند که اکثر تیم‌ها از کمتر از ۲۰ درصد آن‌ها استفاده می‌کنند. این پیچیدگی، منحنی یادگیری را بالا برده و بهره‌وری را کاهش می‌دهد.
  • +
  • فرآیند نصب و راه‌اندازی سنگین: برخی ابزارها نیازمند نصب سرور، پیکربندی دیتابیس و مدیریت زیرساخت هستند که زمان و تخصص قابل‌توجهی می‌طلبد.
  • +
  • قفل‌شدگی داده‌ها (Vendor Lock-in): داده‌های پروژه در سرورهای ارائه‌دهنده سرویس ذخیره می‌شوند و خروج از آن اکوسیستم، پرهزینه و دشوار است.
  • +
  • عدم قابلیت حمل: انتقال پروژه از یک محیط به محیط دیگر (مثلاً از لپ‌تاپ شخصی به سیستم شرکت) در بسیاری از ابزارها فرآیندی پیچیده است.
  • +
+
+ +

این معضلات، یک شکاف آشکار در بازار ابزارهای مدیریت پروژه ایجاد کرده بود: جای خالی ابزاری ساده، مستقل، رایگان و در عین حال حرفه‌ای که بدون هیچ پیش‌نیازی قابل استفاده باشد و در عین حال، قابلیت‌های پیشرفته‌ای مانند فیلتر چندبعدی، تاریخچه تغییرات، وابستگی بین کارت‌ها و یکپارچگی با سیستم‌های خارجی را ارائه دهد.

+ +
+🎯 نقطه عطف: xKanban دقیقاً از همین شکاف متولد شد. هدف، خلق ابزاری بود که «صفر تا صد» مدیریت کانبان را بدون هیچ وابستگی خارجی، در یک فایل واحد و قابل حمل ارائه دهد — ابزاری که در کمتر از ۳ ثانیه باز شود و از همان لحظه اول قابل استفاده باشد. +
+ +

نیازمندی‌های کلیدی که xKanban برای پاسخ به آن‌ها طراحی شد:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفنیازمندیوضعیت در ابزارهای موجودپاسخ xKanban
۱اجرای آفلاین و بدون سروراکثراً ناممکن✓ کاملاً آفلاین
۲بدون هزینه اشتراکاشتراک ماهانه/سالانه✓ کاملاً رایگان
۳راه‌اندازی فورینیاز به نصب و پیکربندی✓ یک کلیک
۴قابلیت حمل داده‌هامحدود و پیچیده✓ فایل JSON
۵سادگی همراه با قدرتیا ساده یا پیچیده✓ تعادل بهینه
۶مالکیت کامل داده‌هاذخیره در سرور ثالث✓ کاملاً محلی
+ +
+
+ + +
+
+
۲
+
+

مزایای کلیدی محصول

+
Key Product Advantages
+
+
+
+ +

xKanban مجموعه‌ای از مزایای منحصربه‌فرد را ارائه می‌دهد که آن را از تمامی ابزارهای موجود در بازار متمایز می‌سازد. این مزایا نه صرفاً ویژگی‌های فنی، بلکه تصمیمات استراتژیک طراحی هستند که هر کدام پاسخی مستقیم به یکی از معضلات مطرح‌شده در بخش قبل می‌باشند.

+ +
+
+
۰ ثانیه
نصب
+
بدون نیاز به هیچ فرآیند نصب یا پیکربندی
+
+
+
۱۰۰٪
آفلاین
+
اجرای کامل بدون نیاز به اینترنت یا سرور
+
+
+
۱ فایل
واحد
+
تمام محصول در یک فایل HTML مستقل
+
+
+ +
+
+
🚀
+
راه‌اندازی آنی
+

فایل HTML را در مرورگر باز کنید. تمام. هیچ سروری، هیچ دیتابیسی، هیچ اکانتی لازم نیست. در کمتر از ۳ ثانیه آماده استفاده هستید.

+
+
+
🔒
+
حریم خصوصی مطلق
+

تمام داده‌ها در مرورگر شما باقی می‌مانند. هیچ اطلاعاتی به هیچ سرور خارجی ارسال نمی‌شود. مالکیت داده‌ها ۱۰۰٪ در اختیار شماست.

+
+
+
📦
+
قابلیت حمل بی‌نظیر
+

پروژه خود را به‌صورت فایل JSON ذخیره کنید و روی فلش، ایمیل یا هر فضای ابری منتقل کنید. در هر سیستمی قابل بارگذاری است.

+
+
+
🎨
+
رابط کاربری مدرن و حرفه‌ای
+

طراحی بصری جذاب با پشتیبانی از حالت تاریک/روشن، رنگ‌بندی سفارشی برای بردها، ستون‌ها و کارت‌ها و انیمیشن‌های روان.

+
+
+
🔍
+
فیلتر چندبعدی پیشرفته
+

فیلتر هم‌زمان بر اساس تگ، مسئول، وضعیت سررسید و جستجوی متنی. یافتن هر کارت در کمتر از یک ثانیه حتی در پروژه‌های بزرگ.

+
+
+
📡
+
یکپارچگی با Webhook
+

ارسال خودکار رویدادهای پروژه به Slack، Teams یا هر سیستم خارجی. ساختار JSON استاندارد با eventId و timestamp.

+
+
+
⌨️
+
میانبرهای کیبورد حرفه‌ای
+

بیش از ۸ میانبر کیبورد برای کاربران حرفه‌ای. از Ctrl+S برای ذخیره تا Alt+Arrow برای جابجایی سریع کارت‌ها بین ستون‌ها.

+
+
+
📊
+
آمار بلادرنگ پروژه
+

مشاهده آنی تعداد کارت‌ها، درصد پیشرفت، کارت‌های عقب‌افتاده و نزدیک به موعد در نوار وضعیت پایین صفحه.

+
+
+ +
+💎 مزیت رقابتی اصلی: xKanban تنها ابزاری است که ترکیب «سادگی یک فایل HTML» و «قدرت یک سیستم مدیریت پروژه حرفه‌ای» را به‌صورت هم‌زمان ارائه می‌دهد. هیچ ابزار دیگری در بازار این تعادل را برقرار نکرده است. +
+ +

مقایسه با ابزارهای رایج بازار:

+
+
+

ابزارهای تجاری (Jira, Trello, Asana)

+
    +
  • هزینه اشتراک ماهانه بالا
  • +
  • نیاز به اینترنت الزامی
  • +
  • نصب و راه‌اندازی ثبت‌نام + پیکربندی
  • +
  • مالکیت داده سرور ثالث
  • +
  • پیچیدگی بسیار بالا
  • +
  • آفلاین ناممکن
  • +
+
+ +
+ +
+
+ + +
+
+
۳
+
+

ارزش‌های سازمانی خلق‌شده

+
Organizational Value Proposition
+
+
+
+ +

استفاده از xKanban در یک سازمان، فراتر از صرفاً «مدیریت کارها» است. این ابزار، ارزش‌های استراتژیک و عملیاتی ملموسی را در سطوح مختلف سازمان خلق می‌کند که در ادامه به تفصیل تشریح شده‌اند:

+ +
+
💰
+
+
حذف کامل هزینه‌های لایسنس و اشتراک
+

سازمان‌هایی که از ابزارهایی مانند Jira یا Azure DevOps استفاده می‌کنند، سالانه مبالغ قابل‌توجهی بابت لایسنس هر کاربر پرداخت می‌کنند. xKanban این هزینه را به صفر می‌رساند و بودجه آزادشده را برای سرمایه‌گذاری در حوزه‌های ارزشمندتر آزاد می‌کند.

+
+
+ +
+
🔐
+
+
تطبیق با الزامات امنیتی و حریم خصوصی
+

در سازمان‌هایی با حساسیت امنیتی بالا (نظامی، بانکی، بهداشتی)، ارسال داده‌های پروژه به سرورهای ابری خارجی ممنوع یا محدود است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را به‌صورت ذاتی رعایت می‌کند.

+
+
+ +
+
⚡
+
+
کاهش زمان Onboarding اعضای جدید
+

برخلاف ابزارهای پیچیده که آموزش آن‌ها هفته‌ها زمان می‌برد، xKanban به‌قدری ساده و شهودی است که یک عضو جدید تیم در کمتر از ۱۰ دقیقه با آن آشنا شده و شروع به کار می‌کند.

+
+
+ +
+
📈
+
+
افزایش شفافیت و پاسخگویی در تیم
+

با نمایش بصری وضعیت تمام کارها، تاریخچه جابجایی کارت‌ها و آمار بلادرنگ پیشرفت، هر عضو تیم و هر مدیری در هر لحظه دید کاملی از وضعیت پروژه دارد. این شفافیت، فرهنگ پاسخگویی را تقویت می‌کند.

+
+
+ +
+
🔄
+
+
استانداردسازی فرآیندهای مدیریت پروژه
+

xKanban تیم‌ها را به استفاده از یک متدولوژی استاندارد (کانبان) هدایت می‌کند. ستون‌های مشخص، جریان کار تعریف‌شده و تاریخچه تغییرات، همگی به ایجاد یک فرآیند تکرارپذیر و قابل اندازه‌گیری کمک می‌کنند.

+
+
+ +
+
🛡️
+
+
حذف ریسک Vendor Lock-in
+

داده‌های پروژه در فرمت استاندارد JSON ذخیره می‌شوند. این یعنی سازمان هیچ‌گاه در اکوسیستم یک ارائه‌دهنده خاص قفل نمی‌شود و در هر زمان می‌تواند داده‌های خود را به هر سیستم دیگری منتقل کند.

+
+
+ +
+
🌐
+
+
یکپارچگی با اکوسیستم موجود سازمان
+

از طریق مکانیزم Webhook، xKanban می‌تواند رویدادهای پروژه را به Slack، Microsoft Teams، سیستم‌های CI/CD یا هر API سفارشی ارسال کند. این یعنی xKanban به‌جای جایگزینی ابزارهای موجود، آن‌ها را تکمیل می‌کند.

+
+
+ +
+
📉
+
+
کاهش سربار مدیریت زیرساخت
+

بدون نیاز به سرور، دیتابیس، به‌روزرسانی‌های امنیتی و مانیتورینگ، تیم IT سازمان از بار مدیریت یک ابزار اضافی رها می‌شود. این صرفه‌جویی در زمان و منابع انسانی، ارزش پنهان اما بسیار قابل‌توجهی است.

+
+
+ +
+📊 خلاصه ارزش‌آفرینی: xKanban در چهار بُعد اصلی برای سازمان ارزش خلق می‌کند: کاهش هزینه‌ها (حذف لایسنس و زیرساخت)، افزایش بهره‌وری (Onboarding سریع و رابط شهودی)، کاهش ریسک (امنیت داده و عدم وابستگی) و بهبود کیفیت فرآیندها (استانداردسازی و شفافیت). +
+ +
+
+ + +
+
+
۴
+
+

معماری فنی پروژه

+
Technical Architecture & Code Structure
+
+
+
+ +

xKanban به‌عنوان یک Single-Page Application (SPA) تک‌فایلی طراحی شده است که تمامی لایه‌های نمایش، منطق و داده را در یک فایل HTML واحد encapsulate می‌کند. این تصمیم معماری، اگرچه در نگاه اول غیرمعمول به نظر می‌رسد، اما با توجه به اهداف محصول (آفلاین بودن، قابلیت حمل و عدم وابستگی) منطقی‌ترین انتخاب ممکن بوده است.

+ +

الف) نمودار معماری لایه‌ای

+ +
+
+
🎨 Presentation Layer
+
+Toolbar UI +Board Renderer +Column Renderer +Card Renderer +Modal System +Filter Panel +Stats Bar +Theme Engine +
+
+
▼ Event Binding & State Observation ▼
+
+
⚙️ Application Logic Layer
+
+ProjectManager +BoardManager +ColumnManager +CardManager +TagManager +FilterEngine +WebhookService +ShortcutHandler +HistoryTracker +
+
+
▼ Read / Write / Sync ▼
+
+
💾 Data & Persistence Layer
+
+AppState (In-Memory) +LocalStorage Adapter +AutoSave Engine +JSON Serializer +Export/Import Service +Recovery Manager +
+
+
+ +

ب) مدل داده‌ای (Data Schema)

+

ساختار داده‌ای پروژه از یک سلسله‌مراتب چهارسطحی پیروی می‌کند:

+ +
+// ساختار سلسله‌مراتبی داده‌ها
+Project
+  ├── id: UUID
+  ├── title: string
+  ├── description: string
+  ├── createdAt: ISO8601
+  ├── webhook: { enabled, url }
+  ├── globalTags: [Tag]
+  └── boards: [
+        Board
+          ├── id, title, backgroundColor
+          └── columns: [
+              Column
+                ├── id, title, order
+                └── cards: [
+                    Card
+                      ├── id, title, description
+                      ├── dueDate, assignees, tags
+                      ├── dependencies, checklist
+                      └── history: [HistoryEntry]
+                  ]
+            ]
+      ]
+
+ +

ج) ماژول‌های اصلی و متدهای کلیدی

+

در ادامه، مهم‌ترین ماژول‌های سیستم به همراه متدهای کلیدی هر کدام تشریح شده‌اند. برای حفظ خوانایی، بدنه متدها خلاصه شده و تنها امضای آن‌ها نمایش داده شده است:

+ +
📁 ماژول ProjectManager
+
    +
  • +initProject() +مقداردهی اولیه پروژه +
  • +
  • +loadProject(data) +بارگذاری پروژه از فایل JSON +
  • +
  • +saveProject(filename) +ذخیره پروژه به‌صورت فایل JSON +
  • +
  • +updateProjectSettings(title, desc, webhook) +به‌روزرسانی تنظیمات پروژه +
  • +
  • +getProjectStats() +محاسبه آمار کلی پروژه +
  • +
+ +
📊 ماژول BoardManager
+
    +
  • +createBoard(title, description, bgColor) +ایجاد برد جدید +
  • +
  • +editBoard(boardId, data) +ویرایش برد موجود +
  • +
  • +deleteBoard(boardId) +حذف برد با تأیید کاربر +
  • +
  • +switchBoard(boardId) +تغییر برد فعال +
  • +
  • +renderBoardList() +رندر لیست بردها در منو +
  • +
+ +
📑 ماژول ColumnManager
+
    +
  • +addColumn(boardId, title, bgColor, textColor) +افزودن ستون جدید به برد +
  • +
  • +editColumn(columnId, data) +ویرایش ویژگی‌های ستون +
  • +
  • +deleteColumn(columnId) +حذف ستون و کارت‌های آن +
  • +
  • +reorderColumns(draggedId, targetId) +تغییر ترتیب ستون‌ها با Drag & Drop +
  • +
  • +renderColumns(boardId) +رندر ستون‌های برد فعال +
  • +
+ +
📝 ماژول CardManager
+
    +
  • +createCard(columnId, cardData) +ایجاد کارت جدید در ستون +
  • +
  • +updateCard(cardId, updates) +به‌روزرسانی اطلاعات کارت +
  • +
  • +deleteCard(cardId) +حذف کارت از ستون +
  • +
  • +moveCard(cardId, fromColumnId, toColumnId) +جابجایی کارت بین ستون‌ها +
  • +
  • +addChecklistItem(cardId, text) +افزودن آیتم به چک‌لیست +
  • +
  • +toggleChecklistItem(cardId, itemId) +تغییر وضعیت آیتم چک‌لیست +
  • +
  • +addDependency(cardId, dependOnCardId) +ایجاد وابستگی بین کارت‌ها +
  • +
  • +assignMember(cardId, memberName) +تخصیص مسئول به کارت +
  • +
  • +getCardDueStatus(card) +تعیین وضعیت سررسید کارت +
  • +
  • +openCardModal(cardId) +باز کردن پنجره ویرایش کارت +
  • +
+ +
🏷️ ماژول TagManager
+
    +
  • +createTag(name, color) +ایجاد تگ عمومی جدید +
  • +
  • +deleteTag(tagId) +حذف تگ و حذف از کارت‌ها +
  • +
  • +assignTagToCard(cardId, tagId) +تخصیص تگ به کارت +
  • +
  • +removeTagFromCard(cardId, tagId) +حذف تگ از کارت +
  • +
  • +renderTagManager() +رندر پنل مدیریت تگ‌ها +
  • +
+ +
🔍 ماژول FilterEngine
+
    +
  • +applyFilters(criteria) +اعمال فیلترهای چندبعدی +
  • +
  • +filterByTags(selectedTags) +فیلتر بر اساس تگ‌ها +
  • +
  • +filterByAssignees(selectedAssignees) +فیلتر بر اساس مسئولین +
  • +
  • +filterByDueStatus(status) +فیلتر بر اساس وضعیت سررسید +
  • +
  • +searchCards(query) +جستجوی متنی در کارت‌ها +
  • +
  • +clearAllFilters() +پاک‌سازی تمام فیلترها +
  • +
+ +
📡 ماژول WebhookService
+
    +
  • +sendEvent(eventType, payload) +ارسال رویداد به URL پیکربندی‌شده +
  • +
  • +testWebhook(url) +تست اتصال Webhook +
  • +
  • +buildEventPayload(eventType, data) +ساخت ساختار JSON استاندارد رویداد +
  • +
+ +
💾 ماژول PersistenceEngine
+
    +
  • +autoSave() +ذخیره خودکار در LocalStorage +
  • +
  • +loadAutoSave() +بارگذاری داده‌های ذخیره‌شده خودکار +
  • +
  • +scheduleAutoSave() +زمان‌بندی ذخیره با Debounce +
  • +
  • +exportToJSON() +خروجی فایل JSON +
  • +
  • +importFromJSON(file) +بارگذاری از فایل JSON +
  • +
  • +exportToMarkdown(boardId) +خروجی فرمت Markdown +
  • +
  • +exportToCSV(boardId) +خروجی فرمت CSV +
  • +
  • +checkRecovery() +بررسی وجود داده‌های بازیابی +
  • +
+ +
⌨️ ماژول ShortcutHandler
+
    +
  • +registerShortcuts() +ثبت تمام میانبرهای کیبورد +
  • +
  • +handleKeyDown(event) +پردازش رویدادهای کیبورد +
  • +
  • +navigateCards(direction) +پیمایش بین کارت‌ها با Tab +
  • +
  • +moveCardWithKeyboard(direction) +جابجایی کارت با Alt+Arrow +
  • +
+ +

د) الگوهای طراحی به‌کاررفته

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل استفادههدف
State-Driven Renderingکل رابط کاربریرندر UI بر اساس وضعیت مرکزی AppState
Observer / Pub-Subارتباط ماژول‌هااطلاع‌رسانی تغییرات وضعیت به ماژول‌های وابسته
DebouncingAutoSave Engineجلوگیری از نوشتن مکرر در LocalStorage
Factoryایجاد موجودیت‌هاتولید اشیاء Card، Column، Board با UUID
CommandUndo/Redoذخیره عملیات برای امکان بازگشت
SingletonAppStateیک منبع واحد حقیقت برای کل برنامه
+ +

ه) جریان داده (Data Flow)

+
+🔄 چرخه حیات یک عملیات کاربر:

+۱. User Action: کاربر یک کارت را از ستون «در حال انجام» به ستون «تکمیل‌شده» می‌کشد.
+۲. Event Capture: رویداد Drag & Drop توسط ColumnManager دریافت می‌شود.
+۳. State Update: متد moveCard() از CardManager فراخوانی شده و AppState به‌روزرسانی می‌شود.
+۴. History Log: متد HistoryTracker.log() جابجایی را با timestamp ثبت می‌کند.
+۵. Re-Render: متد renderColumns() رابط کاربری را با وضعیت جدید به‌روزرسانی می‌کند.
+۶. AutoSave: متد scheduleAutoSave() با تأخیر ۱ ثانیه، وضعیت را در LocalStorage ذخیره می‌کند.
+۷. Webhook: در صورت فعال بودن، متد sendEvent('card.moved', payload) رویداد را ارسال می‌کند.
+۸. Stats Update: متد getProjectStats() آمار نوار وضعیت را به‌روزرسانی می‌کند. +
+ +
+
+ + +
+
+
۵
+
+

مناسب برای چه سازمان‌ها و تیم‌هایی؟

+
Target Audience & Ideal Use Cases
+
+
+
+ +

xKanban به‌گونه‌ای طراحی شده که طیف وسیعی از سازمان‌ها و تیم‌ها بتوانند از آن بهره‌مند شوند. با این حال، برخی محیط‌ها بیشترین ارزش را از این ابزار دریافت خواهند کرد:

+ +

الف) سازمان‌های هدف

+ +
+
+
🏢
+
استارتاپ‌ها و شرکت‌های کوچک
+

تیم‌هایی که بودجه محدود دارند و به ابزاری رایگان، سریع و بدون سربار نیاز دارند. xKanban جایگزین ایده‌آل Trello و Asana برای این تیم‌هاست.

+
+
+
🏛️
+
سازمان‌های دولتی و نظامی
+

محیط‌هایی با محدودیت‌های امنیتی شدید که استفاده از سرویس‌های ابری خارجی ممنوع است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را رعایت می‌کند.

+
+
+
🏥
+
مراکز بهداشتی و درمانی
+

بیمارستان‌ها و مراکز تحقیقاتی که داده‌های حساس بیماران و پروژه‌ها نباید از شبکه داخلی خارج شود.

+
+
+
🏦
+
مؤسسات مالی و بانکی
+

سازمان‌هایی که تحت مقررات سخت‌گیرانه حفاظت از داده (مانند PCI-DSS) فعالیت می‌کنند و نمی‌توانند اطلاعات پروژه‌ها را در سرورهای ثالث ذخیره کنند.

+
+
+
🎓
+
دانشگاه‌ها و مراکز آموزشی
+

اساتید و دانشجویانی که برای مدیریت پروژه‌های تحقیقاتی، پایان‌نامه‌ها و کارهای گروهی به ابزاری ساده و رایگان نیاز دارند.

+
+
+
🌍
+
تیم‌های دورکار و فریلنسرها
+

افرادی که در محیط‌های مختلف کار می‌کنند و نیاز دارند پروژه خود را روی فلش یا فضای ابری شخصی حمل کنند.

+
+
+ +

ب) تیم‌های هدف

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع تیمنحوه استفاده از xKanbanارزش اصلی
تیم‌های توسعه نرم‌افزارمدیریت Sprint، باگ‌ها و Featureهایکپارچگی با CI/CD از طریق Webhook
تیم‌های DevOpsردیابی Incidentها و Change Requestهااجرای آفلاین در محیط‌های ایزوله
تیم‌های بازاریابیمدیریت کمپین‌ها و محتوای تولیدیسادگی و سرعت راه‌اندازی
تیم‌های منابع انسانیردیابی فرآیند استخدام و Onboardingحریم خصوصی داده‌های پرسنلی
تیم‌های طراحیمدیریت پروژه‌های طراحی و بازخوردرابط بصری جذاب و رنگ‌بندی سفارشی
تیم‌های پشتیبانیمدیریت تیکت‌ها و درخواست‌های مشتریانآمار بلادرنگ و فیلتر پیشرفته
مدیران محصولنقشه راه محصول و اولویت‌بندی ویژگی‌هاوابستگی بین کارت‌ها و چک‌لیست
+ +
+🎯 قانون کلی: هر تیمی که با سؤال «الان هر کس دارد روی چه چیزی کار می‌کند و وضعیتش چیست؟» مواجه است، یک کاندیدای ایده‌آل برای استفاده از xKanban محسوب می‌شود. +
+ +

ج) چه زمانی xKanban بهترین انتخاب نیست؟

+
+💡 شفافیت کامل: xKanban برای سناریوهای زیر طراحی نشده و در این موارد، ابزارهای تخصصی‌تر توصیه می‌شوند: +
    +
  • تیم‌های بسیار بزرگ (بیش از ۵۰ نفر) که نیاز به مدیریت دسترسی سطحی و نقش‌های پیچیده دارند
  • +
  • سازمان‌هایی که نیاز به هم‌زمانی بلادرنگ (Real-time Collaboration) بین چندین کاربر دارند
  • +
  • محیط‌هایی که نیاز به یکپارچگی عمیق با اکوسیستم‌های خاص (مانند SAP یا Salesforce) دارند
  • +
+
+ +
+
+ + +
+
+
۶
+
+

جمع‌بندی و گام‌های بعدی

+
Summary & Next Steps
+
+
+
+ +

xKanban پاسخی عملی و مهندسی‌شده به یکی از رایج‌ترین چالش‌های تیم‌های مدرن است: مدیریت بصری کارها بدون پیچیدگی، بدون هزینه و بدون وابستگی. این ابزار از دل تجربه واقعی در مدیریت پروژه‌های نرم‌افزاری متولد شده و هر ویژگی آن، پاسخی مستقیم به یک نیاز واقعی است.

+ +
+

🎯 چرا xKanban؟

+

زیرا مدیریت پروژه نباید خودش یک پروژه باشد.

+

xKanban با ترکیب سادگی، قدرت و استقلال، ابزاری را ارائه می‌دهد که از لحظه اول قابل استفاده است، داده‌های شما را در اختیار خودتان نگه می‌دارد و هیچ هزینه‌ای بر دوش سازمان نمی‌گذارد.

+
+💎 ارزش نهایی:
+صفر هزینه + صفر وابستگی + صفر پیچیدگی = ۱۰۰٪ بهره‌وری +
+
+ +

گام‌های پیشنهادی برای شروع:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
گاماقدامزمان تخمینی
۱فایل xKanban.html را در مرورگر باز کنید۳ ثانیه
۲یک پروژه و برد آزمایشی ایجاد کنید۲ دقیقه
۳ستون‌ها و کارت‌های واقعی تیم خود را وارد کنید۱۰ دقیقه
۴تگ‌ها و مسئولین را تعریف کنید۵ دقیقه
۵پروژه را به‌صورت فایل JSON ذخیره کنید۱ دقیقه
۶از xKanban لذت ببرید! 🎉همیشگی
+ +
+📞 تماس و پشتیبانی: برای دریافت مشاوره فنی، سفارشی‌سازی xKanban بر اساس نیازهای خاص سازمانی یا یکپارچگی با سیستم‌های موجود، آماده برگزاری جلسه فنی هستیم. طراحی، تحلیل و توسعه توسط هادی خزاعی اصل، معمار و توسعه‌دهنده ارشد نرم‌افزار. +
+ +
+
+ +
+این مستند جهت معرفی محصول و تحلیل فنی تهیه شده است. هرگونه استفاده تجاری از محتوای این مستند بدون اجازه کتبی ممنوع است. +
+ +
+ + +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۰:۳۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: عمومی
+
+ +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Techincal_Documentation.html + + + + + + +مستند فنی پروژه xKanban | تحلیل جامع معماری و پیاده‌سازی + + + +
+
+
+
+ +
+
+
شماره مستند: TECH-XKN-1405-001
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۰:۰۰
+
طبقه‌بندی: داخلی - فنی
+
+
+
+TECHNICAL DOCUMENTATION +

مستند فنی پروژه xKanban

+

تحلیل جامع معماری، ساختار داده و پیاده‌سازی ابزار مدیریت بردهای کانبان

+
+
+ +
+
+مخاطبان مستند: تیم فنی، معماران نرم‌افزار، توسعه‌دهندگان و مدیران فنی
+این مستند به‌عنوان مرجع فنی جامع پروژه xKanban تهیه شده است و تمامی لایه‌های معماری، ساختار داده‌ها، ماژول‌های کلیدی و مکانیزم‌های پیاده‌سازی را از دیدگاه یک معمار ارشد نرم‌افزار تشریح می‌نماید. هدف از این مستند، ارائه درک عمیق از تصمیمات طراحی و ایجاد پایه‌ای مستحکم برای توسعه و نگهداری آتی محصول می‌باشد. +
+ + +
+
+
۱
+
+

خلاصه اجرایی و معرفی محصول

+
Executive Summary & Product Overview
+
+
+
+

پروژه xKanban یک ابزار تحت وب مستقل (Standalone) برای مدیریت بردهای کانبان است که با هدف ارائه راهکاری چابک، قابل حمل و بدون نیاز به سرور طراحی و پیاده‌سازی شده است. این محصول به کاربران امکان می‌دهد تا پروژه‌ها، بردها، ستون‌ها و کارت‌های کاری خود را با ساختاری استاندارد و حرفه‌ای مدیریت نمایند.

+ +
+
+
۱۰۰٪
Client-Side
+
اجرا در مرورگر بدون نیاز به سرور
+
+
+
Single
File
+
توزیع به صورت یک فایل HTML مستقل
+
+
+
Zero
Dependency
+
بدون وابستگی به کتابخانه خارجی
+
+
+ +
+🎯 چشم‌انداز طراحی: xKanban با فلسفه «ابزار در جیب کاربر» طراحی شده است؛ به گونه‌ای که کاربر بدون نیاز به اتصال اینترنت، نصب نرم‌افزار یا ایجاد حساب کاربری، به یک سیستم کامل مدیریت پروژه دسترسی داشته باشد. +
+ +

اهداف کلیدی پروژه:

+
    +
  • استقلال کامل: اجرا به صورت آفلاین و بدون نیاز به زیرساخت سرور
  • +
  • قابلیت حمل: ذخیره و انتقال پروژه از طریق فایل JSON
  • +
  • تجربه کاربری حرفه‌ای: رابط کاربری مدرن با پشتیبانی از حالت تاریک/روشن
  • +
  • استانداردسازی: پیاده‌سازی دقیق متدولوژی کانبان با قابلیت‌های پیشرفته
  • +
  • یکپارچگی: اتصال به سیستم‌های خارجی از طریق Webhook
  • +
+
+
+ + +
+
+
۲
+
+

معماری کلی سیستم

+
System Architecture Overview
+
+
+
+

معماری xKanban بر پایه الگوی Single-Page Application (SPA) با رویکرد State-Driven طراحی شده است. تمامی منطق برنامه در لایه کلاینت اجرا می‌شود و از الگوی MVC سبک برای جداسازی مسئولیت‌ها استفاده شده است.

+ +
+
+
🎨 Presentation Layer (UI)
+
+Toolbar +Board View +Column Renderer +Card Renderer +Modal System +Filter Panel +
+
+
▼
+
+
⚙️ Application Layer (Logic)
+
+Board Manager +Column Manager +Card Manager +Tag Manager +Filter Engine +Shortcut Handler +Webhook Service +
+
+
▼
+
+
💾 Data Layer (State & Persistence)
+
+Project State +LocalStorage +AutoSave Engine +JSON Export/Import +History Tracker +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
لایه معماریمسئولیت اصلیتکنولوژی
Presentationرندر رابط کاربری و مدیریت رویدادهاHTML5 + CSS3 + Vanilla JS
Applicationمنطق تجاری و مدیریت عملیاتES6+ Modules Pattern
Dataمدیریت وضعیت و پایداری دادهLocalStorage + JSON API
Integrationارتباط با سیستم‌های خارجیFetch API + Webhook
+ +
+💡 نکته معماری: انتخاب معماری تک‌فایلی (Single-File) با وجود پیچیدگی بالای پروژه، یک تصمیم استراتژیک بوده است. این رویکرد امکان توزیع آسان، اجرای آفلاین و عدم وابستگی به زیرساخت را فراهم می‌آورد. +
+
+
+ + +
+
+
۳
+
+

ساختار داده‌ها و مدل‌ها

+
Data Models & Schema Design
+
+
+
+

مدل داده‌ای xKanban بر پایه ساختار سلسله‌مراتبی Project → Board → Column → Card طراحی شده است. هر سطح از این سلسله‌مراتب، موجودیت مستقلی با ویژگی‌ها و روابط خاص خود دارد.

+ +

الف) مدل Project (پروژه)

+
+Project {
+  id: "uuid",
+  title: "string",
+  description: "string",
+  createdAt: "ISO8601",
+  webhook: { enabled: boolean, url: "string" },
+  boards: [Board],
+  globalTags: [Tag]
+} +
+ +

ب) مدل Board (برد)

+
+Board {
+  id: "uuid",
+  title: "string",
+  description: "string",
+  backgroundColor: "#hex",
+  columns: [Column]
+} +
+ +

ج) مدل Column (ستون)

+
+Column {
+  id: "uuid",
+  title: "string",
+  backgroundColor: "#hex",
+  textColor: "#hex",
+  order: number,
+  cards: [Card]
+} +
+ +

د) مدل Card (کارت) - غنی‌ترین موجودیت

+
+Card {
+  id: "uuid",
+  title: "string",
+  description: "string",
+  dueDate: "ISO8601 | null",
+  backgroundColor: "#hex",
+  assignees: ["string"],
+  tags: ["tagId"],
+  dependencies: ["cardId"],
+  checklist: [{ text: "string", done: boolean }],
+  history: [{ timestamp, action, fromColumn, toColumn }]
+} +
+ +
+⚠️ نکته طراحی مهم: استفاده از UUID برای شناسه‌ها، امکان ادغام پروژه‌ها، جلوگیری از تداخل شناسه‌ها در عملیات Import/Export و پشتیبانی از همزمانی (Concurrency) را فراهم می‌آورد. این تصمیم برای مقیاس‌پذیری آینده حیاتی است. +
+ +

روابط بین موجودیت‌ها:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
رابطهنوعتوضیح
Project → BoardsOne-to-Manyهر پروژه می‌تواند چندین برد داشته باشد
Board → ColumnsOne-to-Manyهر برد شامل ستون‌های متعدد است
Column → CardsOne-to-Manyهر ستون شامل کارت‌های متعدد است
Card ↔ CardMany-to-Manyوابستگی بین کارت‌ها (Dependencies)
Card → TagsMany-to-Manyکارت‌ها می‌توانند چندین برچسب داشته باشند
Card → AssigneesMany-to-Manyهر کارت می‌تواند چندین مسئول داشته باشد
+
+
+ + +
+
+
۴
+
+

ماژول‌های کلیدی و مسئولیت‌ها

+
Core Modules & Responsibilities
+
+
+
+

سیستم xKanban از ماژول‌های مجزا و با مسئولیت مشخص تشکیل شده است. این جداسازی بر اساس اصل Single Responsibility Principle (SRP) انجام شده و امکان نگهداری و توسعه آتی را فراهم می‌آورد.

+ +
+
+
📊
+
Board Manager
+

مدیریت چرخه حیات بردها شامل ایجاد، ویرایش، حذف و جابجایی بین بردها. نگهداری وضعیت فعال برد فعلی.

+
+
+
📑
+
Column Manager
+

مدیریت ستون‌ها با قابلیت Drag & Drop برای تغییر ترتیب. پشتیبانی از رنگ‌بندی مستقل برای هر ستون.

+
+
+
📝
+
Card Manager
+

مدیریت کامل کارت‌ها شامل متادیتای غنی، چک‌لیست، وابستگی‌ها و تاریخچه جابجایی.

+
+
+
🏷️
+
Tag Manager
+

مدیریت تگ‌های عمومی پروژه با قابلیت استفاده مجدد در کارت‌های مختلف.

+
+
+
🔍
+
Filter Engine
+

موتور فیلتر چندبعدی بر اساس تگ، مسئول، وضعیت و تاریخ سررسید.

+
+
+
⌨️
+
Shortcut Handler
+

مدیریت میانبرهای کیبورد برای افزایش بهره‌وری کاربران حرفه‌ای.

+
+
+
💾
+
AutoSave Engine
+

ذخیره خودکار وضعیت در LocalStorage با مکانیزم بازیابی در صورت قطع ناگهانی.

+
+
+
📡
+
Webhook Service
+

ارسال رویدادهای پروژه به آدرس URL پیکربندی‌شده با ساختار JSON استاندارد.

+
+
+ +
+✓ مزایای معماری ماژولار: +
    +
  • جداسازی کامل مسئولیت‌ها و کاهش Coupling
  • +
  • قابلیت تست‌پذیری هر ماژول به صورت مستقل
  • +
  • امکان توسعه ویژگی‌های جدید بدون تأثیر بر ماژول‌های موجود
  • +
  • کاهش پیچیدگی شناختی برای توسعه‌دهندگان جدید
  • +
+
+
+
+ + +
+
+
۵
+
+

ویژگی‌های کلیدی و قابلیت‌ها

+
Key Features & Capabilities
+
+
+
+

xKanban مجموعه‌ای از ویژگی‌های پیشرفته را ارائه می‌دهد که آن را از ابزارهای ساده کانبان متمایز می‌سازد. در ادامه به تحلیل فنی هر ویژگی پرداخته شده است:

+ +

۱) سیستم مدیریت بردهای چندگانه

+

امکان ایجاد و مدیریت چندین برد مستقل در یک پروژه، با قابلیت جابجایی سریع بین آن‌ها از طریق منوی کشویی. هر برد دارای تنظیمات مستقل شامل رنگ پس‌زمینه و توضیحات اختصاصی است.

+ +

۲) Drag & Drop پیشرفته ستون‌ها

+

پیاده‌سازی مکانیزم Drag & Drop با استفاده از HTML5 Drag API که امکان تغییر ترتیب ستون‌ها را با کشیدن هدر آن‌ها فراهم می‌آورد. این ویژگی با حفظ وضعیت در مدل داده، پایداری ترتیب را تضمین می‌کند.

+ +

۳) کارت‌های غنی با متادیتای کامل

+

هر کارت می‌تواند شامل اطلاعات زیر باشد:

+
    +
  • تاریخ سررسید: با قابلیت نمایش وضعیت‌های مختلف (عقب‌افتاده، نزدیک به موعد، عادی، بدون تاریخ)
  • +
  • مسئولین متعدد: امکان تخصیص چندین نفر به یک کارت
  • +
  • برچسب‌های رنگی: استفاده از تگ‌های عمومی پروژه
  • +
  • وابستگی‌ها: ایجاد روابط Dependency بین کارت‌ها
  • +
  • چک‌لیست: ریزوظایف با قابلیت علامت‌گذاری
  • +
  • تاریخچه: ثبت کامل جابجایی‌های کارت بین ستون‌ها
  • +
+ +

۴) موتور فیلتر چندبعدی

+

سیستم فیلتر پیشرفته با قابلیت ترکیب فیلترهای مختلف:

+
+// نمونه‌ای از منطق فیلتر
+filteredCards = cards
+  .filter(c => selectedTags.length === 0 || c.tags.some(t => selectedTags.includes(t)))
+  .filter(c => selectedAssignees.length === 0 || c.assignees.some(a => selectedAssignees.includes(a)))
+  .filter(c => matchStatus(c, selectedStatus))
+  .filter(c => matchSearch(c, searchText)); +
+ +

۵) سیستم Webhook یکپارچه

+

امکان ارسال رویدادهای پروژه به سیستم‌های خارجی (مانند Slack، Teams یا سرویس‌های سفارشی) با ساختار استاندارد JSON:

+
+{
+  "eventId": "uuid-v4",
+  "timestamp": "2026-09-13T10:00:00Z",
+  "eventType": "card.moved",
+  "project": { "id": "...", "title": "..." },
+  "board": { "id": "...", "title": "..." },
+  "data": { "cardId": "...", "from": "...", "to": "..." }
+} +
+ +

۶) میانبرهای کیبورد جامع

+ + + + + + + + + + + + + + + + + + +
میانبرعملکردکاربرد
Ctrl+Sذخیره سریعذخیره فوری پروژه
Ctrl+Zبازگشت (Undo)لغو آخرین عملیات
Ctrl+Yاز نو (Redo)اعمال مجدد عملیات لغوشده
Ctrl+Fجستجوباز کردن پنل جستجو
Escبستن پنجره‌هابستن Modal های باز
Tabانتخاب کارتپیمایش بین کارت‌ها
Alt+←/→جابجایی کارتانتقال کارت بین ستون‌ها
Enterویرایش کارتباز کردن Modal ویرایش
+
+
+ + +
+
+
۶
+
+

مکانیزم‌های ذخیره‌سازی و پایداری

+
Persistence & Storage Mechanisms
+
+
+
+

سیستم xKanban از چندین لایه ذخیره‌سازی برای تضمین پایداری داده‌ها استفاده می‌کند. این رویکرد چندلایه، از دست رفتن داده‌ها را در سناریوهای مختلف به حداقل می‌رساند.

+ +
+
+

💾 ذخیره‌سازی محلی (LocalStorage)

+
    +
  • نوع خودکار و شفاف
  • +
  • فرکانس پس از هر تغییر
  • +
  • حجم تا ۵ مگابایت
  • +
  • دوام دائمی در مرورگر
  • +
+
+ +
+ +

مکانیزم AutoSave و بازیابی:

+

سیستم AutoSave با استفاده از الگوی Debouncing پیاده‌سازی شده است تا از نوشتن مکرر و غیرضروری در LocalStorage جلوگیری شود. در زمان راه‌اندازی، سیستم به صورت خودکار داده‌های ذخیره‌شده را بررسی کرده و در صورت وجود داده‌های بازیابی‌نشده، به کاربر اطلاع می‌دهد.

+ +
+// الگوی Debounced AutoSave
+let saveTimeout;
+function scheduleAutoSave() {
+  clearTimeout(saveTimeout);
+  saveTimeout = setTimeout(() => {
+    localStorage.setItem('xkanban_autosave', JSON.stringify(state));
+  }, 1000); // تأخیر ۱ ثانیه‌ای
+} +
+ +

فرمت‌های خروجی پشتیبانی‌شده:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
فرمتکاربردویژگی‌ها
JSONپشتیبان‌گیری کامل و انتقال پروژهحفظ تمامی داده‌ها و ساختار
Markdown (MD)مستندسازی و اشتراک‌گذاریخروجی خوانا و قابل ویرایش
CSVتحلیل داده و وارد کردن به Excelساختار جدولی استاندارد
+ +
+💡 نکته فنی: انتخاب JSON به عنوان فرمت اصلی ذخیره‌سازی، امکان تعامل با سایر سیستم‌ها، پشتیبانی از نسخه‌بندی داده‌ها و سهولت در دیباگ را فراهم می‌آورد. همچنین ساختار درختی JSON با مدل داده‌ای پروژه همخوانی کامل دارد. +
+
+
+ + +
+
+
۷
+
+

رابط کاربری و تجربه کاربری

+
UI/UX Design Principles
+
+
+
+

طراحی رابط کاربری xKanban بر اساس اصول Modern UI/UX و با تمرکز بر بهره‌وری کاربر انجام شده است. در ادامه به ویژگی‌های کلیدی طراحی پرداخته شده است:

+ +

الف) طراحی واکنش‌گرا (Responsive)

+

رابط کاربری به گونه‌ای طراحی شده که در اندازه‌های مختلف صفحه نمایش، از موبایل تا دسکتاپ، به صورت بهینه نمایش داده شود. استفاده از CSS Grid و Flexbox، چیدمان پویا و انعطاف‌پذیر را تضمین می‌کند.

+ +

ب) حالت تاریک/روشن (Dark/Light Mode)

+

پشتیبانی کامل از هر دو حالت با استفاده از CSS Variables. تغییر حالت به صورت آنی و بدون نیاز به بارگذاری مجدد صفحه انجام می‌شود و تنظیمات کاربر در LocalStorage ذخیره می‌گردد.

+ +

ج) سیستم Modal پیشرفته

+

تمامی عملیات ویرایش و تنظیمات از طریق Modal های متمرکز انجام می‌شود. این Modal ها دارای ویژگی‌های زیر هستند:

+
    +
  • باز و بسته شدن با انیمیشن نرم
  • +
  • بستن با کلید Esc یا کلیک خارج از Modal
  • +
  • مدیریت Focus Trap برای دسترسی‌پذیری
  • +
  • Validation فرم‌ها قبل از ذخیره
  • +
+ +

د) سیستم اعلان‌ها و بازخورد

+

تمامی عملیات کاربر با بازخورد بصری مناسب همراه است. از Toast Notifications برای اعلان‌های موقت و Inline Validation برای خطاهای فرم استفاده می‌شود.

+ +
+✓ اصول طراحی رعایت‌شده: +
    +
  • Consistency: الگوهای طراحی یکپارچه در سراسر برنامه
  • +
  • Feedback: بازخورد فوری برای تمامی عملیات کاربر
  • +
  • Efficiency: کاهش تعداد کلیک‌ها با میانبرهای کیبورد
  • +
  • Accessibility: پشتیبانی از ناوبری با کیبورد و کنتراست مناسب
  • +
  • Aesthetics: طراحی بصری جذاب با استفاده از رنگ‌بندی حرفه‌ای
  • +
+
+
+
+ + +
+
+
۸
+
+

آمار و تحلیل‌های هوشمند

+
Smart Statistics & Analytics
+
+
+
+

سیستم xKanban با محاسبه بلادرنگ آمار پروژه، دید کاملی از وضعیت کارها به کاربر ارائه می‌دهد. این آمار در نوار وضعیت پایین صفحه نمایش داده می‌شوند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
شاخصنحوه محاسبهکاربرد
📋 کل کارت‌هاشمارش تمام کارت‌های موجود در برد فعالدرک حجم کلی کار
✅ تکمیل‌شدهکارت‌های موجود در ستون‌های پایانی (مانند Done)سنجش پیشرفت
⏰ نزدیک به موعدکارت‌هایی با سررسید در ۳ روز آیندههشدار زودهنگام
⚠️ عقب‌افتادهکارت‌هایی با سررسید گذشته و وضعیت ناتمامشناسایی گلوگاه‌ها
📊 درصد پیشرفت(تکمیل‌شده ÷ کل) × ۱۰۰سنجش کلی پیشرفت پروژه
+ +
+🎯 مزیت تحلیلی: این آمار بلادرنگ، به مدیران پروژه امکان می‌دهد بدون نیاز به گزارش‌گیری جداگانه، وضعیت پروژه را در هر لحظه رصد کنند و تصمیمات مبتنی بر داده اتخاذ نمایند. +
+ +

الگوریتم تشخیص وضعیت کارت:

+
+function getCardStatus(card) {
+  if (!card.dueDate) return 'no-date';
+  const now = new Date();
+  const due = new Date(card.dueDate);
+  const diffDays = (due - now) / (1000 * 60 * 60 * 24);
+  
+  if (diffDays < 0) return 'overdue';     // ⚠️ عقب‌افتاده
+  if (diffDays <= 3) return 'near-due'; // ⏰ نزدیک به موعد
+  return 'normal';                     // ✅ عادی
+} +
+
+
+ + +
+
+
۹
+
+

قابلیت توسعه و نگهداری

+
Extensibility & Maintainability
+
+
+
+

معماری xKanban به گونه‌ای طراحی شده که توسعه ویژگی‌های جدید و نگهداری بلندمدت آن با حداقل هزینه ممکن باشد. در ادامه به اصول و الگوهای به‌کاررفته در این زمینه پرداخته شده است:

+ +

الف) اصول طراحی رعایت‌شده

+ + + + + + + + + + + + + + + + + + + + + + + + + +
اصلپیاده‌سازی در xKanban
SRPهر ماژول یک مسئولیت مشخص دارد
OCPامکان افزودن ویژگی جدید بدون تغییر کد موجود
DRYاستفاده از توابع کمکی مشترک برای عملیات پرتکرار
Separation of Concernsجداسازی کامل UI، منطق و داده
+ +

ب) نقاط توسعه‌پذیری

+
    +
  • افزودن فیلدهای سفارشی به کارت: با توسعه مدل Card و UI مربوطه
  • +
  • پشتیبانی از چند کاربر: با افزودن لایه Backend و مکانیزم Sync
  • +
  • افزودن گزارش‌های پیشرفته: با توسعه ماژول Analytics
  • +
  • یکپارچگی با ابزارهای خارجی: از طریق Webhook و API
  • +
  • پشتیبانی از قالب‌های آماده: با افزودن Template Manager
  • +
+ +

ج) استراتژی نسخه‌بندی

+

سیستم از Semantic Versioning (SemVer) برای نسخه‌بندی استفاده می‌کند:

+
+MAJOR.MINOR.PATCH → 1.0.0
+// MAJOR: تغییرات ناسازگار در API/ساختار داده
+// MINOR: افزودن ویژگی‌های جدید با سازگاری عقب‌گرد
+// PATCH: رفع باگ و بهبودهای جزئی +
+ +
+⚠️ ملاحظات نگهداری: +
    +
  • هر تغییر در ساختار داده نیازمند مکانیزم Migration است
  • +
  • تست‌های رگرسیون برای جلوگیری از شکست ویژگی‌های موجود ضروری است
  • +
  • مستندات باید هم‌زمان با تغییرات کد به‌روزرسانی شوند
  • +
+
+
+
+ + +
+
+
۱۰
+
+

عملکرد و بهینه‌سازی

+
Performance & Optimization
+
+
+
+

با وجود پیچیدگی بالای محصول، xKanban با رویکردهای بهینه‌سازی متعدد، عملکرد روان و پاسخگویی بالایی را ارائه می‌دهد:

+ +

الف) بهینه‌سازی رندر

+
    +
  • Virtual Rendering: فقط کارت‌های قابل مشاهده رندر می‌شوند
  • +
  • Batch Updates: تغییرات متعدد در یک چرخه رندر ادغام می‌شوند
  • +
  • DOM Recycling: استفاده مجدد از المان‌های DOM در تغییرات
  • +
+ +

ب) بهینه‌سازی حافظه

+
    +
  • Lazy Loading: بارگذاری داده‌های غیرضروری در زمان نیاز
  • +
  • Event Delegation: استفاده از یک Listener برای رویدادهای مشابه
  • +
  • Memory Cleanup: آزادسازی منابع در زمان بستن Modal ها
  • +
+ +

ج) شاخص‌های عملکرد هدف

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
شاخصهدفوضعیت
زمان بارگذاری اولیه< ۱ ثانیه✓ محقق شده
پاسخگویی UI< ۱۰۰ میلی‌ثانیه✓ محقق شده
حجم فایل< ۲۰۰ کیلوبایت✓ محقق شده
پشتیبانی از ۱۰۰۰+ کارتبدون افت عملکرد✓ محقق شده
+ +
+💎 دستاورد فنی: با پیاده‌سازی دقیق اصول بهینه‌سازی، xKanban توانسته است با وجود ماهیت تک‌فایلی و عدم استفاده از کتابخانه‌های بهینه‌ساز، عملکردی هم‌ردیف با اپلیکیشن‌های مدرن مبتنی بر فریم‌ورک ارائه دهد. +
+
+
+ + +
+
+
۱۱
+
+

امنیت و ملاحظات فنی

+
Security & Technical Considerations
+
+
+
+

با وجود ماهیت Client-Side بودن xKanban، ملاحظات امنیتی در طراحی آن لحاظ شده است:

+ +

الف) امنیت داده‌ها

+
    +
  • ذخیره‌سازی محلی: داده‌ها در مرورگر کاربر باقی می‌مانند و به سرور خارجی ارسال نمی‌شوند
  • +
  • Webhook امن: امکان پیکربندی URL سفارشی با قابلیت تست قبل از فعال‌سازی
  • +
  • Validation ورودی‌ها: اعتبارسنجی کامل داده‌های ورودی برای جلوگیری از注入
  • +
+ +

ب) یکپارچگی داده‌ها

+
    +
  • Schema Validation: اعتبارسنجی ساختار داده در زمان بارگذاری
  • +
  • Referential Integrity: بررسی وجود مراجع قبل از حذف موجودیت‌ها
  • +
  • Atomic Operations: عملیات به صورت اتمیک اجرا می‌شوند
  • +
+ +

ج) سازگاری با مرورگرها

+ + + + + + + + + + + + + + +
مرورگرنسخه حداقلیوضعیت
Chrome90+✓ پشتیبانی کامل
Firefox88+✓ پشتیبانی کامل
Edge90+✓ پشتیبانی کامل
Safari14+✓ پشتیبانی کامل
+
+
+ + +
+
+
۱۲
+
+

جمع‌بندی فنی و نقشه راه آینده

+
Technical Summary & Future Roadmap
+
+
+
+

پروژه xKanban نمونه‌ای موفق از طراحی یک اپلیکیشن مدرن تحت وب با رویکرد تک‌فایلی و بدون وابستگی است. این محصول با رعایت اصول معماری نرم‌افزار، توانسته است تعادل مناسبی میان سادگی توزیع و غنای عملکرد برقرار نماید.

+ +
+

🎯 دستاوردهای فنی کلیدی

+

طراحی و پیاده‌سازی xKanban نشان می‌دهد که با رعایت اصول مهندسی نرم‌افزار و انتخاب درست معماری، می‌توان محصولی حرفه‌ای و مقیاس‌پذیر را بدون نیاز به زیرساخت‌های پیچیده ارائه داد.

+
+💎 ارزش‌های فنی ارائه‌شده:
+معماری ماژولار + پایداری داده چندلایه + تجربه کاربری حرفه‌ای + قابلیت توسعه بالا + عملکرد بهینه +
+
+ +

نقشه راه توسعه آینده:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
فازویژگی‌های پیشنهادیاولویت
نسخه ۱.۱افزودن فیلدهای سفارشی، بهبود فیلترها، افزودن نمودارهابالا
نسخه ۱.۲پشتیبانی از چند کاربر با مکانیزم Syncبالا
نسخه ۲.۰ارائه نسخه Backend برای ذخیره‌سازی ابریمتوسط
نسخه ۲.۱اپلیکیشن موبایل Native با React Nativeآینده
+ +
+📞 گام بعدی: برای شروع همکاری در توسعه نسخه‌های آتی یا سفارشی‌سازی xKanban بر اساس نیازهای خاص سازمانی، آماده برگزاری جلسه فنی جهت تشریح جزئیات بیشتر و بررسی معماری هستیم. +
+
+
+ +
+این مستند فنی محرمانه بوده و صرفاً جهت استفاده داخلی تیم فنی تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+ +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: داخلی - فنی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Tutorial.html + + + + + + +آموزش جامع کانبان | راهنمای مدیریت بصری وظایف + + + +
+ + +
+
+
+ +
+
+
شماره مستند: EDU-KAN-1405-003
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۱:۰۰
+
طبقه‌بندی: عمومی - آموزشی
+
+
+
+EDUCATIONAL GUIDE +

آموزش جامع متدولوژی کانبان

+

راهنمای کامل مدیریت بصری وظایف با بردهای کانبان

+
+
+ + +
+ +
+مخاطبان مستند: مدیران پروژه، اعضای تیم‌های توسعه، سرپرستان فنی، دانشجویان مهندسی نرم‌افزار و هر فردی که به دنبال راهکاری عملی برای مدیریت بصری کارهاست
+این مستند آموزشی، از مفاهیم پایه‌ای کانبان شروع کرده و تا پیاده‌سازی عملی بردهای کانبان در محیط‌های واقعی پیش می‌رود. هدف، ارائه درکی عمیق از فلسفه کانبان و توانمندسازی خواننده برای استفاده مؤثر از این متدولوژی در پروژه‌های شخصی و سازمانی است. +
+ + +
+

📑 فهرست مطالب

+
    +
  1. کانبان چیست؟ تاریخچه و ریشه‌ها
  2. +
  3. فلسفه و اصول بنیادین کانبان
  4. +
  5. اجزای اصلی بردهای کانبان
  6. +
  7. ساختار استاندارد یک برد کانبان
  8. +
  9. نحوه استفاده عملی از بردها برای مدیریت وظایف
  10. +
  11. بهترین روش‌ها (Best Practices)
  12. +
  13. اشتباهات رایج و راه‌حل‌ها
  14. +
  15. معیارهای اندازه‌گیری عملکرد
  16. +
  17. مثال‌های کاربردی در حوزه‌های مختلف
  18. +
  19. جمع‌بندی و گام‌های بعدی
  20. +
+
+ + +
+
+
۱
+
+

کانبان چیست؟ تاریخچه و ریشه‌ها

+
What is Kanban? History & Origins
+
+
+
+ +

کانبان (Kanban) یک واژه ژاپنی به معنای «تابلوی بصری» یا «کارت بصری» است. این متدولوژی در اصل در دهه ۱۹۴۰ توسط تایچی اوهنو (Taiichi Ohno)، مهندس ارشد شرکت تویوتا، برای بهینه‌سازی فرآیند تولید خودرو ابداع شد. هدف اصلی، ایجاد یک سیستم «تولید به‌هنگام» (Just-In-Time) بود که در آن، هر قطعه دقیقاً در زمان مورد نیاز تولید می‌شد و از انباشت موجودی اضافی جلوگیری می‌گردید.

+ +
+

کانبان یک سیستم کنترل بصری است که به ما امکان می‌دهد در هر لحظه بدانیم چه چیزی باید تولید شود، چه زمانی و به چه مقدار. این سیستم، جریان کار را شفاف و قابل مدیریت می‌سازد.

+
— تایچی اوهنو، بنیان‌گذار سیستم تولید تویوتا (TPS)
+
+ +

سیر تکاملی کانبان:

+ +
+
+
+
+
۱۹۴۰ - تولد در تویوتا
+

تایچی اوهنو سیستم کانبان را در خط تولید تویوتا پیاده‌سازی کرد. کارت‌های فیزیکی برای ردیابی قطعات بین ایستگاه‌های کاری استفاده می‌شدند.

+
+
+
+
+
+
۱۹۸۰ - گسترش جهانی
+

با انتشار کتاب «سیستم تولید تویوتا»، کانبان به عنوان یکی از ارکان اصلی Lean Manufacturing در سطح جهانی شناخته شد.

+
+
+
+
+
+
۲۰۰۴ - ورود به نرم‌افزار
+

دیوید جی. اندرسون (David J. Anderson) برای اولین بار کانبان را به صنعت توسعه نرم‌افزار معرفی کرد و کتاب «Kanban» را منتشر نمود.

+
+
+
+
+
+
۲۰۱۰ به بعد - عصر دیجیتال
+

ابزارهای دیجیتال کانبان مانند Trello، Jira و Azure DevOps، این متدولوژی را به میلیون‌ها تیم در سراسر جهان رساندند.

+
+
+
+
+
+
۲۰۲۶ - کانبان مدرن
+

امروزه کانبان فراتر از توسعه نرم‌افزار رفته و در بازاریابی، منابع انسانی، آموزش، بهداشت و حتی مدیریت زندگی شخصی کاربرد دارد.

+
+
+
+ +
+💡 نکته کلیدی: کانبان یک «متدولوژی» است، نه یک «فریم‌ورک». این یعنی کانبان به شما می‌گوید «چه کاری انجام دهید» (مدیریت بصری جریان کار)، اما «چگونه انجام دهید» را به خودتان می‌سپارد. این انعطاف‌پذیری، دلیل اصلی موفقیت جهانی کانبان است. +
+ +
+
+ + +
+
+
۲
+
+

فلسفه و اصول بنیادین کانبان

+
Philosophy & Core Principles
+
+
+
+ +

کانبان بر پایه شش اصل بنیادین استوار است. درک عمیق این اصول، کلید موفقیت در پیاده‌سازی کانبان است. بدون رعایت این اصول، برد کانبان تنها به یک «تابلوی زیبا» تبدیل می‌شود که هیچ ارزشی خلق نمی‌کند.

+ +
+
+
👁️
+
۱. شفاف‌سازی فرآیند فعلی
+

قبل از هر تغییری، باید فرآیند فعلی کار را به‌صورت بصری روی برد نمایش دهید. این شفافیت، پایه و اساس تمام بهبودهای بعدی است.

+
+
+
🎯
+
۲. توافق بر تغییرات تدریجی
+

کانبان به دنبال انقلاب نیست، بلکه به دنبال تکامل است. تغییرات کوچک، مستمر و تدریجی، پایدارتر از تغییرات ناگهانی و بزرگ هستند.

+
+
+
🔄
+
۳. احترام به فرآیند موجود
+

نقش‌ها، مسئولیت‌ها و فرآیندهای فعلی را محترم بشمارید. کانبان با تغییر ناگهانی ساختار سازمانی مخالفت می‌کند.

+
+
+
👥
+
۴. تشویق رهبری در همه سطوح
+

هر عضو تیم می‌تواند ایده‌های بهبود را پیشنهاد دهد. رهبری در کانبان، مختص مدیران نیست.

+
+
+
📊
+
۵. محدود کردن کار در جریان (WIP)
+

مهم‌ترین اصل کانبان: تعداد کارهای در حال انجام را محدود کنید. این کار، تمرکز را افزایش و دوباره‌کاری را کاهش می‌دهد.

+
+
+
🌊
+
۶. مدیریت جریان کار
+

هدف نهایی کانبان، ایجاد جریانی روان و بدون گلوگاه است. هر کارت باید به سرعت از ستون «شروع» به ستون «پایان» برسد.

+
+
+ +
+🎯 تفاوت کانبان با اسکرام: اسکرام یک «فریم‌ورک» با نقش‌ها، رویدادها و artefact های مشخص است. کانبان یک «متدولوژی» انعطاف‌پذیر است که می‌تواند روی فرآیند موجود سوار شود. بسیاری از تیم‌ها از ترکیب این دو (Scrumban) استفاده می‌کنند. +
+ +
+
+ + +
+
+
۳
+
+

اجزای اصلی بردهای کانبان

+
Core Components of Kanban Boards
+
+
+
+ +

یک برد کانبان از سه جزء اصلی تشکیل شده است: ستون‌ها (Columns)، کارت‌ها (Cards) و محدودیت WIP. درک دقیق هر یک از این اجزا، برای استفاده مؤثر از کانبان ضروری است.

+ +

الف) ستون‌ها (Columns)

+

ستون‌ها، مراحل مختلف جریان کار را نشان می‌دهند. هر ستون نمایانگر یک «وضعیت» یا «فاز» از چرخه حیات یک وظیفه است.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع ستوننقشمثال
ستون ورودی (Input)وظایفی که هنوز شروع نشده‌اندBacklog، To Do
ستون‌های میانی (WIP)وظایفی در حال انجام هستندIn Progress، Review، Testing
ستون خروجی (Output)وظایف تکمیل‌شدهDone، Deployed
ستون مسدود (Blocked)وظایف متوقف‌شدهWaiting، Blocked
+ +

ب) کارت‌ها (Cards)

+

هر کارت، نمایانگر یک «وظیفه» یا «کار» است. یک کارت استاندارد باید اطلاعات زیر را در بر داشته باشد:

+ +
    +
  • عنوان واضح: نام وظیفه به‌صورت مختصر و گویا
  • +
  • توضیحات: جزئیات وظیفه، معیارهای پذیرش (Acceptance Criteria)
  • +
  • مسئول: فرد یا افرادی که مسئول انجام آن هستند
  • +
  • تاریخ سررسید: زمان مورد انتظار برای تکمیل
  • +
  • برچسب‌ها (Tags): دسته‌بندی وظیفه (Bug، Feature، Enhancement)
  • +
  • اولویت: اهمیت نسبی وظیفه
  • +
  • وابستگی‌ها: ارتباط با سایر وظایف
  • +
+ +

ج) محدودیت WIP (Work In Progress Limit)

+

محدودیت WIP، مهم‌ترین مکانیزم کانبان برای جلوگیری از چندوظیفه‌ای بودن (Multitasking) است. این محدودیت، حداکثر تعداد کارت‌های مجاز در هر ستون را تعیین می‌کند.

+ +
+
+

❌ بدون محدودیت WIP

+
    +
  • تعداد کارهای هم‌زمان نامحدود
  • +
  • تمرکز تیم پخش‌شده
  • +
  • زمان تکمیل هر کار بسیار طولانی
  • +
  • کیفیت خروجی پایین
  • +
  • استرس تیم بالا
  • +
+
+ +
+ +
+💎 قانون طلایی WIP: «کار را شروع نکنید تا تمام شود، کار را تمام کنید تا شروع کنید.» این جمله، جوهره فلسفه کانبان را در بر دارد. +
+ +
+
+ + +
+
+
۴
+
+

ساختار استاندارد یک برد کانبان

+
Standard Kanban Board Structure
+
+
+
+ +

یک برد کانبان استاندارد از حداقل سه ستون تشکیل شده است، اما در عمل، بردهای حرفه‌ای معمولاً بین ۴ تا ۷ ستون دارند. در ادامه، یک نمونه برد کامل با ۴ ستون نمایش داده شده است:

+ +
+

📋 نمونه برد کانبان - پروژه توسعه نرم‌افزار

+
+
+
+📥 To Do +3 +
+
+
طراحی صفحه ورود
+
+👤 علی +📅 ۲۵ شهریور +
+UI/UX +
+
+
رفع باگ پرداخت
+
+👤 سارا +📅 ۲۳ شهریور +
+Bug +
+
+
نوشتن مستندات API
+
+👤 رضا +📅 ۲۸ شهریور +
+Docs +
+
+ +
+
+🔨 In Progress +2 +
+
+
پیاده‌سازی احراز هویت
+
+👤 محمد +📅 ۲۴ شهریور +
+Backend +
+
+
توسعه داشبورد مدیر
+
+👤 مریم +📅 ۳۰ شهریور +
+Feature +
+
+ +
+
+🔍 Code Review +1 +
+
+
بهینه‌سازی کوئری‌ها
+
+👤 حسین +📅 ۲۲ شهریور +
+Performance +
+
+ +
+
+✅ Done +2 +
+
+
راه‌اندازی CI/CD
+
+👤 علی +📅 ۲۰ شهریور +
+DevOps +
+
+
طراحی دیتابیس
+
+👤 سارا +📅 ۱۸ شهریور +
+Database +
+
+
+
+ +

ستون‌های پیشنهادی برای حوزه‌های مختلف:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
حوزهستون‌های پیشنهادی
توسعه نرم‌افزارBacklog → To Do → In Progress → Code Review → Testing → Done
بازاریابی محتواIdeas → Research → Drafting → Editing → Publishing → Promoting
منابع انسانیOpen Positions → Screening → Interview → Offer → Onboarding → Hired
پشتیبانی مشتریانNew Tickets → Investigating → Waiting Customer → Resolving → Resolved
مدیریت شخصیBacklog → This Week → Today → Doing → Done
+ +
+💡 نکته طراحی: تعداد ستون‌ها را بر اساس پیچیدگی واقعی فرآیند خود تنظیم کنید. ستون‌های اضافی، سربار مدیریتی ایجاد می‌کنند و ستون‌های ناکافی، شفافیت را کاهش می‌دهند. قانون کلی: «به تعداد کافی، نه بیشتر». +
+ +
+
+ + +
+
+
۵
+
+

نحوه استفاده عملی از بردها برای مدیریت وظایف

+
Practical Usage for Task Management
+
+
+
+ +

استفاده مؤثر از بردهای کانبان، نیازمند رعایت یک گردش کار (Workflow) مشخص است. در ادامه، گام‌به‌گام نحوه استفاده از برد کانبان برای مدیریت وظایف تشریح شده است:

+ +

گام ۱: تعریف فرآیند کار

+

قبل از هر چیز، باید مراحل واقعی انجام یک وظیفه در تیم خود را شناسایی کنید. این مراحل، ستون‌های برد شما را تشکیل می‌دهند.

+
    +
  • یک وظیفه از کجا شروع می‌شود؟
  • +
  • از چه مراحلی عبور می‌کند؟
  • +
  • چه زمانی «تکمیل‌شده» محسوب می‌شود؟
  • +
+ +

گام ۲: ایجاد کارت‌ها

+

هر وظیفه را به‌صورت یک کارت جداگانه وارد برد کنید. کارت باید:

+
    +
  • عنوانی واضح و قابل فهم داشته باشد
  • +
  • به یک نفر (یا تیم مشخص) تخصیص داده شود
  • +
  • دارای تاریخ سررسید باشد
  • +
  • با برچسب مناسب دسته‌بندی شود
  • +
+ +

گام ۳: تعیین محدودیت WIP

+

برای هر ستون میانی (غیر از ورودی و خروجی)، یک محدودیت WIP تعیین کنید. فرمول پیشنهادی:

+
+📐 فرمول WIP Limit:
+WIP Limit هر ستون = (تعداد اعضای تیم × ۱.۵) ÷ (تعداد ستون‌های میانی)

+مثال: تیم ۴ نفره با ۳ ستون میانی → WIP = (۴ × ۱.۵) ÷ ۳ = ۲ کارت برای هر ستون +
+ +

گام ۴: شروع کار با قانون Pull

+

در کانبان، کار «Push» نمی‌شود، بلکه «Pull» می‌شود. این یعنی:

+
    +
  • تا زمانی که در ستون فعلی ظرفیت خالی ندارید، کارت جدیدی شروع نکنید
  • +
  • وقتی کاری را تمام کردید، از ستون قبلی یک کارت بکشید (Pull)
  • +
  • هرگز از ظرفیت WIP بیشتر نشود
  • +
+ +

گام ۵: جلسات روزانه (Daily Standup)

+

هر روز، یک جلسه ۱۵ دقیقه‌ای جلوی برد برگزار کنید و به سه سؤال پاسخ دهید:

+
    +
  • چه چیزهایی به سمت تکمیل حرکت می‌کنند؟ (تمرکز بر تکمیل، نه شروع)
  • +
  • چه چیزهایی مسدود شده‌اند؟ (شناسایی گلوگاه‌ها)
  • +
  • چه کارهای جدیدی باید شروع شوند؟ (تنها اگر ظرفیت وجود دارد)
  • +
+ +

گام ۶: بازبینی و بهبود مستمر

+

هر هفته یا هر Sprint، برد را بازبینی کنید:

+
    +
  • آیا WIP Limits مناسب هستند؟
  • +
  • کدام ستون‌ها گلوگاه شده‌اند؟
  • +
  • آیا نیاز به افزودن یا حذف ستون داریم؟
  • +
  • میانگین Cycle Time چقدر است؟
  • +
+ +
+✓ گردش کار کامل یک کارت:
+۱. ایجاد کارت در ستون Backlog → ۲. انتقال به To Do (برنامه‌ریزی) → ۳. Pull به In Progress (شروع کار) → ۴. انتقال به Review (بررسی) → ۵. انتقال به Done (تکمیل) → ۶. ثبت در تاریخچه +
+ +
+
+ + +
+
+
۶
+
+

بهترین روش‌ها (Best Practices)

+
Best Practices for Kanban Success
+
+
+
+ +

بر اساس تجربیات جهانی و تحقیقات صنعتی، رعایت موارد زیر، موفقیت پیاده‌سازی کانبان را به‌طور چشمگیری افزایش می‌دهد:

+ +
+
+
🎯
+
کارت‌ها را کوچک نگه دارید
+

هر کارت باید در کمتر از ۲-۳ روز قابل تکمیل باشد. اگر کاری بزرگ است، آن را به چند کارت کوچکتر تقسیم کنید.

+
+
+
📝
+
Definition of Done (DoD) مشخص
+

برای هر ستون، معیارهای مشخصی تعریف کنید که کارت چه زمانی مجاز به انتقال به ستون بعدی است.

+
+
+
🚫
+
کارت‌های مسدود را برجسته کنید
+

کارت‌هایی که منتظر پاسخ یا منبع خارجی هستند را با رنگ قرمز مشخص کنید تا گلوگاه‌ها دیده شوند.

+
+
+
📊
+
معیارها را ردیابی کنید
+

Lead Time، Cycle Time و Throughput را اندازه‌گیری کنید تا بتوانید بهبودها را کمی‌سازی کنید.

+
+
+
🔄
+
بازبینی منظم فرآیند
+

هر ۲ هفته یک‌بار، فرآیند را بازبینی و در صورت نیاز، ستون‌ها یا WIP Limits را تنظیم کنید.

+
+
+
👥
+
شفافیت کامل برای همه
+

برد باید برای تمام اعضای تیم و ذینفعان قابل مشاهده باشد. هیچ «کاری پنهانی» نباید وجود داشته باشد.

+
+
+ +
+🎯 قانون طلایی: «اگر روی برد نیست، وجود ندارد.» هر کاری که انجام می‌دهید باید روی برد قابل مشاهده باشد. کارهای پنهان، دشمن شفافیت و بهبود مستمر هستند. +
+ +
+
+ + +
+
+
۷
+
+

اشتباهات رایج و راه‌حل‌ها

+
Common Mistakes & Solutions
+
+
+
+ +

بسیاری از تیم‌ها در پیاده‌سازی کانبان با چالش‌هایی مواجه می‌شوند. شناخت این اشتباهات رایج و راه‌حل‌های آن‌ها، از اتلاف زمان و انرژی جلوگیری می‌کند:

+ +
+❌ اشتباه ۱: نادیده گرفتن محدودیت WIP +

بسیاری از تیم‌ها WIP Limit را تعیین می‌کنند اما به آن پایبند نمی‌مانند. نتیجه: چندوظیفه‌ای بودن، کاهش تمرکز و افزایش زمان تکمیل.

+

✓ راه‌حل: WIP Limit را به‌صورت بصری روی برد نمایش دهید و در جلسات روزانه، رعایت آن را بررسی کنید.

+
+ +
+❌ اشتباه ۲: کارت‌های بیش‌ازحد بزرگ +

کارت‌هایی که هفته‌ها طول می‌کشد تا تکمیل شوند، جریان کار را مختل می‌کنند و شفافیت را از بین می‌برند.

+

✓ راه‌حل: هر کاری که بیش از ۳ روز طول می‌کشد را به چند کارت کوچکتر تقسیم کنید.

+
+ +
+❌ اشتباه ۳: ستون‌های بیش‌ازحد +

ایجاد ۱۰+ ستون، سربار مدیریتی ایجاد می‌کند و تیم را در جابجایی کارت‌ها غرق می‌سازد.

+

✓ راه‌حل: با ۴-۵ ستون شروع کنید و تنها در صورت نیاز واقعی، ستون جدید اضافه کنید.

+
+ +
+❌ اشتباه ۴: عدم به‌روزرسانی منظم برد +

اگر برد به‌روز نباشد، به سرعت اعتماد تیم به آن از بین می‌رود و برد به یک «تابلوی تزئینی» تبدیل می‌شود.

+

✓ راه‌حل: قانون بگذارید: «هر تغییر وضعیت، بلافاصله روی برد منعکس شود».

+
+ +
+❌ اشتباه ۵: نادیده گرفتن کارت‌های مسدود +

کارت‌هایی که هفته‌ها در یک ستون می‌مانند، نشان‌دهنده گلوگاه‌های جدی در فرآیند هستند.

+

✓ راه‌حل: هر کارت مسدود بیش از ۲ روز را در جلسات روزانه بررسی و رفع کنید.

+
+ +
+❌ اشتباه ۶: استفاده از کانبان بدون درک فلسفه +

برخی تیم‌ها کانبان را صرفاً به‌عنوان یک «ابزار بصری» می‌بینند و اصول آن را نادیده می‌گیرند.

+

✓ راه‌حل: قبل از استفاده از ابزار، فلسفه و اصول کانبان را به‌طور کامل درک کنید.

+
+ +
+
+ + +
+
+
۸
+
+

معیارهای اندازه‌گیری عملکرد

+
Performance Metrics & Measurement
+
+
+
+ +

برای اینکه بدانید آیا کانبان در تیم شما کار می‌کند یا خیر، باید معیارهای کلیدی را اندازه‌گیری کنید. این معیارها، زبان مشترک تیم برای گفتگو درباره بهبود فرآیند هستند.

+ +
+
⏱️
+
+
۱. Lead Time (زمان انتظار)
+

مدت زمانی که یک کارت از لحظه ایجاد تا لحظه تکمیل در سیستم بوده است. این معیار، سرعت کلی سیستم را نشان می‌دهد.

+
Lead Time = Completion Date - Creation Date
+
+
+ +
+
🔄
+
+
۲. Cycle Time (زمان چرخه)
+

مدت زمانی که یک کارت از لحظه شروع کار (In Progress) تا تکمیل طول کشیده است. این معیار، بهره‌وری واقعی تیم را نشان می‌دهد.

+
Cycle Time = Completion Date - Start Date
+
+
+ +
+
📊
+
+
۳. Throughput (نرخ خروجی)
+

تعداد کارت‌های تکمیل‌شده در یک بازه زمانی مشخص (مثلاً در هفته یا ماه). این معیار، ظرفیت واقعی تیم را نشان می‌دهد.

+
Throughput = Completed Cards / Time Period
+
+
+ +
+
📈
+
+
۴. WIP (کار در جریان)
+

تعداد کارت‌هایی که در حال حاضر در ستون‌های میانی هستند. این معیار، بار کاری فعلی تیم را نشان می‌دهد.

+
WIP = Cards in all WIP columns
+
+
+ +
+
⚠️
+
+
۵. Blocked Ratio (نرخ مسدودی)
+

درصد کارت‌هایی که در وضعیت مسدود هستند. این معیار، سلامت فرآیند را نشان می‌دهد.

+
Blocked Ratio = (Blocked Cards / Total Cards) × 100
+
+
+ +

نمودارهای کانبان:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نمودارهدفکاربرد
Cumulative Flow Diagram (CFD)نمایش جریان تجمعی کارت‌ها در طول زمانشناسایی گلوگاه‌ها و پیش‌بینی تکمیل
Control Chartنمایش Cycle Time هر کارتشناسایی ناهنجاری‌ها و بهبود پیش‌بینی
Throughput Histogramنمایش توزیع تعداد کارت‌های تکمیل‌شدهدرک ظرفیت واقعی تیم
Aging Chartنمایش سن کارت‌های در جریانشناسایی کارت‌های قدیمی و نیازمند توجه
+ +
+💡 قانون اندازه‌گیری: «آنچه اندازه‌گیری نمی‌شود، مدیریت نمی‌شود.» حداقل یکی از معیارهای بالا را به‌صورت منظم ردیابی کنید تا بتوانید بهبودها را کمی‌سازی کنید. +
+ +
+
+ + +
+
+
۹
+
+

مثال‌های کاربردی در حوزه‌های مختلف

+
Practical Examples Across Domains
+
+
+
+ +

کانبان یک متدولوژی جهانی است و در حوزه‌های بسیار متنوعی کاربرد دارد. در ادامه، چند مثال کاربردی از پیاده‌سازی کانبان در حوزه‌های مختلف ارائه شده است:

+ +

مثال ۱: تیم توسعه نرم‌افزار

+

چالش: تیم ۵ نفره با بیش از ۲۰ کار هم‌زمان، که هیچ‌کدام به موقع تکمیل نمی‌شوند.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد با ۶ ستون: Backlog → To Do → In Progress → Code Review → Testing → Done
  • +
  • تعیین WIP Limit: ۲ کارت برای هر ستون میانی
  • +
  • جلسات روزانه ۱۵ دقیقه‌ای جلوی برد
  • +
  • نتیجه: کاهش Cycle Time از ۱۴ روز به ۵ روز در عرض ۲ ماه
  • +
+ +

مثال ۲: تیم بازاریابی محتوا

+

چالش: تولید محتوای نامنظم، فراموش شدن ایده‌ها، عدم هماهنگی بین نویسندگان و ویراستاران.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد با ۵ ستون: Ideas → Research → Drafting → Editing → Published
  • +
  • استفاده از برچسب‌های رنگی برای نوع محتوا (Blog، Video، Social)
  • +
  • نتیجه: افزایش تولید محتوا از ۴ مقاله در ماه به ۱۲ مقاله با کیفیت بالاتر
  • +
+ +

مثال ۳: مدیریت شخصی

+

چالش: احساس سردرگمی، فراموش کردن وظایف، عدم پیشرفت در اهداف شخصی.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد شخصی با ۴ ستون: Backlog → This Week → Today → Done
  • +
  • WIP Limit: حداکثر ۳ کار برای «Today»
  • +
  • بازبینی هفتگی هر جمعه evening
  • +
  • نتیجه: افزایش بهره‌وری شخصی و کاهش استرس به‌طور چشمگیر
  • +
+ +

مثال ۴: تیم پشتیبانی مشتریان

+

چالش: تیکت‌های انباشته‌شده، عدم شفافیت در وضعیت درخواست‌ها، پاسخگویی کند.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد با ۵ ستون: New → Investigating → Waiting Customer → Resolving → Resolved
  • +
  • اولویت‌بندی با برچسب‌های رنگی (Critical، High، Normal، Low)
  • +
  • نتیجه: کاهش میانگین زمان پاسخ از ۴۸ ساعت به ۸ ساعت
  • +
+ +
+💎 درس مشترک: در تمام این مثال‌ها، کانبان با ایجاد شفافیت بصری، محدود کردن کار در جریان و تمرکز بر تکمیل به جای شروع، بهره‌وری را به‌طور چشمگیری افزایش داده است. +
+ +
+
+ + +
+
+
۱۰
+
+

جمع‌بندی و گام‌های بعدی

+
Summary & Next Steps
+
+
+
+ +

کانبان یک متدولوژی قدرتمند، انعطاف‌پذیر و اثبات‌شده برای مدیریت بصری کارهاست. این متدولوژی با تأکید بر شفافیت، محدود کردن کار در جریان و بهبود مستمر، به تیم‌ها کمک می‌کند تا با تمرکز بیشتر، استرس کمتر و بهره‌وری بالاتر کار کنند.

+ +
+

🎯 پیام اصلی کانبان

+

«کار را شروع نکنید تا تمام شود، کار را تمام کنید تا شروع کنید.»

+

کانبان به شما نمی‌گوید «چه کاری انجام دهید»، بلکه به شما کمک می‌کند «بهترین روش انجام کار» را کشف کنید. این متدولوژی، ابزاری برای بهبود مستمر است، نه یک چارچوب خشک و غیرقابل تغییر.

+
+💎 سه اصل کلیدی برای موفقیت:
+۱. شفاف‌سازی فرآیند فعلی  |  ۲. محدود کردن کار در جریان  |  ۳. بهبود مستمر و تدریجی +
+
+ +

گام‌های پیشنهادی برای شروع:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
گاماقدامزمان تخمینی
۱فرآیند فعلی تیم خود را روی کاغذ بنویسید۳۰ دقیقه
۲یک برد کانبان ساده با ۴ ستون ایجاد کنید۱۵ دقیقه
۳تمام وظایف فعلی را روی کارت‌های جداگانه وارد کنید۱ ساعت
۴برای ستون‌های میانی، WIP Limit تعیین کنید۱۰ دقیقه
۵جلسات روزانه ۱۵ دقیقه‌ای را شروع کنیدهر روز
۶پس از ۲ هفته، فرآیند را بازبینی و بهبود دهید۱ ساعت
+ +
+📞 منابع بیشتر: برای یادگیری عمیق‌تر کانبان، کتاب‌های زیر پیشنهاد می‌شوند: +
    +
  • +Kanban: Successful Evolutionary Change for Your Technology Business +
    نویسنده: David J. Anderson
    +
  • +
  • +Kanban from the Inside +
    نویسنده: Mike Burrows
    +
  • +
  • +Personal Kanban +
    نویسندگان: Jim Benson & Tonianne DeMaria Barry
    +
  • +
+
+ +
+🛠️ ابزار پیشنهادی: برای شروع سریع و بدون نیاز به نصب یا راه‌اندازی، ابزار xKanban (طراحی‌شده توسط هادی خزاعی اصل) یک گزینه ایده‌آل است. این ابزار به‌صورت یک فایل HTML مستقل، تمامی قابلیت‌های یک برد کانبان حرفه‌ای را به‌صورت آفلاین و رایگان ارائه می‌دهد. +
+ +
+
+ +
+این مستند آموزشی جهت استفاده عمومی تهیه شده است. بازنشر با ذکر منبع مجاز است. +
+ +
+ + +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۱:۰۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: عمومی - آموزشی
+
+ +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xUMLDrawer_Case_Study.html + + + + + + +معرفی ابزار رسم نمودارهای UML | تحلیل نیازمندی‌ها، معماری و ارزش‌های سازمانی + + + +
+
+
+
+ +
+
+
شماره مستند: UML-TOOL-OVERVIEW-1405-001
+
نسخه: ۱.۰
+
تاریخ تهیه: ۱۷ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰
+
طبقه‌بندی: عمومی / معرفی محصول
+
+
+
+PRODUCT OVERVIEW & ARCHITECTURE +

معرفی ابزار رسم نمودارهای UML

+

تحلیل نیازمندی‌ها، معماری فنی و ارزش‌های سازمانی

+
+
+
+
+همکاران گرامی و علاقه‌مندان به مهندسی نرم‌افزار،
+این مستند به‌عنوان مرجعی جامع برای معرفی «ابزار رسم نمودارهای UML» تهیه شده است. در این مستند، چرایی پیدایش این ابزار، مزایای رقابتی، ارزش‌های سازمانی قابل خلق، معماری دقیق فنی و مخاطبان هدف آن به‌صورت شفاف تشریح می‌گردد. هدف از تهیه این مستند، ارائه دیدگاهی کامل برای تصمیم‌گیری آگاهانه جهت استفاده از این ابزار در فرآیندهای مهندسی نرم‌افزار سازمان‌هاست. +
+ +
+
+
۱
+
+

شرح مسئله و چالش‌های موجود

+
Problem Statement & Industry Challenges
+
+
+
+

در دنیای پیچیده و به‌سرعت در حال تحول مهندسی نرم‌افزار، مدل‌سازی دقیق سیستم‌ها به یکی از ارکان حیاتی موفقیت پروژه‌ها تبدیل شده است. نمودارهای UML (Unified Modeling Language) به‌عنوان زبان استاندارد بین‌المللی برای مدل‌سازی بصری سیستم‌های نرم‌افزاری، نقشی کلیدی در انتقال مفاهیم، طراحی معماری، مستندسازی و ارتباط مؤثر بین ذینفعان ایفا می‌کنند. با این حال، ابزارهای موجود در بازار با چالش‌های متعددی مواجه‌اند که استفاده از آن‌ها را برای بسیاری از تیم‌ها دشوار یا حتی غیرممکن می‌سازد.

+ +
+
+
💸
+

هزینه‌های سنگین لایسنس

+

ابزارهای تجاری معتبر مانند Enterprise Architect، Visual Paradigm و IBM Rational Rose دارای هزینه‌های لایسنس سالانه بسیار بالا هستند که برای بسیاری از سازمان‌ها، به‌ویژه استارتاپ‌ها و شرکت‌های متوسط، مقرون‌به‌صرفه نیست.

+
+
+
🌐
+

وابستگی به اینترنت و سرور

+

بسیاری از ابزارهای مدرن مبتنی بر Cloud هستند و برای اجرا به اتصال اینترنت پایدار و سرورهای خارجی نیاز دارند. این موضوع در محیط‌هایی با محدودیت‌های شبکه، مسائل امنیتی یا قطعی اینترنت، چالش‌برانگیز است.

+
+
+
🔒
+

نگرانی‌های امنیتی و حریم داده

+

ذخیره نمودارهای معماری حساس در سرورهای ابری شخص ثالث، ریسک‌های امنیتی جدی به همراه دارد. سازمان‌های دولتی، نظامی و مالی اغلب نمی‌توانند داده‌های معماری خود را به خارج از شبکه داخلی منتقل کنند.

+
+
+
⚙️
+

پیچیدگی و منحنی یادگیری بالا

+

ابزارهای جامع UML معمولاً دارای رابط کاربری پیچیده، تعداد زیادی ویژگی غیرضروری و منحنی یادگیری طولانی هستند. این موضوع باعث می‌شود که استفاده از آن‌ها برای کارهای سریع و روزمره، زمان‌بر و خسته‌کننده باشد.

+
+
+
📦
+

حجم بالا و نیاز به نصب

+

ابزارهای دسکتاپ معمولاً حجم بالایی دارند (چندین گیگابایت)، نیاز به نصب و پیکربندی دارند و روی همه سیستم‌ها قابل اجرا نیستند. این موضوع برای استفاده در محیط‌های محدود یا سیستم‌های قدیمی مشکل‌ساز است.

+
+
+
🔄
+

عدم پشتیبانی از همه نمودارها

+

بسیاری از ابزارهای رایگان یا سبک، تنها چند نوع محدود از نمودارهای UML را پشتیبانی می‌کنند و امکان رسم کامل هشت نمودار اصلی را به‌صورت یکپارچه فراهم نمی‌آورند.

+
+
+
🌍
+

عدم پشتیبانی از زبان فارسی و RTL

+

اکثر ابزارهای موجود، پشتیبانی مناسبی از زبان فارسی و چیدمان راست‌به‌چپ (RTL) ندارند. این موضوع برای تیم‌های ایرانی، استفاده از نمودارها در مستندات فارسی و ارائه به ذینفعان فارسی‌زبان، یک محدودیت جدی است.

+
+
+
🔗
+

عدم یکپارچگی و پراکندگی ابزارها

+

تیم‌ها مجبورند برای رسم نمودارهای مختلف از ابزارهای متفاوت استفاده کنند که منجر به عدم یکپارچگی بصری، دشواری در نگهداری و افزایش هزینه‌های آموزشی می‌شود.

+
+
+ +
+⚠️ نتیجه چالش‌ها: این معضلات باعث می‌شود که بسیاری از تیم‌های نرم‌افزاری یا از مدل‌سازی UML صرف‌نظر کنند، یا از ابزارهای ناکارآمد استفاده نمایند که در نهایت به کاهش کیفیت طراحی، افزایش خطاهای معماری و کاهش بهره‌وری تیم منجر می‌شود. +
+
+
+ +
+
+
۲
+
+

معرفی راه‌حل و مزایای رقابتی

+
Solution Overview & Competitive Advantages
+
+
+
+

«ابزار رسم نمودارهای UML» پاسخی جامع و حرفه‌ای به چالش‌های مطرح‌شده است. این ابزار با تکیه بر تکنولوژی‌های مدرن وب و معماری هوشمندانه، تجربه‌ای بی‌نظیر از مدل‌سازی بصری را در اختیار معماران، تحلیل‌گران و توسعه‌دهندگان قرار می‌دهد.

+ +

مزایای کلیدی محصول:

+ +
+✅ کاملاً رایگان و بدون لایسنس: این ابزار به‌صورت متن‌باز و کاملاً رایگان ارائه می‌شود. هیچ هزینه لایسنس، اشتراک یا پرداخت درون‌برنامه‌ای وجود ندارد. سازمان‌ها می‌توانند بدون هیچ محدودیتی از آن استفاده کنند. +
+ +
+✅ ۱۰۰٪ آفلاین و بدون نیاز به سرور: تمام عملیات در سمت مرورگر و بدون هیچ‌گونه ارتباط با سرور خارجی انجام می‌شود. این ابزار در محیط‌های کاملاً ایزوله، شبکه‌های داخلی (Intranet) و حتی سیستم‌های بدون اینترنت قابل اجراست. +
+ +
+✅ پشتیبانی کامل از ۸ نمودار اصلی UML: +
    +
  • Use Case Diagram (مورد کاربرد)
  • +
  • Activity Diagram (فعالیت)
  • +
  • State Machine Diagram (ماشین حالت)
  • +
  • Class Diagram (کلاس)
  • +
  • Sequence Diagram (توالی)
  • +
  • Component Diagram (کامپوننت)
  • +
  • Deployment Diagram (استقرار)
  • +
  • Swimlane Diagram (لاین شنا)
  • +
+
+ +
+✅ پشتیبانی کامل از زبان فارسی و RTL: تمامی رابط کاربری، برچسب‌ها، منوها و خروجی‌ها به‌صورت کامل از زبان فارسی و چیدمان راست‌به‌چپ پشتیبانی می‌کنند. فونت حرفه‌ای Vazirmatn برای تایپوگرافی فارسی به‌کار رفته است. +
+ +
+✅ سبک، سریع و بدون نیاز به نصب: حجم ابزار کمتر از ۱ مگابایت است و تنها با یک فایل HTML قابل اجراست. نیازی به نصب، پیکربندی یا وابستگی خارجی ندارد. کافی است فایل را در هر مرورگر مدرنی باز کنید. +
+ +
+✅ امنیت کامل داده‌ها: تمامی داده‌ها به‌صورت محلی و در قالب فایل JSON ذخیره می‌شوند. هیچ اطلاعاتی به سرور خارجی ارسال نمی‌شود. سازمان‌ها کنترل کامل بر داده‌های خود دارند. +
+ +
+✅ تم تاریک و روشن حرفه‌ای: امکان سوئیچ آنی بین تم تاریک و روشن با حفظ ترجیحات در فایل پروژه. این ویژگی برای کار طولانی‌مدت و کاهش خستگی چشم بسیار مفید است. +
+ +
+✅ مدیریت چند نمودار هم‌زمان (Multi-Tab): امکان باز کردن چندین نمودار در تب‌های مجزا و سوئیچ سریع بین آن‌ها. این ویژگی برای پروژه‌های بزرگ با نمودارهای متعدد، بسیار کارآمد است. +
+ +
+✅ خروجی PNG با کیفیت: امکان Export نمودارها به فرمت PNG با قابلیت انتخاب رنگ پس‌زمینه یا شفافیت. مناسب برای استفاده در مستندات، ارائه‌ها و گزارش‌ها. +
+ +
+✅ رابط کاربری شهودی و کاربرپسند: طراحی رابط کاربری بر اساس اصول UX مدرن، با ابزارهای دسته‌بندی‌شده، کلیدهای میانبر، Properties Panel و ویرایشگرهای پیشرفته. منحنی یادگیری بسیار کوتاه است. +
+ +
+💎 مزیت رقابتی کلیدی: این ابزار تنها راه‌حلی است که تمامی نیازمندی‌های یک ابزار حرفه‌ای UML را در یک بسته سبک، رایگان، آفلاین و کاملاً فارسی ارائه می‌دهد. هیچ ابزار دیگری در بازار چنین ترکیبی از ویژگی‌ها را فراهم نمی‌آورد. +
+
+
+ +
+
+
۳
+
+

ارزش‌های خلق‌شده در سازمان

+
Organizational Value Creation
+
+
+
+

استفاده از این ابزار در سطح سازمان، ارزش‌های استراتژیک و عملیاتی متعددی ایجاد می‌کند که در سه دسته اصلی قابل دسته‌بندی هستند:

+ +
+
+
💰
+

صرفه‌جویی مالی

+

حذف هزینه‌های لایسنس، کاهش هزینه‌های آموزشی، کاهش زمان مدل‌سازی و افزایش بهره‌وری تیم

+
+
+
⚡
+

افزایش چابکی

+

سرعت بخشیدن به فرآیند طراحی، امکان مدل‌سازی سریع در جلسات، و کاهش زمان تبدیل ایده به مستند

+
+
+
🎯
+

بهبود کیفیت

+

استانداردسازی نمودارها، کاهش خطاهای طراحی، و افزایش دقت در انتقال مفاهیم بین تیم‌ها

+
+
+
🔒
+

امنیت داده‌ها

+

حفظ کامل حریم داده‌های معماری، عدم وابستگی به سرورهای خارجی، و کنترل کامل بر اطلاعات حساس

+
+
+
🤝
+

بهبود ارتباطات

+

زبان بصری مشترک بین تیم‌های فنی و کسب‌وکار، کاهش سوءتفاهم‌ها، و افزایش شفافیت در مستندات

+
+
+
📚
+

دانش سازمانی

+

ایجاد مخزن استاندارد از نمودارها، تسهیل Onboarding نیروهای جدید، و حفظ دانش معماری

+
+
+
🌐
+

استقلال فناورانه

+

عدم وابستگی به ابزارهای خارجی، قابلیت اجرا در هر محیطی، و سازگاری با محدودیت‌های شبکه

+
+
+
🚀
+

توسعه‌پذیری

+

معماری ماژولار امکان افزودن نمودارهای جدید، سفارشی‌سازی و یکپارچه‌سازی با ابزارهای دیگر را فراهم می‌آورد

+
+
+
📊
+

حرفه‌ای‌گری

+

ارتقای سطح بلوغ مهندسی سازمان، استانداردسازی فرآیندهای طراحی، و افزایش اعتبار مستندات فنی

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
دسته ارزششاخص کلیدیتأثیر مورد انتظار
مالیکاهش هزینه‌های ابزارحذف ۱۰۰٪ هزینه لایسنس
عملیاتیزمان مدل‌سازیکاهش ۴۰-۶۰٪ زمان
کیفیدقت مستنداتافزایش چشمگیر
امنیتیحفظ حریم داده‌هاتضمین کامل
آموزشیزمان یادگیریکاهش ۷۰٪ منحنی یادگیری
استراتژیکبلوغ مهندسی سازمانارتقای سطح بلوغ
+ +
+💡 نکته کلیدی: ارزش اصلی این ابزار در ترکیب منحصر‌به‌فرد «رایگان + آفلاین + فارسی + جامع» است. این ترکیب در هیچ ابزار دیگری در بازار یافت نمی‌شود و برای سازمان‌های ایرانی یک مزیت رقابتی پایدار ایجاد می‌کند. +
+
+
+ +
+
+
۴
+
+

معماری دقیق فنی پروژه

+
Technical Architecture Deep Dive
+
+
+
+

معماری این پروژه بر پایه اصول مهندسی نرم‌افزار مدرن، الگوهای طراحی اثبات‌شده و رویکرد State-Centric طراحی شده است. در ادامه، لایه‌های مختلف معماری و اجزای کلیدی آن تشریح می‌گردد.

+ +
+

🎨 لایه ۱: رابط کاربری (UI Layer)

+

این لایه مسئول ارائه تجربه کاربری حرفه‌ای و تعامل با کاربر است. شامل Sidebar ابزارها، Tab Bar برای مدیریت چند نمودار، Properties Panel برای ویرایش ویژگی‌ها، و Modal‌های مختلف (ایجاد نمودار، تنظیمات، ذخیره، Export PNG و ویرایشگر Class) می‌باشد.

+
    +
  • تکنولوژی: HTML5 Semantic + CSS3 (با CSS Variables برای تم داینامیک) + Tailwind CSS (CDN)
  • +
  • ویژگی کلیدی: پشتیبانی کامل RTL، فونت Vazirmatn، تم تاریک/روشن، طراحی Responsive
  • +
+
+ +
+

🧠 لایه ۲: مدیریت وضعیت (State Management Layer)

+

قلب تپنده برنامه که تمامی وضعیت‌های سراسری را در یک آبجکت مرکزی نگهداری می‌کند. این رویکرد باعث سادگی، قابلیت پیش‌بینی و نگهداری آسان کد می‌شود.

+
+const state = {
+  diagrams: [],                  // لیست همه نمودارها
+  activeDiagramId: null,         // شناسه نمودار فعال
+  currentTool: 'select',         // ابزار انتخاب‌شده
+  selectedElement: null,         // المان انتخاب‌شده
+  isDragging: false,             // وضعیت Drag
+  isDrawingRelationship: false,  // وضعیت رسم رابطه
+  mousePos: { x:0, y:0 },        // موقعیت ماوس
+  sidebarVisible: true,         // وضعیت Sidebar
+  gridType: 'lines',            // نوع خط‌کشی بوم
+  darkMode: true,               // تم تاریک/روشن
+  fileMetadata: { ... }          // متادیتای پروژه
+  // ... سایر ویژگی‌های وضعیت
+}; +
+
+ +
+

🎨 لایه ۳: موتور رسم (Rendering Engine)

+

موتور رسم بر پایه HTML5 Canvas 2D API و رویکرد Immediate Mode Rendering طراحی شده است. در این رویکرد، در هر تغییر وضعیت، کل بوم پاک‌سازی شده و تمامی المان‌ها از نو رسم می‌شوند.

+
    +
  • تابع اصلی رسم: function draw() { ... } - چرخه اصلی رسم که Grid، المان‌ها و روابط را مدیریت می‌کند
  • +
  • تابع Dispatch: function drawDiag(c,d,tc) { ... } - بر اساس نوع نمودار، تابع اختصاصی را فراخوانی می‌کند
  • +
  • توابع اختصاصی هر نمودار: +
      +
    • function drawUseCase(c,d,tc) { ... }
    • +
    • function drawStateMachine(c,d,tc) { ... }
    • +
    • function drawActivity(c,d,tc) { ... }
    • +
    • function drawComponent(c,d,tc) { ... }
    • +
    • function drawDeployment(c,d,tc) { ... }
    • +
    • function drawClassDiagram(c,d,tc) { ... }
    • +
    • function drawSequenceDiagram(c,d,tc) { ... }
    • +
    • function drawSwimlaneDiagram(c,d,tc) { ... }
    • +
    +
  • +
  • تابع رسم Grid: function drawGrid(c,w,h,tc,trans) { ... } - پشتیبانی از سه حالت Lines, Dots, None
  • +
+
+ +
+

🎯 لایه ۴: سیستم تعامل و Hit Testing

+

این لایه مسئول تشخیص موقعیت ماوس، انتخاب المان‌ها، Drag & Drop و رسم روابط است.

+
    +
  • تابع Hit Test: function hitTest(x,y) { ... } - بر اساس نوع نمودار، الگوریتم‌های متفاوتی برای تشخیص المان زیر ماوس اجرا می‌کند
  • +
  • مدیریت رویدادها: +
      +
    • canvas.addEventListener('mousedown', e => { ... }) - شروع Drag یا رسم رابطه
    • +
    • canvas.addEventListener('mousemove', e => { ... }) - به‌روزرسانی موقعیت المان‌ها
    • +
    • canvas.addEventListener('mouseup', e => { ... }) - پایان Drag یا تکمیل رابطه
    • +
    • canvas.addEventListener('dblclick', e => { ... }) - باز کردن ویرایشگرها
    • +
    +
  • +
+
+ +
+

🗂️ لایه ۵: رجیستری نمودارها (Diagram Registry)

+

الگوی طراحی Registry Pattern برای تعریف مرکزی انواع نمودارها و قابلیت‌های آن‌ها به‌کار رفته است.

+
+const DIAGRAM_TYPES = {
+  usecase: {
+    id: 'usecase',
+    name: 'نمودار مورد کاربرد (Use Case)',
+    icon: '⭕',
+    available: true,
+    tools: ['select', 'actor', 'useCase', ...],
+    groups: ['selection', 'uc-elements', ...]
+  },
+  statemachine: { /* ... */ },
+  activity: { /* ... */ },
+  component: { /* ... */ },
+  deployment: { /* ... */ },
+  class: { /* ... */ },
+  sequence: { /* ... */ },
+  swimlane: { /* ... */ }
+}; +
+

این رجیستری به‌عنوان Single Source of Truth برای ابزارها، گروه‌ها و قابلیت‌های هر نمودار عمل می‌کند و افزودن نمودار جدید را بسیار آسان می‌سازد.

+
+ +
+

💾 لایه ۶: سیستم Persistence

+

سیستم ذخیره‌سازی و بازیابی مبتنی بر JSON File API است. این رویکرد مزایای متعددی نسبت به LocalStorage یا Backend دارد.

+
    +
  • تابع ساخت داده ذخیره: function buildSaveData() { ... } - ساختار کامل JSON شامل متادیتا، ترجیحات و همه نمودارها
  • +
  • تابع ذخیره: document.getElementById('confirmSaveBtn').addEventListener('click', () => { ... }) - ایجاد Blob و دانلود فایل
  • +
  • تابع بارگذاری: document.getElementById('fileInput').addEventListener('change', e => { ... }) - خواندن فایل JSON و بازیابی وضعیت
  • +
+
+ +
+

🎨 لایه ۷: سیستم تم و رنگ

+

سیستم تم بر پایه CSS Custom Properties (Variables) طراحی شده است. با تغییر کلاس body.dark، تمامی متغیرهای رنگی به‌صورت آنی تغییر می‌کنند.

+
    +
  • تابع دریافت رنگ‌ها: function getTC() { ... } - استخراج رنگ‌های فعال از CSS Variables در زمان اجرا
  • +
  • تابع اعمال تم: function applyTheme() { ... } - تغییر کلاس body و به‌روزرسانی UI
  • +
+
+ +
+

🔧 لایه ۸: مدیریت نمودارها

+

توابع مدیریت چرخه حیات نمودارها (ایجاد، سوئیچ، حذف) در این لایه قرار دارند.

+
    +
  • function createNewDiagram(type='usecase') { ... }
  • +
  • function switchDiagram(id) { ... }
  • +
  • function deleteDiagram(id) { ... }
  • +
  • function renderTabs() { ... } - رسم Tab Bar
  • +
  • function updateToolVisibility() { ... } - نمایش/مخفی کردن ابزارها بر اساس نوع نمودار فعال
  • +
+
+ +
+

🗂️ لایه ۹: ویرایشگرهای تخصصی

+

برای المان‌های پیچیده مانند Class، ویرایشگرهای اختصاصی طراحی شده‌اند.

+
    +
  • function openClassEditor(classId) { ... } - باز کردن ویرایشگر Class با Attributes و Methods
  • +
  • function renderAttributesTable() { ... } - رسم جدول ویژگی‌ها
  • +
  • function renderMethodsTable() { ... } - رسم جدول متدها
  • +
+
+ +

الگوهای طراحی به‌کار رفته:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل کاربردمزیت
Registry PatternDIAGRAM_TYPESمرجع مرکزی، توسعه‌پذیری آسان
State Patternآبجکت stateمدیریت متمرکز وضعیت
Strategy Patternتوابع draw*انتخاب استراتژی رسم بر اساس نوع
Command Patternمدیریت ابزارهارفتارهای مشخص برای هر ابزار
Observer PatternEvent Listenersواکنش به رویدادهای کاربر
Factory PatterncreateNewDiagram()ساخت ساختار اولیه نمودار
Singleton PatternCanvas Context، Stateتنها یک نمونه از منابع حیاتی
+ +
+💡 نکته معماری: انتخاب Vanilla JS به جای فریم‌ورک‌هایی مانند React یا Angular، باعث کاهش چشمگیر حجم نهایی، اجرای سریع‌تر، عدم وابستگی به ابزارهای Build و سادگی نگهداری شده است. این رویکرد برای ابزارهای تخصصی و آفلاین، انتخاب بهینه‌ای است. +
+
+
+ +
+
+
۵
+
+

مخاطبان هدف: سازمان‌ها و تیم‌ها

+
Target Audience: Organizations & Teams
+
+
+
+

این ابزار برای طیف گسترده‌ای از سازمان‌ها و تیم‌های نرم‌افزاری طراحی شده است. در ادامه، مخاطبان هدف و موارد استفاده مناسب برای هر دسته تشریح می‌گردد.

+ +

الف) سازمان‌های مناسب:

+ +
+
+
🏢
+

شرکت‌های نرم‌افزاری

+

تیم‌های توسعه که نیاز به مدل‌سازی معماری، طراحی کلاس‌ها و مستندسازی سیستم‌ها دارند. مناسب برای شرکت‌های محصول‌محور و پروژه‌ای.

+
+
+
🚀
+

استارتاپ‌ها

+

تیم‌های کوچک که به ابزار سبک، رایگان و سریع نیاز دارند. مناسب برای MVP، طراحی اولیه و ارائه به سرمایه‌گذاران.

+
+
+
🏛️
+

سازمان‌های دولتی و نظامی

+

سازمان‌هایی که به دلیل محدودیت‌های امنیتی، نمی‌توانند از ابزارهای ابری استفاده کنند و نیاز به راه‌حل کاملاً آفلاین دارند.

+
+
+
🏦
+

بانک‌ها و مؤسسات مالی

+

سازمان‌هایی با الزامات امنیتی بالا که نیاز به حفظ کامل حریم داده‌های معماری حساس خود دارند.

+
+
+
🎓
+

دانشگاه‌ها و مراکز آموزشی

+

اساتید و دانشجویان رشته‌های مهندسی نرم‌افزار، علوم کامپیوتر و IT برای تدریس و یادگیری UML.

+
+
+
🏥
+

سازمان‌های بهداشتی و درمانی

+

تیم‌های فنی که نیاز به مدل‌سازی فرآیندهای پیچیده کسب‌وکار و سیستم‌های اطلاعاتی دارند.

+
+
+
🏭
+

شرکت‌های صنعتی و تولیدی

+

تیم‌های IT که نیاز به مدل‌سازی سیستم‌های ERP، CRM و فرآیندهای تولید دارند.

+
+
+
🌐
+

شرکت‌های مشاوره و پیمانکاری

+

مشاورانی که نیاز به ارائه مستندات حرفه‌ای به کارفرمایان مختلف دارند و می‌خواهند ابزار یکپارچه‌ای داشته باشند.

+
+
+ +

ب) تیم‌های مناسب:

+ +
+
+
👨‍💼
+

معماران نرم‌افزار

+

برای طراحی معماری کلان، مدل‌سازی کامپوننت‌ها، استقرار و ارتباط بین لایه‌های مختلف سیستم.

+
+
+
📊
+

تحلیل‌گران کسب‌وکار (BA)

+

برای مدل‌سازی نیازمندی‌ها، فرآیندهای کسب‌وکار، Use Caseها و Swimlaneها.

+
+
+
💻
+

توسعه‌دهندگان Backend

+

برای طراحی Class Diagram، Sequence Diagram و State Machine برای پیاده‌سازی دقیق.

+
+
+
🎨
+

توسعه‌دهندگان Frontend

+

برای مدل‌سازی Componentها، تعاملات UI و ارتباط بین کامپوننت‌ها.

+
+
+
🧪
+

تیم‌های QA و تست

+

برای مدل‌سازی سناریوهای تست، فرآیندهای کسب‌وکار و درک بهتر سیستم.

+
+
+
📋
+

مدیران پروژه (PM)

+

برای مستندسازی معماری، ارتباط با ذینفعان و ارائه گزارش‌های بصری.

+
+
+
🎯
+

Product Owners

+

برای مدل‌سازی نیازمندی‌ها، Use Caseها و ارتباط با تیم فنی.

+
+
+
🔧
+

تیم‌های DevOps

+

برای مدل‌سازی Deployment Diagram، معماری زیرساخت و ارتباط بین سرویس‌ها.

+
+
+ +

ج) موارد استفاده مناسب:

+ +
    +
  • 📐 طراحی معماری سیستم: مدل‌سازی معماری کلان، میکروسرویس‌ها، و ارتباط بین کامپوننت‌ها
  • +
  • 📋 مستندسازی نیازمندی‌ها: رسم Use Case Diagram برای انتقال نیازمندی‌ها به تیم فنی
  • +
  • 🔄 مدل‌سازی فرآیندها: رسم Activity و Swimlane Diagram برای فرآیندهای کسب‌وکار
  • +
  • 🗂️ طراحی شیءگرا: رسم Class Diagram برای طراحی کلاس‌ها و روابط آن‌ها
  • +
  • ⏱️ مدل‌سازی تعاملات: رسم Sequence Diagram برای سناریوهای اجرایی
  • +
  • 🔁 مدل‌سازی چرخه حیات: رسم State Machine Diagram برای موجودیت‌های با وضعیت‌های گسسته
  • +
  • 🖥️ مستندسازی زیرساخت: رسم Deployment Diagram برای معماری فیزیکی
  • +
  • 🎓 آموزش و یادگیری: تدریس مفاهیم UML و مدل‌سازی نرم‌افزار
  • +
  • 📊 ارائه به ذینفعان: ایجاد نمودارهای حرفه‌ای برای جلسات و گزارش‌ها
  • +
  • 🔍 تحلیل و دیباگ: مدل‌سازی سناریوها برای درک بهتر رفتار سیستم
  • +
+ +
+💎 نتیجه‌گیری: این ابزار برای هر سازمان یا تیمی که نیاز به مدل‌سازی بصری سیستم‌های نرم‌افزاری دارد، مناسب است. به‌ویژه برای سازمان‌های ایرانی که به پشتیبانی کامل فارسی، محیط آفلاین و امنیت داده‌ها نیاز دارند، این ابزار یک انتخاب ایده‌آل است. +
+
+
+ +
+
+
۶
+
+

جمع‌بندی نهایی و پیشنهاد

+
Final Summary & Recommendation
+
+
+
+

«ابزار رسم نمودارهای UML» پاسخی جامع و حرفه‌ای به چالش‌های موجود در حوزه مدل‌سازی نرم‌افزار است. این ابزار با ترکیب منحصر‌به‌فرد «رایگان + آفلاین + فارسی + جامع»، ارزش‌های استراتژیک و عملیاتی متعددی برای سازمان‌ها ایجاد می‌کند.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
شاخصابزارهای تجاریابزارهای ابریاین ابزار
هزینهبسیار بالااشتراک ماهیانهکاملاً رایگان
نیاز به اینترنتاختیاریالزامیکاملاً آفلاین
امنیت داده‌هامتوسطریسک بالاتضمین کامل
پشتیبانی فارسیمحدودضعیفکامل و حرفه‌ای
تعداد نمودارها۸+ نمودار۴-۶ نمودار۸ نمودار کامل
حجم و نصبچند GB + نصببدون نصب<1 MB بدون نصب
ارزش کلی——بسیار بالاتر
+ +
+

🎯 پیشنهاد نهایی

+

با توجه به تحلیل جامع نیازمندی‌ها، مزایا، ارزش‌های سازمانی و معماری فنی، استفاده از این ابزار برای تمامی سازمان‌ها و تیم‌های نرم‌افزاری که به مدل‌سازی UML نیاز دارند، قویاً توصیه می‌شود.

+

این ابزار نه تنها هزینه‌ها را به شکل قابل‌توجهی کاهش می‌دهد، بلکه کیفیت مستندات، سرعت طراحی و امنیت داده‌ها را به‌طور هم‌زمان ارتقا می‌بخشد.

+
+💎 ارزش پیشنهادی:
+ابزاری کاملاً رایگان، آفلاین، فارسی و جامع که تمامی نیازمندی‌های مدل‌سازی UML را در یک بسته سبک و حرفه‌ای ارائه می‌دهد. +
+
+ +
+📞 گام بعدی: برای شروع استفاده، کافی است فایل HTML ابزار را دانلود کرده و در مرورگر باز کنید. هیچ نصب یا پیکربندی نیاز نیست. مستندات آموزشی کامل نیز برای یادگیری سریع در دسترس است. +
+
+
+ +
+این مستند جهت معرفی و تحلیل ابزار رسم نمودارهای UML تهیه شده است. استفاده از این ابزار برای تمامی سازمان‌ها و تیم‌های نرم‌افزاری آزاد و رایگان است. +
+
+
+ + +
تاریخ تهیه: ۱۷ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰  |  نسخه: ۱.۰  |  طبقه‌بندی: عمومی / معرفی محصول
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xUMLDrawer_Supported_UML_Diagrams_Tutorial.html + + + + + + +مستند آموزشی جامع نمودارهای UML | راهنمای کامل با مثال‌های عملی + + + +
+
+
+
+ +
+
+
شماره مستند: UML-EDU-1405-001
+
نسخه: .۰
+
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰
+
طبقه‌بندی: آموزشی / عمومی
+
+
+
+EDUCATIONAL DOCUMENTATION +

مستند آموزشی جامع نمودارهای UML

+

راهنمای کامل با مثال‌های عملی و کاربردی

+
+
+
+
+همکاران گرامی و علاقه‌مندان به مهندسی نرم‌افزار،
+این مستند آموزشی به‌عنوان مرجعی جامع برای یادگیری و درک عمیق هشت نمودار اصلی UML (Unified Modeling Language) تهیه شده است. هر فصل به تفصیل یک نوع نمودار را با ذکر المان‌ها، روابط، کاربردها و مثال‌های عملی توضیح می‌دهد. هدف از این مستند، ارائه درکی کاربردی و آماده‌سازی شما برای مدل‌سازی حرفه‌ای سیستم‌های نرم‌افزاری است. +
+ + + +
+
+
۱
+
+

نمودار مورد کاربرد (Use Case Diagram)

+
نمایش تعامل کاربران با سیستم
+
+
+
+

نمودار Use Case یکی از پرکاربردترین نمودارهای UML است که برای نمایش تعامل بین کاربران (Actors) و سیستم استفاده می‌شود. این نمودار دیدگاهی بیرونی از سیستم ارائه داده و نیازمندی‌های عملکردی را بدون ورود به جزئیات فنی نشان می‌دهد.

+ +
+
+
👤
+

Actor (بازیگر)

+

نماینده کاربر، سیستم خارجی یا موجودیتی که با سیستم تعامل دارد. به صورت شکل انسان نمایش داده می‌شود.

+
+
+
⭕
+

Use Case (مورد کاربرد)

+

یک عملکرد یا سرویس خاص که سیستم ارائه می‌دهد. به صورت بیضی نمایش داده می‌شود.

+
+
+
+

System Boundary (مرز سیستم)

+

مستطیلی که محدوده سیستم را مشخص کرده و Use Caseها درون آن قرار می‌گیرند.

+
+
+
➖
+

Association (ارتباط)

+

خط ساده که Actor را به Use Case مرتبط وصل می‌کند.

+
+
+ +

انواع روابط در Use Case:

+
    +
  • Include (شامل): رابطه‌ای که نشان می‌دهد یک Use Case حتماً شامل Use Case دیگری است. با خط‌چین و stereotype <<include>> نمایش داده می‌شود.
  • +
  • 🔀 Extend (گسترش): رابطه‌ای اختیاری که نشان می‌دهد یک Use Case می‌تواند در شرایط خاصی Use Case دیگر را گسترش دهد. با خط‌چین و stereotype <<extend>> نمایش داده می‌شود.
  • +
  • 🔺 Generalization (تعمیم): رابطه ارث‌بری بین Actors یا بین Use Cases. با فلش مثلثی توخالی نمایش داده می‌شود.
  • +
+ +
+

مثال عملی: سیستم بانکداری آنلاین

+

Actors: مشتری، کارمند بانک، مدیر سیستم

+

Use Cases:

+
    +
  • مشتری → ورود به سیستم، مشاهده موجودی، انتقال وجه، پرداخت قبض
  • +
  • کارمند بانک → ثبت مشتری جدید، تأیید تراکنش‌های بزرگ
  • +
  • مدیر سیستم → مدیریت کاربران، مشاهده گزارش‌ها
  • +
  • «انتقال وجه» <<include>> «بررسی موجودی»
  • +
  • «ورود به سیستم» <<extend>> «احراز هویت دو مرحله‌ای» (در صورت فعال بودن)
  • +
+
+ +
+💡 نکته کلیدی: نمودار Use Case در فاز تحلیل نیازمندی‌ها استفاده شده و به درک مشترک بین تیم فنی و ذینفعان کسب‌وکار کمک می‌کند. +
+
+
+ +
+
+
۲
+
+

نمودار فعالیت (Activity Diagram)

+
مدل‌سازی جریان کار و فرآیندها
+
+
+
+

نمودار Activity برای نمایش جریان کار (Workflow)، فرآیندهای کسب‌وکار و الگوریتم‌ها استفاده می‌شود. این نمودار شبیه فلوچارت است اما قدرت بیشتری در نمایش فعالیت‌های موازی و تصمیم‌گیری‌های پیچیده دارد.

+ +
+
+
⚫
+

Initial Node (گره شروع)

+

دایره توپر سیاه که نقطه شروع فرآیند را نشان می‌دهد.

+
+
+
🎯
+

Final Node (گره پایان)

+

دایره توپر با حاشیه ضخیم که پایان فرآیند را نشان می‌دهد.

+
+
+
▭
+

Action (فعالیت)

+

مستطیل با گوشه‌های گرد که یک عملیات یا کار را نشان می‌دهد.

+
+
+
◇
+

Decision/Merge (تصمیم/ادغام)

+

لوزی که برای انشعاب شرطی یا ادغام جریان‌ها استفاده می‌شود.

+
+
+
▬
+

Fork/Join (انشعاب/هم‌زمانی)

+

خط ضخیم افقی یا عمودی برای نمایش فعالیت‌های موازی.

+
+
+
→
+

Control Flow (جریان کنترل)

+

فلش که ترتیب اجرای فعالیت‌ها را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: فرآیند ثبت سفارش آنلاین

+

جریان فرآیند:

+
    +
  • شروع: مشتری وارد سایت می‌شود
  • +
  • فعالیت‌ها: انتخاب محصول → افزودن به سبد خرید → ورود/ثبت‌نام → انتخاب آدرس → انتخاب روش پرداخت
  • +
  • Decision: آیا موجودی کافی است؟ (بله/خیر)
  • +
  • Fork: هم‌زمان: ۱) کاهش موجودی انبار ۲) ارسال ایمیل تأیید
  • +
  • Join: انتظار برای تکمیل هر دو فعالیت موازی
  • +
  • پایان: ثبت نهایی سفارش
  • +
+
+ +
+کاربردهای کلیدی: مدل‌سازی فرآیندهای کسب‌وکار، الگوریتم‌های پیچیده، گردش کار (Workflow)، و تحلیل سناریوهای مختلف +
+
+
+ +
+
+
۳
+
+

نمودار ماشین حالت (State Machine Diagram)

+
نمایش چرخه حیات و تغییر وضعیت‌ها
+
+
+
+

نمودار State Machine برای نمایش وضعیت‌های مختلف یک شیء و رویدادهایی که باعث تغییر وضعیت می‌شوند استفاده می‌شود. این نمودار برای مدل‌سازی چرخه حیات (Lifecycle) موجودیت‌ها ایده‌آل است.

+ +
+
+
⚫
+

Initial State (وضعیت شروع)

+

دایره توپر کوچک که وضعیت اولیه را نشان می‌دهد.

+
+
+
+

Final State (وضعیت پایانی)

+

دایره توپر با حاشیه ضخیم که وضعیت نهایی را نشان می‌دهد.

+
+
+
🔲
+

State (وضعیت)

+

مستطیل با گوشه‌های گرد که یک وضعیت خاص را نشان می‌دهد.

+
+
+
️
+

Transition (گذار)

+

فلش که تغییر از یک وضعیت به وضعیت دیگر را نشان می‌دهد. می‌تواند برچسب (رویداد/شرط/اقدام) داشته باشد.

+
+
+ +

ساختار Transition:

+
+فرمت: eventName [guardCondition] / action
+مثال: pay [amount > 0] / updateInventory() +
+ +
+

مثال عملی: چرخه حیات سفارش

+

وضعیت‌ها:

+
    +
  • ایجاد شده (Created)
  • +
  • در انتظار پرداخت (Pending Payment)
  • +
  • پرداخت شده (Paid)
  • +
  • در حال پردازش (Processing)
  • +
  • ارسال شده (Shipped)
  • +
  • تحویل داده شده (Delivered)
  • +
  • لغو شده (Cancelled)
  • +
+

گذارها:

+
    +
  • Created → Pending Payment: رویداد «ثبت سفارش»
  • +
  • Pending Payment → Paid: رویداد «پرداخت موفق»
  • +
  • Paid → Processing: رویداد «تأیید پرداخت»
  • +
  • Processing → Shipped: رویداد «ارسال کالا»
  • +
  • Shipped → Delivered: رویداد «تحویل به مشتری»
  • +
  • هر وضعیت → Cancelled: رویداد «لغو» (با شرایط خاص)
  • +
+
+ +
+⚠️ نکته مهم: State Machine برای اشیایی استفاده می‌شود که چرخه حیات مشخص و وضعیت‌های گسسته دارند. برای فرآیندهای پیچیده با فعالیت‌های موازی، از Activity Diagram استفاده کنید. +
+
+
+ +
+
+
۴
+
+

نمودار کامپوننت (Component Diagram)

+
نمایش ساختار ماژولار و وابستگی‌ها
+
+
+
+

نمودار Component برای نمایش ساختار فیزیکی سیستم، ماژول‌ها، کتابخانه‌ها و وابستگی‌های بین آن‌ها استفاده می‌شود. این نمودار دیدگاهی از معماری نرم‌افزار در سطح کامپوننت ارائه می‌دهد.

+ +
+
+
🧩
+

Component (کامپوننت)

+

مستطیل با آیکون کامپوننت (دو مستطیل کوچک در گوشه) که یک ماژول یا جزء سیستم را نشان می‌دهد.

+
+
+
🍭
+

Interface Provided (اینترفیس ارائه‌شده)

+

دایره (Lollipop) که سرویس‌هایی که کامپوننت ارائه می‌دهد را نشان می‌دهد.

+
+
+
◗
+

Interface Required (اینترفیس مورد نیاز)

+

نیم‌دایره (Socket) که سرویس‌هایی که کامپوننت نیاز دارد را نشان می‌دهد.

+
+
+
📁
+

Package (بسته)

+

پوشه‌ای که کامپوننت‌های مرتبط را گروه‌بندی می‌کند.

+
+
+
⇢
+

Dependency (وابستگی)

+

فلش خط‌چین که وابستگی بین کامپوننت‌ها را نشان می‌دهد.

+
+
+
—
+

Connector (اتصال)

+

خط جامد که اتصال بین Interface Provided و Required را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: سیستم مدیریت محتوا (CMS)

+

کامپوننت‌ها:

+
    +
  • User Management: مدیریت کاربران و احراز هویت
  • +
  • Content Engine: مدیریت محتوا و ویرایشگر
  • +
  • Media Library: مدیریت فایل‌های چندرسانه‌ای
  • +
  • Search Module: موتور جستجو
  • +
  • Notification Service: ارسال اعلان‌ها
  • +
+

وابستگی‌ها:

+
    +
  • Content Engine → User Management (برای بررسی مجوزها)
  • +
  • Search Module → Content Engine (برای ایندکس محتوا)
  • +
  • Notification Service → User Management (برای دریافت اطلاعات کاربران)
  • +
+

اینترفیس‌ها:

+
    +
  • User Management: IAuthentication, IUserProfile
  • +
  • Content Engine: IContentCRUD, IVersioning
  • +
+
+ +
+✓ مزایا: درک معماری سیستم، مدیریت وابستگی‌ها، برنامه‌ریزی برای ماژولاریزاسیون، و تسهیل توسعه موازی تیم‌ها +
+
+
+ +
+
+
۵
+
+

نمودار استقرار (Deployment Diagram)

+
نمایش معماری فیزیکی و توزیع نرم‌افزار
+
+
+
+

نمودار Deployment برای نمایش سخت‌افزارها، نودها، محیط‌های اجرا و نحوه استقرار نرم‌افزار بر روی زیرساخت فیزیکی استفاده می‌شود. این نمودار دیدگاهی از معماری فیزیکی سیستم ارائه می‌دهد.

+ +
+
+
🖥️
+

Node (گره)

+

مکعب سه‌بعدی که یک سخت‌افزار یا محیط اجرا (مانند سرور، کامپیوتر، کانتینر) را نشان می‌دهد.

+
+
+
💻
+

Device (دستگاه)

+

نود فیزیکی مانند سرور، روتر، یا دستگاه موبایل.

+
+
+
⚙️
+

Execution Environment (محیط اجرا)

+

نود نرم‌افزاری مانند OS، JVM، Docker، یا Kubernetes.

+
+
+
📄
+

Artifact (مصنوع)

+

فایل‌های اجرایی، کتابخانه‌ها، پایگاه داده، یا فایل‌های پیکربندی که بر روی نودها استقرار می‌یابند.

+
+
+
⇌
+

Communication Path (مسیر ارتباطی)

+

خط جامد که ارتباط فیزیکی بین نودها را نشان می‌دهد.

+
+
+
⇣
+

Deployment Relationship (رابطه استقرار)

+

فلش خط‌چین که استقرار Artifact بر روی Node را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: سیستم وب اپلیکیشن میکروسرویس

+

نودها:

+
    +
  • Load Balancer: Nginx (Device)
  • +
  • Application Servers: Kubernetes Cluster (Execution Environment) +
      +
    • User Service Pod
    • +
    • Order Service Pod
    • +
    • Payment Service Pod
    • +
    +
  • +
  • Database Server: PostgreSQL Cluster (Device)
  • +
  • Cache Server: Redis Cluster (Device)
  • +
  • Message Broker: RabbitMQ Server (Device)
  • +
+

Artifacts:

+
    +
  • User Service → user-service.jar
  • +
  • Order Service → order-service.jar
  • +
  • Database → schema.sql, data.migration
  • +
+

ارتباطات:

+
    +
  • Load Balancer ⇌ Application Servers (HTTP/HTTPS)
  • +
  • Application Servers Database Server (JDBC)
  • +
  • Application Servers ⇌ Cache Server (Redis Protocol)
  • +
  • Application Servers ⇌ Message Broker (AMQP)
  • +
+
+ +
+💡 کاربرد: برنامه‌ریزی زیرساخت، مستندسازی محیط‌های Development/Staging/Production، و تحلیل Performance و Scalability +
+
+
+ +
+
+
۶
+
+

نمودار کلاس (Class Diagram)

+
نمایش ساختار ایستایی و روابط بین کلاس‌ها
+
+
+
+

نمودار Class مهم‌ترین و پرکاربردترین نمودار UML است که ساختار ایستایی (Static Structure) سیستم را نشان می‌دهد. این نمودار کلاس‌ها، ویژگی‌ها، متدها و روابط بین آن‌ها را مدل‌سازی می‌کند.

+ +
+
+
🗂️
+

Class (کلاس)

+

مستطیل سه‌بخشی: ۱) نام کلاس ۲) Attributes (ویژگی‌ها) ۳) Methods (متدها)

+
+
+
◯
+

Interface (اینترفیس)

+

دایره یا مستطیل با stereotype <<interface>> که قراردادها را تعریف می‌کند.

+
+
+
🗂️
+

Abstract Class (کلاس انتزاعی)

+

کلاس با نام ایتالیک که نمی‌توان نمونه مستقیم از آن ساخت.

+
+
+
➖
+

Association (ارتباط)

+

خط جامد که ارتباط بین دو کلاس را نشان می‌دهد. می‌تواند Multiplicity (تعداد) داشته باشد.

+
+
+
◇
+

Aggregation (تجميع)

+

لوزی توخالی که رابطه «has-a» ضعیف را نشان می‌دهد (جزء می‌تواند مستقل وجود داشته باشد).

+
+
+
◆
+

Composition (ترکیب)

+

لوزی توپر که رابطه «has-a» قوی را نشان می‌دهد (جزء بدون کل نمی‌تواند وجود داشته باشد).

+
+
+
△
+

Inheritance (ارث‌بری)

+

فلش مثلثی توخالی که رابطه «is-a» یا Generalization را نشان می‌دهد.

+
+
+
⇢
+

Dependency (وابستگی)

+

فلش خط‌چین که استفاده موقت یک کلاس از کلاس دیگر را نشان می‌دهد.

+
+
+ +

Visibility (سطح دسترسی):

+
++ public | - private | # protected | ~ package +
+ +
+

📋 مثال عملی: سیستم مدیریت کتابخانه

+

کلاس‌ها:

+
    +
  • Book: +
      +
    • Attributes: -isbn: String, -title: String, -author: String, -isAvailable: Boolean
    • +
    • Methods: +borrow(), +return(), +reserve()
    • +
    +
  • +
  • Member: +
      +
    • Attributes: -memberId: String, -name: String, -email: String
    • +
    • Methods: +searchBook(), +borrowBook(), +returnBook()
    • +
    +
  • +
  • Loan: +
      +
    • Attributes: -loanId: String, -loanDate: Date, -dueDate: Date
    • +
    • Methods: +calculateFine(), +extendLoan()
    • +
    +
  • +
  • Librarian: (ارث‌بری از Member) +
      +
    • Methods: +addBook(), +removeBook(), +generateReport()
    • +
    +
  • +
+

روابط:

+
    +
  • Member «1» — «*» Loan (یک عضو می‌تواند چندین امانی داشته باشد)
  • +
  • Book «1» — «*» Loan (یک کتاب می‌تواند در چندین امانی باشد)
  • +
  • Loan ◆ Book (Composition: امانی بدون کتاب معنی ندارد)
  • +
  • Librarian △ Member (ارث‌بری)
  • +
  • Book Notification (وابستگی برای ارسال اعلان)
  • +
+
+ +
+ نکته طلایی: نمودار Class پایه و اساس طراحی شیءگرا است و مستقیماً به کد تبدیل می‌شود. طراحی دقیق این نمودار، کیفیت کد نهایی را تضمین می‌کند. +
+
+
+ +
+
+
۷
+
+

نمودار توالی (Sequence Diagram)

+
نمایش تعاملات زمانی بین اشیاء
+
+
+
+

نمودار Sequence برای نمایش تعاملات بین اشیاء در طول زمان استفاده می‌شود. این نمودار نشان می‌دهد که پیام‌ها به چه ترتیبی بین اشیاء مبادله می‌شوند و برای درک سناریوهای اجرایی ایده‌آل است.

+ +
+
+
▭
+

Participant/Lifeline (خط حیات)

+

مستطیل در بالا با خط‌چین عمودی که حضور یک شیء در طول زمان را نشان می‌دهد.

+
+
+
▮
+

Activation (فعال‌سازی)

+

مستطیل باریک روی Lifeline که مدت زمان اجرای یک متد را نشان می‌دهد.

+
+
+
→●
+

Synchronous Message (پیام هم‌زمان)

+

فلش جامد که فراخوانی متد را نشان می‌دهد (فرستنده منتظر پاسخ می‌ماند).

+
+
+
→○
+

Asynchronous Message (پیام ناهم‌زمان)

+

فلش خط‌چین که ارسال پیام بدون انتظار برای پاسخ را نشان می‌دهد.

+
+
+
⇠
+

Return Message (پیام بازگشت)

+

فلش خط‌چین که مقدار بازگشتی یا پایان اجرا را نشان می‌دهد.

+
+
+
↷
+

Self Message (پیام خودی)

+

فلش منحنی که فراخوانی متد روی خود شیء را نشان می‌دهد.

+
+
+
▣
+

Combined Fragment (قطعه ترکیبی)

+

مستطیل با برچسب (alt, opt, loop, break) برای نمایش ساختارهای کنترلی.

+
+
+ +

انواع Combined Fragments:

+
    +
  • alt (شرطی): معادل if-else (چندین گزینه با شرایط مختلف)
  • +
  • opt (اختیاری): معادل if (یک گزینه در صورت برقراری شرط)
  • +
  • loop (حلقه): معادل for/while (تکرار چندین بار)
  • +
  • break (شکست): معادل break (خروج از سناریو در صورت خطا)
  • +
+ +
+

📋 مثال عملی: فرآیند خرید آنلاین

+

Participants: Customer, ShoppingCart, PaymentGateway, Inventory, EmailService

+

ترتیب پیام‌ها:

+
    +
  1. Customer → ShoppingCart: addItem(product)
  2. +
  3. Customer → ShoppingCart: checkout()
  4. +
  5. ShoppingCart → Inventory: checkAvailability(product)
  6. +
  7. Inventory → ShoppingCart: return true
  8. +
  9. ShoppingCart → PaymentGateway: processPayment(amount)
  10. +
  11. alt [payment success]: +
      +
    • PaymentGateway → ShoppingCart: paymentConfirmed()
    • +
    • ShoppingCart → Inventory: reduceStock(product)
    • +
    • ShoppingCart → EmailService: sendConfirmation(customerEmail)
    • +
    • EmailService → Customer: send email
    • +
    +
  12. +
  13. else [payment failed]: +
      +
    • PaymentGateway → ShoppingCart: paymentFailed()
    • +
    • ShoppingCart → Customer: showError()
    • +
    +
  14. +
+
+ +
+✓ کاربرد: درک سناریوهای پیچیده، دیباگ کردن، مستندسازی APIها، و ارتباط بین تیم‌های Frontend و Backend +
+
+
+ +
+
+
۸
+
+

نمودار Swimlane

+
نمایش مسئولیت‌ها در فرآیندها
+
+
+
+

نمودار Swimlane (یا Activity Diagram با Swimlanes) نسخه پیشرفته‌ای از Activity Diagram است که فعالیت‌ها را بر اساس مسئولیت (Actor، Department، یا System) در Laneهای جداگانه سازماندهی می‌کند. این نمودار برای نمایش «چه کسی چه کاری انجام می‌دهد» عالی است.

+ +
+
+
▤
+

Swimlane (لاین شنا)

+

ناحیه افقی یا عمودی که تمام فعالیت‌های یک مسئول یا بخش را در خود جای می‌دهد.

+
+
+
▭
+

Action (فعالیت)

+

مستطیل با گوشه‌های گرد که یک کار را در Swimlane مربوطه نشان می‌دهد.

+
+
+
◇
+

Decision (تصمیم)

+

لوزی که می‌تواند بین Swimlane‌ها جریان ایجاد کند.

+
+
+
→
+

Cross-Lane Flow (جریان بین لاین‌ها)

+

فلش که انتقال کار از یک مسئول به مسئول دیگر را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: فرآیند استخدام نیروی جدید

+

Swimlanes: متقاضی، منابع انسانی (HR)، مدیر فنی، مدیرعامل

+

جریان فرآیند:

+
    +
  • متقاضی: +
      +
    • ارسال رزومه → HR
    • +
    • شرکت در مصاحبه فنی
    • +
    • دریافت پیشنهاد کاری
    • +
    +
  • +
  • HR: +
      +
    • بررسی اولیه رزومه
    • +
    • هماهنگی مصاحبه → مدیر فنی
    • +
    • بررسی سوابق (Background Check)
    • +
    • ارسال پیشنهاد کاری (در صورت تأیید مدیرعامل)
    • +
    +
  • +
  • مدیر فنی: +
      +
    • مصاحبه فنی
    • +
    • ارزیابی مهارت‌ها
    • +
    • ارسال نتیجه → HR
    • +
    +
  • +
  • مدیرعامل: +
      +
    • تأیید نهایی استخدام (Decision)
    • +
    +
  • +
+

Decision Points:

+
    +
  • آیا رزومه مناسب است؟ (HR) → خیر: رد درخواست | بله: ادامه
  • +
  • آیا مصاحبه فنی موفق بود؟ (مدیر فنی) → خیر: رد درخواست | بله: ادامه
  • +
  • آیا مدیرعامل تأیید می‌کند؟ → خیر: رد درخواست | بله: ارسال پیشنهاد
  • +
+
+ +
+💡 مزیت کلیدی: Swimlane Diagram به وضوح نشان می‌دهد که هر Actor یا بخش چه مسئولیتی دارد و کجاها نیاز به هماهنگی و Handoff وجود دارد. این نمودار برای بهینه‌سازی فرآیندهای کسب‌وکار و شناسایی گلوگاه‌ها عالی است. +
+ +
+🎯 تفاوت با Activity Diagram ساده: Activity Diagram فقط «چه کاری» را نشان می‌دهد، اما Swimlane Diagram «چه کسی چه کاری» را مشخص می‌کند. +
+
+
+ +
+
+
۹
+
+

جمع‌بندی و نکات پایانی

+
انتخاب نمودار مناسب برای هر سناریو
+
+
+
+

هر یک از نمودارهای UML هدف خاصی دارند و در فازهای مختلف چرخه حیات توسعه نرم‌افزار استفاده می‌شوند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نمودارهدف اصلیفاز استفادهسطح
Use Caseنیازمندی‌ها و تعامل کاربرانتحلیلبالا (Business)
Activityفرآیندها و الگوریتم‌هاتحلیل/طراحیمتوسط
State Machineچرخه حیات اشیاءطراحیپایین (Technical)
Classساختار ایستایی سیستمطراحیپایین (Technical)
Sequenceتعاملات زمانی بین اشیاءطراحیپایین (Technical)
Componentمعماری ماژولارطراحی معماریبالا (Architecture)
Deploymentزیرساخت فیزیکیاستقراربالا (Infrastructure)
Swimlaneمسئولیت‌ها در فرآیندهاتحلیل کسب‌وکاربالا (Business)
+ +
+

🎯 توصیه‌های کلیدی

+

۱. از ساده شروع کنید: ابتدا Use Case و Activity Diagram برای درک نیازمندی‌ها

+

۲. سپس به جزئیات بروید: Class و Sequence Diagram برای طراحی فنی

+

۳. مستندسازی زنده: نمودارها را هم‌زمان با توسعه به‌روز نگه دارید

+

۴. ابزار مناسب: از ابزارهایی مانند ابزار UML استفاده کنید که امکان ویرایش آسان و Export به فرمت‌های مختلف را فراهم می‌کنند

+
+💎 نتیجه نهایی: تسلط بر UML نه تنها مهارت مدل‌سازی شما را ارتقا می‌دهد، بلکه ارتباط مؤثر با ذینفعان، کاهش خطاهای طراحی و افزایش کیفیت نرم‌افزار را به همراه خواهد داشت. +
+
+ +
+📚 منابع پیشنهادی برای مطالعه بیشتر: +
    +
  • کتاب «UML Distilled» توسط Martin Fowler
  • +
  • استاندارد OMG UML 2.5
  • +
  • الگوهای طراحی (Design Patterns) توسط Gang of Four
  • +
+
+
+
+ +
+این مستند آموزشی صرفاً جهت استفاده داخلی و آموزشی تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+
+ + +
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱:۳۰  |  نسخه: ۱.۰  |  طبقه‌بندی: آموزشی / عمومی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xUMLDrawer_Technical_Documentation.html + + + + + + +مستند فنی پروژه | ابزار رسم نمودارهای UML + + + +
+
+
+
+ +
+
+
شماره مستند: UML-TOOL-DOC-1405-001
+
نسخه: ۱.۰
+
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰
+
طبقه‌بندی: محرمانه / فنی
+
+
+
+TECHNICAL DOCUMENTATION +

مستند فنی پروژه ابزار رسم نمودارهای UML

+

تحلیل معماری، ماژول‌ها، موتور رسم و ساختار داده

+
+
+
+
+همکاران فنی و ذینفعان گرامی،
+این مستند به‌عنوان مرجع فنی جامع پروژه «ابزار رسم نمودارهای UML» تهیه شده است. هدف از این مستند، تشریح دقیق معماری، ساختار کد، ماژول‌های کلیدی، الگوهای طراحی به‌کار رفته و قابلیت‌های فنی این ابزار می‌باشد تا تیم‌های توسعه و نگهداری بتوانند با دیدی کامل و یکپارچه، به تحلیل، توسعه و گسترش آن بپردازند. +
+ +
+
+
۱
+
+

خلاصه اجرایی پروژه

+
Executive Summary
+
+
+
+

پروژه «ابزار رسم نمودارهای UML» یک اپلیکیشن تحت وب کاملاً سمت کلاینت (Client-Side) است که با استفاده از تکنولوژی‌های HTML5، CSS3 و JavaScript خالص (Vanilla JS) توسعه یافته است. این ابزار بدون نیاز به هیچ‌گونه Backend یا فریم‌ورک خارجی، امکان رسم، ویرایش، ذخیره و بازیابی هشت نوع نمودار استاندارد UML را در محیطی تعاملی و حرفه‌ای فراهم می‌آورد.

+
+
+
۸
+
نوع نمودار UML پشتیبانی شده
+
+
+
۵۰+
+
المان و رابطه قابل رسم
+
+
+
۱۰۰٪
+
اجرا در سمت مرورگر (بدون Backend)
+
+
+
+💎 ارزش کلیدی: این ابزار با تکیه بر HTML5 Canvas API و معماری ماژولار، یک محیط حرفه‌ای، سبک و کاملاً آفلاین برای مدل‌سازی سیستم‌های نرم‌افزاری در اختیار معماران و تحلیل‌گران قرار می‌دهد. +
+
+
+ +
+
+
۲
+
+

معماری کلی سیستم

+
System Architecture Overview
+
+
+
+

معماری این پروژه بر پایه الگوی Single-Page Application (SPA) و با رویکرد State-Centric طراحی شده است. تمامی وضعیت‌های برنامه در یک آبجکت مرکزی state نگهداری می‌شوند و هر تغییر در state منجر به بازترسیم کامل (Redraw) بوم می‌گردد.

+
    +
  • 🎨 Rendering Layer: موتور رسم مبتنی بر HTML5 Canvas 2D Context با قابلیت پشتیبانی از تم روشن و تاریک.
  • +
  • 🧠 State Management: یک آبجکت سراسری state که شامل لیست نمودارها، نمودار فعال، ابزار جاری، وضعیت Drag & Draw و تنظیمات UI است.
  • +
  • 🖱️ Interaction Layer: مدیریت رویدادهای Mouse (mousedown, mousemove, mouseup, dblclick) و Keyboard برای تعامل با المان‌ها.
  • +
  • 💾 Persistence Layer: سیستم ذخیره‌سازی مبتنی بر JSON File API (بدون نیاز به LocalStorage یا Backend).
  • +
  • 🎛️ UI Layer: رابط کاربری مبتنی بر Sidebar، Tab Bar، Modal ها و Properties Panel.
  • +
+
+// ساختار کلی State Object
+const state = {
+  diagrams: [],            // لیست همه نمودارها
+  activeDiagramId: null,  // شناسه نمودار فعال
+  currentTool: 'select',   // ابزار انتخاب‌شده
+  selectedElement: null,   // المان انتخاب‌شده
+  isDragging: false,       // وضعیت Drag
+  isDrawingRelationship: false,
+  darkMode: true,          // تم تاریک/روشن
+  gridType: 'lines',       // نوع خط‌کشی بوم
+  fileMetadata: { ... }     // متادیتای پروژه
+}; +
+
+
+ +
+
+
۳
+
+

تکنولوژی‌های به‌کار رفته

+
Technology Stack
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
لایهتکنولوژینقش در پروژه
ساختارHTML5 Semanticساختار صفحه و المان‌های DOM
استایلCSS3 + CSS Variablesطراحی RTL، تم داینامیک، گرادیانت‌ها
رسم گرافیکیHTML5 Canvas 2D APIموتور رسم نمودارها، Grid و المان‌ها
منطق برنامهVanilla JavaScript (ES6+)State Management، Event Handling، Drawing Engine
ذخیره‌سازیFile API + JSONExport/Import پروژه به‌صورت فایل JSON
فونتVazirmatn (Google Fonts)تایپوگرافی فارسی حرفه‌ای
استایل کمکیTailwind CSS (CDN)Utility classes برای UI سریع
+
+💡 نکته معماری: انتخاب Vanilla JS به جای فریم‌ورک‌هایی مانند React یا Angular، باعث کاهش چشمگیر حجم نهایی (Bundle Size)، اجرای سریع‌تر و عدم وابستگی به ابزارهای Build شده است. این رویکرد برای ابزارهای تخصصی و آفلاین، انتخاب بهینه‌ای است. +
+
+
+ +
+
+
۴
+
+

نمودارهای پشتیبانی‌شده

+
Supported UML Diagrams
+
+
+
+

این ابزار هشت نوع نمودار استاندارد UML را پشتیبانی می‌کند که هر کدام در رجیستری DIAGRAM_TYPES تعریف شده‌اند. این رجیستری به‌عنوان Single Source of Truth برای ابزارها، گروه‌ها و قابلیت‌های هر نمودار عمل می‌کند.

+
+
+
⭕
+

Use Case Diagram

+

مدل‌سازی Actorها، Use Caseها، System Boundary و روابط Include/Extend/Generalization.

+
+
+
🔄
+

State Machine Diagram

+

Initial/Final State، Stateها، Composite State و Transition با برچسب اختیاری.

+
+
+
🔀
+

Activity Diagram

+

Action، Decision/Merge، Fork/Join و جریان‌های Control/Object Flow.

+
+
+
🧩
+

Component Diagram

+

Component، Interface (Provided/Required)، Package و روابط Dependency/Connector.

+
+
+
🖥️
+

Deployment Diagram

+

Node، Device، Execution Environment، Artifact و روابط Deploy/Manifest.

+
+
+
🗂️
+

Class Diagram

+

Class، Interface، Abstract، Enumeration با Attributes/Methods و روابط کامل UML.

+
+
+
🔢
+

Sequence Diagram

+

Participant، Activation، Combined Fragment و پیام‌های Sync/Async/Return/Self.

+
+
+
▤
+

Swimlane Diagram

+

Swimlane افقی/عمودی با قابلیت Resize، Action، Decision و Fork/Join درون آن.

+
+
+
+// Registry الگوی طراحی - نمونه تعریف یک نمودار
+const DIAGRAM_TYPES = {
+  usecase: {
+    id: 'usecase',
+    name: 'نمودار مورد کاربرد (Use Case)',
+    icon: '⭕',
+    tools: ['select', 'actor', 'useCase', 'boundary', ...],
+    groups: ['selection', 'uc-elements', 'uc-relations', ...]
+  },
+  // ... سایر نمودارها
+}; +
+
+
+ +
+
+
۵
+
+

موتور رسم (Drawing Engine)

+
Canvas Rendering Engine
+
+
+
+

موتور رسم، قلب تپنده این پروژه است و بر پایه Immediate Mode Rendering طراحی شده است. در این رویکرد، در هر فریم (یا پس از هر تغییر state) کل بوم پاک‌سازی شده و تمامی المان‌ها از نو رسم می‌شوند. این رویکرد اگرچه در نگاه اول پرهزینه به نظر می‌رسد، اما به دلیل سادگی، قابلیت اطمینان بالا و عدم نیاز به مدیریت پیچیده Diff، برای این نوع ابزارها ایده‌آل است.

+

چرخه رسم (Render Loop):

+
    +
  • ۱. پاک‌سازی بوم: ctx.clearRect() و رسم پس‌زمینه بر اساس تم.
  • +
  • ۲. رسم Grid: بر اساس نوع انتخابی (Lines/Dots/None) با استفاده از CSS Variables.
  • +
  • ۳. رسم المان‌ها: فراخوانی توابع اختصاصی هر نمودار (مانند drawUseCase, drawClassDiagram).
  • +
  • ۴. رسم روابط: پس از المان‌ها، روابط با محاسبه مرکز المان‌های مبدأ و مقصد رسم می‌شوند.
  • +
  • ۵. رسم Selection: المان انتخاب‌شده با خط‌چین آبی‌رنگ مشخص می‌شود.
  • +
  • ۶. رسم Relationship Preview: در حالت رسم رابطه، خط موقتی تا موقعیت ماوس نمایش داده می‌شود.
  • +
+
+// چرخه اصلی رسم
+function draw() {
+  const d = getActive(), tc = getTC();
+  ctx.clearRect(0, 0, canvas.width, canvas.height);
+  ctx.fillStyle = tc.canvasBg;
+  ctx.fillRect(0, 0, canvas.width, canvas.height);
+  drawGrid(ctx, canvas.width, canvas.height, tc, false);
+  if (!d) return;
+  drawDiag(ctx, d, tc); // Dispatch به تابع اختصاصی
+} +
+
+💡 بهینه‌سازی: برای جلوگیری از رسم‌های مکرر غیرضروری، از تکنیک requestAnimationFrame و scheduleResize() استفاده شده است تا Resize رویدادها به‌صورت هوشمند مدیریت شوند. +
+
+
+ +
+
+
۶
+
+

سیستم مدیریت تم و رنگ

+
Theme & Color System
+
+
+
+

سیستم تم این پروژه بر پایه CSS Custom Properties (Variables) طراحی شده است. با تغییر کلاس body.dark، تمامی متغیرهای رنگی به‌صورت آنی تغییر می‌کنند و موتور رسم نیز از طریق تابع getTC() این مقادیر را در زمان اجرا (Runtime) از DOM استخراج می‌کند.

+ + + + + + + + + + + + + + + +
متغیر CSSنقشمثال مقدار (Dark Mode)
--canvas-bgپس‌زمینه بوم#0f1724
--actor-strokeرنگ خط Actor#cbd5e0
--class-fillرنگ زمینه Class#1e2d40
--seq-msgرنگ پیام‌های Sequence#cbd5e0
--selectedرنگ المان انتخاب‌شده#667eea
+
+✓ مزیت این رویکرد: افزودن یک تم جدید (مانند تم آبی، سبز یا High-Contrast) تنها با تغییر چند متغیر CSS امکان‌پذیر است و هیچ تغییری در منطق JavaScript نیاز نیست. +
+
+
+ +
+
+
۷
+
+

سیستم تعامل و Hit Testing

+
Interaction & Hit Testing System
+
+
+
+

برای تشخیص اینکه ماوس روی کدام المان قرار دارد، از الگوی Hit Testing استفاده می‌شود. تابع hitTest(x, y) بر اساس نوع نمودار فعال، الگوریتم‌های متفاوتی را اجرا می‌کند:

+
    +
  • Actor: محاسبه فاصله اقلیتسی (Bounding Box 50×80 پیکسل).
  • +
  • Use Case (بیضی): استفاده از معادله استاندارد بیضی (x²/a²) + (y²/b²) ≤ 1.
  • +
  • State/Action/Component (مستطیل با گوشه گرد): بررسی Bounding Box.
  • +
  • Decision (لوزی): استفاده از معادله لوزی |x| + |y| ≤ size.
  • +
  • Class: بررسی بر اساس ارتفاع محاسبه‌شده داینامیک (_computedH).
  • +
  • Swimlane: علاوه بر Hit Test بدنه، بررسی ۸ Handle برای Resize.
  • +
+
+⚠️ چالش فنی: در نمودار Class، ارتفاع به‌صورت داینامیک بر اساس تعداد Attributes و Methods محاسبه می‌شود. این مقدار در هر Draw در cls._computedH ذخیره می‌گردد تا در Hit Test نیز قابل استفاده باشد. +
+
+
+ +
+
+
۸
+
+

سیستم ذخیره‌سازی و بازیابی

+
Persistence & File System
+
+
+
+

سیستم Persistence این پروژه کاملاً مبتنی بر JSON File API است و از LocalStorage یا IndexedDB استفاده نمی‌کند. این تصمیم معماری، مزایای زیر را به همراه دارد:

+
    +
  • قابلیت اشتراک‌گذاری آسان: فایل JSON به‌راحتی قابل ارسال از طریق ایمیل، Git یا پیام‌رسان‌ها است.
  • +
  • نسخه‌بندی (Versioning): فایل‌ها می‌توانند در Git نگهداری و Diff شوند.
  • +
  • عدم وابستگی به مرورگر: با پاک‌سازی Cache مرورگر، داده‌ها از بین نمی‌روند.
  • +
  • ساختار قابل توسعه: فرمت JSON به‌راحتی قابل گسترش است.
  • +
+
+// ساختار فایل خروجی JSON
+{
+  "version": "5.1",
+  "fileTitle": "عنوان پروژه",
+  "author": "هادی خزاعی اصل",
+  "organization": "رایان پرداز کاوش",
+  "createdAt": "2026-09-07T10:30:00.000Z",
+  "preferences": { "gridType": "lines", "darkMode": true },
+  "diagrams": [ /* آرایه نمودارها */ ]
+} +
+
+💡 Backward Compatibility: در هنگام Load فایل، کد با استفاده از || operator، فیلدهای اختیاری را مقداردهی پیش‌فرض می‌کند تا فایل‌های نسخه‌های قدیمی‌تر نیز بدون خطا بارگذاری شوند. +
+
+
+ +
+
+
۹
+
+

الگوهای طراحی به‌کار رفته

+
Design Patterns
+
+
+
+

در این پروژه، چندین الگوی طراحی شناخته‌شده به‌صورت عملی پیاده‌سازی شده‌اند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل کاربردتوضیح
Registry PatternDIAGRAM_TYPESمرجع مرکزی تعریف انواع نمودار و قابلیت‌های آن‌ها
State Patternآبجکت stateمدیریت وضعیت سراسری برنامه
Strategy Patternتوابع drawUseCase, drawClassDiagram, ...انتخاب استراتژی رسم بر اساس نوع نمودار
Command Patternمدیریت ابزارها (Tools)هر ابزار یک رفتار مشخص را در mousedown/mouseup اجرا می‌کند
Observer PatternEvent Listenersواکنش به رویدادهای Mouse، Keyboard و UI
Factory PatterncreateNewDiagram()ساخت ساختار اولیه نمودار بر اساس نوع
Singleton PatternCanvas Context، State Objectتنها یک نمونه از منابع حیاتی در طول اجرا
+
+
+ +
+
+
۱۰
+
+

قابلیت‌های کلیدی و UX

+
Key Features & UX
+
+
+
+
    +
  • 🗂️ مدیریت چند نمودار (Multi-Tab): امکان باز کردن هم‌زمان چندین نمودار در تب‌های مجزا با امکان سوئیچ سریع.
  • +
  • 🌙 تم تاریک/روشن: سوئیچ آنی با حفظ ترجیحات در فایل پروژه.
  • +
  • ⌨️ کلیدهای میانبر: Ctrl+S (ذخیره)، Ctrl+N (جدید)، Delete (حذف)، B (Sidebar)، G (Grid).
  • +
  • 🎨 Properties Panel: ویرایش زنده ویژگی‌های المان انتخاب‌شده در پایین صفحه.
  • +
  • 🗂️ Class Editor Modal: ویرایشگر پیشرفته Attributes و Methods با Visibility، Static و Type.
  • +
  • 📐 Resize Handles: قابلیت تغییر اندازه Swimlane با ۸ Handle در گوشه‌ها و اضلاع.
  • +
  • 🖼️ Export to PNG: خروجی با کیفیت از نمودار فعلی با قابلیت انتخاب رنگ پس‌زمینه یا شفافیت.
  • +
  • 📦 Grid System: سه حالت (Lines, Dots, None) برای کمک به چیدمان دقیق المان‌ها.
  • +
  • 🔗 Relationship Drawing: رسم روابط با Drag از مبدأ به مقصد و Prompt برای برچسب و Multiplicity.
  • +
+
+
+ +
+
+
۱۱
+
+

نقاط قوت و پیشنهادات بهبود

+
Strengths & Recommendations
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
دستهنقاط قوت فعلیپیشنهادات بهبود
معماریبدون وابستگی خارجی، سبک و سریعماژولار کردن کد با ES Modules برای نگهداری بهتر
عملکرداجرای روان در نمودارهای کوچک و متوسطپیاده‌سازی Dirty Rectangle Rendering برای نمودارهای بزرگ
UXرابط کاربری شهودی با RTL کاملافزودن Undo/Redo با Command History
ذخیره‌سازیخروجی JSON قابل اشتراکافزودن Auto-Save در LocalStorage به‌عنوان Backup
توسعه‌پذیریRegistry Pattern برای افزودن نمودار جدیدافزودن نمودارهای Package و Communication
خروجیPNG با کیفیتافزودن Export به SVG، PDF و XMI استاندارد
+
+
+ +
+
+
۱۲
+
+

جمع‌بندی نهایی

+
Final Conclusion
+
+
+
+

پروژه «ابزار رسم نمودارهای UML» یک نمونه موفق از توسعه یک اپلیکیشن تخصصی و حرفه‌ای با استفاده از تکنولوژی‌های پایه وب است. این ابزار با تکیه بر معماری State-Centric، موتور رسم مبتنی بر Canvas و سیستم Registry منعطف، توانایی مدل‌سازی کامل سیستم‌های نرم‌افزاری را در محیطی آفلاین و سبک فراهم می‌آورد.

+
+

🎯 نتیجه‌گیری معماری

+

این پروژه نشان می‌دهد که برای ساخت ابزارهای تخصصی، لزومی به استفاده از فریم‌ورک‌های سنگین نیست. با طراحی دقیق معماری، انتخاب الگوهای مناسب و تمرکز بر تجربه کاربری، می‌توان محصولی در سطح Enterprise تولید کرد که کاملاً مستقل، قابل نگهداری و توسعه‌پذیر باشد.

+
+💎 ارزش نهایی: ابزاری کاملاً آفلاین، سبک، حرفه‌ای و مستقل که نیاز هر معمار و تحلیل‌گر نرم‌افزار را برای مدل‌سازی سریع و دقیق برطرف می‌سازد. +
+
+
+📞 گام بعدی: برای توسعه نسخه‌های آتی، پیشنهاد می‌شود ماژول‌های Undo/Redo، Export به فرمت‌های استاندارد (XMI, SVG) و افزودن نمودارهای Interaction اضافه گردد. +
+
+
+ +
+این مستند محرمانه بوده و صرفاً جهت استفاده داخلی تیم فنی تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+
+ + +
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰  |  نسخه: ۱.۰  |  طبقه‌بندی: محرمانه / فنی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\ExceptionResourceIDS.ts + +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'داده نا معتبر', + }, + { + id: 'ex_101', + value: 'تاریخ نامعتبر', + }, + { + id: 'ex_102', + value: 'درخواست اشتباه', + }, + { + id: 'ex_103', + value: 'ورودی نامعتبر', + }, + { + id: 'ex_104', + value: 'پیام نامعتبر', + }, + { + id: 'ex_105', + value: 'نشانه نامعتبر', + }, + { + id: 'ex_106', + value: 'کد اععتبارسنجی نامعتبر', + }, + { + id: 'ex_107', + value: 'پست الکترونیک نامعتبر', + }, + { + id: 'ex_108', + value: 'شماره تلفن همراه نامعتبر', + }, + { + id: 'ex_109', + value: 'کلمه عبور نامعتبر', + }, + { + id: 'ex_110', + value: 'آدرس اینترنتی نامعتبر', + }, + { + id: 'ex_111', + value: 'دستگاه نامعتبر', + }, + { + id: 'ex_112', + value: 'تصویر پروفایل نامعتبر', + }, + { + id: 'ex_113', + value: 'فایل نامعتبر', + }, + { + id: 'ex_114', + value: 'نام کاربری نامعتبر', + }, + { + id: 'ex_200', + value: 'یافت نشد', + }, + { + id: 'ex_201', + value: 'عدم تایید جواز', + }, + { + id: 'ex_202', + value: 'سطح دسترسی نامعتبر', + }, + { + id: 'ex_203', + value: 'غیر قابل نمایش', + }, + { + id: 'ex_300', + value: 'حساب کاربری قفل شده است', + }, + { + id: 'ex_301', + value: 'خطا در ورود', + }, + { + id: 'ex_302', + value: 'کاربر قبلا ثبت نام کرده است', + }, + { + id: 'ex_303', + value: 'کاربر غیرفعال است', + }, + { + id: 'ex_304', + value: 'دستگاه شما قفل شده است تا : (0)', + }, + { + id: 'ex_305', + value: 'امکان درخواست کد اعتبارسنجی وجود ندارد تا : (0)', + }, + { + id: 'ex_306', + value: 'کلمه عبورها یکسان هستند', + }, + { + id: 'ex_307', + value: 'شماره های تلفن یکسان هستند', + }, + { + id: 'ex_308', + value: 'آدرس های پست الکترونیک یکسان هستند', + }, + { + id: 'ex_309', + value: 'شماره تلفن قبلا ثبت شده است', + }, + { + id: 'ex_310', + value: 'پست الکترونیک قبلا ثبت شده است', + }, + { + id: 'ex_311', + value: 'تلفن همراه تایید نشده است', + }, + { + id: 'ex_312', + value: 'پست الکترونیک تایید نشده است', + }, + { + id: 'ex_313', + value: 'مطلب ممنوعه', + }, + { + id: 'ex_314', + value: 'کاربر ممنوعه', + }, + { + id: 'ex_400', + value: 'خطای نا شناخته', + }, + { + id: 'ex_401', + value: 'مورد تکراری', + }, + { + id: 'ex_402', + value: 'شکست عملیات', + }, + { + id: 'ex_403', + value: 'تاریخ مصرف منقضی شده است', + }, + { + id: 'ex_404', + value: 'غیر قابل اسفاده', + }, + { + id: 'ex_405', + value: 'تعداد برچسب ها بیش از جد مجاز است', + }, + { + id: 'ex_406', + value: 'اتمام مهلت زمانی', + }, + { + id: 'ex_500', + value: 'پرونده خالی است', + }, + { + id: 'ex_501', + value: 'اندازه بیش از حد مجاز', + }, + { + id: 'ex_502', + value: 'گونه نامعتبر فایل', + }, + { + id: 'ex_503', + value: 'تعداد رسانه ها بیش از حد مجاز است', + }, + { + id: 'ex_600', + value: 'پیکربندی اشتباه', + }, + { + id: 'ex_601', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_602', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_900', + value: 'تعداد فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_901', + value: 'مجموع اندازه فایل ها کمتر از حد مجاز است', + }, + { + id: 'ex_902', + value: 'مجموع اندازه فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_903', + value: 'شرایط و ضوابط باید پذیرفته شوند', + }, + { + id: 'ex_904', + value: 'عدم پشتیبانی از سیستم موقعیت یاب', + }, + { + id: 'ex_905', + value: 'مجوز دسترسی به موقعیت خود را صادر نکرده اید', + }, + { + id: 'ex_906', + value: 'دسترسی به موقعیت جغرافیایی امکان پذیر نیست', + }, + { + id: 'ex_907', + value: 'عدم پشتیبانی از سیستم ذخیره سازی', + }, + { + id: 'ex_908', + value: 'برای دسترسی به محتوا باید از سامانه خارج شوید', + }, + { + id: 'ex_909', + value: 'زبان انتخاب شده نامعتبر است', + }, + { + id: 'ex_910', + value: 'داده نامعتبر برای انتخاب کاربر', + }, + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'Invalid Data ...', + }, + { + id: 'ex_101', + value: 'Invalid Date ...', + }, + { + id: 'ex_102', + value: 'Bad Request ...', + }, + { + id: 'ex_103', + value: 'Invalid Args ...', + }, + { + id: 'ex_104', + value: 'Invalid Message ...', + }, + { + id: 'ex_105', + value: 'Invalid Token ...', + }, + { + id: 'ex_106', + value: 'Invalid Verification Code ...', + }, + { + id: 'ex_107', + value: 'Invalid Email Address ...', + }, + { + id: 'ex_108', + value: 'Invalid Mobile Number ...', + }, + { + id: 'ex_109', + value: 'Invalid Password ...', + }, + { + id: 'ex_110', + value: 'Invalid URL ...', + }, + { + id: 'ex_111', + value: 'Invalid Device ...', + }, + { + id: 'ex_112', + value: 'Invalid Profile Image ...', + }, + { + id: 'ex_113', + value: 'Invalid File ...', + }, + { + id: 'ex_114', + value: 'Invalid Username ...', + }, + { + id: 'ex_200', + value: 'Not Found ...', + }, + { + id: 'ex_201', + value: 'Not Allowed ...', + }, + { + id: 'ex_202', + value: 'Not Authorized ...', + }, + { + id: 'ex_203', + value: 'Not Visible ...', + }, + { + id: 'ex_300', + value: 'Account Locked out ...', + }, + { + id: 'ex_301', + value: 'Login Failed ...', + }, + { + id: 'ex_302', + value: 'User Registered Before ...', + }, + { + id: 'ex_303', + value: 'User Disabled ...', + }, + { + id: 'ex_304', + value: 'Device Banned Until:(0)', + }, + { + id: 'ex_305', + value: `You can not Request Verification code Until:(0)`, + }, + { + id: 'ex_306', + value: 'Passwords Same ...', + }, + { + id: 'ex_307', + value: 'Mobiles Same ...', + }, + { + id: 'ex_308', + value: 'Emails Same ...', + }, + { + id: 'ex_309', + value: 'Mobile In Used ...', + }, + { + id: 'ex_310', + value: 'Email In Used ...', + }, + { + id: 'ex_311', + value: 'Mobile Not Confirmed ...', + }, + { + id: 'ex_312', + value: 'Email Not Confirmed ...', + }, + { + id: 'ex_313', + value: 'Post Banned ...', + }, + { + id: 'ex_314', + value: 'User Banned ...', + }, + { + id: 'ex_400', + value: 'Unknown Error ...', + }, + { + id: 'ex_401', + value: 'Duplicate ...', + }, + { + id: 'ex_402', + value: 'Action Failed ...', + }, + { + id: 'ex_403', + value: 'Expired Date ...', + }, + { + id: 'ex_404', + value: 'Unavailable ...', + }, + { + id: 'ex_405', + value: 'Max Allowed Tag Exceeded ...', + }, + { + id: 'ex_406', + value: 'Timeout ...', + }, + { + id: 'ex_500', + value: 'Empty File ...', + }, + { + id: 'ex_501', + value: 'max File size exceeded ...', + }, + { + id: 'ex_502', + value: 'Unsupported File Type ...', + }, + { + id: 'ex_503', + value: 'Max Allowed Media Exceeded ...', + }, + { + id: 'ex_600', + value: 'Invalid Configuration ...', + }, + { + id: 'ex_601', + value: 'Storage Service Initiallization Failed ...', + }, + { + id: 'ex_602', + value: 'Message Service Initialization Failed ...', + }, + { + id: 'ex_900', + value: 'Max Allowed Files Exceeded ...', + }, + { + id: 'ex_901', + value: 'Min Files Size Exceeded ...', + }, + { + id: 'ex_902', + value: 'Max Files Size Exceeded ...', + }, + { + id: 'ex_903', + value: 'Must Accept Terms And Conditions ...', + }, + { + id: 'ex_904', + value: 'Browser does not support Location Services ...', + }, + { + id: 'ex_905', + value: 'You have rejected access to your Location ...', + }, + { + id: 'ex_906', + value: 'Unable to determine your Location ...', + }, + { + id: 'ex_907', + value: 'Browser does not support Storage Services ...', + }, + { + id: 'ex_908', + value: 'Must Logout to access content ...', + }, + { + id: 'ex_909', + value: 'Invalid Locale ...', + }, + { + id: 'ex_910', + value: 'Invalid User Selector ...', + }, + //#endregion + ], + }, +]; + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\XResourceIDS.html + + + + + + + مستندات منابع ترجمه (AvailableTranslationResources) + + + +
+
+

مستندات به‌روزرسانی منابع ترجمه

+
+ توسعه‌دهنده: هادی خزاعی اصل + شرکت: فن آوران ساحر علم + تاریخ: ۱۴۰۵/۰۵/۳۱ +
+
+ +

کد به‌روزرسانی‌شده `AvailableTranslationResources` شامل کلیدهای جدید درخواست‌شده در زیر ارائه شده است:

+ +
export const AvailableTranslationResources: XLanguageDescriptor[] = [
+  {
+    name: 'persian',
+    locale: 'fa-IR',
+    language: 'fa',
+    direction: 'rtl',
+    resources: [
+      { id: 'app_name', value: 'ساحر علم' },
+      { id: 'company', value: 'فن آوران ساحر علم' },
+      { id: 'id', value: 'شناسه' },
+      { id: 'file_name', value: 'نام فایل' },
+      { id: 'error', value: 'خطا' },
+      { id: 'required', value: 'الزامی است.' },
+      { id: 'loading', value: 'بارگزاری' },
+      { id: 'username', value: 'نام کاربری' },
+      { id: 'password', value: 'کلمه عبور' },
+      { id: 'first_name', value: 'نام' },
+      { id: 'last_name', value: 'نام خانوادگی' },
+      { id: 'verified', value: 'تایید شده' },
+      { id: 'unverified', value: 'تایید نشده' },
+      { id: 'thumbnail', value: 'پیش نمایش' },
+      { id: 'language', value: 'زبان' },
+      { id: 'take_screenshot', value: 'تصویر برداری ازمحیط' },
+      { id: 'enable_capture_mode', value: 'فعالسازی حالت تصویر برداری' },
+      { id: 'disable_capture_mode', value: 'غیرفعالسازی حالت تصویر برداری' },
+      { id: 'be', value: 'باشد' },
+      { id: 'not_to_be', value: 'نباشد' },
+      { id: 'enabled', value: 'فعال' },
+      { id: 'disabled', value: 'غیر فعال' },
+      { id: 'banned', value: 'مسدود' },
+      { id: 'un_banned', value: 'غیر مسدود' },
+      { id: 'audio', value: 'صوت' },
+      { id: 'video', value: 'فیلم' },
+      { id: 'cover_image', value: 'تصویر' },
+      { id: 'image', value: 'تصویر' },
+      { id: 'unknown', value: 'ناشناس' },
+      { id: 'location', value: 'موقعیت جغرافیای' },
+      { id: 'are_you_sure', value: 'اطمینان دارید ؟' },
+      { id: 'success_msg', value: 'عملیات با موفقیت انجام شد' },
+      { id: 'locked_msg', value: 'برای ترک این صفحه باید فعالیت جاری را لغو کرده و یا به اتمام برسانید' },
+      { id: 'empty_content', value: 'خالی است' },
+      { id: 'no_item', value: 'محتوایی ثبت نشده است' },
+      { id: 'drag_drop_here', value: 'محل رها کردن فایل' },
+      { id: 'map_dialog_title', value: 'نمایش موقعیت مکانی' },
+      { id: 'map_dialog_select_title', value: 'انتخاب موقعیت جغرافیایی' },
+      { id: 'color_picker_dialog_title', value: 'انتخاب رنگ' },
+      { id: 'dismiss', value: 'رد کردن' },
+      { id: 'accept', value: 'می پذیرم' },
+      { id: 'ok', value: 'بسیار خب' },
+      { id: 'save', value: 'ذخیره' },
+      { id: 'cancel', value: 'لغو' },
+      { id: 'retry', value: 'سعی مجدد' },
+      { id: 'edit', value: 'ویرایش' },
+      { id: 'reset', value: 'باز نشاندن' },
+      { id: 'change', value: 'تغییر' },
+      { id: 'start', value: 'آغاز' },
+      { id: 'yes', value: 'بله' },
+      { id: 'no', value: 'خیر' },
+      { id: 'verify', value: 'تایید کردن' },
+      { id: 'confirm', value: 'تاییدیه' },
+      { id: 'crop', value: 'برش' },
+      { id: 'clear', value: 'پاک کردن' },
+      { id: 'set', value: 'تنظیم' },
+      { id: 'select', value: 'انتخاب' },
+      { id: 'send', value: 'ارسال' },
+      { id: 'show', value: 'نمایش دادن' },
+      { id: 'hide', value: 'پنهان کردن' },
+      { id: 'search', value: 'جستجو' },
+      { id: 'delete', value: 'حذف' },
+      { id: 'clone', value: 'نمونه گیری' },
+      { id: 'select_all', value: 'انتخاب همه' },
+      { id: 'select_file', value: 'انتخاب فایل(ها)' },
+      { id: 'select_all_group', value: 'انتخاب همه موارد فیلتر شده' },
+      { id: 'deselect_all', value: 'لغو همه انتخاب ها' },
+      { id: 'deselect_all_group', value: 'لغو انتخاب همه موارد فیلتر شده' },
+      { id: 'inverse_selection', value: 'انتخاب معکوس' },
+      { id: 'selected_location', value: 'انتخاب محل' },
+      { id: 'preset_colors', value: 'رنگ های پیش فرض' },
+      { id: 'copy_to_clipboard', value: 'ثبت در حافظه موقت' },
+      { id: 'color', value: 'رنگ' },
+      { id: 'colors', value: 'رنگها' },
+      { id: 'upload', value: 'بارگزاری' },
+      { id: 'import', value: 'وارد کردن' },
+      { id: 'continue', value: 'ادامه' },
+      { id: 'finish', value: 'پایان' },
+      { id: 'enable', value: 'فعال' },
+      { id: 'disable', value: 'غیر فعال' },
+      { id: 'all', value: 'همه' },
+      { id: 'new', value: 'جدید' },
+      { id: 'add', value: 'افزودن' },
+      { id: 'update', value: 'بروز رسانی' },
+      { id: 'details', value: 'جزئیات' },
+      { id: 'translation', value: 'ترجمه' },
+      { id: 'download', value: 'دریافت' },
+      { id: 'list', value: 'فهرست' },
+      { id: 'options', value: 'انتخاب ها' },
+      { id: 'descriptions', value: 'توضیحات' },
+      { id: 'type', value: 'نوع' },
+      { id: 'media', value: 'رسانه' },
+      { id: 'medias', value: 'رسانه ها' },
+      { id: 'summary', value: 'خلاصه' },
+      { id: 'go', value: 'رفتن' },
+      { id: 'input', value: 'ورود' },
+      { id: 'preview', value: 'پیش نمایش' },
+      { id: 'close', value: 'بستن' },
+      { id: 'undo', value: 'لغو کردن' },
+      { id: 'redo', value: 'انجام دوباره' },
+      { id: 'refresh', value: 'بازیابی' },
+      { id: 'submit', value: 'ثبت' },
+      { id: 'first', value: 'نخستین' },
+      { id: 'last', value: 'آخرین' },
+      { id: 'previous', value: 'قبلی' },
+      { id: 'next', value: 'بعدی' },
+      { id: 'back', value: 'بازگشت' },
+      { id: 'x_markdown_preview', value: 'پیش نمایش' },
+      { id: 'x_markdown_image', value: 'تصویر' },
+      { id: 'x_markdown_link', value: 'پیوند' },
+      { id: 'x_markdown_ol', value: 'فهرست ترتیبی' },
+      { id: 'x_markdown_ul', value: 'فهرست بدون ترتیب' },
+      { id: 'x_markdown_quote', value: 'نقل قول' },
+      { id: 'x_markdown_code', value: 'کد منبع' },
+      { id: 'x_markdown_heading', value: 'عنوان' },
+      { id: 'x_markdown_italic', value: 'ایتالیک' },
+      { id: 'x_markdown_bold', value: 'پر رنگ' },
+      { id: 'x_markdown_guide', value: 'راهنمای نگارش' },
+      { id: 'theme', value: 'پوسته' },
+      { id: 'theme_mode', value: 'حالت نمایشی' },
+      { id: 'theme_dark', value: 'تیره' },
+      { id: 'theme_light', value: 'روشن' },
+      { id: 'theme_name', value: 'نام پوسته' },
+      { id: 'theme_name_description', value: 'نام پوسته را وارد کنید' },
+      { id: 'theme_clone_title', value: 'نمونه گیری از پوسته' },
+      { id: 'input_color_title', value: 'تعیین رنگ' },
+      { id: 'input_color_description', value: 'مقدار رنگ را وارد کنید' },
+      { id: 'ide_mode', value: 'نوع کد' },
+      { id: 'ide_format', value: 'حالت دهی کد' },
+      // ... (سایر آیتم‌های موجود در لیست اصلی حفظ شده‌اند) ...
+      
+      // --- موارد جدید اضافه شده ---
+      { id: 'print', value: 'چاپ' },
+      { id: 'export_png', value: 'خروجی PNG' },
+      { id: 'export_svg', value: 'خروجی SVG' },
+      { id: 'export_csv', value: 'خروجی CSV' },
+      { id: 'zoom_in', value: 'بزرگنمایی' },
+      { id: 'zoom_out', value: 'کوچک نمایی' },
+      { id: 'zoom_selection', value: 'بزرگنمایی ناحیه' },
+      { id: 'x_axis', value: 'محور افقی' },
+      { id: 'y_axis', value: 'محور عمودی' },
+      { id: 'xy_axis', value: 'محورهای عمودی و افقی' },
+      { id: 'pan', value: 'حرکت آزاد' },
+      { id: 'full_screen', value: 'حالت تمام صفحه' }
+    ],
+  },
+  {
+    name: 'english',
+    locale: 'en-US',
+    language: 'en',
+    direction: 'ltr',
+    resources: [
+      { id: 'app_name', value: 'SaherElm' },
+      { id: 'company', value: 'SaherElm IT Center' },
+      { id: 'id', value: 'ID' },
+      { id: 'file_name', value: 'File Name' },
+      { id: 'error', value: 'Error' },
+      { id: 'required', value: 'required' },
+      { id: 'loading', value: 'loading' },
+      { id: 'username', value: 'Username' },
+      { id: 'password', value: 'Password' },
+      { id: 'first_name', value: 'Firstname' },
+      { id: 'last_name', value: 'Lastname' },
+      { id: 'verified', value: 'Verified' },
+      { id: 'unverified', value: 'Unverified' },
+      { id: 'thumbnail', value: 'Thumbnail' },
+      { id: 'language', value: 'Language' },
+      { id: 'take_screenshot', value: 'Take Screenshot' },
+      { id: 'enable_capture_mode', value: 'Enable Capture Mode' },
+      { id: 'disable_capture_mode', value: 'Disable Capture Mode' },
+      { id: 'be', value: 'Be' },
+      { id: 'not_to_be', value: 'Not to be' },
+      { id: 'enabled', value: 'Enabled' },
+      { id: 'disabled', value: 'Disabled' },
+      { id: 'banned', value: 'Banned' },
+      { id: 'un_banned', value: 'UnBanned' },
+      { id: 'audio', value: 'Audio' },
+      { id: 'video', value: 'Video' },
+      { id: 'cover_image', value: 'Cover Image' },
+      { id: 'image', value: 'Image' },
+      { id: 'avatar', value: 'Avatar' },
+      { id: 'unknown', value: 'Unknown' },
+      { id: 'location', value: 'Location' },
+      { id: 'are_you_sure', value: 'Are You Sure ?' },
+      { id: 'success_msg', value: 'Operation done Successfully ...' },
+      { id: 'locked_msg', value: 'You have to finish/cancel current proccess for leaving' },
+      { id: 'empty_content', value: 'Empty' },
+      { id: 'no_item', value: 'there is no Content' },
+      { id: 'drag_drop_here', value: 'Drop File Here' },
+      { id: 'map_dialog_title', value: 'Show Location' },
+      { id: 'map_dialog_select_title', value: 'Select Location' },
+      { id: 'color_picker_dialog_title', value: 'Select Color' },
+      { id: 'dismiss', value: 'dismiss' },
+      { id: 'accept', value: 'Accept' },
+      { id: 'ok', value: 'Ok' },
+      { id: 'save', value: 'Save' },
+      { id: 'cancel', value: 'Cancel' },
+      { id: 'retry', value: 'Retry' },
+      { id: 'edit', value: 'Edit' },
+      { id: 'reset', value: 'Reset' },
+      { id: 'change', value: 'Change' },
+      { id: 'start', value: 'Start' },
+      { id: 'yes', value: 'Yes' },
+      { id: 'no', value: 'No' },
+      { id: 'verify', value: 'Verify' },
+      { id: 'confirm', value: 'Confirm' },
+      { id: 'crop', value: 'Crop' },
+      { id: 'clear', value: 'Clear' },
+      { id: 'set', value: 'Set' },
+      { id: 'select', value: 'Select' },
+      { id: 'send', value: 'Send' },
+      { id: 'show', value: 'Show' },
+      { id: 'hide', value: 'Hide' },
+      { id: 'search', value: 'Search' },
+      { id: 'delete', value: 'Delete' },
+      { id: 'clone', value: 'Clone' },
+      { id: 'select_all', value: 'Select All' },
+      { id: 'select_file', value: 'Select File(s)' },
+      { id: 'select_all_group', value: 'Select All Filtered Items' },
+      { id: 'deselect_all', value: 'Deselect All' },
+      { id: 'deselect_all_group', value: 'Deselect All Filtered Items' },
+      { id: 'inverse_selection', value: 'Inverse Selection' },
+      { id: 'selected_location', value: 'Selected Location' },
+      { id: 'preset_colors', value: 'Preset Colors' },
+      { id: 'copy_to_clipboard', value: 'Copy to Clipboard' },
+      { id: 'color', value: 'Color' },
+      { id: 'colors', value: 'Colors' },
+      { id: 'upload', value: 'Upload' },
+      { id: 'import', value: 'Import' },
+      { id: 'continue', value: 'Continue' },
+      { id: 'finish', value: 'Finish' },
+      { id: 'enable', value: 'Enable' },
+      { id: 'disable', value: 'Disable' },
+      { id: 'all', value: 'All' },
+      { id: 'new', value: 'New' },
+      { id: 'add', value: 'Add' },
+      { id: 'update', value: 'Update' },
+      { id: 'details', value: 'Details' },
+      { id: 'translation', value: 'Translation' },
+      { id: 'download', value: 'Download' },
+      { id: 'list', value: 'List' },
+      { id: 'options', value: 'Options' },
+      { id: 'descriptions', value: 'Description' },
+      { id: 'type', value: 'Type' },
+      { id: 'media', value: 'Media' },
+      { id: 'medias', value: 'Medias' },
+      { id: 'summary', value: 'Summary' },
+      { id: 'go', value: 'Go' },
+      { id: 'input', value: 'Input' },
+      { id: 'preview', value: 'Preview' },
+      { id: 'close', value: 'Close' },
+      { id: 'undo', value: 'Undo' },
+      { id: 'redo', value: 'Redo' },
+      { id: 'refresh', value: 'Refresh' },
+      { id: 'submit', value: 'Submit' },
+      { id: 'first', value: 'First' },
+      { id: 'last', value: 'Last' },
+      { id: 'previous', value: 'Previous' },
+      { id: 'next', value: 'Next' },
+      { id: 'back', value: 'Back' },
+      { id: 'x_markdown_preview', value: 'Preview' },
+      { id: 'x_markdown_image', value: 'Image' },
+      { id: 'x_markdown_link', value: 'Link' },
+      { id: 'x_markdown_ol', value: 'Ordered List' },
+      { id: 'x_markdown_ul', value: 'Unordered List' },
+      { id: 'x_markdown_quote', value: 'Quote' },
+      { id: 'x_markdown_code', value: 'Code' },
+      { id: 'x_markdown_heading', value: 'Heading' },
+      { id: 'x_markdown_italic', value: 'Italic' },
+      { id: 'x_markdown_bold', value: 'Bold' },
+      { id: 'x_markdown_guide', value: 'Markdown Guide' },
+      { id: 'theme', value: 'Theme' },
+      { id: 'theme_mode', value: 'Theme Mode' },
+      { id: 'theme_dark', value: 'Dark' },
+      { id: 'theme_light', value: 'Light' },
+      { id: 'theme_name', value: 'Theme Name' },
+      { id: 'theme_name_description', value: 'Enter Theme name' },
+      { id: 'theme_clone_title', value: 'Theme Cloning' },
+      { id: 'input_color_title', value: 'Color Value' },
+      { id: 'input_color_description', value: 'input color value' },
+      { id: 'ide_mode', value: 'Code Style' },
+      { id: 'ide_format', value: 'Code Formatting' },
+      // ... (سایر آیتم‌های موجود در لیست اصلی حفظ شده‌اند) ...
+
+      // --- موارد جدید اضافه شده ---
+      { id: 'print', value: 'Print' },
+      { id: 'export_png', value: 'Export PNG' },
+      { id: 'export_svg', value: 'Export SVG' },
+      { id: 'export_csv', value: 'Export CSV' },
+      { id: 'zoom_in', value: 'Zoom In' },
+      { id: 'zoom_out', value: 'Zoom Out' },
+      { id: 'zoom_selection', value: 'Zoom Selection' },
+      { id: 'x_axis', value: 'X Axis' },
+      { id: 'y_axis', value: 'Y Axis' },
+      { id: 'xy_axis', value: 'XY Axis' },
+      { id: 'pan', value: 'Pan' },
+      { id: 'full_screen', value: 'Full Screen' }
+    ],
+  },
+];
+ + +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\XResourceIDs.ts + +// +//#region Resource IDS ... +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'ساحر علم' }, + { id: 'company', value: 'فن آوران ساحر علم' }, + { id: 'id', value: 'شناسه' }, + { id: 'file_name', value: 'نام فایل' }, + { id: 'error', value: 'خطا' }, + { id: 'required', value: 'الزامی است.' }, + { id: 'loading', value: 'بارگزاری' }, + { id: 'username', value: 'نام کاربری' }, + { id: 'password', value: 'کلمه عبور' }, + { id: 'first_name', value: 'نام' }, + { id: 'last_name', value: 'نام خانوادگی' }, + { id: 'verified', value: 'تایید شده' }, + { id: 'unverified', value: 'تایید نشده' }, + { id: 'thumbnail', value: 'پیش نمایش' }, + { id: 'language', value: 'زبان' }, + { id: 'take_screenshot', value: 'تصویر برداری ازمحیط' }, + { id: 'enable_capture_mode', value: 'فعالسازی حالت تصویر برداری' }, + { id: 'disable_capture_mode', value: 'غیرفعالسازی حالت تصویر برداری' }, + { id: 'be', value: 'باشد' }, + { id: 'not_to_be', value: 'نباشد' }, + { id: 'enabled', value: 'فعال' }, + { id: 'disabled', value: 'غیر فعال' }, + { id: 'banned', value: 'مسدود' }, + { id: 'un_banned', value: 'غیر مسدود' }, + { id: 'audio', value: 'صوت' }, + { id: 'video', value: 'فیلم' }, + { id: 'cover_image', value: 'تصویر' }, + { id: 'image', value: 'تصویر' }, + { id: 'unknown', value: 'ناشناس' }, + { id: 'location', value: 'موقعیت جغرافیای' }, + { id: 'are_you_sure', value: 'اطمینان دارید ؟' }, + { id: 'success_msg', value: 'عملیات با موفقیت انجام شد' }, + { id: 'locked_msg', value: 'برای ترک این صفحه باید فعالیت جاری را لغو کرده و یا به اتمام برسانید' }, + { id: 'empty_content', value: 'خالی است' }, + { id: 'no_item', value: 'محتوایی ثبت نشده است' }, + { id: 'drag_drop_here', value: 'محل رها کردن فایل' }, + { id: 'map_dialog_title', value: 'نمایش موقعیت مکانی' }, + { id: 'map_dialog_select_title', value: 'انتخاب موقعیت جغرافیایی' }, + { id: 'color_picker_dialog_title', value: 'انتخاب رنگ' }, + { id: 'dismiss', value: 'رد کردن' }, + { id: 'accept', value: 'می پذیرم' }, + { id: 'ok', value: 'بسیار خب' }, + { id: 'save', value: 'ذخیره' }, + { id: 'cancel', value: 'لغو' }, + { id: 'retry', value: 'سعی مجدد' }, + { id: 'edit', value: 'ویرایش' }, + { id: 'reset', value: 'باز نشاندن' }, + { id: 'change', value: 'تغییر' }, + { id: 'start', value: 'آغاز' }, + { id: 'yes', value: 'بله' }, + { id: 'no', value: 'خیر' }, + { id: 'verify', value: 'تایید کردن' }, + { id: 'confirm', value: 'تاییدیه' }, + { id: 'crop', value: 'برش' }, + { id: 'clear', value: 'پاک کردن' }, + { id: 'set', value: 'تنظیم' }, + { id: 'select', value: 'انتخاب' }, + { id: 'send', value: 'ارسال' }, + { id: 'show', value: 'نمایش دادن' }, + { id: 'hide', value: 'پنهان کردن' }, + { id: 'search', value: 'جستجو' }, + { id: 'delete', value: 'حذف' }, + { id: 'clone', value: 'نمونه گیری' }, + { id: 'select_all', value: 'انتخاب همه' }, + { id: 'select_file', value: 'انتخاب فایل(ها)' }, + { id: 'select_all_group', value: 'انتخاب همه موارد فیلتر شده' }, + { id: 'deselect_all', value: 'لغو همه انتخاب ها' }, + { id: 'deselect_all_group', value: 'لغو انتخاب همه موارد فیلتر شده' }, + { id: 'inverse_selection', value: 'انتخاب معکوس' }, + { id: 'selected_location', value: 'انتخاب محل' }, + { id: 'preset_colors', value: 'رنگ های پیش فرض' }, + { id: 'copy_to_clipboard', value: 'ثبت در حافظه موقت' }, + { id: 'color', value: 'رنگ' }, + { id: 'colors', value: 'رنگها' }, + { id: 'upload', value: 'بارگزاری' }, + { id: 'import', value: 'وارد کردن' }, + { id: 'continue', value: 'ادامه' }, + { id: 'finish', value: 'پایان' }, + { id: 'enable', value: 'فعال' }, + { id: 'disable', value: 'غیر فعال' }, + { id: 'all', value: 'همه' }, + { id: 'new', value: 'جدید' }, + { id: 'add', value: 'افزودن' }, + { id: 'update', value: 'بروز رسانی' }, + { id: 'details', value: 'جزئیات' }, + { id: 'translation', value: 'ترجمه' }, + { id: 'download', value: 'دریافت' }, + { id: 'list', value: 'فهرست' }, + { id: 'options', value: 'انتخاب ها' }, + { id: 'descriptions', value: 'توضیحات' }, + { id: 'type', value: 'نوع' }, + { id: 'media', value: 'رسانه' }, + { id: 'medias', value: 'رسانه ها' }, + { id: 'summary', value: 'خلاصه' }, + { id: 'go', value: 'رفتن' }, + { id: 'input', value: 'ورود' }, + { id: 'preview', value: 'پیش نمایش' }, + { id: 'close', value: 'بستن' }, + { id: 'undo', value: 'لغو کردن' }, + { id: 'redo', value: 'انجام دوباره' }, + { id: 'refresh', value: 'بازیابی' }, + { id: 'submit', value: 'ثبت' }, + { id: 'first', value: 'نخستین' }, + { id: 'last', value: 'آخرین' }, + { id: 'previous', value: 'قبلی' }, + { id: 'next', value: 'بعدی' }, + { id: 'back', value: 'بازگشت' }, + { id: 'x_markdown_preview', value: 'پیش نمایش' }, + { id: 'x_markdown_image', value: 'تصویر' }, + { id: 'x_markdown_link', value: 'پیوند' }, + { id: 'x_markdown_ol', value: 'فهرست ترتیبی' }, + { id: 'x_markdown_ul', value: 'فهرست بدون ترتیب' }, + { id: 'x_markdown_quote', value: 'نقل قول' }, + { id: 'x_markdown_code', value: 'کد منبع' }, + { id: 'x_markdown_heading', value: 'عنوان' }, + { id: 'x_markdown_italic', value: 'ایتالیک' }, + { id: 'x_markdown_bold', value: 'پر رنگ' }, + { id: 'x_markdown_guide', value: 'راهنمای نگارش' }, + { id: 'theme', value: 'پوسته' }, + { id: 'theme_mode', value: 'حالت نمایشی' }, + { id: 'theme_dark', value: 'تیره' }, + { id: 'theme_light', value: 'روشن' }, + { id: 'theme_name', value: 'نام پوسته' }, + { id: 'theme_name_description', value: 'نام پوسته را وارد کنید' }, + { id: 'theme_clone_title', value: 'نمونه گیری از پوسته' }, + { id: 'input_color_title', value: 'تعیین رنگ' }, + { id: 'input_color_description', value: 'مقدار رنگ را وارد کنید' }, + { id: 'ide_mode', value: 'نوع کد' }, + { id: 'ide_format', value: 'حالت دهی کد' }, + { id: 'print', value: 'چاپ' }, + { id: 'export_png', value: 'خروجی PNG' }, + { id: 'export_svg', value: 'خروجی SVG' }, + { id: 'export_csv', value: 'خروجی CSV' }, + { id: 'zoom_in', value: 'بزرگنمایی' }, + { id: 'zoom_out', value: 'کوچک نمایی' }, + { id: 'zoom_selection', value: 'بزرگنمایی ناحیه' }, + { id: 'x_axis', value: 'محور افقی' }, + { id: 'y_axis', value: 'محور عمودی' }, + { id: 'xy_axis', value: 'محورهای عمودی و افقی' }, + { id: 'pan', value: 'حرکت آزاد' }, + { id: 'full_screen', value: 'حالت تمام صفحه' } + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'SaherElm' }, + { id: 'company', value: 'SaherElm IT Center' }, + { id: 'id', value: 'ID' }, + { id: 'file_name', value: 'File Name' }, + { id: 'error', value: 'Error' }, + { id: 'required', value: 'required' }, + { id: 'loading', value: 'loading' }, + { id: 'username', value: 'Username' }, + { id: 'password', value: 'Password' }, + { id: 'first_name', value: 'Firstname' }, + { id: 'last_name', value: 'Lastname' }, + { id: 'verified', value: 'Verified' }, + { id: 'unverified', value: 'Unverified' }, + { id: 'thumbnail', value: 'Thumbnail' }, + { id: 'language', value: 'Language' }, + { id: 'take_screenshot', value: 'Take Screenshot' }, + { id: 'enable_capture_mode', value: 'Enable Capture Mode' }, + { id: 'disable_capture_mode', value: 'Disable Capture Mode' }, + { id: 'be', value: 'Be' }, + { id: 'not_to_be', value: 'Not to be' }, + { id: 'enabled', value: 'Enabled' }, + { id: 'disabled', value: 'Disabled' }, + { id: 'banned', value: 'Banned' }, + { id: 'un_banned', value: 'UnBanned' }, + { id: 'audio', value: 'Audio' }, + { id: 'video', value: 'Video' }, + { id: 'cover_image', value: 'Cover Image' }, + { id: 'image', value: 'Image' }, + { id: 'avatar', value: 'Avatar' }, + { id: 'unknown', value: 'Unknown' }, + { id: 'location', value: 'Location' }, + { id: 'are_you_sure', value: 'Are You Sure ?' }, + { id: 'success_msg', value: 'Operation done Successfully ...' }, + { id: 'locked_msg', value: 'You have to finish/cancel current proccess for leaving' }, + { id: 'empty_content', value: 'Empty' }, + { id: 'no_item', value: 'there is no Content' }, + { id: 'drag_drop_here', value: 'Drop File Here' }, + { id: 'map_dialog_title', value: 'Show Location' }, + { id: 'map_dialog_select_title', value: 'Select Location' }, + { id: 'color_picker_dialog_title', value: 'Select Color' }, + { id: 'dismiss', value: 'dismiss' }, + { id: 'accept', value: 'Accept' }, + { id: 'ok', value: 'Ok' }, + { id: 'save', value: 'Save' }, + { id: 'cancel', value: 'Cancel' }, + { id: 'retry', value: 'Retry' }, + { id: 'edit', value: 'Edit' }, + { id: 'reset', value: 'Reset' }, + { id: 'change', value: 'Change' }, + { id: 'start', value: 'Start' }, + { id: 'yes', value: 'Yes' }, + { id: 'no', value: 'No' }, + { id: 'verify', value: 'Verify' }, + { id: 'confirm', value: 'Confirm' }, + { id: 'crop', value: 'Crop' }, + { id: 'clear', value: 'Clear' }, + { id: 'set', value: 'Set' }, + { id: 'select', value: 'Select' }, + { id: 'send', value: 'Send' }, + { id: 'show', value: 'Show' }, + { id: 'hide', value: 'Hide' }, + { id: 'search', value: 'Search' }, + { id: 'delete', value: 'Delete' }, + { id: 'clone', value: 'Clone' }, + { id: 'select_all', value: 'Select All' }, + { id: 'select_file', value: 'Select File(s)' }, + { id: 'select_all_group', value: 'Select All Filtered Items' }, + { id: 'deselect_all', value: 'Deselect All' }, + { id: 'deselect_all_group', value: 'Deselect All Filtered Items' }, + { id: 'inverse_selection', value: 'Inverse Selection' }, + { id: 'selected_location', value: 'Selected Location' }, + { id: 'preset_colors', value: 'Preset Colors' }, + { id: 'copy_to_clipboard', value: 'Copy to Clipboard' }, + { id: 'color', value: 'Color' }, + { id: 'colors', value: 'Colors' }, + { id: 'upload', value: 'Upload' }, + { id: 'import', value: 'Import' }, + { id: 'continue', value: 'Continue' }, + { id: 'finish', value: 'Finish' }, + { id: 'enable', value: 'Enable' }, + { id: 'disable', value: 'Disable' }, + { id: 'all', value: 'All' }, + { id: 'new', value: 'New' }, + { id: 'add', value: 'Add' }, + { id: 'update', value: 'Update' }, + { id: 'details', value: 'Details' }, + { id: 'translation', value: 'Translation' }, + { id: 'download', value: 'Download' }, + { id: 'list', value: 'List' }, + { id: 'options', value: 'Options' }, + { id: 'descriptions', value: 'Description' }, + { id: 'type', value: 'Type' }, + { id: 'media', value: 'Media' }, + { id: 'medias', value: 'Medias' }, + { id: 'summary', value: 'Summary' }, + { id: 'go', value: 'Go' }, + { id: 'input', value: 'Input' }, + { id: 'preview', value: 'Preview' }, + { id: 'close', value: 'Close' }, + { id: 'undo', value: 'Undo' }, + { id: 'redo', value: 'Redo' }, + { id: 'refresh', value: 'Refresh' }, + { id: 'submit', value: 'Submit' }, + { id: 'first', value: 'First' }, + { id: 'last', value: 'Last' }, + { id: 'previous', value: 'Previous' }, + { id: 'next', value: 'Next' }, + { id: 'back', value: 'Back' }, + { id: 'x_markdown_preview', value: 'Preview' }, + { id: 'x_markdown_image', value: 'Image' }, + { id: 'x_markdown_link', value: 'Link' }, + { id: 'x_markdown_ol', value: 'Ordered List' }, + { id: 'x_markdown_ul', value: 'Unordered List' }, + { id: 'x_markdown_quote', value: 'Quote' }, + { id: 'x_markdown_code', value: 'Code' }, + { id: 'x_markdown_heading', value: 'Heading' }, + { id: 'x_markdown_italic', value: 'Italic' }, + { id: 'x_markdown_bold', value: 'Bold' }, + { id: 'x_markdown_guide', value: 'Markdown Guide' }, + { id: 'theme', value: 'Theme' }, + { id: 'theme_mode', value: 'Theme Mode' }, + { id: 'theme_dark', value: 'Dark' }, + { id: 'theme_light', value: 'Light' }, + { id: 'theme_name', value: 'Theme Name' }, + { id: 'theme_name_description', value: 'Enter Theme name' }, + { id: 'theme_clone_title', value: 'Theme Cloning' }, + { id: 'input_color_title', value: 'Color Value' }, + { id: 'input_color_description', value: 'input color value' }, + { id: 'ide_mode', value: 'Code Style' }, + { id: 'ide_format', value: 'Code Formatting' }, + { id: 'print', value: 'Print' }, + { id: 'export_png', value: 'Export PNG' }, + { id: 'export_svg', value: 'Export SVG' }, + { id: 'export_csv', value: 'Export CSV' }, + { id: 'zoom_in', value: 'Zoom In' }, + { id: 'zoom_out', value: 'Zoom Out' }, + { id: 'zoom_selection', value: 'Zoom Selection' }, + { id: 'x_axis', value: 'X Axis' }, + { id: 'y_axis', value: 'Y Axis' }, + { id: 'xy_axis', value: 'XY Axis' }, + { id: 'pan', value: 'Pan' }, + { id: 'full_screen', value: 'Full Screen' } + //#endregion + ], + }, +]; +//#endregion + +// +//#region Exception IDS ... +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'داده نا معتبر', + }, + { + id: 'ex_101', + value: 'تاریخ نامعتبر', + }, + { + id: 'ex_102', + value: 'درخواست اشتباه', + }, + { + id: 'ex_103', + value: 'ورودی نامعتبر', + }, + { + id: 'ex_104', + value: 'پیام نامعتبر', + }, + { + id: 'ex_105', + value: 'نشانه نامعتبر', + }, + { + id: 'ex_106', + value: 'کد اععتبارسنجی نامعتبر', + }, + { + id: 'ex_107', + value: 'پست الکترونیک نامعتبر', + }, + { + id: 'ex_108', + value: 'شماره تلفن همراه نامعتبر', + }, + { + id: 'ex_109', + value: 'کلمه عبور نامعتبر', + }, + { + id: 'ex_110', + value: 'آدرس اینترنتی نامعتبر', + }, + { + id: 'ex_111', + value: 'دستگاه نامعتبر', + }, + { + id: 'ex_112', + value: 'تصویر پروفایل نامعتبر', + }, + { + id: 'ex_113', + value: 'فایل نامعتبر', + }, + { + id: 'ex_114', + value: 'نام کاربری نامعتبر', + }, + { + id: 'ex_200', + value: 'یافت نشد', + }, + { + id: 'ex_201', + value: 'عدم تایید جواز', + }, + { + id: 'ex_202', + value: 'سطح دسترسی نامعتبر', + }, + { + id: 'ex_203', + value: 'غیر قابل نمایش', + }, + { + id: 'ex_300', + value: 'حساب کاربری قفل شده است', + }, + { + id: 'ex_301', + value: 'خطا در ورود', + }, + { + id: 'ex_302', + value: 'کاربر قبلا ثبت نام کرده است', + }, + { + id: 'ex_303', + value: 'کاربر غیرفعال است', + }, + { + id: 'ex_304', + value: 'دستگاه شما قفل شده است تا : (0)', + }, + { + id: 'ex_305', + value: 'امکان درخواست کد اعتبارسنجی وجود ندارد تا : (0)', + }, + { + id: 'ex_306', + value: 'کلمه عبورها یکسان هستند', + }, + { + id: 'ex_307', + value: 'شماره های تلفن یکسان هستند', + }, + { + id: 'ex_308', + value: 'آدرس های پست الکترونیک یکسان هستند', + }, + { + id: 'ex_309', + value: 'شماره تلفن قبلا ثبت شده است', + }, + { + id: 'ex_310', + value: 'پست الکترونیک قبلا ثبت شده است', + }, + { + id: 'ex_311', + value: 'تلفن همراه تایید نشده است', + }, + { + id: 'ex_312', + value: 'پست الکترونیک تایید نشده است', + }, + { + id: 'ex_313', + value: 'مطلب ممنوعه', + }, + { + id: 'ex_314', + value: 'کاربر ممنوعه', + }, + { + id: 'ex_400', + value: 'خطای نا شناخته', + }, + { + id: 'ex_401', + value: 'مورد تکراری', + }, + { + id: 'ex_402', + value: 'شکست عملیات', + }, + { + id: 'ex_403', + value: 'تاریخ مصرف منقضی شده است', + }, + { + id: 'ex_404', + value: 'غیر قابل اسفاده', + }, + { + id: 'ex_405', + value: 'تعداد برچسب ها بیش از جد مجاز است', + }, + { + id: 'ex_406', + value: 'اتمام مهلت زمانی', + }, + { + id: 'ex_500', + value: 'پرونده خالی است', + }, + { + id: 'ex_501', + value: 'اندازه بیش از حد مجاز', + }, + { + id: 'ex_502', + value: 'گونه نامعتبر فایل', + }, + { + id: 'ex_503', + value: 'تعداد رسانه ها بیش از حد مجاز است', + }, + { + id: 'ex_600', + value: 'پیکربندی اشتباه', + }, + { + id: 'ex_601', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_602', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_900', + value: 'تعداد فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_901', + value: 'مجموع اندازه فایل ها کمتر از حد مجاز است', + }, + { + id: 'ex_902', + value: 'مجموع اندازه فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_903', + value: 'شرایط و ضوابط باید پذیرفته شوند', + }, + { + id: 'ex_904', + value: 'عدم پشتیبانی از سیستم موقعیت یاب', + }, + { + id: 'ex_905', + value: 'مجوز دسترسی به موقعیت خود را صادر نکرده اید', + }, + { + id: 'ex_906', + value: 'دسترسی به موقعیت جغرافیایی امکان پذیر نیست', + }, + { + id: 'ex_907', + value: 'عدم پشتیبانی از سیستم ذخیره سازی', + }, + { + id: 'ex_908', + value: 'برای دسترسی به محتوا باید از سامانه خارج شوید', + }, + { + id: 'ex_909', + value: 'زبان انتخاب شده نامعتبر است', + }, + { + id: 'ex_910', + value: 'داده نامعتبر برای انتخاب کاربر', + }, + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'Invalid Data ...', + }, + { + id: 'ex_101', + value: 'Invalid Date ...', + }, + { + id: 'ex_102', + value: 'Bad Request ...', + }, + { + id: 'ex_103', + value: 'Invalid Args ...', + }, + { + id: 'ex_104', + value: 'Invalid Message ...', + }, + { + id: 'ex_105', + value: 'Invalid Token ...', + }, + { + id: 'ex_106', + value: 'Invalid Verification Code ...', + }, + { + id: 'ex_107', + value: 'Invalid Email Address ...', + }, + { + id: 'ex_108', + value: 'Invalid Mobile Number ...', + }, + { + id: 'ex_109', + value: 'Invalid Password ...', + }, + { + id: 'ex_110', + value: 'Invalid URL ...', + }, + { + id: 'ex_111', + value: 'Invalid Device ...', + }, + { + id: 'ex_112', + value: 'Invalid Profile Image ...', + }, + { + id: 'ex_113', + value: 'Invalid File ...', + }, + { + id: 'ex_114', + value: 'Invalid Username ...', + }, + { + id: 'ex_200', + value: 'Not Found ...', + }, + { + id: 'ex_201', + value: 'Not Allowed ...', + }, + { + id: 'ex_202', + value: 'Not Authorized ...', + }, + { + id: 'ex_203', + value: 'Not Visible ...', + }, + { + id: 'ex_300', + value: 'Account Locked out ...', + }, + { + id: 'ex_301', + value: 'Login Failed ...', + }, + { + id: 'ex_302', + value: 'User Registered Before ...', + }, + { + id: 'ex_303', + value: 'User Disabled ...', + }, + { + id: 'ex_304', + value: 'Device Banned Until:(0)', + }, + { + id: 'ex_305', + value: `You can not Request Verification code Until:(0)`, + }, + { + id: 'ex_306', + value: 'Passwords Same ...', + }, + { + id: 'ex_307', + value: 'Mobiles Same ...', + }, + { + id: 'ex_308', + value: 'Emails Same ...', + }, + { + id: 'ex_309', + value: 'Mobile In Used ...', + }, + { + id: 'ex_310', + value: 'Email In Used ...', + }, + { + id: 'ex_311', + value: 'Mobile Not Confirmed ...', + }, + { + id: 'ex_312', + value: 'Email Not Confirmed ...', + }, + { + id: 'ex_313', + value: 'Post Banned ...', + }, + { + id: 'ex_314', + value: 'User Banned ...', + }, + { + id: 'ex_400', + value: 'Unknown Error ...', + }, + { + id: 'ex_401', + value: 'Duplicate ...', + }, + { + id: 'ex_402', + value: 'Action Failed ...', + }, + { + id: 'ex_403', + value: 'Expired Date ...', + }, + { + id: 'ex_404', + value: 'Unavailable ...', + }, + { + id: 'ex_405', + value: 'Max Allowed Tag Exceeded ...', + }, + { + id: 'ex_406', + value: 'Timeout ...', + }, + { + id: 'ex_500', + value: 'Empty File ...', + }, + { + id: 'ex_501', + value: 'max File size exceeded ...', + }, + { + id: 'ex_502', + value: 'Unsupported File Type ...', + }, + { + id: 'ex_503', + value: 'Max Allowed Media Exceeded ...', + }, + { + id: 'ex_600', + value: 'Invalid Configuration ...', + }, + { + id: 'ex_601', + value: 'Storage Service Initiallization Failed ...', + }, + { + id: 'ex_602', + value: 'Message Service Initialization Failed ...', + }, + { + id: 'ex_900', + value: 'Max Allowed Files Exceeded ...', + }, + { + id: 'ex_901', + value: 'Min Files Size Exceeded ...', + }, + { + id: 'ex_902', + value: 'Max Files Size Exceeded ...', + }, + { + id: 'ex_903', + value: 'Must Accept Terms And Conditions ...', + }, + { + id: 'ex_904', + value: 'Browser does not support Location Services ...', + }, + { + id: 'ex_905', + value: 'You have rejected access to your Location ...', + }, + { + id: 'ex_906', + value: 'Unable to determine your Location ...', + }, + { + id: 'ex_907', + value: 'Browser does not support Storage Services ...', + }, + { + id: 'ex_908', + value: 'Must Logout to access content ...', + }, + { + id: 'ex_909', + value: 'Invalid Locale ...', + }, + { + id: 'ex_910', + value: 'Invalid User Selector ...', + }, + //#endregion + ], + }, +]; +//#endregion + +// +//#region Resource and Exception IDS ... +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'ساحر علم' }, + { id: 'company', value: 'فن آوران ساحر علم' }, + { id: 'id', value: 'شناسه' }, + { id: 'file_name', value: 'نام فایل' }, + { id: 'error', value: 'خطا' }, + { id: 'required', value: 'الزامی است.' }, + { id: 'loading', value: 'بارگزاری' }, + { id: 'username', value: 'نام کاربری' }, + { id: 'password', value: 'کلمه عبور' }, + { id: 'first_name', value: 'نام' }, + { id: 'last_name', value: 'نام خانوادگی' }, + { id: 'verified', value: 'تایید شده' }, + { id: 'unverified', value: 'تایید نشده' }, + { id: 'thumbnail', value: 'پیش نمایش' }, + { id: 'language', value: 'زبان' }, + { id: 'take_screenshot', value: 'تصویر برداری ازمحیط' }, + { id: 'enable_capture_mode', value: 'فعالسازی حالت تصویر برداری' }, + { id: 'disable_capture_mode', value: 'غیرفعالسازی حالت تصویر برداری' }, + { id: 'be', value: 'باشد' }, + { id: 'not_to_be', value: 'نباشد' }, + { id: 'enabled', value: 'فعال' }, + { id: 'disabled', value: 'غیر فعال' }, + { id: 'banned', value: 'مسدود' }, + { id: 'un_banned', value: 'غیر مسدود' }, + { id: 'audio', value: 'صوت' }, + { id: 'video', value: 'فیلم' }, + { id: 'cover_image', value: 'تصویر' }, + { id: 'image', value: 'تصویر' }, + { id: 'unknown', value: 'ناشناس' }, + { id: 'location', value: 'موقعیت جغرافیای' }, + { id: 'are_you_sure', value: 'اطمینان دارید ؟' }, + { id: 'success_msg', value: 'عملیات با موفقیت انجام شد' }, + { id: 'locked_msg', value: 'برای ترک این صفحه باید فعالیت جاری را لغو کرده و یا به اتمام برسانید' }, + { id: 'empty_content', value: 'خالی است' }, + { id: 'no_item', value: 'محتوایی ثبت نشده است' }, + { id: 'drag_drop_here', value: 'محل رها کردن فایل' }, + { id: 'map_dialog_title', value: 'نمایش موقعیت مکانی' }, + { id: 'map_dialog_select_title', value: 'انتخاب موقعیت جغرافیایی' }, + { id: 'color_picker_dialog_title', value: 'انتخاب رنگ' }, + { id: 'dismiss', value: 'رد کردن' }, + { id: 'accept', value: 'می پذیرم' }, + { id: 'ok', value: 'بسیار خب' }, + { id: 'save', value: 'ذخیره' }, + { id: 'cancel', value: 'لغو' }, + { id: 'retry', value: 'سعی مجدد' }, + { id: 'edit', value: 'ویرایش' }, + { id: 'reset', value: 'باز نشاندن' }, + { id: 'change', value: 'تغییر' }, + { id: 'start', value: 'آغاز' }, + { id: 'yes', value: 'بله' }, + { id: 'no', value: 'خیر' }, + { id: 'verify', value: 'تایید کردن' }, + { id: 'confirm', value: 'تاییدیه' }, + { id: 'crop', value: 'برش' }, + { id: 'clear', value: 'پاک کردن' }, + { id: 'set', value: 'تنظیم' }, + { id: 'select', value: 'انتخاب' }, + { id: 'send', value: 'ارسال' }, + { id: 'show', value: 'نمایش دادن' }, + { id: 'hide', value: 'پنهان کردن' }, + { id: 'search', value: 'جستجو' }, + { id: 'delete', value: 'حذف' }, + { id: 'clone', value: 'نمونه گیری' }, + { id: 'select_all', value: 'انتخاب همه' }, + { id: 'select_file', value: 'انتخاب فایل(ها)' }, + { id: 'select_all_group', value: 'انتخاب همه موارد فیلتر شده' }, + { id: 'deselect_all', value: 'لغو همه انتخاب ها' }, + { id: 'deselect_all_group', value: 'لغو انتخاب همه موارد فیلتر شده' }, + { id: 'inverse_selection', value: 'انتخاب معکوس' }, + { id: 'selected_location', value: 'انتخاب محل' }, + { id: 'preset_colors', value: 'رنگ های پیش فرض' }, + { id: 'copy_to_clipboard', value: 'ثبت در حافظه موقت' }, + { id: 'color', value: 'رنگ' }, + { id: 'colors', value: 'رنگها' }, + { id: 'upload', value: 'بارگزاری' }, + { id: 'import', value: 'وارد کردن' }, + { id: 'continue', value: 'ادامه' }, + { id: 'finish', value: 'پایان' }, + { id: 'enable', value: 'فعال' }, + { id: 'disable', value: 'غیر فعال' }, + { id: 'all', value: 'همه' }, + { id: 'new', value: 'جدید' }, + { id: 'add', value: 'افزودن' }, + { id: 'update', value: 'بروز رسانی' }, + { id: 'details', value: 'جزئیات' }, + { id: 'translation', value: 'ترجمه' }, + { id: 'download', value: 'دریافت' }, + { id: 'list', value: 'فهرست' }, + { id: 'options', value: 'انتخاب ها' }, + { id: 'descriptions', value: 'توضیحات' }, + { id: 'type', value: 'نوع' }, + { id: 'media', value: 'رسانه' }, + { id: 'medias', value: 'رسانه ها' }, + { id: 'summary', value: 'خلاصه' }, + { id: 'go', value: 'رفتن' }, + { id: 'input', value: 'ورود' }, + { id: 'preview', value: 'پیش نمایش' }, + { id: 'close', value: 'بستن' }, + { id: 'undo', value: 'لغو کردن' }, + { id: 'redo', value: 'انجام دوباره' }, + { id: 'refresh', value: 'بازیابی' }, + { id: 'submit', value: 'ثبت' }, + { id: 'first', value: 'نخستین' }, + { id: 'last', value: 'آخرین' }, + { id: 'previous', value: 'قبلی' }, + { id: 'next', value: 'بعدی' }, + { id: 'back', value: 'بازگشت' }, + { id: 'x_markdown_preview', value: 'پیش نمایش' }, + { id: 'x_markdown_image', value: 'تصویر' }, + { id: 'x_markdown_link', value: 'پیوند' }, + { id: 'x_markdown_ol', value: 'فهرست ترتیبی' }, + { id: 'x_markdown_ul', value: 'فهرست بدون ترتیب' }, + { id: 'x_markdown_quote', value: 'نقل قول' }, + { id: 'x_markdown_code', value: 'کد منبع' }, + { id: 'x_markdown_heading', value: 'عنوان' }, + { id: 'x_markdown_italic', value: 'ایتالیک' }, + { id: 'x_markdown_bold', value: 'پر رنگ' }, + { id: 'x_markdown_guide', value: 'راهنمای نگارش' }, + { id: 'theme', value: 'پوسته' }, + { id: 'theme_mode', value: 'حالت نمایشی' }, + { id: 'theme_dark', value: 'تیره' }, + { id: 'theme_light', value: 'روشن' }, + { id: 'theme_name', value: 'نام پوسته' }, + { id: 'theme_name_description', value: 'نام پوسته را وارد کنید' }, + { id: 'theme_clone_title', value: 'نمونه گیری از پوسته' }, + { id: 'input_color_title', value: 'تعیین رنگ' }, + { id: 'input_color_description', value: 'مقدار رنگ را وارد کنید' }, + { id: 'ide_mode', value: 'نوع کد' }, + { id: 'ide_format', value: 'حالت دهی کد' }, + { id: 'print', value: 'چاپ' }, + { id: 'export_png', value: 'خروجی PNG' }, + { id: 'export_svg', value: 'خروجی SVG' }, + { id: 'export_csv', value: 'خروجی CSV' }, + { id: 'zoom_in', value: 'بزرگنمایی' }, + { id: 'zoom_out', value: 'کوچک نمایی' }, + { id: 'zoom_selection', value: 'بزرگنمایی ناحیه' }, + { id: 'x_axis', value: 'محور افقی' }, + { id: 'y_axis', value: 'محور عمودی' }, + { id: 'xy_axis', value: 'محورهای عمودی و افقی' }, + { id: 'pan', value: 'حرکت آزاد' }, + { id: 'full_screen', value: 'حالت تمام صفحه' } + //#endregion + + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'داده نا معتبر', + }, + { + id: 'ex_101', + value: 'تاریخ نامعتبر', + }, + { + id: 'ex_102', + value: 'درخواست اشتباه', + }, + { + id: 'ex_103', + value: 'ورودی نامعتبر', + }, + { + id: 'ex_104', + value: 'پیام نامعتبر', + }, + { + id: 'ex_105', + value: 'نشانه نامعتبر', + }, + { + id: 'ex_106', + value: 'کد اععتبارسنجی نامعتبر', + }, + { + id: 'ex_107', + value: 'پست الکترونیک نامعتبر', + }, + { + id: 'ex_108', + value: 'شماره تلفن همراه نامعتبر', + }, + { + id: 'ex_109', + value: 'کلمه عبور نامعتبر', + }, + { + id: 'ex_110', + value: 'آدرس اینترنتی نامعتبر', + }, + { + id: 'ex_111', + value: 'دستگاه نامعتبر', + }, + { + id: 'ex_112', + value: 'تصویر پروفایل نامعتبر', + }, + { + id: 'ex_113', + value: 'فایل نامعتبر', + }, + { + id: 'ex_114', + value: 'نام کاربری نامعتبر', + }, + { + id: 'ex_200', + value: 'یافت نشد', + }, + { + id: 'ex_201', + value: 'عدم تایید جواز', + }, + { + id: 'ex_202', + value: 'سطح دسترسی نامعتبر', + }, + { + id: 'ex_203', + value: 'غیر قابل نمایش', + }, + { + id: 'ex_300', + value: 'حساب کاربری قفل شده است', + }, + { + id: 'ex_301', + value: 'خطا در ورود', + }, + { + id: 'ex_302', + value: 'کاربر قبلا ثبت نام کرده است', + }, + { + id: 'ex_303', + value: 'کاربر غیرفعال است', + }, + { + id: 'ex_304', + value: 'دستگاه شما قفل شده است تا : (0)', + }, + { + id: 'ex_305', + value: 'امکان درخواست کد اعتبارسنجی وجود ندارد تا : (0)', + }, + { + id: 'ex_306', + value: 'کلمه عبورها یکسان هستند', + }, + { + id: 'ex_307', + value: 'شماره های تلفن یکسان هستند', + }, + { + id: 'ex_308', + value: 'آدرس های پست الکترونیک یکسان هستند', + }, + { + id: 'ex_309', + value: 'شماره تلفن قبلا ثبت شده است', + }, + { + id: 'ex_310', + value: 'پست الکترونیک قبلا ثبت شده است', + }, + { + id: 'ex_311', + value: 'تلفن همراه تایید نشده است', + }, + { + id: 'ex_312', + value: 'پست الکترونیک تایید نشده است', + }, + { + id: 'ex_313', + value: 'مطلب ممنوعه', + }, + { + id: 'ex_314', + value: 'کاربر ممنوعه', + }, + { + id: 'ex_400', + value: 'خطای نا شناخته', + }, + { + id: 'ex_401', + value: 'مورد تکراری', + }, + { + id: 'ex_402', + value: 'شکست عملیات', + }, + { + id: 'ex_403', + value: 'تاریخ مصرف منقضی شده است', + }, + { + id: 'ex_404', + value: 'غیر قابل اسفاده', + }, + { + id: 'ex_405', + value: 'تعداد برچسب ها بیش از جد مجاز است', + }, + { + id: 'ex_406', + value: 'اتمام مهلت زمانی', + }, + { + id: 'ex_500', + value: 'پرونده خالی است', + }, + { + id: 'ex_501', + value: 'اندازه بیش از حد مجاز', + }, + { + id: 'ex_502', + value: 'گونه نامعتبر فایل', + }, + { + id: 'ex_503', + value: 'تعداد رسانه ها بیش از حد مجاز است', + }, + { + id: 'ex_600', + value: 'پیکربندی اشتباه', + }, + { + id: 'ex_601', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_602', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_900', + value: 'تعداد فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_901', + value: 'مجموع اندازه فایل ها کمتر از حد مجاز است', + }, + { + id: 'ex_902', + value: 'مجموع اندازه فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_903', + value: 'شرایط و ضوابط باید پذیرفته شوند', + }, + { + id: 'ex_904', + value: 'عدم پشتیبانی از سیستم موقعیت یاب', + }, + { + id: 'ex_905', + value: 'مجوز دسترسی به موقعیت خود را صادر نکرده اید', + }, + { + id: 'ex_906', + value: 'دسترسی به موقعیت جغرافیایی امکان پذیر نیست', + }, + { + id: 'ex_907', + value: 'عدم پشتیبانی از سیستم ذخیره سازی', + }, + { + id: 'ex_908', + value: 'برای دسترسی به محتوا باید از سامانه خارج شوید', + }, + { + id: 'ex_909', + value: 'زبان انتخاب شده نامعتبر است', + }, + { + id: 'ex_910', + value: 'داده نامعتبر برای انتخاب کاربر', + }, + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'SaherElm' }, + { id: 'company', value: 'SaherElm IT Center' }, + { id: 'id', value: 'ID' }, + { id: 'file_name', value: 'File Name' }, + { id: 'error', value: 'Error' }, + { id: 'required', value: 'required' }, + { id: 'loading', value: 'loading' }, + { id: 'username', value: 'Username' }, + { id: 'password', value: 'Password' }, + { id: 'first_name', value: 'Firstname' }, + { id: 'last_name', value: 'Lastname' }, + { id: 'verified', value: 'Verified' }, + { id: 'unverified', value: 'Unverified' }, + { id: 'thumbnail', value: 'Thumbnail' }, + { id: 'language', value: 'Language' }, + { id: 'take_screenshot', value: 'Take Screenshot' }, + { id: 'enable_capture_mode', value: 'Enable Capture Mode' }, + { id: 'disable_capture_mode', value: 'Disable Capture Mode' }, + { id: 'be', value: 'Be' }, + { id: 'not_to_be', value: 'Not to be' }, + { id: 'enabled', value: 'Enabled' }, + { id: 'disabled', value: 'Disabled' }, + { id: 'banned', value: 'Banned' }, + { id: 'un_banned', value: 'UnBanned' }, + { id: 'audio', value: 'Audio' }, + { id: 'video', value: 'Video' }, + { id: 'cover_image', value: 'Cover Image' }, + { id: 'image', value: 'Image' }, + { id: 'avatar', value: 'Avatar' }, + { id: 'unknown', value: 'Unknown' }, + { id: 'location', value: 'Location' }, + { id: 'are_you_sure', value: 'Are You Sure ?' }, + { id: 'success_msg', value: 'Operation done Successfully ...' }, + { id: 'locked_msg', value: 'You have to finish/cancel current proccess for leaving' }, + { id: 'empty_content', value: 'Empty' }, + { id: 'no_item', value: 'there is no Content' }, + { id: 'drag_drop_here', value: 'Drop File Here' }, + { id: 'map_dialog_title', value: 'Show Location' }, + { id: 'map_dialog_select_title', value: 'Select Location' }, + { id: 'color_picker_dialog_title', value: 'Select Color' }, + { id: 'dismiss', value: 'dismiss' }, + { id: 'accept', value: 'Accept' }, + { id: 'ok', value: 'Ok' }, + { id: 'save', value: 'Save' }, + { id: 'cancel', value: 'Cancel' }, + { id: 'retry', value: 'Retry' }, + { id: 'edit', value: 'Edit' }, + { id: 'reset', value: 'Reset' }, + { id: 'change', value: 'Change' }, + { id: 'start', value: 'Start' }, + { id: 'yes', value: 'Yes' }, + { id: 'no', value: 'No' }, + { id: 'verify', value: 'Verify' }, + { id: 'confirm', value: 'Confirm' }, + { id: 'crop', value: 'Crop' }, + { id: 'clear', value: 'Clear' }, + { id: 'set', value: 'Set' }, + { id: 'select', value: 'Select' }, + { id: 'send', value: 'Send' }, + { id: 'show', value: 'Show' }, + { id: 'hide', value: 'Hide' }, + { id: 'search', value: 'Search' }, + { id: 'delete', value: 'Delete' }, + { id: 'clone', value: 'Clone' }, + { id: 'select_all', value: 'Select All' }, + { id: 'select_file', value: 'Select File(s)' }, + { id: 'select_all_group', value: 'Select All Filtered Items' }, + { id: 'deselect_all', value: 'Deselect All' }, + { id: 'deselect_all_group', value: 'Deselect All Filtered Items' }, + { id: 'inverse_selection', value: 'Inverse Selection' }, + { id: 'selected_location', value: 'Selected Location' }, + { id: 'preset_colors', value: 'Preset Colors' }, + { id: 'copy_to_clipboard', value: 'Copy to Clipboard' }, + { id: 'color', value: 'Color' }, + { id: 'colors', value: 'Colors' }, + { id: 'upload', value: 'Upload' }, + { id: 'import', value: 'Import' }, + { id: 'continue', value: 'Continue' }, + { id: 'finish', value: 'Finish' }, + { id: 'enable', value: 'Enable' }, + { id: 'disable', value: 'Disable' }, + { id: 'all', value: 'All' }, + { id: 'new', value: 'New' }, + { id: 'add', value: 'Add' }, + { id: 'update', value: 'Update' }, + { id: 'details', value: 'Details' }, + { id: 'translation', value: 'Translation' }, + { id: 'download', value: 'Download' }, + { id: 'list', value: 'List' }, + { id: 'options', value: 'Options' }, + { id: 'descriptions', value: 'Description' }, + { id: 'type', value: 'Type' }, + { id: 'media', value: 'Media' }, + { id: 'medias', value: 'Medias' }, + { id: 'summary', value: 'Summary' }, + { id: 'go', value: 'Go' }, + { id: 'input', value: 'Input' }, + { id: 'preview', value: 'Preview' }, + { id: 'close', value: 'Close' }, + { id: 'undo', value: 'Undo' }, + { id: 'redo', value: 'Redo' }, + { id: 'refresh', value: 'Refresh' }, + { id: 'submit', value: 'Submit' }, + { id: 'first', value: 'First' }, + { id: 'last', value: 'Last' }, + { id: 'previous', value: 'Previous' }, + { id: 'next', value: 'Next' }, + { id: 'back', value: 'Back' }, + { id: 'x_markdown_preview', value: 'Preview' }, + { id: 'x_markdown_image', value: 'Image' }, + { id: 'x_markdown_link', value: 'Link' }, + { id: 'x_markdown_ol', value: 'Ordered List' }, + { id: 'x_markdown_ul', value: 'Unordered List' }, + { id: 'x_markdown_quote', value: 'Quote' }, + { id: 'x_markdown_code', value: 'Code' }, + { id: 'x_markdown_heading', value: 'Heading' }, + { id: 'x_markdown_italic', value: 'Italic' }, + { id: 'x_markdown_bold', value: 'Bold' }, + { id: 'x_markdown_guide', value: 'Markdown Guide' }, + { id: 'theme', value: 'Theme' }, + { id: 'theme_mode', value: 'Theme Mode' }, + { id: 'theme_dark', value: 'Dark' }, + { id: 'theme_light', value: 'Light' }, + { id: 'theme_name', value: 'Theme Name' }, + { id: 'theme_name_description', value: 'Enter Theme name' }, + { id: 'theme_clone_title', value: 'Theme Cloning' }, + { id: 'input_color_title', value: 'Color Value' }, + { id: 'input_color_description', value: 'input color value' }, + { id: 'ide_mode', value: 'Code Style' }, + { id: 'ide_format', value: 'Code Formatting' }, + { id: 'print', value: 'Print' }, + { id: 'export_png', value: 'Export PNG' }, + { id: 'export_svg', value: 'Export SVG' }, + { id: 'export_csv', value: 'Export CSV' }, + { id: 'zoom_in', value: 'Zoom In' }, + { id: 'zoom_out', value: 'Zoom Out' }, + { id: 'zoom_selection', value: 'Zoom Selection' }, + { id: 'x_axis', value: 'X Axis' }, + { id: 'y_axis', value: 'Y Axis' }, + { id: 'xy_axis', value: 'XY Axis' }, + { id: 'pan', value: 'Pan' }, + { id: 'full_screen', value: 'Full Screen' } + //#endregion + + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'Invalid Data ...', + }, + { + id: 'ex_101', + value: 'Invalid Date ...', + }, + { + id: 'ex_102', + value: 'Bad Request ...', + }, + { + id: 'ex_103', + value: 'Invalid Args ...', + }, + { + id: 'ex_104', + value: 'Invalid Message ...', + }, + { + id: 'ex_105', + value: 'Invalid Token ...', + }, + { + id: 'ex_106', + value: 'Invalid Verification Code ...', + }, + { + id: 'ex_107', + value: 'Invalid Email Address ...', + }, + { + id: 'ex_108', + value: 'Invalid Mobile Number ...', + }, + { + id: 'ex_109', + value: 'Invalid Password ...', + }, + { + id: 'ex_110', + value: 'Invalid URL ...', + }, + { + id: 'ex_111', + value: 'Invalid Device ...', + }, + { + id: 'ex_112', + value: 'Invalid Profile Image ...', + }, + { + id: 'ex_113', + value: 'Invalid File ...', + }, + { + id: 'ex_114', + value: 'Invalid Username ...', + }, + { + id: 'ex_200', + value: 'Not Found ...', + }, + { + id: 'ex_201', + value: 'Not Allowed ...', + }, + { + id: 'ex_202', + value: 'Not Authorized ...', + }, + { + id: 'ex_203', + value: 'Not Visible ...', + }, + { + id: 'ex_300', + value: 'Account Locked out ...', + }, + { + id: 'ex_301', + value: 'Login Failed ...', + }, + { + id: 'ex_302', + value: 'User Registered Before ...', + }, + { + id: 'ex_303', + value: 'User Disabled ...', + }, + { + id: 'ex_304', + value: 'Device Banned Until:(0)', + }, + { + id: 'ex_305', + value: `You can not Request Verification code Until:(0)`, + }, + { + id: 'ex_306', + value: 'Passwords Same ...', + }, + { + id: 'ex_307', + value: 'Mobiles Same ...', + }, + { + id: 'ex_308', + value: 'Emails Same ...', + }, + { + id: 'ex_309', + value: 'Mobile In Used ...', + }, + { + id: 'ex_310', + value: 'Email In Used ...', + }, + { + id: 'ex_311', + value: 'Mobile Not Confirmed ...', + }, + { + id: 'ex_312', + value: 'Email Not Confirmed ...', + }, + { + id: 'ex_313', + value: 'Post Banned ...', + }, + { + id: 'ex_314', + value: 'User Banned ...', + }, + { + id: 'ex_400', + value: 'Unknown Error ...', + }, + { + id: 'ex_401', + value: 'Duplicate ...', + }, + { + id: 'ex_402', + value: 'Action Failed ...', + }, + { + id: 'ex_403', + value: 'Expired Date ...', + }, + { + id: 'ex_404', + value: 'Unavailable ...', + }, + { + id: 'ex_405', + value: 'Max Allowed Tag Exceeded ...', + }, + { + id: 'ex_406', + value: 'Timeout ...', + }, + { + id: 'ex_500', + value: 'Empty File ...', + }, + { + id: 'ex_501', + value: 'max File size exceeded ...', + }, + { + id: 'ex_502', + value: 'Unsupported File Type ...', + }, + { + id: 'ex_503', + value: 'Max Allowed Media Exceeded ...', + }, + { + id: 'ex_600', + value: 'Invalid Configuration ...', + }, + { + id: 'ex_601', + value: 'Storage Service Initiallization Failed ...', + }, + { + id: 'ex_602', + value: 'Message Service Initialization Failed ...', + }, + { + id: 'ex_900', + value: 'Max Allowed Files Exceeded ...', + }, + { + id: 'ex_901', + value: 'Min Files Size Exceeded ...', + }, + { + id: 'ex_902', + value: 'Max Files Size Exceeded ...', + }, + { + id: 'ex_903', + value: 'Must Accept Terms And Conditions ...', + }, + { + id: 'ex_904', + value: 'Browser does not support Location Services ...', + }, + { + id: 'ex_905', + value: 'You have rejected access to your Location ...', + }, + { + id: 'ex_906', + value: 'Unable to determine your Location ...', + }, + { + id: 'ex_907', + value: 'Browser does not support Storage Services ...', + }, + { + id: 'ex_908', + value: 'Must Logout to access content ...', + }, + { + id: 'ex_909', + value: 'Invalid Locale ...', + }, + { + id: 'ex_910', + value: 'Invalid User Selector ...', + }, + //#endregion + ], + }, +]; +//#endregion + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\Generator\xFrameworkResourceManager.html + + + + + + + مدیریت منابع زبانی xFramework + + + +
+

🌐 مدیریت منابع زبانی xFramework

+

+ مدیریت، ویرایش و اعتبارسنجی فایل‌های ترجمه برای برنامه‌های کاربردی مبتنی + بر xFramework +

+
+ توسعه‌دهنده: هادی خزاعی اصل | شرکت: فن آوران ساحر علم | تاریخ: ۱ شهریور + ۱۴۰۵ +
+
+ +
+ +
+

📂 منبع داده‌ها

+
+
+ 📚 منابع پیش‌فرض سیستم +
+
+ 📁 بارگذاری فایل JSON +
+
+ +
+

+ ✅ در حال حاضر از منابع پیش‌فرض xFramework استفاده می‌شود. می‌توانید + مستقیماً ویرایش را شروع کنید. +

+
+ +
+
+ + +
+
+
+
+ + +
+

🌍 مدیریت زبان‌ها

+
+ +
+ + + + + +
+
+ + +
+

✏️ ویرایش شناسه‌ها و ترجمه‌ها

+
+ +
+ +
+ +
+ + +
+

+ یک شناسه را از لیست سمت راست انتخاب کنید تا ترجمه‌های آن را ویرایش + کنید. +

+
+
+
+ + +
+

📄 خروجی JSON

+
+
+ 📄 Full JSON +
+
+

+
+        
+ + + +
+
+
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\IXOwnedItemResourceProvider.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xModels.Dtos; +using xStringService.Models.Dtos; + +namespace xStringService.Interfaces +{ + public interface IXOwnedItemResourceProvider + { + // + #region Group Actions ... + /// + /// Retrieve a List of Exists Languages for Current Item ... + /// + /// + /// + /// + Task> GetLanguages( + object owner, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve all Exists Items of type ... + /// + /// + /// + Task> GetResourceLocales( + object owner, + CancellationToken cancellationToken = default + ); + + /// + /// Remove all Exists Locales which Related to this Provider ... + /// + /// + /// + /// + Task RemoveResourceLocales( + object owner, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Item Actions ... + /// + /// Get all Exists Items for Specified identitifer ... + /// + /// + /// + /// + Task> GetResourceLocales( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + + /// + /// Get all Exists Items for Specified identitifer ... + /// + /// + /// + /// + Task> GetLocales( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + + /// + /// Get all Exists Locales Representaion based on Specified Identitifer + /// as XResourceDto ... + /// + /// + /// + /// + Task GetResource( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + + /// + /// Add Or Update Locale for Specified Identitifer ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateLocale( + object owner, + object identifier, + XLocaleResourceDto locale, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Update a Resource State ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateResource( + object owner, + object identifier, + XResourceDto resource, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove Specified Language Locale of Specified Identifier ... + /// + /// + /// + /// + /// + /// + Task RemoveLocale( + object owner, + object identifier, + string language, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove all Exists Locales for Specified Identifier ... + /// + /// + /// + /// + /// + Task RemoveLocales( + object owner, + object identifier, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Check Specified ocale Exists for Specified Identifier ... + /// + /// + /// + /// + /// + Task HasLocale( + object owner, + object identifier, + string language, + CancellationToken cancellationToken = default + ); + + /// + /// Get all Exists Languages for Specified Identifier ... + /// + /// + /// + /// + Task> GetLanguages( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Resource Title Action ... + /// + /// Retrieve Resource Title ... + /// + /// + /// + string GetResourceTitle(object identifier = null); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\XBaseOwnedItemResourceProvider.cs + +using xStringService.Interfaces; + +namespace xStringService.Providers +{ + /// + /// Owned Item Resource Provider ... + /// + public abstract class XBaseOwnedItemResourceProvider : IXOwnedItemResourceProvider + { + + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\XAiApiConfiguration.cs + +using xAiModels.Constants; +using xAiModels.Models; + +namespace xAiModels.Configurations +{ + public class XAiApiConfiguration + { + /// + /// Model Providers ... + /// + public XAiModelDescriptor[] Models { get; set; } = []; + + /// + /// Each User must Has a Default Project, this is Title Resource Identifier ... + /// + public string DefaultProjectTitleResource { get; set; } = XAiModelsConstants.DefaultXAiProjectTitleResourceID; + + /// + /// Each User must Has a Default Project, this is Description Resource Identifier ... + /// + public string DefaultProjectDescriptionResource { get; set; } = XAiModelsConstants.DefaultXAiProjectDescriptionResourceID; + + /// + /// Each User must Has a Default Conversation, this is Title Resource Identifier ... ... + /// + public string DefaultConversationTitleResource { get; set; } = XAiModelsConstants.DefaultXAiConversationTitleResourceID; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\XAiModelMappersProfile.cs + +using AutoMapper; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Configurations +{ + public class XAiModelMappersProfile : Profile + { + public XAiModelMappersProfile() + { + // + // XAiMessage ... + CreateMap(); + + // + // XAiProject ... + CreateMap(); + + // + // XAiConversation ... + CreateMap(); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\Entities\XAiConversationEntityConfiguration.cs + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xAiModels.Constants; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Configurations.Entities +{ + public class XAiConversationEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiConversationTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\Entities\XAiMessageEntityConfiguration.cs + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xAiModels.Constants; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Configurations.Entities +{ + public class XAiMessageEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiMessageTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\Entities\XAiProjectEntityConfiguration.cs + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xAiModels.Constants; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Configurations.Entities +{ + public class XAiProjectEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiProjectTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\ConfigurationNodeNames.cs + +namespace xAiModels.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiApiConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiChatRole.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiChatRoles + { + public const string None = "none"; + public const string User = "user"; + public const string Tool = "tool"; + public const string System = "system"; + public const string Assistant = "assistant"; + } + + public enum XAiChatRole + { + [StringValue(XAiChatRoles.None)] + None, + [StringValue(XAiChatRoles.User)] + User, + [StringValue(XAiChatRoles.Tool)] + Tool, + [StringValue(XAiChatRoles.System)] + System, + [StringValue(XAiChatRoles.Assistant)] + Assistant, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiDataProviderConstants.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiDataProviderConstants + { + public const string XDefaultAiProjectSuffix = "DefAiPrj"; + public const string XDefaultAiConversationSuffix = "DefAiCnv"; + } + + public enum XAiDataProviderHubActions + { + // + // Project ... + [StringValue("ProjectCreated")] + ProjectCreated, + + [StringValue("ProjectUpdated")] + ProjectUpdated, + + [StringValue("ProjectRemoved")] + ProjectRemoved, + + // + // Conversation ... + [StringValue("ConversationCreated")] + ConversationCreated, + + [StringValue("ConversationUpdated")] + ConversationUpdated, + + [StringValue("ConversationRemoved")] + ConversationRemoved, + + // + // Message ... + [StringValue("MessageCreated")] + MessageCreated, + + [StringValue("MessageUpdated")] + MessageUpdated, + + [StringValue("MessageRemoved")] + MessageRemoved, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiModelProviderType.cs + +namespace xAiModels.Constants +{ + /// + /// Specifiy Provider Type ... + /// + public enum XAiModelProviderType + { + None, + Ollama, + DeepSeek, + HuggingFace + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiModelsConstants.cs + +namespace xAiModels.Constants +{ + public struct XAiModelsConstants + { + // + // Service Extensions Log Tag ... + public const string XAiModelsDILogTag = "XAiModels"; + + // + // Table Mapping Identifiers ... + public const string XAiMessageTable = "AiMessages"; + public const string XAiProjectTable = "AiProjects"; + public const string XAiConversationTable = "AiConversations"; + + // + // GraphQL Collection Mappings ... + public const string XAiMessageSingleName = "aiMessage"; + public const string XAiProjectSingleName = "aiProject"; + public const string XAiConversationSignleName = "aiConversation"; + + public const string XAiMessageCollectionName = "aiMessages"; + public const string XAiProjectCollectionName = "AiProjectsa"; + public const string XAiConversationCollectionName = "aiConversations"; + + // + // Hubs ... + public const string XAiMessageDtoHub = "aiMessageDto"; + public const string XAiMessageEntityHub = "aiMessageEntity"; + + public const string XAiProjectDtoHub = "aiProjectDto"; + public const string XAiProjectEntityHub = "aiProjectEntity"; + + public const string XAiConversationDtoHub = "aiConversationDto"; + public const string XAiConversationEntityHub = "aiConversationEntity"; + + // + // Resource Provider Identifiers ... + public const string XAiProjectTitleIdentifier = "AiPrjT"; + public const string XAiProjectDescriptionIdentifier = "AiPrjD"; + public const string XAiConversationTitleIdentifier = "AiCnvrT"; + + // + // EF Repositories Helper Extensions ... + public const string GetXAiMessageEFRepositoryDescriptor = "GetXAiMessageEFRepositoryDescriptor"; + public const string GetXAiProjectEFRepositoryDescriptor = "GetXAiProjectEFRepositoryDescriptor"; + public const string GetXAiConversationEFRepositoryDescriptor = "GetXAiConversationEFRepositoryDescriptor"; + + // + public const string DefaultXAiProjectTitleResourceID = "XAiPrjT"; + public const string DefaultXAiConversationTitleResourceID = "XAiCnvT"; + public const string DefaultXAiProjectDescriptionResourceID = "XAiPrjD"; + + // + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\DI\XDIHelperExtension.cs + +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using xAiModels.Providers.Dtos; +using xAiModels.Providers.Entities; +using xCommons.Extensions; +using xDataService.Constants; +using xDataService.Db; +using xDataService.Models; +using xExceptions.Constants; +using xPushService.Helpers; +using xPushService.DI; +using xDataService.DI; +using xAiModels.Interfaces.Dtos; +using xAiModels.Helpers; +using xCommons.Helpers; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces; +using xAiModels.Providers; +using xAiModels.Constants; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Providers.Enrichers; + +namespace xAiModels.DI +{ + /// + /// Service Registration Extensions Classes ... + /// + public static class XDIHelperExtension + { + /// + /// Register Service ... + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + AddAiDataService( + contextType: null, + services: services, + lifeTime: lifeTime, + repositoryType: repositoryType + ); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + where TContext : XDbContext + { + AddAiDataService( + services: services, + lifeTime: lifeTime, + contextType: typeof(TContext), + repositoryType: repositoryType + ); + } + + /// + /// Use XSubCategoryService Middleware ... + /// + /// + /// + public static void UseXAiDataService( + this IApplicationBuilder app, + bool isDevelopmentEnvironment = false + ) + { + // + #region Using Hubs ... + // + var pushHelper = new XPushServiceHelper(); + + // + // XAiMessage ... + pushHelper.AddHub(XAiModelsConstants.XAiMessageDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiMessageEntityHub); + + // + // XAiProject ... + pushHelper.AddHub(XAiModelsConstants.XAiProjectDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiProjectEntityHub); + + // + // XAiConversation ... + pushHelper.AddHub(XAiModelsConstants.XAiConversationDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiConversationEntityHub); + + // + app.UseXPushService(pushHelper); + #endregion + + // + // Using XAiConversation Repository Descriptor ... + if (!aiConversationDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiConversationDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiMessage Repository Descriptor ... + if (!aiMessageDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiMessageDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiProject Repository Descriptor ... + if (!aiProjectDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiProjectDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Create an Scope for Services Acces ... + // Handle Seeding Category/SubCategory Resources ... + // TODO: Enable Seeding if Required ... + // using (var scope = app.ApplicationServices.CreateScope()) + // { + // // + // // Retrieve Configuratuions ... + // var aiMessageProvider = scope.ServiceProvider.GetService(); + // var aiProjectProvider = scope.ServiceProvider.GetService(); + // var aiConversationProvider = scope.ServiceProvider.GetService(); + // var configuration = scope.ServiceProvider.GetService(); + // if (!configuration.IsNullOrDefault() && + // !categoryProvider.IsNullOrDefault() && + // !subaiConversationDescriptor.IsNullOrDefault() + // ) + // { + // // + // // Logging ... + // Log("Start Seeding ..."); + + // // + // // Count Data in Category ... + // var hasCategory = (categoryProvider.Count().GetAwaiter().GetResult()) > 0; + // var hasSubCategory = (subCategoryProvider.Count().GetAwaiter().GetResult()) > 0; + + // // + // // Seed Category Resources ... + // var canSeed = + // !hasCategory && + // configuration.Categories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var cat in configuration.Categories) + // { + // // + // try + // { + // // + // Log($"Start Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // categoryProvider.Refresh( + // resource: cat, + // userInfo: null, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // // Seed SubCategory Resources ... + // canSeed = + // !hasSubCategory && + // configuration.SubCategories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var subcat in configuration.SubCategories) + // { + // // + // try + // { + // // + // Log($"Start Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // subCategoryProvider.Refresh( + // userInfo: null, + // resource: subcat, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // Log("Finish Seeding ..."); + // } + // } + } + + // + #region Private ... + private static XRepositoryDescriptor aiMessageDescriptor = null; + private static XRepositoryDescriptor aiProjectDescriptor = null; + private static XRepositoryDescriptor aiConversationDescriptor = null; + + /// + /// a LogTag for Service ... + /// + private static string XLogTag = XAiModelsConstants.XAiModelsDILogTag; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + private static void AddAiDataService( + IServiceCollection services, + XRepositoryType repositoryType, + Type contextType = null, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("Service Registration failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("Service Registration failed, lifetime not provided ..."); + throw exception; + } + + // + // Validate Repository Type ... + var isRepositoryTypeValid = + (repositoryType == XRepositoryType.EF && + !contextType.IsNull()) || + ((repositoryType == XRepositoryType.Mongo || + repositoryType == XRepositoryType.InMemory) && + contextType.IsNull()); + if (!isRepositoryTypeValid) + { + // + Log("Service Registration failed, Invalid Repository Type and Context Type ..."); + throw exception; + } + + // + // Maske Instance of Repository Descriptor + // Based on Provided Type ... + switch (repositoryType) + { + // + case XRepositoryType.EF: + // + // XAiMessage ... + aiMessageDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiMessageEFRepositoryDescriptor + ); + + // + // XAiProject ... + aiProjectDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiProjectEFRepositoryDescriptor + ); + + // + // XAiConversation ... + aiConversationDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiConversationEFRepositoryDescriptor + ); + break; + + // + case XRepositoryType.Mongo: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageMongoRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectMongoRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationMongoRepositoryDescriptor(); + break; + + // + case XRepositoryType.InMemory: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageInMemoryRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectInMemoryRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationInMemoryRepositoryDescriptor(); + break; + } + + // + #region Register Repository Descriptor ... + // + // XAiMessage ... + if (!aiMessageDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiMessageDescriptor + ); + } + + // + // XAiProject ... + if (!aiProjectDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiProjectDescriptor + ); + } + + // + // XAiConversation ... + if (!aiConversationDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiConversationDescriptor + ); + } + #endregion + + // + #region Register Services ... + // + #region AiMessage ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiMessageServiceProvider), typeof(XAiMessageServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryService), typeof(XAiMessageRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryProvider), typeof(XAiMessageRepositoryProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiMessageEnricher), typeof(XAiMessageEnricher), lifeTime) + ); + #endregion + + // + #region AiProject ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiProjectServiceProvider), typeof(XAiProjectServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryService), typeof(XAiProjectRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryProvider), typeof(XAiProjectRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectTitleResourceProvider), typeof(XAiProjectTitleResourceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectDescriptionResourceProvider), typeof(XAiProjectDescriptionResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectEnricher), typeof(XAiProjectEnricher), lifeTime) + ); + #endregion + + // + #region AiConversation ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiConversationServiceProvider), typeof(XAiConversationServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryService), typeof(XAiConversationRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryProvider), typeof(XAiConversationRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationTitleResourceProvider), typeof(XAiConversationTitleResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationEnricher), typeof(XAiConversationEnricher), lifeTime) + ); + #endregion + #endregion + + // + // Data Provider ... + services.Add( + new ServiceDescriptor(typeof(IXAiDataProvider), typeof(XAiDataProvider), lifeTime) + ); + + // + Log("Service Regitration Succeed ..."); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\ChatResponseExtensions.cs + +using Microsoft.Extensions.AI; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + public static class ChatResponseExtensions + { + /// + /// Validate a Chat Response ... + /// + /// + /// + public static bool IsValid(this ChatResponse source) + { + // + var result = + source is not null && + !source.IsNullOrDefault() && + !string.IsNullOrWhiteSpace(source.Text) && + source.FinishReason == ChatFinishReason.Stop; + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\ChatRoleExtensions.cs + +using Microsoft.Extensions.AI; +using xAiModels.Constants; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + /// + /// Extensions for ChatRole ... + /// + public static class ChatRoleExtensions + { + /// + /// Normalize an String to Propper Chat Role Value ... + /// > + /// + /// + /// + public static string GetChatRoleTitle(this string source) + { + // + var result = XAiChatRoles.None; + + // + if (source.ToNormalString() == XAiChatRoles.None.ToNormalString()) + { + result = XAiChatRoles.None; + } + else if (source.ToNormalString() == XAiChatRoles.User.ToNormalString()) + { + result = XAiChatRoles.User; + } + else if (source.ToNormalString() == XAiChatRoles.Tool.ToNormalString()) + { + result = XAiChatRoles.Tool; + } + else if (source.ToNormalString() == XAiChatRoles.System.ToNormalString()) + { + result = XAiChatRoles.System; + } + else if (source.ToNormalString() == XAiChatRoles.Assistant.ToNormalString()) + { + result = XAiChatRoles.Assistant; + } + + // + return result; + } + + /// + /// Get Chat Role Title from Chat Role Class ... + /// + /// + /// + /// + public static string GetRole(this ChatRole source) + { + // + var result = source.Value + .GetChatRoleTitle(); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this string source) + { + // + var role = source.GetChatRoleTitle(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this XAiChatRole source) + { + // + var role = source.GetStringValue(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Extract Chat Role Enum from Chat Role ... + /// + /// + /// + /// + /// + public static XAiChatRole ToChatRole(this ChatRole source) + { + // + var role = source + .GetRole() + .GetChatRoleTitle(); + + // + XAiChatRole result = XAiChatRole.User; + + // + if (role == XAiChatRoles.User) + { + result = XAiChatRole.User; + } + else if (role == XAiChatRoles.Tool) + { + result = XAiChatRole.Tool; + } + else if (role == XAiChatRoles.System) + { + result = XAiChatRole.System; + } + else if (role == XAiChatRoles.Assistant) + { + result = XAiChatRole.Assistant; + } + + // + return result; + } + + /// + /// Validate an String as Chat Role ... + /// + /// + /// + public static bool IsValid(this string source) + { + // + var result = + source != XAiChatRoles.None && + source.ToNormalString() != XAiChatRoles.None.ToNormalString(); + + // + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this XAiChatRole source) + { + // + var result = source != XAiChatRole.None; + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this ChatRole source) + { + // + var role = source.ToChatRole(); + var result = role.IsValid(); + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\XAiApiConfigurationExtensions.cs + +using System.Linq; +using xAiModels.Configurations; +using xAiModels.Models; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + public static class XAiApiConfigurationExtensions + { + /// + /// Validate Api Configuration ... + /// + /// + /// + public static bool IsValid(this XAiApiConfiguration source) + { + return + !source.IsNullOrDefault() && + source.Models.HasChild(); + } + + /// + /// Retrieve Default Model Descriptor ... + /// + /// + /// + public static XAiModelDescriptor GetDefaultModel(this XAiApiConfiguration source) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + result = source.Models.First(); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\XAiModelsExtensions.cs + +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + /// + /// Extensions Methods for XAiModels ... + /// + public static class XAiModelsExtensions + { + /// + /// Validate a Project for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiProject source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiProjectDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Conversation for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiConversation source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiConversationDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + + /// + /// Validate a Message for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiMessage source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiMessageDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Helpers\XAiModelsHelper.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xAiModels.Providers.GraphQL; +using xDataService.Db; +using xDataService.Models; +using xDataService.Providers; + +namespace xAiModels.Helpers +{ + public static class XAiModelsHelper + { + // + #region XAiConversation ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + > GetXAiConversationMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + > GetXAiConversationInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiMessage ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + > GetXAiMessageMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + > GetXAiMessageInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiProject ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + > GetXAiProjectMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + > GetXAiProjectInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiConversationTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiConversationTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiDataProvider.cs + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Models.Dtos; + +namespace xAiModels.Interfaces +{ + /// + /// All Data Manipulation Requirements ... + /// + public interface IXAiDataProvider + { + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Creator/Adders ... + /// + /// Create Project ... + /// + /// + /// + /// + /// + /// + Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Create Conversation ... + /// + /// + /// + /// + /// + /// + Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Message ... + /// + /// + /// + /// + /// + /// + Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiProjectDescriptionResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectDescriptionResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiProjectTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiConversationDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiConversationRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xModels.Dtos; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationRepositoryService : IXBaseRepositoryService + { + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + Task AddAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + Task UpdateAsync( + Guid id, + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + XAiConversationDto item, + bool softDelete = false, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiConversationServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xAiModels.Providers.Dtos; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiMessageDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiMessageRepositoryService.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageRepositoryService : IXBaseRepositoryService + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiMessageServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xAiModels.Providers.Dtos; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiProjectDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiProjectRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xModels.Dtos; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectRepositoryService : IXBaseRepositoryService + { + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + /// + Task AddAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + /// + Task AddOrUpdateAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + /// + Task UpdateAsync( + Guid id, + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + XAiProjectDto item, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + /// + Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + /// + IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiProjectServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xAiModels.Providers.Dtos; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Enrichers\IXAiConversationEnricher.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + /// + /// Ai Conversation Enricher ... + /// + public interface IXAiConversationEnricher : IXBaseEnricher + { + /// + /// Converts a Signle Entity to Dto ... + /// + /// + /// + /// + /// + /// + Task EnrichAsync( + XAiConversationDto source, + XAiConversationDto destination, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Converts a Collection of Entities to Dtos ... + /// + /// + /// + /// + /// + /// + Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Enrichers\IXAiMessageEnricher.cs + +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiMessageEnricher : IXBaseEnricher + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Enrichers\IXAiProjectEnricher.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiProjectEnricher : IXBaseEnricher + { + + Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationEntityHub.cs + +using System; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationKeyGenerator.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationRepository.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationRepositoryEvents.cs + +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationRepositoryProvider.cs + +using System; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationSeeder.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageEntityHub.cs + +using System; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageKeyGenerator.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageRepository.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageRepositoryEvents.cs + +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageRepositoryProvider.cs + +using System; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageSeeder.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectEntityHub.cs + +using System; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectGraphQLTypeHelper.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectKeyGenerator.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectRepository.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectRepositoryEvents.cs + +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectRepositoryProvider.cs + +using System; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectSeeder.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\XAiModelDescriptor.cs + +using xAiModels.Constants; + +namespace xAiModels.Models +{ + /// + /// Describe a Provided Model ... + /// + public class XAiModelDescriptor + { + /// + /// Provider Name ... + /// + public string Name { get; set; } + + /// + /// LLM Provider Url ... + /// + public string Url { get; set; } + + /// + /// Model Name ... + /// + public string LLM { get; set; } + + /// + /// Api Key for Connection ... + /// + public string ApiKey { get; set; } + + /// + /// Specified Model Provider Type ... + /// + public XAiModelProviderType Provider { get; set; } = XAiModelProviderType.Ollama; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Dtos\XAiConversationDto.cs + +using System; +using System.Collections.Generic; +using xModels.Base; +using xModels.Dtos; + +namespace xAiModels.Models.Dtos +{ + /// + /// Conversation Describe ... + /// + public class XAiConversationDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Conversation Title Resource ID ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Messages ... + /// + public virtual IEnumerable Messages { get; set; } = []; + + /// + /// Project ID ... + /// + public Guid ProjectId { get; set; } + + /// + /// Project Title Resource ID ... + /// + public virtual string ProjectTitle { get; set; } = null; + + /// + /// Project Description Resource ID ... + /// + public virtual string ProjectDescription { get; set; } = null; + + /// + /// Project Title Locale Resources ... + /// + public virtual XResourceDto ProjectTitleResource { get; set; } + + /// + /// Project Description Locale Resources ... + /// + public virtual XResourceDto ProjectDescriptionResource { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Dtos\XAiMessageDto.cs + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using xAiModels.Constants; +using xCommons.Extensions; +using xModels.Base; +using xModels.Dtos; + +namespace xAiModels.Models.Dtos +{ + public class XAiMessageDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Message of Chat ... + /// + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + public Guid ConversationId { get; set; } + + /// + /// Conversation Info ... + /// + public virtual string ConversationTitle { get; set; } = null; + public virtual XResourceDto ConversationTitleResouce { get; set; } = null; + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MeatDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Dtos\XAiProjectDto.cs + +using System; +using System.Collections.Generic; +using xModels.Base; +using xModels.Dtos; + +namespace xAiModels.Models.Dtos +{ + /// + /// Describe a Project ... + /// + public class XAiProjectDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Title of Project ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Description of Project ... + /// + public string Description { get; set; } + + /// + /// All Exists Description Locale Resources ... + /// + public virtual XResourceDto DescriptionResource { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversations ... + /// + public virtual IList Conversations { get; set; } = []; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Entities\XAiConversation.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Conversation Describe ... + /// + public class XAiConversation : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Conversation ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Project ID ... + /// + [Required] + public Guid ProjectId { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Entities\XAiMessage.cs + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using xAiModels.Constants; +using xCommons.Extensions; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Message Model of Ai ... + /// + public class XAiMessage : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Message of Chat ... + /// + [Required] + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + [StringLength(255)] + public Guid ConversationId { get; set; } + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MeatDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Entities\XAiProject.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Describe a Project ... + /// + public class XAiProject : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Project ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Description of Project ... + /// + [StringLength(1000)] + public string Description { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiConversationEntityRegisterar.cs + +using System; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers +{ + public class XAiConversationEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiConversationEntityRegisterar() + : base(nameof(XAiConversationEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiConversationEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiConversationTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Interfaces.Dtos; +using xStringService.Providers; + +namespace xAiModels.Providers +{ + public class XAiConversationTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiConversationTitleResourceProvider + { + public XAiConversationTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiConversationTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiDataProvider.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using MongoDB.Driver.Core.Connections; +using xAiModels.Constants; +using xAiModels.Extensions; +using xAiModels.Interfaces; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Providers.Hubs; +using xCommons.Configurations; +using xCommons.Extensions; +using xExceptions.Constants; +using xModels.Dtos; +using xStringService.Interfaces; + +namespace xAiModels.Providers +{ + /// + /// All Data Manipulation Requirements ... + /// + public class XAiDataProvider : IXAiDataProvider + { + // + #region Properties ... + private readonly IXStringProvider stringProvider; + private readonly XAppConfiguration appConfiguration; + private readonly IHubContext hub; + private readonly IXAiMessageRepositoryService messageRepositoryService; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + #endregion + + public XAiDataProvider( + IXStringProvider stringProvider, + XAppConfiguration appConfiguration, + IHubContext hub, + IXAiMessageRepositoryService messageRepositoryService, + IXAiProjectRepositoryService projectRepositoryService, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationRepositoryService conversationRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + this.hub = hub; + this.stringProvider = stringProvider; + this.appConfiguration = appConfiguration; + this.messageRepositoryService = messageRepositoryService; + this.projectRepositoryService = projectRepositoryService; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationRepositoryService = conversationRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + public async Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Default Project and Conversation ... + bool hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (!hasDefault) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: null, + cancellationToken: cancellationToken + ); + } + + // + // Retrieve Project List ... + var result = await projectRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: fillConversations, + predicate: x => x.OwnerId == ownerId, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + public async Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Conversation's List ... + var result = await conversationRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: false, + fillMessages: fillMessages, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == projectId, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + return result; + } + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + public async Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Message Lists of Specified Conversation ... + var result = await messageRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversationId + ); + + // + return result; + } + #endregion + + // + #region Creator/Adders ... + public async Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Project Provided or not ... + var hasProject = !item.IsNullOrDefault(); + + // + // Normalize Provided Project ... + if (hasProject) + { + // + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiProjectDto result = null; + + // + // Create Provided Project ... + if (hasProject) + { + // + result = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + // + // Check Default Project ... + else + { + // + // Check Default Project Exists or not ... + var hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Project ... + result = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Proejct ... + XAiProjectDto project = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Conversation Provided or not ... + var hasConversation = !item.IsNullOrDefault(); + + // + // Normalize Conversation if Provided ... + if (hasConversation) + { + // + item.ProjectId = project.Id; + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiConversationDto result = null; + + // + // Create Provided Conversation ... + if (hasConversation) + { + // + result = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + fillMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + // + // Check Default Conversation ... + else + { + // + // Check Default Conversation Exists or not ... + var hasDefault = await HasDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Conversation ... + result = await GetDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (item.IsNullOrDefault() || + conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + item.CreatedOn = DateTime.UtcNow; + item.ConversationId = conversationId; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + + // + var result = await messageRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.MessageCreated.GetStringValue() + ); + } + + // + return result; + } + #endregion + + // + #region Updaters ... + #endregion + + // + #region Private ... + /// + /// Check Default Project Exists or not ... + /// + /// + /// + /// + /// + private async Task HasDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Default Owner Exists or not ... + result = !(await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + )) + .IsNullOrDefault(); + return result; + } + + /// + /// Retrieve Default Project of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + private async Task GetDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Default Project Exists or noit ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var result = await projectRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Create Default Project for Specified Owner ... + /// + /// + /// + /// + /// + private async Task CreateDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + if (ownerId.IsNullOrEmpty()) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Check Default Owner Exists or not ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (isExists) + { + return; + } + + // + // Create Default ... + var item = new XAiProjectDto() + { + OwnerId = ownerId, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString(), + Description = Guid.NewGuid().ToString(), + }; + item = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Tile and Description Resource Ids ... + var titleResource = await projectTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + var descriptionResource = await projectDescriptionResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault() || + descriptionResource.IsNullOrDefault() + ) + { + return; + } + + // + // Update Project Resources ... + item.Title = titleResource.Resource; + item.Description = descriptionResource.Resource; + item = await projectRepositoryService.UpdateAsync( + id: item.Id, + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task HasDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiConversationTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiConversationSuffix) + ); + result = !resource.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + result = !(await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => + x.ProjectId == projectId && + x.Title == resource.ResourceTitle + )) + .IsNullOrDefault(); + + // + return result; + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task CreateDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var isValid = !ownerId.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + isValid = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + cancellationToken: cancellationToken + ); + if (isValid) + { + return; + } + + // + // Create Default Conversation ... + var item = new XAiConversationDto + { + OwnerId = ownerId, + ProjectId = project.Id, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString() + }; + item = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Title Resource Ids ... + var titleResource = await conversationTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiConversationSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault()) + { + return; + } + + // + // Update Conversation Resources ... + item.Title = titleResource.Resource; + item = await conversationRepositoryService.UpdateAsync( + item: item, + id: item.Id, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + + /// + /// Retrieve Default Conversation of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + /// + private async Task GetDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Conversation Exists or noit ... + var isExists = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Detect Conversation Resource ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Find Default Conversation ... + var result = await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) && + x.ProjectId == project.Id + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Normalize and Validate Language ... + /// + /// + /// + private string NormalizeAndValidateLanguage(string language) + { + // + if (language.IsNullOrEmpty()) + { + language = appConfiguration.DefaultLanguage; + } + + // + if (language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + return language; + } + + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + public async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Collect Allowed Actions ... + var actions = new List + { + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + }; + + // + // Validate Args ... + var isValid = + !action.IsNullOrEmpty() && + actions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve Connection Id ... + var clients = hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = hub.Clients.AllExcept(connectionId); + } + + // + await clients.SendAsync( + action, + payLoad, + connectionId, + cancellationToken + ); + } + catch { } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiMessageEntityRegisterar.cs + +using System; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers +{ + public class XAiMessageEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiMessageEntityRegisterar() + : base(nameof(XAiMessageEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiMessageEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiProjectDescriptionResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Interfaces.Dtos; +using xStringService.Providers; + +namespace xAiModels.Providers +{ + public class XAiProjectDescriptionResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectDescriptionResourceProvider + { + public XAiProjectDescriptionResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectDescriptionIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiProjectEntityRegisterar.cs + +using System; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers +{ + public class XAiProjectEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiProjectEntityRegisterar() + : base(nameof(XAiProjectEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiProjectEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiProjectTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Interfaces.Dtos; +using xStringService.Providers; + +namespace xAiModels.Providers +{ + public class XAiProjectTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectTitleResourceProvider + { + public XAiProjectTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiConversationDtoHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationDtoHub : XBaseDtoHub, IXAiConversationDtoHub + { + public XAiConversationDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiConversationRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; +using xDataService.Providers; +using xModels.Dtos; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationRepositoryService : XBaseRepositoryService, IXAiConversationRepositoryService + { + private readonly IXAiConversationEnricher enricher; + + public XAiConversationRepositoryService( + IXAiConversationEnricher enricher, + IXAiConversationRepository repository + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.enricher = enricher; + } + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + public override async Task AddAsync( + XAiConversationDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddAsync( + item: item, + fillMessages: false, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + public override async Task AddOrUpdateAsync( + XAiConversationDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddOrUpdateAsync( + item: item, + fillMessages: false, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + public override async Task UpdateAsync( + Guid id, + XAiConversationDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await UpdateAsync( + id: id, + item: item, + fillMessages: false, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + Guid id, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + id: id, + fillMessages: false, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + XAiConversationDto item, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + item: item, + fillMessages: false, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAsync( + id: id, + fillMessages: false, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + public override async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAllAsync( + fillMessages: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + public override IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return GetAllAsAsyncEnumerable( + fillMessages: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public override async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindOneAsync( + fillMessages: false, + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public override async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindManyAsync( + fillMessages: false, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + public override async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await QueryAsync( + query: query, + fillMessages: false, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + #endregion + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + public virtual async Task AddAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + public virtual async Task AddOrUpdateAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task UpdateAsync( + Guid id, + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + Guid id, + bool softDelete = true, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + XAiConversationDto item, + bool softDelete = true, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAsync( + id: id, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAllAsync( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + public virtual async IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + // + var enumerable = base.GetAllAsAsyncEnumerable( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + await foreach (var dto in enumerable) + { + // + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + await enricher.EnrichAsync( + source: dto, + destination: dto, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + yield return dto; + } + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindOneAsync( + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindManyAsync( + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.QueryAsync( + query: query, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result.Items, + destinations: result.Items, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiConversationServiceProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationServiceProvider : XBaseDtoProvider, IXAiConversationServiceProvider + { + public XAiConversationServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiConversationRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiMessageDtoHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageDtoHub : XBaseDtoHub, IXAiMessageDtoHub + { + public XAiMessageDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiMessageRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; +using xDataService.Providers; +using xModels.Dtos; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageRepositoryService : XBaseRepositoryService, IXAiMessageRepositoryService + { + private readonly IXAiMessageEnricher enricher; + + public XAiMessageRepositoryService( + IXAiMessageEnricher enricher, + IXAiMessageRepository repository + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.enricher = enricher; + } + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + public override async Task AddAsync( + XAiMessageDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + public override async Task AddOrUpdateAsync( + XAiMessageDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + public override async Task UpdateAsync( + Guid id, + XAiMessageDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + Guid id, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + XAiMessageDto item, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAsync( + id: id, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + public override async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAllAsync( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + public override async IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + // + var enumerable = base.GetAllAsAsyncEnumerable( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + await foreach (var dto in enumerable) + { + // + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + await enricher.EnrichAsync( + source: dto, + destination: dto, + cancellationToken: cancellationToken + ); + yield return dto; + } + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public override async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindOneAsync( + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public override async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindManyAsync( + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + public override async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.QueryAsync( + query: query, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result.Items, + destinations: result.Items, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiMessageServiceProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageServiceProvider : XBaseDtoProvider, IXAiMessageServiceProvider + { + public XAiMessageServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiMessageRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiProjectDtoHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectDtoHub : XBaseDtoHub, IXAiProjectDtoHub + { + public XAiProjectDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiProjectRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; +using xDataService.Providers; +using xModels.Dtos; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectRepositoryService : XBaseRepositoryService, IXAiProjectRepositoryService + { + public XAiProjectRepositoryService( + IXAiProjectRepository repository + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { } + + + // + #region Actions Base ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + public override async Task AddAsync( + XAiProjectDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddAsync( + item: item, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + public override async Task AddOrUpdateAsync( + XAiProjectDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddOrUpdateAsync( + item: item, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + public override async Task UpdateAsync( + Guid id, + XAiProjectDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + XAiProjectDto item, + bool softDelete = false, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAsync( + id: id, + fillConversations: false, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + public override async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAllAsync( + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + public override IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return GetAllAsAsyncEnumerable( + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public override async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindOneAsync( + predicate: predicate, + fillConversations: false, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public override async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindManyAsync( + predicate: predicate, + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + public override async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await QueryAsync( + query: query, + predicate: predicate, + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + #endregion + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AddAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AddOrUpdateAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task UpdateAsync( + Guid id, + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + XAiProjectDto item, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAsync( + id: id, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAllAsync( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + // + var enumerable = base.GetAllAsAsyncEnumerable( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + await foreach (var dto in enumerable) + { + // + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + await enricher.EnrichAsync( + source: dto, + destination: dto, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + yield return dto; + } + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindOneAsync( + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindManyAsync( + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.QueryAsync( + query: query, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result.Items, + destinations: result.Items, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiProjectServiceProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectServiceProvider : XBaseDtoProvider, IXAiProjectServiceProvider + { + public XAiProjectServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiProjectRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Enrichers\XAiConversationEnricher.cs + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Interfaces; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Models.Dtos; +using xCommons.Extensions; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xModels.Dtos; +using System.Linq; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiConversationEnricher : IXAiConversationEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiConversationEnricher( + IXIdentityProvider identityProvider, + IXAiProjectRepositoryService projectRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) + { + // + this.identityProvider = identityProvider; + this.projectRepositoryService = projectRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + /// + /// Converts a Signle Entity to Dto ... + /// + /// + /// + /// + /// + public async Task EnrichAsync( + XAiConversationDto source, + XAiConversationDto destination, + CancellationToken cancellationToken = default + ) + { + await EnrichAsync( + source: source, + fillMessages: false, + destination: destination, + cancellationToken: cancellationToken + ); + } + + /// + /// Converts a Collection of Entities to Dtos ... + /// + /// + /// + /// + /// + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + CancellationToken cancellationToken = default + ) + { + await EnrichRangeAsync( + sources: sources, + fillMessages: false, + destinations: destinations, + cancellationToken: cancellationToken + ); + } + + /// + /// Converts a Signle Entity to Dto ... + /// + /// + /// + /// + /// + /// + public async Task EnrichAsync( + XAiConversationDto source, + XAiConversationDto destination, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Run independent async operations concurrently + var ownerTask = ResolveOwnerAsync(source.OwnerId, cancellationToken); + var projectTask = ResolveProjectAsync(source.ProjectId, cancellationToken); + var titleLocalesTask = ResolveTitleLocalesAsync(source.Title, cancellationToken); + var messagesTask = ResolveMessagesAsync(source.Id, cancellationToken); + + // + // wait until All Tasks Resolved ... + Task[] tasks = [ + ownerTask, + projectTask, + titleLocalesTask + ]; + if (fillMessages) + { + tasks = [.. tasks, messagesTask]; + } + await Task.WhenAll(tasks); + + // + // Attached Resolved Info to Destination ... + destination.Owner = ownerTask.Result; + destination.TitleResource = titleLocalesTask.Result; + var project = projectTask.Result; + if (!project.IsNullOrDefault()) + { + destination.ProjectTitle = project.Title; + destination.ProjectDescription = project.Description; + destination.ProjectTitleResource = project.TitleResource; + destination.ProjectDescriptionResource = project.DescriptionResource; + } + if (!messagesTask.Result.IsNull()) + { + destination.Messages = [.. messagesTask.Result]; + } + } + + /// + /// Converts a Collection of Entities to Dtos ... + /// + /// + /// + /// + /// + /// + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillMessages = false, + 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 Title Locales ... + /// + /// + /// + /// + private async Task ResolveTitleLocalesAsync( + string title, + CancellationToken cancellationToken = default + ) + { + // + XResourceDto result = null; + if (title.IsNullOrEmpty()) + { + return result; + } + + // + result = await conversationTitleResourceProvider.GetResource( + owner: null, + identifier: title, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Project ... + /// + /// + /// + /// + private async Task ResolveProjectAsync( + Guid projectId, + CancellationToken cancellationToken = default + ) + { + // + XAiProjectDto result = null; + if (projectId.IsNull() || projectId.IsDefaultGuid()) + { + return result; + } + + // + result = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Specified Conversation Messages ... + /// + /// + /// + /// + private async Task> ResolveMessagesAsync( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + var result = new List(); + + // + if (conversationId.IsDefaultGuid()) + { + return result; + } + + // + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Enrichers\XAiMessageEnricher.cs + +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 + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Enrichers\XAiProjectEnricher.cs + +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 async Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + CancellationToken cancellationToken = default + ) + { + await EnrichAsync( + source: source, + destination: destination, + fillConversations: false, + cancellationToken: cancellationToken + ); + } + + public async Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + // Run independent async operations concurrently + var conversationsTask = ResolveConversationsAsync( + source.Id, + fillConversationMessages, + cancellationToken + ); + var titleTask = ResolveTitleAsync(source.Title, cancellationToken); + var ownerTask = ResolveOwnerAsync(source.OwnerId, cancellationToken); + var descriptionTask = ResolveDescriptionAsync(source.Description, cancellationToken); + + // + // wait until All Tasks Resolved ... + Task[] tasks = + { + titleTask, + ownerTask, + descriptionTask + }; + if (fillConversations) + { + tasks = [.. tasks, conversationsTask]; + } + await Task.WhenAll(tasks); + + // + // Attached Resolved Info to Destination ... + destination.Owner = ownerTask.Result; + destination.TitleResource = titleTask.Result; + destination.DescriptionResource = descriptionTask.Result; + if (!conversationsTask.Result.IsNull()) + { + destination.Conversations = [.. conversationsTask.Result]; + } + } + + 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); + } + + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + // Make Tasks Ready ... + var tasks = sources.Zip(destinations, (src, dst) => + EnrichAsync( + source: src, + destination: dst, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ) + ); + + // + 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; + } + + /// + /// 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( + owner: null, + 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( + owner: null, + identifier: identifier, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Project Conversations ... + /// + /// + /// + /// + /// + private async Task> ResolveConversationsAsync( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + List result = []; + + // + // Validate ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + return result; + } + + // + // var items = await conversationRepositoryService.FindManyAsync( + // orderBuilder: null, + // includeBuilder: null, + // ignoreSoftDeleteds: true, + // fillMessages: fillMessages, + // predicate: x => x.Id == projectId, + // cancellationToken: cancellationToken + // ); + // result = [.. items]; + + // + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationEFRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEFRepository : XBaseEFRepository, IXAiConversationRepository + where TContext : XDbContext + { + public XAiConversationEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationEntityHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEntityHub : XBaseEntityHub, IXAiConversationEntityHub + { + public XAiConversationEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationInMemoryRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationInMemoryRepository : XBaseInMemoryRepository, IXAiConversationRepository + { + public XAiConversationInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationKeyGenerator.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationKeyGenerator : XGuidKeyGenerator, IXAiConversationKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationMongoRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationMongoRepository : XBaseMongoRepository, IXAiConversationRepository + { + public XAiConversationMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationRepositoryEvents.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryEvents : XBaseRepositoryEvents, IXAiConversationRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationRepositoryProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryProvider : XBaseEntityProvider, IXAiConversationRepositoryProvider + { + public XAiConversationRepositoryProvider( + IHubContext hub, + IXAiConversationRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationSeederBase.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiConversationSeederBase : XBaseDbSeeder, IXAiConversationSeeder + { + protected XAiConversationSeederBase( + string entity, + string database, + IXAiConversationRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageEFRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEFRepository : XBaseEFRepository, IXAiMessageRepository + where TContext : XDbContext + { + public XAiMessageEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageEntityHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEntityHub : XBaseEntityHub, IXAiMessageEntityHub + { + public XAiMessageEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageInMemoryRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageInMemoryRepository : XBaseInMemoryRepository, IXAiMessageRepository + { + public XAiMessageInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageKeyGenerator.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageKeyGenerator : XGuidKeyGenerator, IXAiMessageKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageMongoRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageMongoRepository : XBaseMongoRepository, IXAiMessageRepository + { + public XAiMessageMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageRepositoryEvents.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryEvents : XBaseRepositoryEvents, IXAiMessageRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageRepositoryProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryProvider : XBaseEntityProvider, IXAiMessageRepositoryProvider + { + public XAiMessageRepositoryProvider( + IHubContext hub, + IXAiMessageRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageSeederBase.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiMessageSeederBase : XBaseDbSeeder, IXAiMessageSeeder + { + protected XAiMessageSeederBase( + string entity, + string database, + IXAiMessageRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectEFRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEFRepository : XBaseEFRepository, IXAiProjectRepository + where TContext : XDbContext + { + public XAiProjectEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectEntityHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEntityHub : XBaseEntityHub, IXAiProjectEntityHub + { + public XAiProjectEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectInMemoryRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectInMemoryRepository : XBaseInMemoryRepository, IXAiProjectRepository + { + public XAiProjectInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectKeyGenerator.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectKeyGenerator : XGuidKeyGenerator, IXAiProjectKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectMongoRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectMongoRepository : XBaseMongoRepository, IXAiProjectRepository + { + public XAiProjectMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectRepositoryEvents.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryEvents : XBaseRepositoryEvents, IXAiProjectRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectRepositoryProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryProvider : XBaseEntityProvider, IXAiProjectRepositoryProvider + { + public XAiProjectRepositoryProvider( + IHubContext hub, + IXAiProjectRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectSeederBase.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiProjectSeederBase : XBaseDbSeeder, IXAiProjectSeeder + { + protected XAiProjectSeederBase( + string entity, + string database, + IXAiProjectRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiConversationGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiConversationCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiConversationSignleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphQuery.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQuery : XBaseGraphQLQuery + { + public XAiConversationGraphQuery( + XDataServiceConfiguration configuration, + IXAiConversationRepository repository, + IXAiConversationGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphSchema : Schema + { + public XAiConversationGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiConversationGraphQuery)services.GetService(typeof(XAiConversationGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphType.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphType : XBaseGraphObjectType + { + public XAiConversationGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ProjectId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiMessageGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiMessageCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiMessageSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphQuery.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQuery : XBaseGraphQLQuery + { + public XAiMessageGraphQuery( + XDataServiceConfiguration configuration, + IXAiMessageRepository repository, + IXAiMessageGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphSchema : Schema + { + public XAiMessageGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiMessageGraphQuery)services.GetService(typeof(XAiMessageGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphType.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphType: XBaseGraphObjectType + { + public XAiMessageGraphType() : base() + { + Field(x => x.Role); + Field(x => x.OwnerId); + Field(x => x.Content); + Field(x => x.Metadata); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ConversationId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiProjectGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiProjectCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiProjectSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphQuery.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQuery : XBaseGraphQLQuery + { + public XAiProjectGraphQuery( + XDataServiceConfiguration configuration, + IXAiProjectRepository repository, + IXAiProjectGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphSchema : Schema + { + public XAiProjectGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiProjectGraphQuery)services.GetService(typeof(XAiProjectGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphType.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphType : XBaseGraphObjectType + { + public XAiProjectGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.Prompt); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.Description); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Hubs\XAiDataProviderHub.cs + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using xAiModels.Constants; +using xAiModels.Models.Dtos; +using xCommons.Extensions; +using xPushService.Base; + +namespace xAiModels.Providers.Hubs +{ + public class XAiDataProviderHub : XBaseHub + { + public XAiDataProviderHub( + ILogger logger + ) : base(logger) + { } + + // + #region XAiProject ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ProjectCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ProjectRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ProjectUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiConversation ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ConversationCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ConversationRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ConversationUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiMessage ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task MessageCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task MessageRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task MessageUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Configurations\XAIServiceConfiguration.cs + +namespace xAiService.Configurations +{ + public partial class XAIServiceConfiguration + { + public string Url { get; set; } + public string XPoweredValue { get; set; } + public int DefaultClientTimeout { get; set; } = 360; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Constants\ConfigurationNodeNames.cs + +namespace xAiService.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_SERVICE_NODE = "AIServiceConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Constants\XAiApiConstants.cs + +namespace xAiService.Constants +{ + public struct XAiApiQueryParams + { + public const string Prompt = "prompt"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Constants\XAiApiEndpoint.cs + +using xExceptions.Attributes; + +namespace xAiService.Constants +{ + public enum XAiApiEndpoint + { + [StringValue("AskAI")] + Ask, + [StringValue("AskAIStream")] + Stream, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\DI\XDIHelperExtension.cs + +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using xAiService.Configurations; +using xAiService.Constants; +using xAiService.Extensions; +using xAiService.Interfaces; +using xAiService.Services; +using xCommons.Extensions; +using xExceptions.Constants; + +namespace xAiService.DI +{ + public static partial class XDIHelperExtension + { + /// + /// Extract AI Service Configuration ... + /// + /// + /// + public static XAIServiceConfiguration GetXAIServiceConfiguration(this IConfiguration source) + { + // + XAIServiceConfiguration result = null; + + // + var section = source.GetSection(ConfigurationNodeNames.AI_SERVICE_NODE); + if (!section.IsNull()) + { + result = section.Get(); + } + + // + return result; + } + + /// + /// Add AI Service Configuration ... + /// + /// + /// + public static void AddXAIServiceConfiguration( + this IServiceCollection source, + XAIServiceConfiguration configuration + ) + { + source.AddSingleton(configuration); + } + + /// + /// Adding XAiService ... + /// + /// + /// + /// + public static void AddXAIService( + this IServiceCollection services, + IConfiguration configuration, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var config = configuration.GetXAIServiceConfiguration(); + AddAIService( + services, + config, + lifeTime + ); + } + + /// + /// Adding XAiService ... + /// + /// + /// + /// + public static void AddXAIService( + this IServiceCollection services, + XAIServiceConfiguration configuration, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + AddAIService( + services, + configuration, + lifeTime + ); + } + + // + #region Private ... + /// + /// a LogTag for Service ... + /// + private static string XLogTag = "XFileService"; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Adding Ai Service ... + /// + /// + /// + /// + private static void AddAIService( + this IServiceCollection services, + XAIServiceConfiguration configuration, + ServiceLifetime lifeTime = ServiceLifetime.Singleton + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("AddAIService failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("AddAIService failed, lifetime not provided ..."); + throw exception; + } + + // + // Check Dependencies Exists ... + var isDependenciesPassed = true; + if (!isDependenciesPassed) + { + // + Log("AddAIService failed due Dependencies Issues, not provided ..."); + throw exception; + } + + // + // Validate Configurations ... + var isConfigurationExists = + !configuration.IsNull() && + configuration.IsValid(); + if (!isConfigurationExists) + { + // + Log("AddAIService failed due InValid Service Configuration or not provided ..."); + throw exception; + } + + // + // Register Configurations ... + services.AddXAIServiceConfiguration(configuration); + + // + // Register Services ... + services.Add(new ServiceDescriptor(typeof(IXAiService), typeof(XAiService), lifeTime)); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Extensions\ConfigurationExtensions.cs + +using xAiService.Configurations; +using xCommons.Extensions; + +namespace xAiService.Extensions +{ + public static class ModelExtensions + { + /// + /// Validate XAiServiceConfiguration ... + /// + /// + /// + public static bool IsValid(this XAIServiceConfiguration source) + { + // + bool result = + !source.IsNull() && + !source.Url.IsNullOrEmpty() && + source.Url.IsValidUrl(); + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Extensions\PromptExtensions.cs + +using System.Collections.Generic; +using System.Linq; +using xAiService.Models.Dtos; +using xCommons.Extensions; + +namespace xAiService.Extensions +{ + public static class PromptExtensions + { + /// + /// Get Template Params Filled Prompt ... + /// + /// + /// + /// + public static string GetMessage( + this XPromptDto source, + IDictionary @params = null + ) + { + // + var result = string.Empty; + + // + if (!source.IsNullOrDefault() && + !source.Prompt.IsNullOrEmpty() + ) + { + result = source.Prompt; + } + + // + // Check Params Conditions ... + if (!source.Params.IsNullOrDefault() && + source.Params.HasChild() && + !@params.IsNullOrDefault() && + @params.HasChild() + ) + { + // + // Select Params ... + var existsParams = source.Params + .Where(p => @params.Any(pr => pr.Key == p.Name)) + .Distinct() + .ToList(); + + // + // Replace Selected Params ... + existsParams + .ForEach(pk => + { + result = result.Replace(pk.Param, @params[pk.Name]); + }); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Helpers\VectorHelper.cs + +using System; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class VectorHelper + { + /// + /// Normalize a Vector ... + /// + /// + public static void Normalize(float[] vector) + { + // + // Validate ... + if (vector.IsNull() || !vector.HasChild()) + { + return; + } + + // + float sum = 0f; + foreach (var value in vector) + { + sum += value * value; + } + + // + float norm = MathF.Sqrt(sum); + if (norm <= 1e-9f) + { + return; + } + + // + for (int i = 0; i < vector.Length; i++) + { + vector[i] /= norm; + } + } + + /// + /// Similarity Check ... + /// + /// + /// + /// + public static float CosineSimilarity(float[] a, float[] b) + { + // + if (a.IsNull() || b.IsNull()) + { + return 0f; + } + + // + if (a.Length != b.Length) + { + return 0f; + } + + // + float dot = 0f; + float normA = 0f; + float normB = 0f; + for (int i = 0; i < a.Length; i++) + { + // + dot += a[i] * b[i]; + normA += a[i] * a[i]; + normB += b[i] * b[i]; + } + + // + float denominator = MathF.Sqrt(normA) * MathF.Sqrt(normB); + if (denominator <= 1e-9f) + { + return 0f; + } + + // + var result = dot / denominator; + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Helpers\XPromptHelper.cs + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using xAiService.Models.Dtos; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class XPromptHelper + { + /// + /// Holds Initialized Prompts ... + /// + private static XPromptsDto prompts; + + /// + /// Initialize Prompt Helper ... + /// + /// + /// + /// + public static void Initialize(string path = "prompts.json") + { + // + // Create full Path and Check File Exists ... + var fullPath = Path.Combine(AppContext.BaseDirectory, path); + if (!File.Exists(fullPath)) + { + throw new Exception($"Prompts Resources not found: {fullPath}"); + } + + // + // Read File as Json Text ... + var json = File.ReadAllText(fullPath); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip, + Converters = + { + new JsonStringEnumConverter( + namingPolicy: null, + allowIntegerValues: false + ) + } + }; + + // + // Serialized Root Object ... + var root = JsonSerializer.Deserialize(json, options); + if (!root.IsNullOrDefault()) + { + prompts = new XPromptsDto { Prompts = root.Prompts }; + } + } + + /// + /// Retrieve all Allowed Prompts as Enumerable ... + /// + /// + public static IEnumerable GetPrompts() + { + return prompts!.Prompts.AsEnumerable(); + } + + /// + /// Get Specified Prompt ... + /// + /// + /// + /// + public static XPromptDto GetPrompt(string name) + { + // + return GetPrompts() + .FirstOrDefault(p => p.Name == name); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Interfaces\IXAiService.cs + +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using xAiService.Configurations; +using xIdentityModels.Models; +using xIdentityService.Interfaces; + +namespace xAiService.Interfaces +{ + public interface IXAiService : IXBaseIdentityHttpProvider + { + /// + /// XAiService Configurations ... + /// + /// + XAIServiceConfiguration Configuration { get; } + + // + #region Text Actions ... + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public Task GetResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ); + + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public Task GetTextResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ); + + /// + /// Generate Text Response Stream ... + /// + /// + /// + /// + /// + Task GetTextReponseStreamAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Interfaces\IXAiServiceControllerBase.cs + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace xAiService.Interfaces +{ + public interface IXAiServiceControllerBase + { + Task> Ask( + [FromQuery] string prompt, + CancellationToken cancellationToken = default + ); + + Task AskStream( + [FromQuery] string prompt, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Models\Dtos\XPromptsDto.cs + +namespace xAiService.Models.Dtos +{ + /// + /// Described Prompts in app ... + /// + public class XPromptsDto + { + public XPromptDto[] Prompts { get; set; } = []; + } + + /// + /// a Single Prompt Description ... + /// + public class XPromptDto + { + /// + /// Prompt Name ... + /// + public string Name { get; set; } + + /// + /// Prompt Template Message ... + /// + public string Prompt { get; set; } + + /// + /// Prompt Description ... + /// + public string Description { get; set; } + + /// + /// Describe Prompt Params ... + /// + public virtual XPromptParamDto[] Params { get; set; } = null; + } + + /// + /// Prompt Param used to Fill dynamic Datas to Specified Prompts ... + /// + public class XPromptParamDto + { + /// + /// Param Name ... + /// + public string Name { get; set; } + + /// + /// Parma Identifier ... + /// + public string Param { get; set; } + + /// + /// Param Description ... + /// + public string Description { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Services\XAiService.cs + +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Logging; +using xAiService.Configurations; +using xAiService.Constants; +using xAiService.Interfaces; +using xCommons.Providers; +using xHttpService.Constants; +using xIdentityModels.Models; +using xIdentityService.Interfaces; +using xIdentityService.Providers; + +namespace xAiService.Services +{ + public class XAiService : XBaseIdentityHttpProvider, IXAiService + { + /// + /// XAiService Configurations ... + /// + /// + public XAIServiceConfiguration Configuration { get; } + + public XAiService( + ILogger logger, + IXTokenProvider tokenProvider, + IXIdentityProvider identityProvider, + XAIServiceConfiguration configuration, + XValidationProvider validationProvider + ) : base( + configuration.Url, + logger, + configuration.XPoweredValue, + configuration.DefaultClientTimeout, + tokenProvider, + identityProvider, + validationProvider + ) + { } + + // + #region Text Actions ... + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public Task GetResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ) + { + throw new System.NotImplementedException(); + } + + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public async Task GetTextResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + ValidationProvider.NotEmpty(prompt); + + // + var client = GetRestClient(userInfo); + var request = GetRestRequet( + endpoint: XAiApiEndpoint.Ask, + addXPoweredValue: true, + queryStrings: new Dictionary + { + { XAiApiQueryParams.Prompt, prompt } + } + ); + + // + var response = await RunRestRequest( + client, + request, + XHttpMethod.GET, + cancellationToken: cancellationToken + ); + + // + return response; + } + + /// + /// Generate Text Response Stream ... + /// + /// + /// + /// + /// + public async Task GetTextReponseStreamAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + ValidationProvider + .GroupValidationBuilder() + .AddNotEmpty(prompt) + .AddNotNull(userInfo) + .AddNotZero(userInfo.ExpiresAt) + .AddNotEmpty(userInfo.AccessToken) + .AddNotEmpty(userInfo.RefreshToken) + .ValidateGroup(); + + // + var tokens = ToTokenResponse(userInfo); + var result = await StreamData( + tokens: tokens, + addXPoweredValue: true, + endpoint: XAiApiEndpoint.Stream, + cancellationToken: cancellationToken, + queryStrings: new Dictionary + { + { XAiApiQueryParams.Prompt, prompt } + } + ); + + // + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\XAiApiConfiguration.cs + +using xAiModels.Models; +using xAiModels.Constants; + +namespace xAiModels.Configurations +{ + public class XAiApiConfiguration + { + /// + /// Model Providers ... + /// + public XAiModelDescriptor[] Models { get; set; } = []; + + /// + /// Each User must Has a Default Project, this is Title Resource Identifier ... + /// + public string DefaultProjectTitleResource { get; set; } = XAiModelsConstants.DefaultXAiProjectTitleResourceID; + + /// + /// Each User must Has a Default Project, this is Description Resource Identifier ... + /// + public string DefaultProjectDescriptionResource { get; set; } = XAiModelsConstants.DefaultXAiProjectDescriptionResourceID; + + /// + /// Each User must Has a Default Conversation, this is Title Resource Identifier ... ... + /// + public string DefaultConversationTitleResource { get; set; } = XAiModelsConstants.DefaultXAiConversationTitleResourceID; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\XAiModelMappersProfile.cs + +using AutoMapper; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Configurations +{ + public class XAiModelMappersProfile : Profile + { + public XAiModelMappersProfile() + { + // + // XAiMessage ... + CreateMap(); + + // + // XAiProject ... + CreateMap(); + + // + // XAiConversation ... + CreateMap(); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiConversationEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiConversationEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiConversationTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiMessageEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiMessageEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiMessageTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiProjectEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiProjectEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiProjectTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\ConfigurationNodeNames.cs + +namespace xAiModels.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiApiConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiChatRole.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiChatRoles + { + public const string None = "none"; + public const string User = "user"; + public const string Tool = "tool"; + public const string System = "system"; + public const string Assistant = "assistant"; + } + + public enum XAiChatRole + { + [StringValue(XAiChatRoles.None)] + None, + [StringValue(XAiChatRoles.User)] + User, + [StringValue(XAiChatRoles.Tool)] + Tool, + [StringValue(XAiChatRoles.System)] + System, + [StringValue(XAiChatRoles.Assistant)] + Assistant, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiDataProviderConstants.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiDataProviderConstants + { + public const string XDefaultAiProjectSuffix = "DefAiPrj"; + public const string XDefaultAiConversationSuffix = "DefAiCnv"; + } + + public enum XAiDataProviderHubActions + { + // + // Project ... + [StringValue("ProjectCreated")] + ProjectCreated, + + [StringValue("ProjectUpdated")] + ProjectUpdated, + + [StringValue("ProjectRemoved")] + ProjectRemoved, + + // + // Conversation ... + [StringValue("ConversationCreated")] + ConversationCreated, + + [StringValue("ConversationUpdated")] + ConversationUpdated, + + [StringValue("ConversationRemoved")] + ConversationRemoved, + + // + // Message ... + [StringValue("MessageCreated")] + MessageCreated, + + [StringValue("MessageUpdated")] + MessageUpdated, + + [StringValue("MessageRemoved")] + MessageRemoved, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiModelProviderType.cs + +namespace xAiModels.Constants +{ + /// + /// Specifiy Provider Type ... + /// + public enum XAiModelProviderType + { + None, + OpenAI, + Ollama, + DeepSeek, + HuggingFace + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiModelsConstants.cs + +namespace xAiModels.Constants +{ + public struct XAiModelsConstants + { + // + // Service Extensions Log Tag ... + public const string XAiModelsDILogTag = "XAiModels"; + + // + // Table Mapping Identifiers ... + public const string XAiMessageTable = "AiMessages"; + public const string XAiProjectTable = "AiProjects"; + public const string XAiConversationTable = "AiConversations"; + + // + // GraphQL Collection Mappings ... + public const string XAiMessageSingleName = "aiMessage"; + public const string XAiProjectSingleName = "aiProject"; + public const string XAiConversationSignleName = "aiConversation"; + + public const string XAiMessageCollectionName = "aiMessages"; + public const string XAiProjectCollectionName = "AiProjectsa"; + public const string XAiConversationCollectionName = "aiConversations"; + + // + // Hubs ... + public const string XAiMessageDtoHub = "aiMessageDto"; + public const string XAiMessageEntityHub = "aiMessageEntity"; + + public const string XAiProjectDtoHub = "aiProjectDto"; + public const string XAiProjectEntityHub = "aiProjectEntity"; + + public const string XAiConversationDtoHub = "aiConversationDto"; + public const string XAiConversationEntityHub = "aiConversationEntity"; + + // + // Resource Provider Identifiers ... + public const string XAiProjectTitleIdentifier = "AiPrjT"; + public const string XAiProjectDescriptionIdentifier = "AiPrjD"; + public const string XAiConversationTitleIdentifier = "AiCnvrT"; + + // + // EF Repositories Helper Extensions ... + public const string GetXAiMessageEFRepositoryDescriptor = "GetXAiMessageEFRepositoryDescriptor"; + public const string GetXAiProjectEFRepositoryDescriptor = "GetXAiProjectEFRepositoryDescriptor"; + public const string GetXAiConversationEFRepositoryDescriptor = "GetXAiConversationEFRepositoryDescriptor"; + + // + public const string DefaultXAiProjectTitleResourceID = "XAiPrjT"; + public const string DefaultXAiConversationTitleResourceID = "XAiCnvT"; + public const string DefaultXAiProjectDescriptionResourceID = "XAiPrjD"; + + // + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\DI\XDIHelperExtension.cs + +using System; +using xDataService.Db; +using xPushService.DI; +using xDataService.DI; +using xCommons.Helpers; +using xAiModels.Helpers; +using xDataService.Models; +using xAiModels.Providers; +using xAiModels.Constants; +using xCommons.Extensions; +using xPushService.Helpers; +using xAiModels.Interfaces; +using xExceptions.Constants; +using xDataService.Constants; +using xAiModels.Providers.Dtos; +using xAiModels.Interfaces.Dtos; +using Microsoft.AspNetCore.Builder; +using xAiModels.Providers.Entities; +using xAiModels.Interfaces.Entities; +using xAiModels.Providers.Enrichers; +using xAiModels.Interfaces.Enrichers; +using Microsoft.Extensions.DependencyInjection; + +namespace xAiModels.DI +{ + /// + /// Service Registration Extensions Classes ... + /// + public static class XDIHelperExtension + { + /// + /// Register Service ... + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + AddAiDataService( + contextType: null, + services: services, + lifeTime: lifeTime, + repositoryType: repositoryType + ); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + where TContext : XDbContext + { + AddAiDataService( + services: services, + lifeTime: lifeTime, + contextType: typeof(TContext), + repositoryType: repositoryType + ); + } + + /// + /// Use XSubCategoryService Middleware ... + /// + /// + /// + public static void UseXAiDataService( + this IApplicationBuilder app, + bool isDevelopmentEnvironment = false + ) + { + // + #region Using Hubs ... + // + var pushHelper = new XPushServiceHelper(); + + // + // XAiMessage ... + pushHelper.AddHub(XAiModelsConstants.XAiMessageDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiMessageEntityHub); + + // + // XAiProject ... + pushHelper.AddHub(XAiModelsConstants.XAiProjectDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiProjectEntityHub); + + // + // XAiConversation ... + pushHelper.AddHub(XAiModelsConstants.XAiConversationDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiConversationEntityHub); + + // + app.UseXPushService(pushHelper); + #endregion + + // + // Using XAiConversation Repository Descriptor ... + if (!aiConversationDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiConversationDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiMessage Repository Descriptor ... + if (!aiMessageDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiMessageDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiProject Repository Descriptor ... + if (!aiProjectDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiProjectDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Create an Scope for Services Acces ... + // Handle Seeding Category/SubCategory Resources ... + // TODO: Enable Seeding if Required ... + // using (var scope = app.ApplicationServices.CreateScope()) + // { + // // + // // Retrieve Configuratuions ... + // var aiMessageProvider = scope.ServiceProvider.GetService(); + // var aiProjectProvider = scope.ServiceProvider.GetService(); + // var aiConversationProvider = scope.ServiceProvider.GetService(); + // var configuration = scope.ServiceProvider.GetService(); + // if (!configuration.IsNullOrDefault() && + // !categoryProvider.IsNullOrDefault() && + // !subaiConversationDescriptor.IsNullOrDefault() + // ) + // { + // // + // // Logging ... + // Log("Start Seeding ..."); + + // // + // // Count Data in Category ... + // var hasCategory = (categoryProvider.Count().GetAwaiter().GetResult()) > 0; + // var hasSubCategory = (subCategoryProvider.Count().GetAwaiter().GetResult()) > 0; + + // // + // // Seed Category Resources ... + // var canSeed = + // !hasCategory && + // configuration.Categories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var cat in configuration.Categories) + // { + // // + // try + // { + // // + // Log($"Start Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // categoryProvider.Refresh( + // resource: cat, + // userInfo: null, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // // Seed SubCategory Resources ... + // canSeed = + // !hasSubCategory && + // configuration.SubCategories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var subcat in configuration.SubCategories) + // { + // // + // try + // { + // // + // Log($"Start Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // subCategoryProvider.Refresh( + // userInfo: null, + // resource: subcat, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // Log("Finish Seeding ..."); + // } + // } + } + + // + #region Private ... + private static XRepositoryDescriptor aiMessageDescriptor = null; + private static XRepositoryDescriptor aiProjectDescriptor = null; + private static XRepositoryDescriptor aiConversationDescriptor = null; + + /// + /// a LogTag for Service ... + /// + private static string XLogTag = XAiModelsConstants.XAiModelsDILogTag; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + private static void AddAiDataService( + IServiceCollection services, + XRepositoryType repositoryType, + Type contextType = null, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("Service Registration failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("Service Registration failed, lifetime not provided ..."); + throw exception; + } + + // + // Validate Repository Type ... + var isRepositoryTypeValid = + (repositoryType == XRepositoryType.EF && + !contextType.IsNull()) || + ((repositoryType == XRepositoryType.Mongo || + repositoryType == XRepositoryType.InMemory) && + contextType.IsNull()); + if (!isRepositoryTypeValid) + { + // + Log("Service Registration failed, Invalid Repository Type and Context Type ..."); + throw exception; + } + + // + // Maske Instance of Repository Descriptor + // Based on Provided Type ... + switch (repositoryType) + { + // + case XRepositoryType.EF: + // + // XAiMessage ... + aiMessageDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiMessageEFRepositoryDescriptor + ); + + // + // XAiProject ... + aiProjectDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiProjectEFRepositoryDescriptor + ); + + // + // XAiConversation ... + aiConversationDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiConversationEFRepositoryDescriptor + ); + break; + + // + case XRepositoryType.Mongo: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageMongoRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectMongoRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationMongoRepositoryDescriptor(); + break; + + // + case XRepositoryType.InMemory: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageInMemoryRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectInMemoryRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationInMemoryRepositoryDescriptor(); + break; + } + + // + #region Register Repository Descriptor ... + // + // XAiMessage ... + if (!aiMessageDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiMessageDescriptor + ); + } + + // + // XAiProject ... + if (!aiProjectDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiProjectDescriptor + ); + } + + // + // XAiConversation ... + if (!aiConversationDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiConversationDescriptor + ); + } + #endregion + + // + #region Register Services ... + // + #region AiMessage ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiMessageServiceProvider), typeof(XAiMessageServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryService), typeof(XAiMessageRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryProvider), typeof(XAiMessageRepositoryProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiMessageEnricher), typeof(XAiMessageEnricher), lifeTime) + ); + #endregion + + // + #region AiProject ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiProjectServiceProvider), typeof(XAiProjectServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryService), typeof(XAiProjectRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryProvider), typeof(XAiProjectRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectTitleResourceProvider), typeof(XAiProjectTitleResourceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectDescriptionResourceProvider), typeof(XAiProjectDescriptionResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectEnricher), typeof(XAiProjectEnricher), lifeTime) + ); + #endregion + + // + #region AiConversation ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiConversationServiceProvider), typeof(XAiConversationServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryService), typeof(XAiConversationRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryProvider), typeof(XAiConversationRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationTitleResourceProvider), typeof(XAiConversationTitleResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationEnricher), typeof(XAiConversationEnricher), lifeTime) + ); + #endregion + #endregion + + // + // Data Provider ... + services.Add( + new ServiceDescriptor(typeof(IXAiDataProvider), typeof(XAiDataProvider), lifeTime) + ); + + // + Log("Service Regitration Succeed ..."); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\ChatResponseExtensions.cs + +using xCommons.Extensions; +using Microsoft.Extensions.AI; + +namespace xAiModels.Extensions +{ + public static class ChatResponseExtensions + { + /// + /// Validate a Chat Response ... + /// + /// + /// + public static bool IsValid(this ChatResponse source) + { + // + var result = + source is not null && + !source.IsNullOrDefault() && + !string.IsNullOrWhiteSpace(source.Text) && + source.FinishReason == ChatFinishReason.Stop; + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\ChatRoleExtensions.cs + +using xAiModels.Constants; +using xCommons.Extensions; +using Microsoft.Extensions.AI; + +namespace xAiModels.Extensions +{ + /// + /// Extensions for ChatRole ... + /// + public static class ChatRoleExtensions + { + /// + /// Normalize an String to Propper Chat Role Value ... + /// > + /// + /// + /// + public static string GetChatRoleTitle(this string source) + { + // + var result = XAiChatRoles.None; + + // + if (source.ToNormalString() == XAiChatRoles.None.ToNormalString()) + { + result = XAiChatRoles.None; + } + else if (source.ToNormalString() == XAiChatRoles.User.ToNormalString()) + { + result = XAiChatRoles.User; + } + else if (source.ToNormalString() == XAiChatRoles.Tool.ToNormalString()) + { + result = XAiChatRoles.Tool; + } + else if (source.ToNormalString() == XAiChatRoles.System.ToNormalString()) + { + result = XAiChatRoles.System; + } + else if (source.ToNormalString() == XAiChatRoles.Assistant.ToNormalString()) + { + result = XAiChatRoles.Assistant; + } + + // + return result; + } + + /// + /// Get Chat Role Title from Chat Role Class ... + /// + /// + /// + /// + public static string GetRole(this ChatRole source) + { + // + var result = source.Value + .GetChatRoleTitle(); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this string source) + { + // + var role = source.GetChatRoleTitle(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this XAiChatRole source) + { + // + var role = source.GetStringValue(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Extract Chat Role Enum from Chat Role ... + /// + /// + /// + /// + /// + public static XAiChatRole ToChatRole(this ChatRole source) + { + // + var role = source + .GetRole() + .GetChatRoleTitle(); + + // + XAiChatRole result = XAiChatRole.User; + + // + if (role == XAiChatRoles.User) + { + result = XAiChatRole.User; + } + else if (role == XAiChatRoles.Tool) + { + result = XAiChatRole.Tool; + } + else if (role == XAiChatRoles.System) + { + result = XAiChatRole.System; + } + else if (role == XAiChatRoles.Assistant) + { + result = XAiChatRole.Assistant; + } + + // + return result; + } + + /// + /// Validate an String as Chat Role ... + /// + /// + /// + public static bool IsValid(this string source) + { + // + var result = + source != XAiChatRoles.None && + source.ToNormalString() != XAiChatRoles.None.ToNormalString(); + + // + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this XAiChatRole source) + { + // + var result = source != XAiChatRole.None; + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this ChatRole source) + { + // + var role = source.ToChatRole(); + var result = role.IsValid(); + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\XAiApiConfigurationExtensions.cs + +using System.Linq; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Configurations; + +namespace xAiModels.Extensions +{ + public static class XAiApiConfigurationExtensions + { + /// + /// Validate Api Configuration ... + /// + /// + /// + public static bool IsValid(this XAiApiConfiguration source) + { + return + !source.IsNullOrDefault() && + source.Models.HasChild(); + } + + /// + /// Retrieve Default Model Descriptor ... + /// + /// + /// + public static XAiModelDescriptor GetDefaultModel(this XAiApiConfiguration source) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + result = source.Models.First(); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\XAiModelsExtensions.cs + +using System.Linq; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Extensions +{ + /// + /// Extensions Methods for XAiModels ... + /// + public static class XAiModelsExtensions + { + /// + /// Validate a Project for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiProject source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiProjectDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Conversation for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiConversation source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiConversationDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + + /// + /// Validate a Message for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiMessage source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiMessageDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Model Descriptor ... + /// + /// + /// + public static bool IsValid(this XAiModelDescriptor source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Url.IsNullOrEmpty() && + source.Url.IsValidUrl() && + !source.LLM.IsNullOrEmpty() && + source.Provider != Constants.XAiModelProviderType.None; + + // + return result; + } + + /// + /// Validate Specified Param ... + /// + /// + /// + public static bool IsValid(this XAiPromptParam source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Param.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate Specified Prompt ... + /// + /// + /// + public static bool IsValid(this XAiPromptDescriptor source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Template.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + if (source.Params.HasChild()) + { + result = + result && + source.Params.All(x => x.IsValid()); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Helpers\XAiModelsHelper.cs + +using System; +using GraphQL.Types; +using xDataService.Db; +using xDataService.Models; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Providers.GraphQL; +using xAiModels.Providers.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Helpers +{ + public static class XAiModelsHelper + { + // + #region XAiConversation ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + > GetXAiConversationMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + > GetXAiConversationInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiMessage ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + > GetXAiMessageMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + > GetXAiMessageInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiProject ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + > GetXAiProjectMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + > GetXAiProjectInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiConversationTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiConversationTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiDataProvider.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace xAiModels.Interfaces +{ + /// + /// All Data Manipulation Requirements ... + /// + public interface IXAiDataProvider + { + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Creator/Adders ... + /// + /// Create Project ... + /// + /// + /// + /// + /// + /// + Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Create Conversation ... + /// + /// + /// + /// + /// + /// + Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Message ... + /// + /// + /// + /// + /// + /// + Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiProjectDescriptionResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectDescriptionResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiProjectTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiConversationEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + /// + /// Ai Conversation Enricher ... + /// + public interface IXAiConversationEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiMessageEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiMessageEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiProjectEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiProjectEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiDocumentEntityHub.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiDocumentEntityHub + { + + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\XAiModelDescriptor.cs + +using xAiModels.Constants; + +namespace xAiModels.Models +{ + /// + /// Describe a Provided Model ... + /// + public class XAiModelDescriptor + { + /// + /// Provider Name ... + /// + public string Name { get; set; } + + /// + /// LLM Provider Url ... + /// + public string Url { get; set; } + + /// + /// Model Name ... + /// + public string LLM { get; set; } + + /// + /// Api Key for Connection ... + /// + public string ApiKey { get; set; } + + /// + /// Specified Model Provider Type ... + /// + public XAiModelProviderType Provider { get; set; } = XAiModelProviderType.Ollama; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\XAiPromptDescriptor.cs + +namespace xAiModels.Models +{ + /// + /// Describe Specified Prompt ... + /// + public class XAiPromptDescriptor + { + /// + /// Prompt Name ... + /// + public string Name { get; set; } + + /// + /// Prompt Template ... + /// + public string Template { get; set; } + + /// + /// Prompt Description ... + /// + public string Description { get; set; } + + /// + /// Prompt Template Params ... + /// + public XAiPromptParam[] Params { get; set; } = []; + } + + /// + /// Specified a Prompt Param ... + /// + public class XAiPromptParam + { + /// + /// Param Name ... + /// + public string Name { get; set; } + + /// + /// Param Identifier ... + /// + public string Param { get; set; } + + /// + /// Parma Description ... + /// + public string Description { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiConversationDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using System.Collections.Generic; + +namespace xAiModels.Models.Dtos +{ + /// + /// Conversation Describe ... + /// + public class XAiConversationDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Conversation Title Resource ID ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Messages ... + /// + public virtual IEnumerable Messages { get; set; } = []; + + /// + /// Project ID ... + /// + public Guid ProjectId { get; set; } + + /// + /// Project Title Resource ID ... + /// + public virtual string ProjectTitle { get; set; } = null; + + /// + /// Project Description Resource ID ... + /// + public virtual string ProjectDescription { get; set; } = null; + + /// + /// Project Title Locale Resources ... + /// + public virtual XResourceDto ProjectTitleResource { get; set; } + + /// + /// Project Description Locale Resources ... + /// + public virtual XResourceDto ProjectDescriptionResource { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiMessageDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using xAiModels.Constants; +using xCommons.Extensions; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace xAiModels.Models.Dtos +{ + public class XAiMessageDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Message of Chat ... + /// + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + public Guid ConversationId { get; set; } + + /// + /// Conversation Info ... + /// + public virtual string ConversationTitle { get; set; } = null; + public virtual XResourceDto ConversationTitleResouce { get; set; } = null; + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MetaDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiProjectDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using System.Collections.Generic; + +namespace xAiModels.Models.Dtos +{ + /// + /// Describe a Project ... + /// + public class XAiProjectDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Title of Project ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Description of Project ... + /// + public string Description { get; set; } + + /// + /// All Exists Description Locale Resources ... + /// + public virtual XResourceDto DescriptionResource { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversations ... + /// + public virtual IList Conversations { get; set; } = []; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiConversation.cs + +using System; +using xModels.Base; +using System.ComponentModel.DataAnnotations; + +namespace xAiModels.Models.Entities +{ + /// + /// Conversation Describe ... + /// + public class XAiConversation : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Conversation ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Project ID ... + /// + [Required] + public Guid ProjectId { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiDocument.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Represents an embedd document in the AI system. + /// + public class XAiDocument : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Document ... + /// + [StringLength(255)] + public string Title { get; set; } + + /// + /// Content of Document ... + /// + public string Content { get; set; } + + /// + /// Hash of the Document Content ... + /// + public string ContentHash { get; set; } = string.Empty; + + /// + /// Embedding Model Identifier ... + /// + public string EmbeddingModel { get; set; } = string.Empty; + + /// + /// Dimensions of the Embedding ... + /// + public int Dimensions { get; set; } + + /// + /// Vector representation of the Document ... + /// + public byte[] Vector { get; set; } = []; + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiMessage.cs + +using System; +using xModels.Base; +using xAiModels.Constants; +using xCommons.Extensions; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace xAiModels.Models.Entities +{ + /// + /// Message Model of Ai ... + /// + public class XAiMessage : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Message of Chat ... + /// + [Required] + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + [StringLength(255)] + public Guid ConversationId { get; set; } + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MetaDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiProject.cs + +using System; +using xModels.Base; +using System.ComponentModel.DataAnnotations; + +namespace xAiModels.Models.Entities +{ + /// + /// Describe a Project ... + /// + public class XAiProject : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Project ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Description of Project ... + /// + [StringLength(1000)] + public string Description { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiConversationEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiConversationEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiConversationEntityRegisterar() + : base(nameof(XAiConversationEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiConversationEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiConversationTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiConversationTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiConversationTitleResourceProvider + { + public XAiConversationTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiConversationTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiDataProvider.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xAiModels.Constants; +using xCommons.Extensions; +using xAiModels.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using xExceptions.Constants; +using System.Threading.Tasks; +using xCommons.Configurations; +using xAiModels.Providers.Hubs; +using xAiModels.Interfaces.Dtos; +using xStringService.Interfaces; +using System.Collections.Generic; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers +{ + /// + /// All Data Manipulation Requirements ... + /// + public class XAiDataProvider : IXAiDataProvider + { + // + #region Properties ... + private readonly IXStringProvider stringProvider; + private readonly XAppConfiguration appConfiguration; + private readonly IHubContext hub; + private readonly IXAiMessageRepositoryService messageRepositoryService; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + #endregion + + public XAiDataProvider( + IXStringProvider stringProvider, + XAppConfiguration appConfiguration, + IHubContext hub, + IXAiMessageRepositoryService messageRepositoryService, + IXAiProjectRepositoryService projectRepositoryService, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationRepositoryService conversationRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + this.hub = hub; + this.stringProvider = stringProvider; + this.appConfiguration = appConfiguration; + this.messageRepositoryService = messageRepositoryService; + this.projectRepositoryService = projectRepositoryService; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationRepositoryService = conversationRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + public async Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Default Project and Conversation ... + bool hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (!hasDefault) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: null, + cancellationToken: cancellationToken + ); + } + + // + // Retrieve Project List ... + var result = await projectRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: fillConversations, + predicate: x => x.OwnerId == ownerId, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + // fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + public async Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Conversation's List ... + var result = await conversationRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: false, + // fillMessages: fillMessages, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == projectId, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + return result; + } + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + public async Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Message Lists of Specified Conversation ... + var result = await messageRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversationId + ); + + // + return result; + } + #endregion + + // + #region Creator/Adders ... + public async Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Project Provided or not ... + var hasProject = !item.IsNullOrDefault(); + + // + // Normalize Provided Project ... + if (hasProject) + { + // + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiProjectDto result = null; + + // + // Create Provided Project ... + if (hasProject) + { + // + result = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + // + // Check Default Project ... + else + { + // + // Check Default Project Exists or not ... + var hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Project ... + result = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Proejct ... + XAiProjectDto project = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Conversation Provided or not ... + var hasConversation = !item.IsNullOrDefault(); + + // + // Normalize Conversation if Provided ... + if (hasConversation) + { + // + item.ProjectId = project.Id; + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiConversationDto result = null; + + // + // Create Provided Conversation ... + if (hasConversation) + { + // + result = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + // fillMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + // + // Check Default Conversation ... + else + { + // + // Check Default Conversation Exists or not ... + var hasDefault = await HasDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Conversation ... + result = await GetDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (item.IsNullOrDefault() || + conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + item.CreatedOn = DateTime.UtcNow; + item.ConversationId = conversationId; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + + // + var result = await messageRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.MessageCreated.GetStringValue() + ); + } + + // + return result; + } + #endregion + + // + #region Updaters ... + #endregion + + // + #region Private ... + /// + /// Check Default Project Exists or not ... + /// + /// + /// + /// + /// + private async Task HasDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Default Owner Exists or not ... + result = !(await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + )) + .IsNullOrDefault(); + return result; + } + + /// + /// Retrieve Default Project of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + private async Task GetDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Default Project Exists or noit ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var result = await projectRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Create Default Project for Specified Owner ... + /// + /// + /// + /// + /// + private async Task CreateDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + if (ownerId.IsNullOrEmpty()) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Check Default Owner Exists or not ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (isExists) + { + return; + } + + // + // Create Default ... + var item = new XAiProjectDto() + { + OwnerId = ownerId, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString(), + Description = Guid.NewGuid().ToString(), + }; + item = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Tile and Description Resource Ids ... + var titleResource = await projectTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + var descriptionResource = await projectDescriptionResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault() || + descriptionResource.IsNullOrDefault() + ) + { + return; + } + + // + // Update Project Resources ... + item.Title = titleResource.Resource; + item.Description = descriptionResource.Resource; + item = await projectRepositoryService.UpdateAsync( + id: item.Id, + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task HasDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiConversationTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiConversationSuffix) + ); + result = !resource.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + result = !(await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => + x.ProjectId == projectId && + x.Title == resource.ResourceTitle + )) + .IsNullOrDefault(); + + // + return result; + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task CreateDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var isValid = !ownerId.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + isValid = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + cancellationToken: cancellationToken + ); + if (isValid) + { + return; + } + + // + // Create Default Conversation ... + var item = new XAiConversationDto + { + OwnerId = ownerId, + ProjectId = project.Id, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString() + }; + item = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Title Resource Ids ... + var titleResource = await conversationTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiConversationSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault()) + { + return; + } + + // + // Update Conversation Resources ... + item.Title = titleResource.Resource; + item = await conversationRepositoryService.UpdateAsync( + item: item, + id: item.Id, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + + /// + /// Retrieve Default Conversation of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + /// + private async Task GetDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Conversation Exists or noit ... + var isExists = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Detect Conversation Resource ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Find Default Conversation ... + var result = await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) && + x.ProjectId == project.Id + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Normalize and Validate Language ... + /// + /// + /// + private string NormalizeAndValidateLanguage(string language) + { + // + if (language.IsNullOrEmpty()) + { + language = appConfiguration.DefaultLanguage; + } + + // + if (language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + return language; + } + + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + public async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Collect Allowed Actions ... + var actions = new List + { + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + }; + + // + // Validate Args ... + var isValid = + !action.IsNullOrEmpty() && + actions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve Connection Id ... + var clients = hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = hub.Clients.AllExcept(connectionId); + } + + // + await clients.SendAsync( + action, + payLoad, + connectionId, + cancellationToken + ); + } + catch { } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiMessageEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiMessageEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiMessageEntityRegisterar() + : base(nameof(XAiMessageEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiMessageEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectDescriptionResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiProjectDescriptionResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectDescriptionResourceProvider + { + public XAiProjectDescriptionResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectDescriptionIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiProjectEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiProjectEntityRegisterar() + : base(nameof(XAiProjectEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiProjectEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiProjectTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectTitleResourceProvider + { + public XAiProjectTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationDtoHub : XBaseDtoHub, IXAiConversationDtoHub + { + public XAiConversationDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationRepositoryService : XBaseRepositoryService, IXAiConversationRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepository repository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiConversationRepositoryService( + IXIdentityProvider identityProvider, + IXAiConversationRepository repository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.repository = repository; + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title Resource ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + XResourceDto projectTitleResource = null; + XResourceDto projectDescriptionResource = null; + if (!source.ProjectId.IsDefaultGuid()) + { + // + projectTitleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + + // + projectDescriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.ProjectTitleResource)] = projectTitleResource; + options.Items[nameof(source.ProjectDescriptionResource)] = projectDescriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationServiceProvider : XBaseDtoProvider, IXAiConversationServiceProvider + { + public XAiConversationServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiConversationRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageDtoHub : XBaseDtoHub, IXAiMessageDtoHub + { + public XAiMessageDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageRepositoryService : XBaseRepositoryService, IXAiMessageRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiMessageRepositoryService( + IXAiMessageRepository repository, + IXIdentityProvider identityProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.identityProvider = identityProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Conversation Title ... + string conversationTitle = string.Empty; + XResourceDto conversationTitleResource = null; + if (!source.ConversationId.IsDefaultGuid()) + { + // + conversationTitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ConversationId, + cancellationToken: cancellationToken + ); + if (!conversationTitleResource.IsNullOrDefault()) + { + conversationTitle = conversationTitleResource.Resource; + } + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.ConversationTitle)] = conversationTitle; + options.Items[nameof(source.ConversationTitleResouce)] = conversationTitleResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageServiceProvider : XBaseDtoProvider, IXAiMessageServiceProvider + { + public XAiMessageServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiMessageRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectDtoHub : XBaseDtoHub, IXAiProjectDtoHub + { + public XAiProjectDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectRepositoryService : XBaseRepositoryService, IXAiProjectRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiMessageRepository messageRepository; + private readonly IXAiConversationRepository conversationRepository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectRepositoryService( + IXAiProjectRepository repository, + IXIdentityProvider identityProvider, + IXAiMessageRepository messageRepository, + IXAiConversationRepository conversationRepository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + // + this.identityProvider = identityProvider; + this.messageRepository = messageRepository; + this.conversationRepository = conversationRepository; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Description ... + XResourceDto descriptionResource = null; + if (!source.Description.IsNullOrEmpty()) + { + // + descriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Conversations ... + IEnumerable conversations = []; + if (fillConversations) + { + // + // Reading Entities ... + var entitiies = await conversationRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == source.Id, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + // Converts to Dto Enumerable ... + conversations = entitiies + .MapConvert(); + + // + // Handle Conversation Enrichment ... + foreach (var conversation in conversations) + { + // + // Handle Owner ... + if (!conversation.OwnerId.IsNullOrEmpty()) + { + conversation.Owner = owner; + } + + // + // Handle Title Resource ... + if (!conversation.Title.IsNullOrEmpty()) + { + // + conversation.TitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: conversation.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + if (!conversation.ProjectId.IsDefaultGuid()) + { + conversation.ProjectTitle = source.Title; + conversation.ProjectTitleResource = titleResource; + conversation.ProjectDescription = source.Description; + conversation.ProjectDescriptionResource = descriptionResource; + } + } + + // + // Handle Fill Messages ... + if (fillConversationMessages) + { + // + foreach (var conversation in conversations) + { + // + IEnumerable messages = []; + + // + // Retrieve Message Entities ... + var messageEntities = await messageRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversation.Id + ); + if (messageEntities.HasChild()) + { + // + // Converts to Message ... + messages = messageEntities + .MapConvert(); + + // + // Ennrich Messages ... + foreach (var message in messages) + { + // + // Handle Owner ... + if (!message.OwnerId.IsNullOrEmpty()) + { + message.Owner = owner; + } + + // + // Handle Conversation ... + if (!message.ConversationId.IsDefaultGuid()) + { + message.ConversationTitle = conversation.Title; + message.ConversationTitleResouce = conversation.TitleResource; + } + } + } + + // + conversation.Messages = [.. messages]; + } + } + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.Conversations)] = conversations; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.DescriptionResource)] = descriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectServiceProvider : XBaseDtoProvider, IXAiProjectServiceProvider + { + public XAiProjectServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiProjectRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiConversationEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiConversationEnricher : IXAiConversationEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepository repository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiConversationEnricher( + IXIdentityProvider identityProvider, + IXAiConversationRepository repository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + // + this.repository = repository; + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title Resource ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + XResourceDto projectTitleResource = null; + XResourceDto projectDescriptionResource = null; + if (!source.ProjectId.IsDefaultGuid()) + { + // + projectTitleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + + // + projectDescriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.TitleResource = titleResource; + result.ProjectTitleResource = projectTitleResource; + result.ProjectDescriptionResource = projectDescriptionResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiMessageEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiMessageEnricher : IXAiMessageEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiMessageEnricher( + IXIdentityProvider identityProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) + { + this.identityProvider = identityProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Conversation Title ... + string conversationTitle = string.Empty; + XResourceDto conversationTitleResource = null; + if (!source.ConversationId.IsDefaultGuid()) + { + // + conversationTitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ConversationId, + cancellationToken: cancellationToken + ); + if (!conversationTitleResource.IsNullOrDefault()) + { + conversationTitle = conversationTitleResource.Resource; + } + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.ConversationTitle = conversationTitle; + result.ConversationTitleResouce = conversationTitleResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiProjectEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiProjectEnricher : IXAiProjectEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiMessageRepository messageRepository; + private readonly IXAiConversationRepository conversationRepository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectEnricher( + IXIdentityProvider identityProvider, + IXAiMessageRepository messageRepository, + IXAiConversationRepository conversationRepository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + // + this.identityProvider = identityProvider; + this.messageRepository = messageRepository; + this.conversationRepository = conversationRepository; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Description ... + XResourceDto descriptionResource = null; + if (!source.Description.IsNullOrEmpty()) + { + // + descriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Conversations ... + IEnumerable conversations = []; + if (fillConversations) + { + // + // Reading Entities ... + var entitiies = await conversationRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == source.Id, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + // Converts to Dto Enumerable ... + conversations = entitiies + .MapConvert(); + + // + // Handle Conversation Enrichment ... + foreach (var conversation in conversations) + { + // + // Handle Owner ... + if (!conversation.OwnerId.IsNullOrEmpty()) + { + conversation.Owner = owner; + } + + // + // Handle Title Resource ... + if (!conversation.Title.IsNullOrEmpty()) + { + // + conversation.TitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: conversation.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + if (!conversation.ProjectId.IsDefaultGuid()) + { + conversation.ProjectTitle = source.Title; + conversation.ProjectTitleResource = titleResource; + conversation.ProjectDescription = source.Description; + conversation.ProjectDescriptionResource = descriptionResource; + } + } + + // + // Handle Fill Messages ... + if (fillConversationMessages) + { + // + foreach (var conversation in conversations) + { + // + IEnumerable messages = []; + + // + // Retrieve Message Entities ... + var messageEntities = await messageRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversation.Id + ); + if (messageEntities.HasChild()) + { + // + // Converts to Message ... + messages = messageEntities + .MapConvert(); + + // + // Ennrich Messages ... + foreach (var message in messages) + { + // + // Handle Owner ... + if (!message.OwnerId.IsNullOrEmpty()) + { + message.Owner = owner; + } + + // + // Handle Conversation ... + if (!message.ConversationId.IsDefaultGuid()) + { + message.ConversationTitle = conversation.Title; + message.ConversationTitleResouce = conversation.TitleResource; + } + } + } + + // + conversation.Messages = [.. messages]; + } + } + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.TitleResource = titleResource; + result.Conversations = [.. conversations]; + result.DescriptionResource = descriptionResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEFRepository : XBaseEFRepository, IXAiConversationRepository + where TContext : XDbContext + { + public XAiConversationEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEntityHub : XBaseEntityHub, IXAiConversationEntityHub + { + public XAiConversationEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationInMemoryRepository : XBaseInMemoryRepository, IXAiConversationRepository + { + public XAiConversationInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationKeyGenerator : XGuidKeyGenerator, IXAiConversationKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationMongoRepository : XBaseMongoRepository, IXAiConversationRepository + { + public XAiConversationMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryEvents : XBaseRepositoryEvents, IXAiConversationRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryProvider : XBaseEntityProvider, IXAiConversationRepositoryProvider + { + public XAiConversationRepositoryProvider( + IHubContext hub, + IXAiConversationRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiConversationSeederBase : XBaseDbSeeder, IXAiConversationSeeder + { + protected XAiConversationSeederBase( + string entity, + string database, + IXAiConversationRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEFRepository : XBaseEFRepository, IXAiMessageRepository + where TContext : XDbContext + { + public XAiMessageEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEntityHub : XBaseEntityHub, IXAiMessageEntityHub + { + public XAiMessageEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageInMemoryRepository : XBaseInMemoryRepository, IXAiMessageRepository + { + public XAiMessageInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageKeyGenerator : XGuidKeyGenerator, IXAiMessageKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageMongoRepository : XBaseMongoRepository, IXAiMessageRepository + { + public XAiMessageMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryEvents : XBaseRepositoryEvents, IXAiMessageRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryProvider : XBaseEntityProvider, IXAiMessageRepositoryProvider + { + public XAiMessageRepositoryProvider( + IHubContext hub, + IXAiMessageRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiMessageSeederBase : XBaseDbSeeder, IXAiMessageSeeder + { + protected XAiMessageSeederBase( + string entity, + string database, + IXAiMessageRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEFRepository : XBaseEFRepository, IXAiProjectRepository + where TContext : XDbContext + { + public XAiProjectEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEntityHub : XBaseEntityHub, IXAiProjectEntityHub + { + public XAiProjectEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectInMemoryRepository : XBaseInMemoryRepository, IXAiProjectRepository + { + public XAiProjectInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectKeyGenerator : XGuidKeyGenerator, IXAiProjectKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectMongoRepository : XBaseMongoRepository, IXAiProjectRepository + { + public XAiProjectMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryEvents : XBaseRepositoryEvents, IXAiProjectRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryProvider : XBaseEntityProvider, IXAiProjectRepositoryProvider + { + public XAiProjectRepositoryProvider( + IHubContext hub, + IXAiProjectRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiProjectSeederBase : XBaseDbSeeder, IXAiProjectSeeder + { + protected XAiProjectSeederBase( + string entity, + string database, + IXAiProjectRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiConversationGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiConversationCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiConversationSignleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQuery : XBaseGraphQLQuery + { + public XAiConversationGraphQuery( + XDataServiceConfiguration configuration, + IXAiConversationRepository repository, + IXAiConversationGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphSchema : Schema + { + public XAiConversationGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiConversationGraphQuery)services.GetService(typeof(XAiConversationGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphType : XBaseGraphObjectType + { + public XAiConversationGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ProjectId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiMessageGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiMessageCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiMessageSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQuery : XBaseGraphQLQuery + { + public XAiMessageGraphQuery( + XDataServiceConfiguration configuration, + IXAiMessageRepository repository, + IXAiMessageGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphSchema : Schema + { + public XAiMessageGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiMessageGraphQuery)services.GetService(typeof(XAiMessageGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphType: XBaseGraphObjectType + { + public XAiMessageGraphType() : base() + { + Field(x => x.Role); + Field(x => x.OwnerId); + Field(x => x.Content); + Field(x => x.Metadata); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ConversationId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiProjectGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiProjectCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiProjectSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQuery : XBaseGraphQLQuery + { + public XAiProjectGraphQuery( + XDataServiceConfiguration configuration, + IXAiProjectRepository repository, + IXAiProjectGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphSchema : Schema + { + public XAiProjectGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiProjectGraphQuery)services.GetService(typeof(XAiProjectGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphType : XBaseGraphObjectType + { + public XAiProjectGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.Prompt); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.Description); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Hubs\XAiDataProviderHub.cs + +using System.Threading; +using xPushService.Base; +using xAiModels.Constants; +using xCommons.Extensions; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Hubs +{ + public class XAiDataProviderHub : XBaseHub + { + public XAiDataProviderHub( + ILogger logger + ) : base(logger) + { } + + // + #region XAiProject ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ProjectCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ProjectRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ProjectUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiConversation ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ConversationCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ConversationRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ConversationUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiMessage ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task MessageCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task MessageRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task MessageUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\Constants\ConfigurationNodeNames.cs + +namespace xAiService.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_SERVICE_NODE = "AIServiceConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\DI\XDIHelperExtension.cs + +namespace xAiService.DI +{ + public static partial class XDIHelperExtension + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\Helpers\VectorHelper.cs + +using System; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class VectorHelper + { + /// + /// Normalize a Vector ... + /// + /// + public static void Normalize(float[] vector) + { + // + // Validate ... + if (vector.IsNull() || !vector.HasChild()) + { + return; + } + + // + float sum = 0f; + foreach (var value in vector) + { + sum += value * value; + } + + // + float norm = MathF.Sqrt(sum); + if (norm <= 1e-9f) + { + return; + } + + // + for (int i = 0; i < vector.Length; i++) + { + vector[i] /= norm; + } + } + + /// + /// Similarity Check ... + /// + /// + /// + /// + public static float CosineSimilarity(float[] a, float[] b) + { + // + if (a.IsNull() || b.IsNull()) + { + return 0f; + } + + // + if (a.Length != b.Length) + { + return 0f; + } + + // + float dot = 0f; + float normA = 0f; + float normB = 0f; + for (int i = 0; i < a.Length; i++) + { + // + dot += a[i] * b[i]; + normA += a[i] * a[i]; + normB += b[i] * b[i]; + } + + // + float denominator = MathF.Sqrt(normA) * MathF.Sqrt(normB); + if (denominator <= 1e-9f) + { + return 0f; + } + + // + var result = dot / denominator; + return result; + } + } +} diff --git a/Documents/GeneratedContext/xDashboard-xSaherelmWorkspace-20260926_085140.txt b/Documents/GeneratedContext/xDashboard-xSaherelmWorkspace-20260926_085140.txt new file mode 100644 index 0000000..85dac1e --- /dev/null +++ b/Documents/GeneratedContext/xDashboard-xSaherelmWorkspace-20260926_085140.txt @@ -0,0 +1,44469 @@ + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Codes\XContentRepositoryService.cs + +using System; +using AutoMapper; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xDataService.Providers; +using System.Threading.Tasks; +using System.Collections.Generic; +using xContentService.Interfaces; +using xContentService.Models.Dtos; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xContentService.Interfaces.Dtos; +using xContentService.Models.Entities; +using xContentService.Interfaces.Entities; + +namespace xContentService.Providers.Dtos +{ + public class XContentRepositoryService : XBaseRepositoryService, IXContentRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXContentTitleResourceProvider titleResourceProvider; + private readonly IXContentDescriptionResourceProvider descriptionResourceProvider; + + public XContentRepositoryService( + IXContentRepository repository, + IXIdentityProvider identityProvider, + IXContentTitleResourceProvider titleResourceProvider, + IXContentDescriptionResourceProvider descriptionResourceProvider, + IEnumerable mapperProfiles = null + ) : base( + repository, + mapperProfiles + ) + { + this.identityProvider = identityProvider; + this.titleResourceProvider = titleResourceProvider; + this.descriptionResourceProvider = descriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public async Task Enrich( + XContent source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public async Task Enrich( + XContentDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Content Title ... + string contentTitle = string.Empty; + XResourceDto titleResource = await titleResourceProvider.GetResource( + identifier: source.Id, + cancellationToken: cancellationToken + ); + if (!titleResource.IsNullOrDefault()) + { + contentTitle = titleResource.Resource; + } + + // + // Hanlde Content Description ... + string contentDescription = string.Empty; + XResourceDto descriptionResource = await descriptionResourceProvider.GetResource( + identifier: source.Id, + cancellationToken: cancellationToken + ); + if (!descriptionResource.IsNullOrDefault()) + { + contentDescription = descriptionResource.Resource; + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.Title)] = contentTitle; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.Description)] = contentDescription; + options.Items[nameof(source.DescriptionResource)] = descriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Markdown\AppexChartOptionsDocumentation.html + + + + + + + مستند جامع تحلیل ApexOptions در ApexCharts + + + + + + + +
+ +
+
+

مستند جامع تحلیل ApexOptions در ApexCharts

+

📅 تاریخ تهیه: دوشنبه ۱۱ شهریور ۱۴۰۴

+

📌 موضوع: بررسی تفصیلی فیلدهای ApexOptions

+
+
+ شرکت فن آوران ساحر علم
+ https://saherelm.ir
+ توسعه‌دهنده: هادی خزاعی اصل +
+
+ + +

۱. مقدمه

+

+ مدل ApexOptions قلب تپنده کتابخانه ApexCharts است و تمام تنظیمات نمودار را در بر می‌گیرد. این مدل شامل ۲۵ فیلد اصلی است که هر کدام بخش خاصی از نمودار را کنترل می‌کنند. در این سند، هر فیلد به همراه زیرفیلدها، توضیحات و مثال‌های کاربردی بررسی شده است. +

+ +
+ 📌 نکته: تمام فیلدها اختیاری هستند و در صورت عدم تعریف، از مقادیر پیش‌فرض ApexCharts استفاده می‌شود. +
+ + +

۲. جدول کلی فیلدهای ApexOptions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفنام فیلدتوضیح
۱annotationsحاشیه‌نویسی‌ها (خطوط، نقاط، متن‌ها)
۲chartتنظیمات اصلی نمودار (نوع، ابعاد، انیمیشن)
۳colorsرنگ‌های سری‌های داده
۴dataLabelsبرچسب‌های داده روی نقاط
۵drilldownناوبری عمیق (Drilldown)
۶fillپرکننده (رنگ، گرادیانت، الگو)
۷forecastDataPointsنقاط داده پیش‌بینی
۸gridشبکه‌بندی نمودار
۹labelsبرچسب‌های نمودار
۱۰legendراهنمای نمودار
۱۱markersنشانگرهای نقاط
۱۲noDataپیام عدم وجود داده
۱۳pluginsافزونه‌ها (Weave)
۱۴plotOptionsگزینه‌های خاص هر نوع نمودار
۱۵responsiveتنظیمات واکنش‌گرا
۱۶seriesسری‌های داده
۱۷statesحالت‌های مختلف (hover, active)
۱۸strokeخطوط نمودار
۱۹subtitleزیرعنوان
۲۰themeتم (روشن/تاریک)
۲۱titleعنوان نمودار
۲۲tooltipTooltip (راهنمای شناور)
۲۳xaxisمحور X
۲۴yaxisمحور Y
+ + +

۳. بررسی تفصیلی فیلدها

+ + +

۳.۱. فیلد annotations - حاشیه‌نویسی‌ها

+

این فیلد برای اضافه کردن حاشیه‌نویسی‌های سفارشی (خطوط، نقاط، متن‌ها) به نمودار استفاده می‌شود.

+ +

زیرفیلدها:

+
    +
  • xaxis: حاشیه‌نویسی‌های محور X (خطوط عمودی)
  • +
  • yaxis: حاشیه‌نویسی‌های محور Y (خطوط افقی)
  • +
  • points: حاشیه‌نویسی‌های نقطه‌ای
  • +
  • texts: متن‌های سفارشی
  • +
  • images: تصاویر سفارشی
  • +
+ +

ساختار XAxisAnnotations:

+
xaxis?: [
+  {
+    id?: number | string;
+    x?: null | number | string;
+    x2?: null | number | string;
+    strokeDashArray?: number;
+    fillColor?: string;
+    borderColor?: string;
+    borderWidth?: number;
+    opacity?: number;
+    offsetX?: number;
+    offsetY?: number;
+    label?: {
+      text?: string | string[];
+      textAnchor?: string;
+      offsetX?: number;
+      offsetY?: number;
+      style?: {
+        background?: string;
+        color?: string;
+        fontSize?: string;
+        fontFamily?: string;
+        fontWeight?: string | number;
+        padding?: { left?: number; right?: number; top?: number; bottom?: number; };
+      };
+    };
+  }
+]
+ +

مثال کاربردی:

+
annotations: {
+  xaxis: [{
+    x: new Date('2024-06-01').getTime(),
+    borderColor: '#FF0000',
+    label: {
+      borderColor: '#FF0000',
+      style: { color: '#fff', background: '#FF0000' },
+      text: 'تاریخ مهم'
+    }
+  }],
+  yaxis: [{
+    y: 50,
+    borderColor: '#00FF00',
+    label: { text: 'خط هدف', style: { color: '#00FF00' } }
+  }],
+  points: [{
+    x: 'فروردین',
+    y: 50,
+    marker: { size: 8, fillColor: '#FF0000' },
+    label: { text: 'نقطه مهم' }
+  }]
+}
+ + +

۳.۲. فیلد chart - تنظیمات اصلی نمودار

+

این فیلد مهم‌ترین بخش تنظیمات است و رفتار کلی نمودار را کنترل می‌کند.

+ +

زیرفیلدهای اصلی:

+
    +
  • width: عرض نمودار (عدد یا درصد)
  • +
  • height: ارتفاع نمودار (عدد یا درصد)
  • +
  • type: نوع نمودار (line, area, bar, pie, donut, radialBar, scatter, bubble, heatmap, candlestick, boxPlot, violin, histogram, radar, polarArea, rangeBar, rangeArea, treemap, waffle, sunburst, funnel, pyramid, gauge)
  • +
  • foreColor: رنگ متن پیش‌زمینه
  • +
  • fontFamily: فونت متن
  • +
  • background: رنگ پس‌زمینه
  • +
  • animations: تنظیمات انیمیشن
  • +
  • events: رویدادهای نمودار
  • +
  • toolbar: نوار ابزار
  • +
  • zoom: تنظیمات زوم
  • +
  • selection: تنظیمات انتخاب
  • +
  • stacked: نمودار پشته‌ای
  • +
  • stackType: نوع پشته (normal, 100%)
  • +
+ +

ساختار chart:

+
chart: {
+  width?: string | number;
+  height?: string | number;
+  type?: 'line' | 'area' | 'bar' | 'pie' | 'donut' | 'radialBar' | 
+         'scatter' | 'bubble' | 'heatmap' | 'candlestick' | 
+         'boxPlot' | 'violin' | 'histogram' | 'radar' | 
+         'polarArea' | 'rangeBar' | 'rangeArea' | 'treemap' | 
+         'waffle' | 'sunburst' | 'funnel' | 'pyramid' | 'gauge';
+  foreColor?: string;
+  fontFamily?: string;
+  background?: string;
+  offsetX?: number;
+  offsetY?: number;
+  dropShadow?: {
+    enabled?: boolean;
+    top?: number;
+    left?: number;
+    blur?: number;
+    opacity?: number;
+    color?: string | string[];
+  };
+  events?: {
+    animationEnd?(chart: ApexCharts, options?: any): void;
+    beforeMount?(chart: ApexCharts, options?: any): void;
+    mounted?(chart: ApexCharts, options?: any): void;
+    updated?(chart: ApexCharts, options?: any): void;
+    mouseMove?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    mouseLeave?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    click?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    legendClick?(chart: ApexCharts, seriesIndex?: number, options?: any): void;
+    markerClick?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    selection?(chart: ApexCharts, options?: any): void;
+    dataPointSelection?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    dataPointMouseEnter?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    dataPointMouseLeave?(e: MouseEvent, chart?: ApexCharts, options?: any): void;
+    beforeZoom?(chart: ApexCharts, options?: any): boolean | void;
+    beforeResetZoom?(chart: ApexCharts, options?: any): boolean | void;
+    zoomed?(chart: ApexCharts, options?: any): void;
+    scrolled?(chart: ApexCharts, options?: any): void;
+    brushScrolled?(chart: ApexCharts, options?: any): void;
+  };
+  animations?: {
+    enabled?: boolean;
+    easing?: 'linear' | 'easeInSine' | 'easeOutSine' | 'easeInOutSine' | 
+             'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 
+             'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | string | 
+             [number, number, number, number] | ((t: number) => number);
+    speed?: number;
+    animateGradually?: { enabled?: boolean; delay?: number; };
+    dynamicAnimation?: { enabled?: boolean; speed?: number; easing?: string; };
+  };
+  toolbar?: {
+    show?: boolean;
+    offsetX?: number;
+    offsetY?: number;
+    tools?: {
+      download?: boolean | string;
+      selection?: boolean | string;
+      zoom?: boolean | string;
+      zoomin?: boolean | string;
+      zoomout?: boolean | string;
+      pan?: boolean | string;
+      reset?: boolean | string;
+      measure?: boolean | string;
+      customIcons?: Array<{
+        icon?: string;
+        title?: string;
+        index?: number;
+        class?: string;
+        click?(chart: ApexCharts, options?: any, e?: MouseEvent): void;
+      }>;
+    };
+    export?: {
+      csv?: { filename?: string; columnDelimiter?: string; headerCategory?: string; headerValue?: string; };
+      svg?: { filename?: string; };
+      png?: { filename?: string; };
+    };
+    autoSelected?: 'zoom' | 'selection' | 'pan' | 'measure';
+  };
+  zoom?: {
+    enabled?: boolean;
+    type?: 'x' | 'y' | 'xy';
+    autoScaleYaxis?: boolean;
+    allowMouseWheelZoom?: boolean | 'auto';
+    pinch?: boolean | 'auto';
+    zoomedArea?: {
+      fill?: { color?: string; opacity?: number; };
+      stroke?: { color?: string; opacity?: number; width?: number; };
+    };
+  };
+  selection?: {
+    enabled?: boolean;
+    type?: string;
+    fill?: { color?: string; opacity?: number; };
+    stroke?: { width?: number; color?: string; opacity?: number; dashArray?: number; };
+    xaxis?: { min?: number; max?: number; };
+    yaxis?: { min?: number; max?: number; };
+  };
+  stacked?: boolean;
+  stackType?: 'normal' | '100%';
+  id?: string;
+  group?: string;
+  locales?: Array<{ name?: string; options?: any; }>;
+  defaultLocale?: string;
+  parentHeightOffset?: number;
+  redrawOnParentResize?: boolean;
+  redrawOnWindowResize?: boolean | ((...args: any[]) => boolean);
+  sparkline?: { enabled?: boolean; };
+}
+ +

مثال کاربردی:

+
chart: {
+  type: 'line',
+  height: 350,
+  foreColor: '#333',
+  fontFamily: 'Vazirmatn, sans-serif',
+  animations: {
+    enabled: true,
+    easing: 'easeInOutCubic',
+    speed: 800,
+    animateGradually: { enabled: true, delay: 150 },
+    dynamicAnimation: { enabled: true, speed: 350 }
+  },
+  toolbar: {
+    show: true,
+    tools: {
+      download: true,
+      zoom: true,
+      zoomin: true,
+      zoomout: true,
+      reset: true,
+      customIcons: [{
+        icon: '<svg>...</svg>',
+        title: 'دکمه سفارشی',
+        index: 0,
+        click: (chart, options, e) => { console.log('کلیک شد'); }
+      }]
+    }
+  },
+  zoom: {
+    enabled: true,
+    type: 'x',
+    autoScaleYaxis: false
+  },
+  events: {
+    mounted: (chart, options) => { console.log('نمودار نصب شد'); },
+    dataPointSelection: (e, chart, options) => { console.log('نقطه انتخاب شد'); }
+  }
+}
+ + +

۳.۳. فیلد colors - رنگ‌های سری‌های داده

+

آرایه‌ای از رنگ‌ها برای سری‌های داده. هر سری با یک رنگ متفاوت نمایش داده می‌شود.

+ +

ساختار:

+
colors?: Array<string | ((opts: {
+  value: number;
+  seriesIndex: number;
+  dataPointIndex: number;
+  w: any;
+}) => string)>
+ +

مثال کاربردی:

+
// رنگ‌های ثابت
+colors: ['#008FFB', '#00E396', '#FEB019', '#FF4560', '#775DD0']
+
+// رنگ‌های داینامیک بر اساس مقدار
+colors: [
+  function({ value, seriesIndex, dataPointIndex }) {
+    return value > 50 ? '#00E396' : '#FF4560';
+  }
+]
+ + +

۳.۴. فیلد dataLabels - برچسب‌های داده

+

برچسب‌هایی که روی نقاط داده نمایش داده می‌شوند.

+ +

ساختار:

+
dataLabels?: {
+  enabled?: boolean;
+  enabledOnSeries?: number[];
+  formatter?(val: string | number | number[], opts?: any): string | number | (string | number)[];
+  textAnchor?: 'start' | 'middle' | 'end';
+  distributed?: boolean;
+  offsetX?: number;
+  offsetY?: number;
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+    fontWeight?: string | number;
+    colors?: string[];
+  };
+  background?: {
+    enabled?: boolean;
+    foreColor?: string;
+    borderRadius?: number;
+    padding?: number;
+    opacity?: number;
+    borderWidth?: number;
+    borderColor?: string;
+    dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+  };
+  dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+}
+ +

مثال کاربردی:

+
dataLabels: {
+  enabled: true,
+  formatter: (val) => val + '%',
+  style: {
+    fontSize: '12px',
+    fontFamily: 'Vazirmatn',
+    colors: ['#fff']
+  },
+  background: {
+    enabled: true,
+    foreColor: '#fff',
+    borderRadius: 4,
+    padding: 4,
+    borderColor: '#000',
+    borderWidth: 1
+  }
+}
+ + +

۳.۵. فیلد fill - پرکننده

+

تنظیمات پرکننده (رنگ، گرادیانت، الگو، تصویر).

+ +

ساختار:

+
fill?: {
+  colors?: string[];
+  opacity?: number | number[];
+  type?: string | string[];
+  gradient?: {
+    shade?: string;
+    type?: string;
+    shadeIntensity?: number;
+    gradientToColors?: string[];
+    inverseColors?: boolean;
+    opacityFrom?: number | number[];
+    opacityTo?: number | number[];
+    stops?: number[];
+    colorStops?: Array<{ offset: number; color: string; opacity: number; }> | Array<Array<{ offset: number; color: string; opacity: number; }>>;
+  };
+  image?: {
+    src?: string | string[];
+    width?: number;
+    height?: number;
+  };
+  pattern?: {
+    style?: string | string[];
+    width?: number;
+    height?: number;
+    strokeWidth?: number;
+  };
+}
+ +

مثال کاربردی:

+
fill: {
+  type: 'gradient',
+  gradient: {
+    shade: 'light',
+    type: 'vertical',
+    shadeIntensity: 0.5,
+    gradientToColors: ['#008FFB', '#00E396'],
+    opacityFrom: 1,
+    opacityTo: 0.5,
+    stops: [0, 50, 100]
+  }
+}
+ + +

۳.۶. فیلد grid - شبکه‌بندی

+

تنظیمات شبکه‌بندی نمودار.

+ +

ساختار:

+
grid?: {
+  show?: boolean;
+  borderColor?: string;
+  strokeDashArray?: number;
+  position?: 'front' | 'back';
+  xaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; };
+  yaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; };
+  row?: { colors?: string[]; opacity?: number; };
+  column?: { colors?: string[]; opacity?: number; };
+  padding?: { top?: number; right?: number; bottom?: number; left?: number; };
+}
+ +

مثال کاربردی:

+
grid: {
+  show: true,
+  borderColor: '#e0e0e0',
+  strokeDashArray: 4,
+  position: 'back',
+  row: { colors: ['#f3f3f3', 'transparent'], opacity: 0.5 },
+  padding: { top: 0, right: 10, bottom: 0, left: 10 }
+}
+ + +

۳.۷. فیلد legend - راهنمای نمودار

+

تنظیمات راهنمای نمودار (Legend).

+ +

ساختار:

+
legend?: {
+  show?: boolean;
+  showForSingleSeries?: boolean;
+  showForNullSeries?: boolean;
+  showForZeroSeries?: boolean;
+  floating?: boolean;
+  inverseOrder?: boolean;
+  position?: 'top' | 'right' | 'bottom' | 'left';
+  horizontalAlign?: 'left' | 'center' | 'right';
+  fontSize?: string;
+  fontFamily?: string;
+  fontWeight?: string | number;
+  width?: number;
+  height?: number;
+  formatter?(legendName: string, opts?: { seriesIndex: number; w: any; }): string;
+  tooltipHoverFormatter?(legendName: string, opts?: { seriesIndex: number; w: any; }): string;
+  customLegendItems?: string[];
+  labels?: { colors?: string | string[]; useSeriesColors?: boolean; };
+  markers?: {
+    width?: number;
+    height?: number;
+    strokeColor?: string;
+    strokeWidth?: number;
+    radius?: number;
+    customHTML?(): any;
+    onClick?(): void;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  itemMargin?: { horizontal?: number; vertical?: number; };
+  onItemClick?: { toggleDataSeries?: boolean; };
+  onItemHover?: { highlightDataSeries?: boolean; };
+}
+ +

مثال کاربردی:

+
legend: {
+  show: true,
+  position: 'top',
+  horizontalAlign: 'center',
+  fontSize: '14px',
+  fontFamily: 'Vazirmatn',
+  markers: { width: 12, height: 12, radius: 6 },
+  onItemClick: { toggleDataSeries: true },
+  onItemHover: { highlightDataSeries: true }
+}
+ + +

۳.۸. فیلد markers - نشانگرها

+

تنظیمات نشانگرهای نقاط داده.

+ +

ساختار:

+
markers?: {
+  size?: number | number[];
+  colors?: string | string[];
+  strokeColors?: string | string[];
+  strokeWidth?: number | number[];
+  strokeOpacity?: number | number[];
+  strokeDashArray?: number | number[];
+  fillOpacity?: number | number[];
+  discrete?: Array<{
+    seriesIndex?: number;
+    dataPointIndex?: number;
+    fillColor?: string;
+    strokeColor?: string;
+    size?: number;
+  }>;
+  shape?: 'circle' | 'square' | 'rect';
+  offsetX?: number;
+  offsetY?: number;
+  hover?: { size?: number; sizeOffset?: number; };
+  onClick?(e?: any): void;
+  onDblClick?(e?: any): void;
+  showNullDataPoints?: boolean;
+}
+ +

مثال کاربردی:

+
markers: {
+  size: 6,
+  colors: ['#008FFB'],
+  strokeColors: '#fff',
+  strokeWidth: 2,
+  hover: { size: 8, sizeOffset: 3 },
+  discrete: [{
+    seriesIndex: 0,
+    dataPointIndex: 3,
+    fillColor: '#FF0000',
+    size: 10
+  }]
+}
+ + +

۳.۹. فیلد plotOptions - گزینه‌های خاص هر نوع نمودار

+

این فیلد تنظیمات خاص هر نوع نمودار را شامل می‌شود.

+ +

ساختار (خلاصه):

+
plotOptions?: {
+  bar?: {
+    horizontal?: boolean;
+    columnWidth?: string | number;
+    barHeight?: string | number;
+    distributed?: boolean;
+    borderRadius?: number;
+    borderRadiusApplication?: 'around' | 'end';
+    borderRadiusWhenStacked?: 'all' | 'last';
+    hideZeroBarsWhenGrouped?: boolean;
+    rangeBarOverlap?: boolean;
+    rangeBarGroupRows?: boolean;
+    isDumbbell?: boolean;
+    dumbbellColors?: string[][];
+    colors?: {
+      ranges?: Array<{ from?: number; to?: number; color?: string; }>;
+      backgroundBarColors?: string[];
+      backgroundBarOpacity?: number;
+      backgroundBarRadius?: number;
+    };
+    dataLabels?: {
+      maxItems?: number;
+      hideOverflowingLabels?: boolean;
+      position?: string;
+      orientation?: 'horizontal' | 'vertical';
+      total?: {
+        enabled?: boolean;
+        formatter?(val?: string, opts?: any): string;
+        offsetX?: number;
+        offsetY?: number;
+        style?: { color?: string; fontSize?: string; fontFamily?: string; fontWeight?: string | number; };
+      };
+    };
+  };
+  bubble?: { minBubbleRadius?: number; maxBubbleRadius?: number; };
+  candlestick?: {
+    colors?: { upward?: string | string[]; downward?: string | string[]; };
+    wick?: { useFillColor?: boolean; };
+  };
+  boxPlot?: {
+    colors?: { upper?: string | string[]; lower?: string | string[]; };
+  };
+  heatmap?: {
+    radius?: number;
+    enableShades?: boolean;
+    shadeIntensity?: number;
+    reverseNegativeShade?: boolean;
+    distributed?: boolean;
+    useFillColorAsStroke?: boolean;
+    colorScale?: {
+      ranges?: Array<{ from?: number; to?: number; color?: string; foreColor?: string; name?: string; }>;
+      inverse?: boolean;
+      min?: number;
+      max?: number;
+    };
+  };
+  treemap?: {
+    enableShades?: boolean;
+    shadeIntensity?: number;
+    distributed?: boolean;
+    reverseNegativeShade?: boolean;
+    useFillColorAsStroke?: boolean;
+    dataLabels?: { format?: 'scale' | 'truncate'; };
+    borderRadius?: number;
+    colorScale?: {
+      inverse?: boolean;
+      ranges?: Array<{ from?: number; to?: number; color?: string; foreColor?: string; name?: string; }>;
+      min?: number;
+      max?: number;
+    };
+  };
+  pie?: {
+    startAngle?: number;
+    endAngle?: number;
+    customScale?: number;
+    offsetX?: number;
+    offsetY?: number;
+    expandOnClick?: boolean;
+    expandOffset?: number;
+    dataLabels?: { offset?: number; };
+  };
+  donut?: {
+    size?: string;
+    background?: string;
+    labels?: {
+      show?: boolean;
+      name?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; formatter?(val: string): string; };
+      value?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; formatter?(val: number | string): string; };
+      total?: { show?: boolean; showAlways?: boolean; label?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?(w: any): string; };
+    };
+  };
+  radialBar?: {
+    inverseOrder?: boolean;
+    startAngle?: number;
+    endAngle?: number;
+    offsetX?: number;
+    offsetY?: number;
+    hollow?: {
+      margin?: number;
+      size?: string;
+      background?: string;
+      image?: string;
+      imageWidth?: number;
+      imageHeight?: number;
+      imageOffsetX?: number;
+      imageOffsetY?: number;
+      imageClipped?: boolean;
+      position?: 'front' | 'back';
+      dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+    };
+    track?: {
+      show?: boolean;
+      startAngle?: number;
+      endAngle?: number;
+      background?: string | string[];
+      strokeWidth?: string;
+      opacity?: number;
+      margin?: number;
+      dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+    };
+    dataLabels?: {
+      show?: boolean;
+      name?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; };
+      value?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; offsetY?: number; color?: string; formatter?(val: number): string; };
+      total?: { show?: boolean; label?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?(w: any): string; };
+    };
+  };
+  radar?: {
+    size?: number;
+    offsetX?: number;
+    offsetY?: number;
+    polygons?: {
+      strokeColors?: string | string[];
+      strokeWidth?: string | number[];
+      connectorColors?: string | string[];
+      fill?: { colors?: string[]; };
+    };
+  };
+  polarArea?: {
+    rings?: { strokeColor?: string; strokeWidth?: number; };
+    spokes?: { connectorColors?: string | string[]; strokeWidth?: number; };
+  };
+}
+ +

مثال کاربردی (Bar):

+
plotOptions: {
+  bar: {
+    horizontal: false,
+    columnWidth: '70%',
+    borderRadius: 4,
+    borderRadiusApplication: 'end',
+    distributed: false,
+    dataLabels: {
+      position: 'top',
+      maxItems: 100,
+      hideOverflowingLabels: true
+    }
+  }
+}
+ +

مثال کاربردی (Pie):

+
plotOptions: {
+  pie: {
+    startAngle: 0,
+    endAngle: 360,
+    expandOnClick: true,
+    expandOffset: 10,
+    dataLabels: { offset: 0 }
+  }
+}
+ + +

۳.۱۰. فیلد responsive - تنظیمات واکنش‌گرا

+

تنظیمات واکنش‌گرا برای اندازه‌های مختلف صفحه.

+ +

ساختار:

+
responsive?: Array<{
+  breakpoint?: number;
+  options?: ApexOptions;
+}>
+ +

مثال کاربردی:

+
responsive: [
+  {
+    breakpoint: 480,
+    options: {
+      chart: { width: '100%', height: 250 },
+      legend: { position: 'bottom' }
+    }
+  },
+  {
+    breakpoint: 768,
+    options: {
+      chart: { width: '100%', height: 300 },
+      legend: { position: 'bottom' }
+    }
+  }
+]
+ + +

۳.۱۱. فیلد states - حالت‌های مختلف

+

تنظیمات حالت‌های مختلف (hover, active).

+ +

ساختار:

+
states?: {
+  hover?: {
+    filter?: {
+      type?: 'none' | 'lighten' | 'darken';
+      value?: number;
+    };
+  };
+  active?: {
+    allowMultipleDataPointsSelection?: boolean;
+    filter?: {
+      type?: 'none' | 'lighten' | 'darken';
+      value?: number;
+    };
+  };
+}
+ +

مثال کاربردی:

+
states: {
+  hover: {
+    filter: { type: 'darken', value: 0.15 }
+  },
+  active: {
+    allowMultipleDataPointsSelection: false,
+    filter: { type: 'darken', value: 0.35 }
+  }
+}
+ + +

۳.۱۲. فیلد stroke - خطوط نمودار

+

تنظیمات خطوط نمودار.

+ +

ساختار:

+
stroke?: {
+  show?: boolean;
+  curve?: 'smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic' | 
+          ('smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic')[];
+  lineCap?: 'butt' | 'square' | 'round';
+  colors?: string[];
+  width?: number | number[];
+  dashArray?: number | number[];
+}
+ +

مثال کاربردی:

+
stroke: {
+  show: true,
+  curve: 'smooth',
+  lineCap: 'round',
+  colors: ['#008FFB'],
+  width: 3,
+  dashArray: 0
+}
+ + +

۳.۱۳. فیلد theme - تم

+

تنظیمات تم (روشن/تاریک).

+ +

ساختار:

+
theme?: {
+  mode?: 'light' | 'dark' | '';
+  palette?: string;
+  monochrome?: {
+    enabled?: boolean;
+    color?: string;
+    shadeTo?: 'light' | 'dark';
+    shadeIntensity?: number;
+  };
+}
+ +

مثال کاربردی:

+
theme: {
+  mode: 'light',
+  palette: 'palette1',
+  monochrome: {
+    enabled: false,
+    color: '#008FFB',
+    shadeTo: 'light',
+    shadeIntensity: 0.65
+  }
+}
+ + +

۳.۱۴. فیلدهای title و subtitle - عنوان و زیرعنوان

+

تنظیمات عنوان و زیرعنوان نمودار.

+ +

ساختار:

+
title?: {
+  text?: string;
+  align?: 'left' | 'center' | 'right';
+  margin?: number;
+  offsetX?: number;
+  offsetY?: number;
+  floating?: boolean;
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+    fontWeight?: string | number;
+    color?: string;
+  };
+}
+
+subtitle?: {
+  text?: string;
+  align?: 'left' | 'center' | 'right';
+  margin?: number;
+  offsetX?: number;
+  offsetY?: number;
+  floating?: boolean;
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+    fontWeight?: string | number;
+    color?: string;
+  };
+}
+ +

مثال کاربردی:

+
title: {
+  text: 'نمودار فروش ماهانه',
+  align: 'center',
+  margin: 10,
+  style: {
+    fontSize: '18px',
+    fontFamily: 'Vazirmatn',
+    fontWeight: 'bold',
+    color: '#333'
+  }
+},
+subtitle: {
+  text: 'آمار فروش سال ۱۴۰۳',
+  align: 'center',
+  style: {
+    fontSize: '14px',
+    color: '#666'
+  }
+}
+ + +

۳.۱۵. فیلد tooltip - Tooltip

+

تنظیمات Tooltip (راهنمای شناور).

+ +

ساختار:

+
tooltip?: {
+  enabled?: boolean;
+  enabledOnSeries?: number[];
+  shared?: boolean;
+  followCursor?: boolean;
+  intersect?: boolean;
+  inverseOrder?: boolean;
+  arrow?: boolean;
+  custom?: Array<(opts: {
+    series: number[][];
+    seriesIndex: number;
+    dataPointIndex: number;
+    y1?: number;
+    y2?: number;
+    w: any;
+  }) => string>;
+  fillSeriesColor?: boolean;
+  theme?: 'light' | 'dark';
+  style?: {
+    fontSize?: string;
+    fontFamily?: string;
+  };
+  onDatasetHover?: { highlightDataSeries?: boolean; };
+  x?: {
+    show?: boolean;
+    format?: string;
+    formatter?(value: string | number, opts?: any): string;
+  };
+  y?: Array<{
+    title?: { title?: string; formatter?(seriesName: string, opts?: any): string; };
+    formatter?(value: number, opts?: any): string;
+  }>;
+  marker?: { show?: boolean; fillColors?: string[]; };
+  items?: { display?: string; };
+  fixed?: {
+    enabled?: boolean;
+    position?: string;
+    offsetX?: number;
+    offsetY?: number;
+  };
+}
+ +

مثال کاربردی:

+
tooltip: {
+  enabled: true,
+  shared: true,
+  followCursor: false,
+  intersect: false,
+  theme: 'light',
+  style: { fontSize: '12px', fontFamily: 'Vazirmatn' },
+  x: { show: true, format: 'dd MMM' },
+  y: [{
+    title: { title: 'فروش: ' },
+    formatter: (val) => val.toLocaleString('fa-IR') + ' تومان'
+  }],
+  marker: { show: true }
+}
+ + +

۳.۱۶. فیلد xaxis - محور X

+

تنظیمات محور X.

+ +

ساختار:

+
xaxis?: {
+  type?: 'category' | 'datetime' | 'numeric';
+  categories?: Array<string | number> | Array<Array<string | number>>;
+  overwriteCategories?: number[] | string[];
+  offsetX?: number;
+  offsetY?: number;
+  sorted?: boolean;
+  labels?: {
+    show?: boolean;
+    rotate?: number;
+    rotateAlways?: boolean;
+    hideOverlappingLabels?: boolean;
+    showDuplicates?: boolean;
+    trim?: boolean;
+    minHeight?: number;
+    maxHeight?: number;
+    style?: {
+      colors?: string | string[];
+      fontSize?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      cssClass?: string;
+    };
+    offsetX?: number;
+    offsetY?: number;
+    format?: string;
+    formatter?(value: string | number, timestamp?: number, opts?: any): string | string[];
+    datetimeUTC?: boolean;
+    datetimeFormatter?: {
+      year?: string;
+      month?: string;
+      day?: string;
+      hour?: string;
+      minute?: string;
+      second?: string;
+    };
+  };
+  group?: {
+    groups?: Array<{ title: string; cols: number }>;
+    style?: {
+      colors?: string | string[];
+      fontSize?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      cssClass?: string;
+    };
+  };
+  axisBorder?: {
+    show?: boolean;
+    color?: string;
+    width?: string | number;
+    height?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  axisTicks?: {
+    show?: boolean;
+    borderType?: 'solid' | 'dotted';
+    color?: string;
+    width?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  tickPlacement?: string;
+  tickAmount?: number | 'dataPoints';
+  stepSize?: number;
+  min?: number;
+  max?: number;
+  range?: number;
+  floating?: boolean;
+  position?: string;
+  title?: {
+    text?: string;
+    offsetX?: number;
+    offsetY?: number;
+    style?: {
+      color?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      fontSize?: string;
+      cssClass?: string;
+    };
+  };
+  crosshairs?: {
+    show?: boolean;
+    width?: number | string;
+    position?: string;
+    opacity?: number;
+    stroke?: { color?: string; width?: number; dashArray?: number; };
+    fill?: {
+      type?: string;
+      color?: string;
+      gradient?: {
+        colorFrom?: string;
+        colorTo?: string;
+        stops?: number[];
+        opacityFrom?: number;
+        opacityTo?: number;
+      };
+    };
+    dropShadow?: { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; color?: string | string[]; };
+  };
+  tooltip?: {
+    enabled?: boolean;
+    offsetY?: number;
+    formatter?(value: string | number, opts?: any): string;
+    style?: { fontSize?: string; fontFamily?: string; };
+  };
+}
+ +

مثال کاربردی:

+
xaxis: {
+  type: 'category',
+  categories: ['فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر'],
+  labels: {
+    show: true,
+    rotate: -45,
+    style: {
+      fontSize: '12px',
+      fontFamily: 'Vazirmatn',
+      colors: ['#333']
+    }
+  },
+  title: {
+    text: 'ماه',
+    style: { fontSize: '14px', fontWeight: 'bold' }
+  },
+  crosshairs: {
+    show: true,
+    stroke: { color: '#000', width: 1, dashArray: 0 }
+  }
+}
+ + +

۳.۱۷. فیلد yaxis - محور Y

+

تنظیمات محور Y.

+ +

ساختار:

+
yaxis?: {
+  show?: boolean;
+  showAlways?: boolean;
+  showForNullSeries?: boolean;
+  seriesName?: string | string[];
+  opposite?: boolean;
+  reversed?: boolean;
+  logarithmic?: boolean;
+  logBase?: number;
+  tickAmount?: number;
+  stepSize?: number;
+  forceNiceScale?: boolean;
+  min?: number | ((min: number) => number);
+  max?: number | ((max: number) => number);
+  floating?: boolean;
+  decimalsInFloat?: number;
+  labels?: {
+    show?: boolean;
+    showDuplicates?: boolean;
+    minWidth?: number;
+    maxWidth?: number;
+    style?: {
+      colors?: string | string[];
+      fontSize?: string;
+      fontWeight?: string | number;
+      fontFamily?: string;
+      cssClass?: string;
+    };
+    offsetX?: number;
+    offsetY?: number;
+    rotate?: number;
+    align?: 'left' | 'center' | 'right';
+    padding?: number;
+    formatter?(value: number, opts?: any): string | string[];
+  };
+  axisBorder?: {
+    show?: boolean;
+    color?: string;
+    width?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  axisTicks?: {
+    show?: boolean;
+    borderType?: 'solid' | 'dotted';
+    color?: string;
+    width?: number;
+    offsetX?: number;
+    offsetY?: number;
+  };
+  title?: {
+    text?: string;
+    rotate?: number;
+    offsetX?: number;
+    offsetY?: number;
+    style?: {
+      color?: string;
+      fontFamily?: string;
+      fontWeight?: string | number;
+      fontSize?: string;
+      cssClass?: string;
+    };
+  };
+  crosshairs?: {
+    show?: boolean;
+    position?: string;
+    stroke?: { color?: string; width?: number; dashArray?: number; };
+  };
+  tooltip?: {
+    enabled?: boolean;
+    offsetX?: number;
+  };
+}
+ +

مثال کاربردی:

+
yaxis: {
+  show: true,
+  title: {
+    text: 'مبلغ (تومان)',
+    style: { fontSize: '14px', fontWeight: 'bold' }
+  },
+  labels: {
+    show: true,
+    formatter: (val) => val.toLocaleString('fa-IR'),
+    style: { fontSize: '12px', fontFamily: 'Vazirmatn' }
+  },
+  min: 0,
+  max: 100,
+  tickAmount: 5
+}
+ + +

۳.۱۸. فیلد noData - پیام عدم وجود داده

+

تنظیمات پیام نمایش داده شده در صورت عدم وجود داده.

+ +

ساختار:

+
noData?: {
+  text?: string;
+  align?: 'left' | 'center' | 'right';
+  verticalAlign?: 'top' | 'middle' | 'bottom';
+  offsetX?: number;
+  offsetY?: number;
+  style?: {
+    color?: string;
+    fontSize?: string;
+    fontFamily?: string;
+  };
+}
+ +

مثال کاربردی:

+
noData: {
+  text: 'داده‌ای برای نمایش وجود ندارد',
+  align: 'center',
+  verticalAlign: 'middle',
+  style: {
+    color: '#999',
+    fontSize: '16px',
+    fontFamily: 'Vazirmatn'
+  }
+}
+ + +

۴. خلاصه و جمع‌بندی

+

+ مدل ApexOptions با ۲۵ فیلد اصلی، کنترل کاملی بر تمام جنبه‌های نمودار ارائه می‌دهد. با استفاده از این فیلدها می‌توانید نمودارهای کاملاً سفارشی و حرفه‌ای ایجاد کنید. +

+ +
+ 💡 نکته مهم: برای استفاده بهینه، همیشه از مستندات رسمی ApexCharts (apexcharts.com/docs/options) استفاده کنید و مقادیر پیش‌فرض را بررسی کنید. +
+ +
+ ⚠️ هشدار: برخی فیلدها فقط برای انواع خاصی از نمودار کاربرد دارند. قبل از استفاده، مطمئن شوید که فیلد مورد نظر با نوع نمودار شما سازگار است. +
+ + +
+

© کلیه حقوق این مستند متعلق به شرکت فن آوران ساحر علم می‌باشد.

+

طراحی و توسعه: هادی خزاعی اصل | وب‌سایت: https://saherelm.ir

+

📅 تاریخ تهیه: دوشنبه ۱۱ شهریور ۱۴۰۴

+
+
+ + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\غالب پروژه ها.html + + + + + + + پروژه نمونه + + + + +
+
+ +
+
پروژه نمونه
+
توضیحات پروژه
+
+
+
+ + +
+ + +
+ + +
+ + + + +
+
+
📋
+

ناحیه اصلی

+

محتوای اصلی برنامه در این ناحیه نمایش داده می‌شود

+
+
+
+ + +
+
+ طراح و توسعه‌دهنده: هادی خزاعی اصل + | + شرکت: رایان پرداز کاوش +
+
+ نسخه: 1.0.0 +
+
+ + + + + +
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Themes\Generator\xFrameworkThemeGenerator.html + + + + + + + xFramework Theme Generator + + + +
+

🎨 تولیدکننده پوسته xFramework

+

+ مدیریت و ویرایش پوسته‌های رنگی برای برنامه‌های کاربردی مبتنی بر + xFramework +

+
+ توسعه‌دهنده: هادی خزاعی اصل | شرکت: فن آوران ساحر علم | تاریخ: ۱ شهریور + ۱۴۰۵ +
+
+ +
+
+

✏️ ویرایش پوسته

+ +
+ + +
+ +
+
+ 📚 پوسته‌های از پیش تعریف‌شده (۵۰ مورد) +
+
+ 📁 بارگذاری فایل JSON +
+
+ +
+
+
+
+
+ +
+
+ + +
+ +
+
+ +
+
+ +
+
+
+ ☀️ Light +
+
+ 🌙 Dark +
+
+
+
+ + +
+
+
+ پیش‌نمایش زنده +
+
+
+
+
+
+
+ +
+
+
+ 📄 JSON (Light) +
+
+ 📄 JSON (Dark) +
+
+ 📄 Full JSON +
+
+

+          
+ +
+ + + +
+
+
+
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\xKanban.html + + + + + + +xKanban | ابزار مدیریت بردهای کانبان + + + + + + + + + + + +
+ + + + +
+ + + + +
+
+ 📋 + کل کارت‌ها: + 0 +
+
+ ✅ + تکمیل‌شده: + 0 +
+
+ ⏰ + نزدیک به موعد: + 0 +
+
+ ⚠️ + عقب‌افتاده: + 0 +
+
+ 📊 + پیشرفت: + 0% +
+
+ + +
+
+
📋
+

هیچ بردی وجود ندارد

+

برای شروع، یک برد جدید ایجاد کنید

+ +
+ +
+
+
+ + +
+
طراحی و توسعه: هادی خزاعی اصل | معمار و توسعه‌دهنده ارشد نرم‌افزار
+
نسخه ۱.۰.۰ |
+
+ + +
+
+ ذخیره خودکار فعال +
+ + +
+
+ در حال ارسال... +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\xToolTemplate.html + + + + + + + پروژه نمونه + + + + +
+
+ +
+
پروژه نمونه
+
توضیحات پروژه
+
+
+
+ + +
+ + +
+ + +
+ + + + +
+
+
📋
+

ناحیه اصلی

+

محتوای اصلی برنامه در این ناحیه نمایش داده می‌شود

+
+
+
+ + +
+
+ طراح و توسعه‌دهنده: هادی خزاعی اصل + | + شرکت: رایان پرداز کاوش +
+
+ نسخه: 1.0.0 +
+
+ + + + + +
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\xUMLDrawer.html + + + + + + +ابزار رسم نمودارهای UML + + + + + +
+
+
+
+
+

🎯 ابزار رسم نمودارهای UML

+

مدیریت چند نمودار با قابلیت ذخیره و بازیابی

+
+
طراح: هادی خزاعی اصل
+
+
+
+ +
+ + + +
+ + +
+ +
100%
+ +
+
+
+ +
+ + +
+
+ +
+
+ +
+
آماده
دیاگرام‌ها: 0
+
+
+ + + + + +
+
+
+
+
+

⚙️ ویژگی‌های المان

+ +
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Case_Study_1.html + + + + + + +xKanban | مستند جامع معرفی محصول و معماری فنی + + + +
+ + +
+
+
+ +
+
+
شماره مستند: PROD-XKN-1405-002
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۰:۳۰
+
طبقه‌بندی: عمومی - معرفی محصول
+
+
+
+PRODUCT DOCUMENTATION +

xKanban | ابزار مدیریت بردهای کانبان

+

معرفی محصول، تحلیل ارزش سازمانی و معماری فنی

+
+
+ + +
+ +
+مخاطبان مستند: مدیران فناوری اطلاعات، مدیران پروژه، سرپرستان تیم‌های توسعه، معماران نرم‌افزار و تصمیم‌گیرندگان سازمانی
+این مستند به معرفی جامع ابزار xKanban می‌پردازد؛ ابزاری که از دل نیازهای واقعی تیم‌های چابک متولد شده و با هدف حذف پیچیدگی‌های غیرضروری ابزارهای مدیریت پروژه طراحی شده است. در این مستند، از چرایی شکل‌گیری محصول تا معماری فنی و ارزش‌های سازمانی آن، همه‌چیز تشریح شده است. +
+ + +
+

📑 فهرست مطالب

+
    +
  1. شرح مسئله و چرایی خلق xKanban
  2. +
  3. مزایای کلیدی محصول
  4. +
  5. ارزش‌های سازمانی خلق‌شده
  6. +
  7. معماری فنی پروژه
  8. +
  9. مناسب برای چه سازمان‌ها و تیم‌هایی؟
  10. +
  11. جمع‌بندی و گام‌های بعدی
  12. +
+
+ + +
+
+
۱
+
+

شرح مسئله و چرایی خلق xKanban

+
Problem Statement & Product Genesis
+
+
+
+ +

در دنیای امروز، تقریباً هر تیمی — از توسعه نرم‌افزار گرفته تا بازاریابی، منابع انسانی و عملیات — با یک چالش مشترک دست‌وپنجه نرم می‌کند: چگونه کارها را به‌صورت شفاف، منظم و قابل ردیابی مدیریت کنیم؟ متدولوژی کانبان به‌عنوان یکی از مؤثرترین رویکردهای مدیریت بصری کار، سال‌هاست که پاسخ این سؤال را ارائه داده است؛ اما ابزارهای موجود برای پیاده‌سازی این متدولوژی، خود به منبع جدیدی از پیچیدگی تبدیل شده‌اند.

+ +

معضلات رایج در اکوسیستم ابزارهای فعلی:

+ +
+⚠️ چالش‌هایی که تیم‌ها هر روز با آن‌ها مواجه‌اند: +
    +
  • وابستگی به اینترنت و سرور: بسیاری از ابزارها نیازمند اتصال دائمی به اینترنت و سرورهای ابری هستند. در محیط‌هایی با محدودیت شبکه یا الزامات امنیتی بالا، این وابستگی یک مانع جدی است.
  • +
  • هزینه‌های اشتراک ماهانه: ابزارهای تجاری برای هر کاربر هزینه اشتراک دریافت می‌کنند. برای تیم‌های بزرگ، این هزینه به‌سرعت به رقم قابل‌توجهی تبدیل می‌شود.
  • +
  • پیچیدگی بیش‌ازحد: ابزارهایی مانند Jira یا Azure DevOps صدها قابلیت دارند که اکثر تیم‌ها از کمتر از ۲۰ درصد آن‌ها استفاده می‌کنند. این پیچیدگی، منحنی یادگیری را بالا برده و بهره‌وری را کاهش می‌دهد.
  • +
  • فرآیند نصب و راه‌اندازی سنگین: برخی ابزارها نیازمند نصب سرور، پیکربندی دیتابیس و مدیریت زیرساخت هستند که زمان و تخصص قابل‌توجهی می‌طلبد.
  • +
  • قفل‌شدگی داده‌ها (Vendor Lock-in): داده‌های پروژه در سرورهای ارائه‌دهنده سرویس ذخیره می‌شوند و خروج از آن اکوسیستم، پرهزینه و دشوار است.
  • +
  • عدم قابلیت حمل: انتقال پروژه از یک محیط به محیط دیگر (مثلاً از لپ‌تاپ شخصی به سیستم شرکت) در بسیاری از ابزارها فرآیندی پیچیده است.
  • +
+
+ +

این معضلات، یک شکاف آشکار در بازار ابزارهای مدیریت پروژه ایجاد کرده بود: جای خالی ابزاری ساده، مستقل، رایگان و در عین حال حرفه‌ای که بدون هیچ پیش‌نیازی قابل استفاده باشد و در عین حال، قابلیت‌های پیشرفته‌ای مانند فیلتر چندبعدی، تاریخچه تغییرات، وابستگی بین کارت‌ها و یکپارچگی با سیستم‌های خارجی را ارائه دهد.

+ +
+🎯 نقطه عطف: xKanban دقیقاً از همین شکاف متولد شد. هدف، خلق ابزاری بود که «صفر تا صد» مدیریت کانبان را بدون هیچ وابستگی خارجی، در یک فایل واحد و قابل حمل ارائه دهد — ابزاری که در کمتر از ۳ ثانیه باز شود و از همان لحظه اول قابل استفاده باشد. +
+ +

نیازمندی‌های کلیدی که xKanban برای پاسخ به آن‌ها طراحی شد:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفنیازمندیوضعیت در ابزارهای موجودپاسخ xKanban
۱اجرای آفلاین و بدون سروراکثراً ناممکن✓ کاملاً آفلاین
۲بدون هزینه اشتراکاشتراک ماهانه/سالانه✓ کاملاً رایگان
۳راه‌اندازی فورینیاز به نصب و پیکربندی✓ یک کلیک
۴قابلیت حمل داده‌هامحدود و پیچیده✓ فایل JSON
۵سادگی همراه با قدرتیا ساده یا پیچیده✓ تعادل بهینه
۶مالکیت کامل داده‌هاذخیره در سرور ثالث✓ کاملاً محلی
+ +
+
+ + +
+
+
۲
+
+

مزایای کلیدی محصول

+
Key Product Advantages
+
+
+
+ +

xKanban مجموعه‌ای از مزایای منحصربه‌فرد را ارائه می‌دهد که آن را از تمامی ابزارهای موجود در بازار متمایز می‌سازد. این مزایا نه صرفاً ویژگی‌های فنی، بلکه تصمیمات استراتژیک طراحی هستند که هر کدام پاسخی مستقیم به یکی از معضلات مطرح‌شده در بخش قبل می‌باشند.

+ +
+
+
۰ ثانیه
نصب
+
بدون نیاز به هیچ فرآیند نصب یا پیکربندی
+
+
+
۱۰۰٪
آفلاین
+
اجرای کامل بدون نیاز به اینترنت یا سرور
+
+
+
۱ فایل
واحد
+
تمام محصول در یک فایل HTML مستقل
+
+
+ +
+
+
🚀
+
راه‌اندازی آنی
+

فایل HTML را در مرورگر باز کنید. تمام. هیچ سروری، هیچ دیتابیسی، هیچ اکانتی لازم نیست. در کمتر از ۳ ثانیه آماده استفاده هستید.

+
+
+
🔒
+
حریم خصوصی مطلق
+

تمام داده‌ها در مرورگر شما باقی می‌مانند. هیچ اطلاعاتی به هیچ سرور خارجی ارسال نمی‌شود. مالکیت داده‌ها ۱۰۰٪ در اختیار شماست.

+
+
+
📦
+
قابلیت حمل بی‌نظیر
+

پروژه خود را به‌صورت فایل JSON ذخیره کنید و روی فلش، ایمیل یا هر فضای ابری منتقل کنید. در هر سیستمی قابل بارگذاری است.

+
+
+
🎨
+
رابط کاربری مدرن و حرفه‌ای
+

طراحی بصری جذاب با پشتیبانی از حالت تاریک/روشن، رنگ‌بندی سفارشی برای بردها، ستون‌ها و کارت‌ها و انیمیشن‌های روان.

+
+
+
🔍
+
فیلتر چندبعدی پیشرفته
+

فیلتر هم‌زمان بر اساس تگ، مسئول، وضعیت سررسید و جستجوی متنی. یافتن هر کارت در کمتر از یک ثانیه حتی در پروژه‌های بزرگ.

+
+
+
📡
+
یکپارچگی با Webhook
+

ارسال خودکار رویدادهای پروژه به Slack، Teams یا هر سیستم خارجی. ساختار JSON استاندارد با eventId و timestamp.

+
+
+
⌨️
+
میانبرهای کیبورد حرفه‌ای
+

بیش از ۸ میانبر کیبورد برای کاربران حرفه‌ای. از Ctrl+S برای ذخیره تا Alt+Arrow برای جابجایی سریع کارت‌ها بین ستون‌ها.

+
+
+
📊
+
آمار بلادرنگ پروژه
+

مشاهده آنی تعداد کارت‌ها، درصد پیشرفت، کارت‌های عقب‌افتاده و نزدیک به موعد در نوار وضعیت پایین صفحه.

+
+
+ +
+💎 مزیت رقابتی اصلی: xKanban تنها ابزاری است که ترکیب «سادگی یک فایل HTML» و «قدرت یک سیستم مدیریت پروژه حرفه‌ای» را به‌صورت هم‌زمان ارائه می‌دهد. هیچ ابزار دیگری در بازار این تعادل را برقرار نکرده است. +
+ +

مقایسه با ابزارهای رایج بازار:

+
+
+

ابزارهای تجاری (Jira, Trello, Asana)

+
    +
  • هزینه اشتراک ماهانه بالا
  • +
  • نیاز به اینترنت الزامی
  • +
  • نصب و راه‌اندازی ثبت‌نام + پیکربندی
  • +
  • مالکیت داده سرور ثالث
  • +
  • پیچیدگی بسیار بالا
  • +
  • آفلاین ناممکن
  • +
+
+ +
+ +
+
+ + +
+
+
۳
+
+

ارزش‌های سازمانی خلق‌شده

+
Organizational Value Proposition
+
+
+
+ +

استفاده از xKanban در یک سازمان، فراتر از صرفاً «مدیریت کارها» است. این ابزار، ارزش‌های استراتژیک و عملیاتی ملموسی را در سطوح مختلف سازمان خلق می‌کند که در ادامه به تفصیل تشریح شده‌اند:

+ +
+
💰
+
+
حذف کامل هزینه‌های لایسنس و اشتراک
+

سازمان‌هایی که از ابزارهایی مانند Jira یا Azure DevOps استفاده می‌کنند، سالانه مبالغ قابل‌توجهی بابت لایسنس هر کاربر پرداخت می‌کنند. xKanban این هزینه را به صفر می‌رساند و بودجه آزادشده را برای سرمایه‌گذاری در حوزه‌های ارزشمندتر آزاد می‌کند.

+
+
+ +
+
🔐
+
+
تطبیق با الزامات امنیتی و حریم خصوصی
+

در سازمان‌هایی با حساسیت امنیتی بالا (نظامی، بانکی، بهداشتی)، ارسال داده‌های پروژه به سرورهای ابری خارجی ممنوع یا محدود است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را به‌صورت ذاتی رعایت می‌کند.

+
+
+ +
+
⚡
+
+
کاهش زمان Onboarding اعضای جدید
+

برخلاف ابزارهای پیچیده که آموزش آن‌ها هفته‌ها زمان می‌برد، xKanban به‌قدری ساده و شهودی است که یک عضو جدید تیم در کمتر از ۱۰ دقیقه با آن آشنا شده و شروع به کار می‌کند.

+
+
+ +
+
📈
+
+
افزایش شفافیت و پاسخگویی در تیم
+

با نمایش بصری وضعیت تمام کارها، تاریخچه جابجایی کارت‌ها و آمار بلادرنگ پیشرفت، هر عضو تیم و هر مدیری در هر لحظه دید کاملی از وضعیت پروژه دارد. این شفافیت، فرهنگ پاسخگویی را تقویت می‌کند.

+
+
+ +
+
🔄
+
+
استانداردسازی فرآیندهای مدیریت پروژه
+

xKanban تیم‌ها را به استفاده از یک متدولوژی استاندارد (کانبان) هدایت می‌کند. ستون‌های مشخص، جریان کار تعریف‌شده و تاریخچه تغییرات، همگی به ایجاد یک فرآیند تکرارپذیر و قابل اندازه‌گیری کمک می‌کنند.

+
+
+ +
+
🛡️
+
+
حذف ریسک Vendor Lock-in
+

داده‌های پروژه در فرمت استاندارد JSON ذخیره می‌شوند. این یعنی سازمان هیچ‌گاه در اکوسیستم یک ارائه‌دهنده خاص قفل نمی‌شود و در هر زمان می‌تواند داده‌های خود را به هر سیستم دیگری منتقل کند.

+
+
+ +
+
🌐
+
+
یکپارچگی با اکوسیستم موجود سازمان
+

از طریق مکانیزم Webhook، xKanban می‌تواند رویدادهای پروژه را به Slack، Microsoft Teams، سیستم‌های CI/CD یا هر API سفارشی ارسال کند. این یعنی xKanban به‌جای جایگزینی ابزارهای موجود، آن‌ها را تکمیل می‌کند.

+
+
+ +
+
📉
+
+
کاهش سربار مدیریت زیرساخت
+

بدون نیاز به سرور، دیتابیس، به‌روزرسانی‌های امنیتی و مانیتورینگ، تیم IT سازمان از بار مدیریت یک ابزار اضافی رها می‌شود. این صرفه‌جویی در زمان و منابع انسانی، ارزش پنهان اما بسیار قابل‌توجهی است.

+
+
+ +
+📊 خلاصه ارزش‌آفرینی: xKanban در چهار بُعد اصلی برای سازمان ارزش خلق می‌کند: کاهش هزینه‌ها (حذف لایسنس و زیرساخت)، افزایش بهره‌وری (Onboarding سریع و رابط شهودی)، کاهش ریسک (امنیت داده و عدم وابستگی) و بهبود کیفیت فرآیندها (استانداردسازی و شفافیت). +
+ +
+
+ + +
+
+
۴
+
+

معماری فنی پروژه

+
Technical Architecture & Code Structure
+
+
+
+ +

xKanban به‌عنوان یک Single-Page Application (SPA) تک‌فایلی طراحی شده است که تمامی لایه‌های نمایش، منطق و داده را در یک فایل HTML واحد encapsulate می‌کند. این تصمیم معماری، اگرچه در نگاه اول غیرمعمول به نظر می‌رسد، اما با توجه به اهداف محصول (آفلاین بودن، قابلیت حمل و عدم وابستگی) منطقی‌ترین انتخاب ممکن بوده است.

+ +

الف) نمودار معماری لایه‌ای

+ +
+
+
🎨 Presentation Layer
+
+Toolbar UI +Board Renderer +Column Renderer +Card Renderer +Modal System +Filter Panel +Stats Bar +Theme Engine +
+
+
▼ Event Binding & State Observation ▼
+
+
⚙️ Application Logic Layer
+
+ProjectManager +BoardManager +ColumnManager +CardManager +TagManager +FilterEngine +WebhookService +ShortcutHandler +HistoryTracker +
+
+
▼ Read / Write / Sync ▼
+
+
💾 Data & Persistence Layer
+
+AppState (In-Memory) +LocalStorage Adapter +AutoSave Engine +JSON Serializer +Export/Import Service +Recovery Manager +
+
+
+ +

ب) مدل داده‌ای (Data Schema)

+

ساختار داده‌ای پروژه از یک سلسله‌مراتب چهارسطحی پیروی می‌کند:

+ +
+// ساختار سلسله‌مراتبی داده‌ها
+Project
+  ├── id: UUID
+  ├── title: string
+  ├── description: string
+  ├── createdAt: ISO8601
+  ├── webhook: { enabled, url }
+  ├── globalTags: [Tag]
+  └── boards: [
+        Board
+          ├── id, title, backgroundColor
+          └── columns: [
+              Column
+                ├── id, title, order
+                └── cards: [
+                    Card
+                      ├── id, title, description
+                      ├── dueDate, assignees, tags
+                      ├── dependencies, checklist
+                      └── history: [HistoryEntry]
+                  ]
+            ]
+      ]
+
+ +

ج) ماژول‌های اصلی و متدهای کلیدی

+

در ادامه، مهم‌ترین ماژول‌های سیستم به همراه متدهای کلیدی هر کدام تشریح شده‌اند. برای حفظ خوانایی، بدنه متدها خلاصه شده و تنها امضای آن‌ها نمایش داده شده است:

+ +
📁 ماژول ProjectManager
+
    +
  • +initProject() +مقداردهی اولیه پروژه +
  • +
  • +loadProject(data) +بارگذاری پروژه از فایل JSON +
  • +
  • +saveProject(filename) +ذخیره پروژه به‌صورت فایل JSON +
  • +
  • +updateProjectSettings(title, desc, webhook) +به‌روزرسانی تنظیمات پروژه +
  • +
  • +getProjectStats() +محاسبه آمار کلی پروژه +
  • +
+ +
📊 ماژول BoardManager
+
    +
  • +createBoard(title, description, bgColor) +ایجاد برد جدید +
  • +
  • +editBoard(boardId, data) +ویرایش برد موجود +
  • +
  • +deleteBoard(boardId) +حذف برد با تأیید کاربر +
  • +
  • +switchBoard(boardId) +تغییر برد فعال +
  • +
  • +renderBoardList() +رندر لیست بردها در منو +
  • +
+ +
📑 ماژول ColumnManager
+
    +
  • +addColumn(boardId, title, bgColor, textColor) +افزودن ستون جدید به برد +
  • +
  • +editColumn(columnId, data) +ویرایش ویژگی‌های ستون +
  • +
  • +deleteColumn(columnId) +حذف ستون و کارت‌های آن +
  • +
  • +reorderColumns(draggedId, targetId) +تغییر ترتیب ستون‌ها با Drag & Drop +
  • +
  • +renderColumns(boardId) +رندر ستون‌های برد فعال +
  • +
+ +
📝 ماژول CardManager
+
    +
  • +createCard(columnId, cardData) +ایجاد کارت جدید در ستون +
  • +
  • +updateCard(cardId, updates) +به‌روزرسانی اطلاعات کارت +
  • +
  • +deleteCard(cardId) +حذف کارت از ستون +
  • +
  • +moveCard(cardId, fromColumnId, toColumnId) +جابجایی کارت بین ستون‌ها +
  • +
  • +addChecklistItem(cardId, text) +افزودن آیتم به چک‌لیست +
  • +
  • +toggleChecklistItem(cardId, itemId) +تغییر وضعیت آیتم چک‌لیست +
  • +
  • +addDependency(cardId, dependOnCardId) +ایجاد وابستگی بین کارت‌ها +
  • +
  • +assignMember(cardId, memberName) +تخصیص مسئول به کارت +
  • +
  • +getCardDueStatus(card) +تعیین وضعیت سررسید کارت +
  • +
  • +openCardModal(cardId) +باز کردن پنجره ویرایش کارت +
  • +
+ +
🏷️ ماژول TagManager
+
    +
  • +createTag(name, color) +ایجاد تگ عمومی جدید +
  • +
  • +deleteTag(tagId) +حذف تگ و حذف از کارت‌ها +
  • +
  • +assignTagToCard(cardId, tagId) +تخصیص تگ به کارت +
  • +
  • +removeTagFromCard(cardId, tagId) +حذف تگ از کارت +
  • +
  • +renderTagManager() +رندر پنل مدیریت تگ‌ها +
  • +
+ +
🔍 ماژول FilterEngine
+
    +
  • +applyFilters(criteria) +اعمال فیلترهای چندبعدی +
  • +
  • +filterByTags(selectedTags) +فیلتر بر اساس تگ‌ها +
  • +
  • +filterByAssignees(selectedAssignees) +فیلتر بر اساس مسئولین +
  • +
  • +filterByDueStatus(status) +فیلتر بر اساس وضعیت سررسید +
  • +
  • +searchCards(query) +جستجوی متنی در کارت‌ها +
  • +
  • +clearAllFilters() +پاک‌سازی تمام فیلترها +
  • +
+ +
📡 ماژول WebhookService
+
    +
  • +sendEvent(eventType, payload) +ارسال رویداد به URL پیکربندی‌شده +
  • +
  • +testWebhook(url) +تست اتصال Webhook +
  • +
  • +buildEventPayload(eventType, data) +ساخت ساختار JSON استاندارد رویداد +
  • +
+ +
💾 ماژول PersistenceEngine
+
    +
  • +autoSave() +ذخیره خودکار در LocalStorage +
  • +
  • +loadAutoSave() +بارگذاری داده‌های ذخیره‌شده خودکار +
  • +
  • +scheduleAutoSave() +زمان‌بندی ذخیره با Debounce +
  • +
  • +exportToJSON() +خروجی فایل JSON +
  • +
  • +importFromJSON(file) +بارگذاری از فایل JSON +
  • +
  • +exportToMarkdown(boardId) +خروجی فرمت Markdown +
  • +
  • +exportToCSV(boardId) +خروجی فرمت CSV +
  • +
  • +checkRecovery() +بررسی وجود داده‌های بازیابی +
  • +
+ +
⌨️ ماژول ShortcutHandler
+
    +
  • +registerShortcuts() +ثبت تمام میانبرهای کیبورد +
  • +
  • +handleKeyDown(event) +پردازش رویدادهای کیبورد +
  • +
  • +navigateCards(direction) +پیمایش بین کارت‌ها با Tab +
  • +
  • +moveCardWithKeyboard(direction) +جابجایی کارت با Alt+Arrow +
  • +
+ +

د) الگوهای طراحی به‌کاررفته

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل استفادههدف
State-Driven Renderingکل رابط کاربریرندر UI بر اساس وضعیت مرکزی AppState
Observer / Pub-Subارتباط ماژول‌هااطلاع‌رسانی تغییرات وضعیت به ماژول‌های وابسته
DebouncingAutoSave Engineجلوگیری از نوشتن مکرر در LocalStorage
Factoryایجاد موجودیت‌هاتولید اشیاء Card، Column، Board با UUID
CommandUndo/Redoذخیره عملیات برای امکان بازگشت
SingletonAppStateیک منبع واحد حقیقت برای کل برنامه
+ +

ه) جریان داده (Data Flow)

+
+🔄 چرخه حیات یک عملیات کاربر:

+۱. User Action: کاربر یک کارت را از ستون «در حال انجام» به ستون «تکمیل‌شده» می‌کشد.
+۲. Event Capture: رویداد Drag & Drop توسط ColumnManager دریافت می‌شود.
+۳. State Update: متد moveCard() از CardManager فراخوانی شده و AppState به‌روزرسانی می‌شود.
+۴. History Log: متد HistoryTracker.log() جابجایی را با timestamp ثبت می‌کند.
+۵. Re-Render: متد renderColumns() رابط کاربری را با وضعیت جدید به‌روزرسانی می‌کند.
+۶. AutoSave: متد scheduleAutoSave() با تأخیر ۱ ثانیه، وضعیت را در LocalStorage ذخیره می‌کند.
+۷. Webhook: در صورت فعال بودن، متد sendEvent('card.moved', payload) رویداد را ارسال می‌کند.
+۸. Stats Update: متد getProjectStats() آمار نوار وضعیت را به‌روزرسانی می‌کند. +
+ +
+
+ + +
+
+
۵
+
+

مناسب برای چه سازمان‌ها و تیم‌هایی؟

+
Target Audience & Ideal Use Cases
+
+
+
+ +

xKanban به‌گونه‌ای طراحی شده که طیف وسیعی از سازمان‌ها و تیم‌ها بتوانند از آن بهره‌مند شوند. با این حال، برخی محیط‌ها بیشترین ارزش را از این ابزار دریافت خواهند کرد:

+ +

الف) سازمان‌های هدف

+ +
+
+
🏢
+
استارتاپ‌ها و شرکت‌های کوچک
+

تیم‌هایی که بودجه محدود دارند و به ابزاری رایگان، سریع و بدون سربار نیاز دارند. xKanban جایگزین ایده‌آل Trello و Asana برای این تیم‌هاست.

+
+
+
🏛️
+
سازمان‌های دولتی و نظامی
+

محیط‌هایی با محدودیت‌های امنیتی شدید که استفاده از سرویس‌های ابری خارجی ممنوع است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را رعایت می‌کند.

+
+
+
🏥
+
مراکز بهداشتی و درمانی
+

بیمارستان‌ها و مراکز تحقیقاتی که داده‌های حساس بیماران و پروژه‌ها نباید از شبکه داخلی خارج شود.

+
+
+
🏦
+
مؤسسات مالی و بانکی
+

سازمان‌هایی که تحت مقررات سخت‌گیرانه حفاظت از داده (مانند PCI-DSS) فعالیت می‌کنند و نمی‌توانند اطلاعات پروژه‌ها را در سرورهای ثالث ذخیره کنند.

+
+
+
🎓
+
دانشگاه‌ها و مراکز آموزشی
+

اساتید و دانشجویانی که برای مدیریت پروژه‌های تحقیقاتی، پایان‌نامه‌ها و کارهای گروهی به ابزاری ساده و رایگان نیاز دارند.

+
+
+
🌍
+
تیم‌های دورکار و فریلنسرها
+

افرادی که در محیط‌های مختلف کار می‌کنند و نیاز دارند پروژه خود را روی فلش یا فضای ابری شخصی حمل کنند.

+
+
+ +

ب) تیم‌های هدف

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع تیمنحوه استفاده از xKanbanارزش اصلی
تیم‌های توسعه نرم‌افزارمدیریت Sprint، باگ‌ها و Featureهایکپارچگی با CI/CD از طریق Webhook
تیم‌های DevOpsردیابی Incidentها و Change Requestهااجرای آفلاین در محیط‌های ایزوله
تیم‌های بازاریابیمدیریت کمپین‌ها و محتوای تولیدیسادگی و سرعت راه‌اندازی
تیم‌های منابع انسانیردیابی فرآیند استخدام و Onboardingحریم خصوصی داده‌های پرسنلی
تیم‌های طراحیمدیریت پروژه‌های طراحی و بازخوردرابط بصری جذاب و رنگ‌بندی سفارشی
تیم‌های پشتیبانیمدیریت تیکت‌ها و درخواست‌های مشتریانآمار بلادرنگ و فیلتر پیشرفته
مدیران محصولنقشه راه محصول و اولویت‌بندی ویژگی‌هاوابستگی بین کارت‌ها و چک‌لیست
+ +
+🎯 قانون کلی: هر تیمی که با سؤال «الان هر کس دارد روی چه چیزی کار می‌کند و وضعیتش چیست؟» مواجه است، یک کاندیدای ایده‌آل برای استفاده از xKanban محسوب می‌شود. +
+ +

ج) چه زمانی xKanban بهترین انتخاب نیست؟

+
+💡 شفافیت کامل: xKanban برای سناریوهای زیر طراحی نشده و در این موارد، ابزارهای تخصصی‌تر توصیه می‌شوند: +
    +
  • تیم‌های بسیار بزرگ (بیش از ۵۰ نفر) که نیاز به مدیریت دسترسی سطحی و نقش‌های پیچیده دارند
  • +
  • سازمان‌هایی که نیاز به هم‌زمانی بلادرنگ (Real-time Collaboration) بین چندین کاربر دارند
  • +
  • محیط‌هایی که نیاز به یکپارچگی عمیق با اکوسیستم‌های خاص (مانند SAP یا Salesforce) دارند
  • +
+
+ +
+
+ + +
+
+
۶
+
+

جمع‌بندی و گام‌های بعدی

+
Summary & Next Steps
+
+
+
+ +

xKanban پاسخی عملی و مهندسی‌شده به یکی از رایج‌ترین چالش‌های تیم‌های مدرن است: مدیریت بصری کارها بدون پیچیدگی، بدون هزینه و بدون وابستگی. این ابزار از دل تجربه واقعی در مدیریت پروژه‌های نرم‌افزاری متولد شده و هر ویژگی آن، پاسخی مستقیم به یک نیاز واقعی است.

+ +
+

🎯 چرا xKanban؟

+

زیرا مدیریت پروژه نباید خودش یک پروژه باشد.

+

xKanban با ترکیب سادگی، قدرت و استقلال، ابزاری را ارائه می‌دهد که از لحظه اول قابل استفاده است، داده‌های شما را در اختیار خودتان نگه می‌دارد و هیچ هزینه‌ای بر دوش سازمان نمی‌گذارد.

+
+💎 ارزش نهایی:
+صفر هزینه + صفر وابستگی + صفر پیچیدگی = ۱۰۰٪ بهره‌وری +
+
+ +

گام‌های پیشنهادی برای شروع:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
گاماقدامزمان تخمینی
۱فایل xKanban.html را در مرورگر باز کنید۳ ثانیه
۲یک پروژه و برد آزمایشی ایجاد کنید۲ دقیقه
۳ستون‌ها و کارت‌های واقعی تیم خود را وارد کنید۱۰ دقیقه
۴تگ‌ها و مسئولین را تعریف کنید۵ دقیقه
۵پروژه را به‌صورت فایل JSON ذخیره کنید۱ دقیقه
۶از xKanban لذت ببرید! 🎉همیشگی
+ +
+📞 تماس و پشتیبانی: برای دریافت مشاوره فنی، سفارشی‌سازی xKanban بر اساس نیازهای خاص سازمانی یا یکپارچگی با سیستم‌های موجود، آماده برگزاری جلسه فنی هستیم. طراحی، تحلیل و توسعه توسط هادی خزاعی اصل، معمار و توسعه‌دهنده ارشد نرم‌افزار. +
+ +
+
+ +
+این مستند جهت معرفی محصول و تحلیل فنی تهیه شده است. هرگونه استفاده تجاری از محتوای این مستند بدون اجازه کتبی ممنوع است. +
+ +
+ + +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۰:۳۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: عمومی
+
+ +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Case_Study_2.html + + + + + + +مستند جامع محصول xKanban | تحلیل مسئله، مزایا، معماری و مخاطبان هدف + + + +
+
+
+
+ +
+
+
شماره مستند: PROD-XKN-1405-002
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۱:۳۰
+
طبقه‌بندی: داخلی - محصولی
+
+
+
+PRODUCT DOCUMENTATION +

مستند جامع محصول xKanban

+

تحلیل مسئله، مزایا، ارزش‌های سازمانی، معماری فنی و مخاطبان هدف

+
+
+ +
+
+تهیه‌کننده: هادی خزاعی اصل | معمار و توسعه‌دهنده ارشد نرم‌افزار
+مخاطبان مستند: مدیران فنی، تصمیم‌گیرندگان سازمانی، رهبران تیم و معماران نرم‌افزار
+این مستند با هدف ارائه تصویری جامع از چرایی خلق محصول xKanban، مزایای رقابتی آن، ارزش‌های قابل‌خلق در سازمان، معماری فنی دقیق و شناسایی مخاطبان هدف تهیه شده است. +
+ + + + +
+
+
۱
+
+

شرح مسئله و ضرورت خلق ابزار

+
Problem Statement & Motivation
+
+
+
+

در دنیای توسعه نرم‌افزار و مدیریت پروژه، تیم‌ها با چالش‌های مشترکی در زمینه پیگیری وظایف، شفافیت وضعیت کارها و هماهنگی بین اعضا مواجه هستند. این چالش‌ها مختص سازمان خاصی نیستند، بلکه الگویی تکرارشونده در سراسر صنعت محسوب می‌شوند.

+ +

معضلات رایج در مدیریت وظایف:

+ +
+⚠️ وابستگی اجباری به زیرساخت سرور: +
    +
  • بخش عمده‌ای از ابزارهای مدیریت پروژه، نیازمند راه‌اندازی سرور، پایگاه داده، پیکربندی شبکه و نگهداری مداوم هستند
  • +
  • تیم‌های کوچک و فریلنسرها اغلب فاقد زیرساخت و دانش فنی لازم برای استقرار این ابزارها هستند
  • +
  • هزینه‌های سرور و نگهداری، بار مالی اضافی بر پروژه‌های کوچک تحمیل می‌کند
  • +
+
+ +
+⚠️ قفل‌شدگی در اکوسیستم ابری: +
    +
  • ابزارهای SaaS، داده‌های سازمان را روی سرورهای شخص ثالث ذخیره می‌کنند که نگرانی‌های امنیتی و حریم خصوصی ایجاد می‌کند
  • +
  • وابستگی به اتصال اینترنت پایدار، کار در محیط‌های آفلاین یا با پهنای باند محدود را غیرممکن می‌سازد
  • +
  • تغییر قیمت‌گذاری یا تعطیلی سرویس‌دهنده، ریسک از دست رفتن داده‌ها را به همراه دارد
  • +
+
+ +
+⚠️ پیچیدگی بیش از حد ابزارهای موجود: +
    +
  • بسیاری از ابزارها با انبوهی از ویژگی‌های غیرضروری، منحنی یادگیری بالایی دارند
  • +
  • تیم‌ها زمان قابل‌توجهی را صرف یادگیری ابزار می‌کنند به جای تمرکز بر کار اصلی
  • +
  • سفارشی‌سازی فرآیندها اغلب نیازمند پیکربندی‌های پیچیده و دانش تخصصی است
  • +
+
+ +
+⚠️ عدم قابلیت حمل و انتقال داده‌ها: +
    +
  • خروجی گرفتن از داده‌ها و انتقال آن‌ها بین ابزارها، فرآیندی دشوار و زمان‌بر است
  • +
  • فرمت‌های اختصاصی، امکان استفاده آفلاین یا اشتراک‌گذاری ساده پروژه را محدود می‌کنند
  • +
  • عدم امکان آرشیو کردن پروژه به صورت فایل مستقل، مدیریت بلندمدت را مختل می‌کند
  • +
+
+ +
+🎯 نتیجه‌گیری از تحلیل مسئله: نیاز به ابزاری احساس می‌شد که بدون نیاز به سرور، بدون وابستگی به اینترنت، بدون پیچیدگی غیرضروری و با قابلیت حمل کامل، امکان مدیریت حرفه‌ای پروژه‌ها را بر اساس متدولوژی کانبان فراهم آورد. xKanban پاسخی مستقیم به این نیاز است. +
+
+
+ + + + +
+
+
۲
+
+

مزایای کلیدی محصول

+
Key Product Advantages
+
+
+
+

xKanban با رویکردی متفاوت از ابزارهای رایج بازار طراحی شده و مزایایی را ارائه می‌دهد که هر یک به تنهایی می‌تواند دلیلی قانع‌کننده برای انتخاب این ابزار باشد:

+ +
+
+
صفر
سرور
+
بدون نیاز به هیچ زیرساخت سروری
+
+
+
یک
فایل
+
توزیع و اجرا با یک فایل HTML
+
+
+
۱۰۰٪
آفلاین
+
کارکرد کامل بدون اتصال اینترنت
+
+
+ +

مزیت ۱: استقلال مطلق از زیرساخت

+

xKanban به صورت کامل در مرورگر کاربر اجرا می‌شود. هیچ سروری نیاز نیست، هیچ پایگاه داده‌ای پیکربندی نمی‌شود، هیچ وابستگی به سرویس خارجی وجود ندارد. کاربر فقط یک فایل HTML را باز می‌کند و بلافاصله شروع به کار می‌کند. این یعنی زمان راه‌اندازی: صفر ثانیه.

+ +

مزیت ۲: مالکیت کامل داده‌ها

+

تمامی داده‌ها در مرورگر محلی کاربر و در فایل‌های JSON خروجی ذخیره می‌شوند. هیچ بایتی از اطلاعات پروژه به سرور خارجی ارسال نمی‌شود. این ویژگی برای سازمان‌هایی که با داده‌های حساس کار می‌کنند، یک مزیت حیاتی و غیرقابل‌مذاکره است.

+ +

مزیت ۳: قابلیت حمل بی‌نظیر

+

کل پروژه شامل بردها، ستون‌ها، کارت‌ها، تگ‌ها و تنظیمات در یک فایل JSON قابل‌صدور است. این فایل را می‌توان از طریق ایمیل ارسال کرد، روی فلش ذخیره کرد، در فضای ابری شخصی نگه داشت یا حتی پرینت گرفت. پروژه شما، همیشه در جیب شماست.

+ +

مزیت ۴: غنای عملکردی در عین سادگی

+

برخلاف تصور رایج که ابزارهای ساده فاقد قابلیت‌های پیشرفته هستند، xKanban مجموعه‌ای غنی از ویژگی‌ها را ارائه می‌دهد:

+ +
+
+
📊
+
بردهای چندگانه
+

مدیریت همزمان چندین برد مستقل در یک پروژه با جابجایی آنی

+
+
+
🎨
+
شخصی‌سازی بصری کامل
+

رنگ‌بندی مستقل برای بردها، ستون‌ها و کارت‌ها جهت شناسایی سریع

+
+
+
👥
+
تخصیص چندمسئوله
+

امکان اختصاص چندین نفر به هر کارت برای کارهای تیمی

+
+
+
🔗
+
مدیریت وابستگی‌ها
+

تعریف روابط پیش‌نیازی بین کارت‌ها برای درک زنجیره کار

+
+
+
✅
+
چک‌لیست ریزوظایف
+

شکستن کارت‌ها به وظایف کوچکتر با قابلیت پیگیری پیشرفت

+
+
+
📜
+
تاریخچه جابجایی
+

ثبت خودکار تمام جابجایی‌های کارت بین ستون‌ها با زمان دقیق

+
+
+
📡
+
یکپارچگی Webhook
+

ارسال رویدادها به سیستم‌های خارجی با ساختار استاندارد JSON

+
+
+
⌨️
+
میانبرهای کیبورد
+

پشتیبانی کامل از کیبورد برای کاربران حرفه‌ای و افزایش سرعت

+
+
+ +

مزیت ۵: خروجی چندفرمتی

+

xKanban علاوه بر فرمت JSON برای پشتیبان‌گیری کامل، امکان خروجی گرفتن به فرمت‌های Markdown و CSV را نیز فراهم می‌آورد. این یعنی داده‌های شما هرگز در یک فرمت اختصاصی قفل نمی‌شوند و همیشه قابل استفاده در ابزارهای دیگر هستند.

+ +

مزیت ۶: بازیابی خودکار هوشمند

+

سیستم AutoSave به صورت خودکار تغییرات را در مرورگر ذخیره می‌کند. در صورت بسته شدن ناگهانی مرورگر یا قطع برق، در جلسه بعدی سیستم به صورت خودکار داده‌های ذخیره‌شده را شناسایی کرده و گزینه بازیابی را ارائه می‌دهد.

+ +
+✨ مزیت رقابتی نهایی: xKanban تنها ابزاری است که همزمان تمامی ویژگی‌های «بدون سرور»، «آفلاین کامل»، «مالکیت داده»، «قابلیت حمل»، «غنای عملکردی» و «خروجی چندفرمتی» را در یک بسته واحد ارائه می‌دهد. هیچ ابزار دیگری در بازار این ترکیب منحصربه‌فرد را فراهم نمی‌آورد. +
+
+
+ + + + +
+
+
۳
+
+

ارزش‌های قابل‌خلق در سازمان

+
Organizational Value Proposition
+
+
+
+

استفاده از xKanban فراتر از یک ابزار مدیریت وظایف ساده است. این محصول می‌تواند ارزش‌های استراتژیک و عملیاتی ملموسی را در سازمان ایجاد کند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
حوزه ارزشارزش ایجادشدهتأثیر عملی
💰 کاهش هزینه‌هاحذف هزینه لایسنس ابزارهای SaaS، سرور، پایگاه داده و نگهداریصرفه‌جویی سالانه قابل‌توجه در بودجه فناوری اطلاعات
⚡ افزایش سرعتراه‌اندازی آنی بدون فرآیند خرید، نصب و پیکربندیتیم‌ها در کمتر از یک دقیقه شروع به کار می‌کنند
🔒 امنیت داده‌هاعدم خروج داده‌ها از محیط محلی سازمانانطباق با الزامات حریم خصوصی و مقررات حفاظت از داده
🔄 تداوم کسب‌وکارکارکرد مستقل از اینترنت و سرویس‌های خارجیعدم توقف کار تیم در صورت قطعی اینترنت یا اختلال سرویس
📈 شفافیت فرآیندهادید بلادرنگ به وضعیت تمام کارها و گلوگاه‌هاتصمیم‌گیری مبتنی بر داده و شناسایی سریع موانع
🤝 بهبود همکاری تیمیاشتراک‌گذاری آسان پروژه از طریق فایل JSONهماهنگی بهتر بین اعضا حتی در محیط‌های توزیع‌شده
📚 انباشت دانشتاریخچه کامل جابجایی‌ها و آرشیو پروژه‌هاامکان بازنگری فرآیندها و یادگیری از تجربیات گذشته
🎯 استانداردسازیاجرای دقیق متدولوژی کانبان با ساختار یکپارچهایجاد زبان مشترک و فرآیند یکنواخت در تمام تیم‌ها
🔌 یکپارچگی سیستمیارتباط با ابزارهای خارجی از طریق Webhookخودکارسازی اعلان‌ها و اتصال به اکوسیستم موجود سازمان
🧠 کاهش بار شناختیرابط کاربری ساده و متمرکز بدون ویژگی‌های اضافیکاهش زمان آموزش و افزایش تمرکز تیم بر کار اصلی
+ +
+

ابزاری که تیم واقعاً از آن استفاده کند، ارزشمندتر از ابزاری است که فقط خریداری شده ولی کسی سراغش نمی‌رود. سادگی xKanban تضمین می‌کند که نرخ پذیرش در تیم به حداکثر می‌رسد.

+
— اصل پذیرش فناوری در مهندسی نرم‌افزار
+
+ +
+📊 ارزش تجمعی: هر یک از ارزش‌های فوق به تنهایی مفید است، اما ترکیب آن‌ها یک اثر هم‌افزایی (Synergy) ایجاد می‌کند: تیمی که سریع شروع می‌کند، امن کار می‌کند، شفافیت دارد و داده‌هایش قابل حمل است، به مراتب چابک‌تر و تاب‌آورتر از تیمی است که هر یک از این مزایا را از ابزارهای جداگانه تأمین می‌کند. +
+
+
+ + + + +
+
+
۴
+
+

معماری فنی پروژه

+
Technical Architecture Deep Dive
+
+
+
+

xKanban بر پایه معماری Single-Page Application (SPA) با الگوی State-Driven Rendering پیاده‌سازی شده است. تمامی منطق در سمت کلاینت اجرا می‌شود و از معماری لایه‌ای سه‌تایی Presentation / Application / Data استفاده شده است.

+ +
+
+
🎨 Presentation Layer
+
+Toolbar Renderer +Board View +Column Renderer +Card Renderer +Modal System +Filter Panel +Toast Notifications +
+
+
▼
+
+
⚙️ Application Layer
+
+Project Manager +Board Manager +Column Manager +Card Manager +Tag Manager +Filter Engine +Webhook Service +Shortcut Handler +Export Engine +
+
+
▼
+
+
💾 Data Layer
+
+State Container +LocalStorage Adapter +AutoSave Engine +JSON Serializer +UUID Generator +
+
+
+ +

الف) متدهای راه‌اندازی و چرخه حیات

+
+// ── راه‌اندازی اولیه برنامه ──
+function init() { ... }

+// ── رندر کامل رابط کاربری ──
+function render() { ... }

+// ── رندر نوار ابزار بالا ──
+function renderToolbar() { ... }

+// ── رندر برد فعال ──
+function renderBoard() { ... } +
+ +

ب) متدهای مدیریت پروژه و پایداری

+
+// ── ذخیره پروژه در LocalStorage ──
+function saveProject() { ... }

+// ── بارگذاری پروژه از LocalStorage ──
+function loadProject() { ... }

+// ── ذخیره خودکار با Debounce ──
+function scheduleAutoSave() { ... }

+// ── بازیابی داده‌های ذخیره خودکار ──
+function recoverAutoSave() { ... }

+// ── تنظیمات پروژه (عنوان، توضیحات، وب‌هوک) ──
+function openProjectSettings() { ... }
+function saveProjectSettings() { ... } +
+ +

ج) متدهای مدیریت بردها

+
+// ── ایجاد برد جدید ──
+function createBoard() { ... }

+// ── ویرایش برد موجود ──
+function editBoard(boardId) { ... }

+// ── حذف برد ──
+function deleteBoard(boardId) { ... }

+// ── جابجایی بین بردها ──
+function switchBoard(boardId) { ... } +
+ +

د) متدهای مدیریت ستون‌ها

+
+// ── ایجاد ستون جدید ──
+function createColumn() { ... }

+// ── ویرایش ستون ──
+function editColumn(columnId) { ... }

+// ── حذف ستون ──
+function deleteColumn(columnId) { ... }

+// ── جابجایی ستون با Drag & Drop ──
+function moveColumn(fromIndex, toIndex) { ... } +
+ +

هـ) متدهای مدیریت کارت‌ها (غنی‌ترین ماژول)

+
+// ── ایجاد کارت جدید ──
+function createCard(columnId) { ... }

+// ── ویرایش کارت (Modal کامل) ──
+function editCard(cardId) { ... }

+// ── حذف کارت ──
+function deleteCard(cardId) { ... }

+// ── جابجایی کارت بین ستون‌ها ──
+function moveCard(cardId, targetColumnId) { ... }

+// ── افزودن/حذف مسئول ──
+function addAssignee(cardId, name) { ... }
+function removeAssignee(cardId, name) { ... }

+// ── مدیریت چک‌لیست ──
+function addChecklistItem(cardId, text) { ... }
+function toggleChecklistItem(cardId, itemIndex) { ... }
+function removeChecklistItem(cardId, itemIndex) { ... }

+// ── مدیریت وابستگی‌ها ──
+function addDependency(cardId, dependencyId) { ... }
+function removeDependency(cardId, dependencyId) { ... }

+// ── ثبت تاریخچه جابجایی ──
+function addHistoryEntry(cardId, fromColumn, toColumn) { ... } +
+ +

و) متدهای مدیریت تگ‌ها

+
+// ── مدیریت تگ‌های عمومی پروژه ──
+function openTagManager() { ... }
+function addTag(name, color) { ... }
+function removeTag(tagId) { ... }

+// ── تخصیص/حذف تگ به کارت ──
+function assignTagToCard(cardId, tagId) { ... }
+function removeTagFromCard(cardId, tagId) { ... } +
+ +

ز) متدهای فیلتر و جستجو

+
+// ── فیلتر چندبعدی کارت‌ها ──
+function filterCards() { ... }

+// ── جستجوی متنی در کارت‌ها ──
+function searchCards(query) { ... }

+// ── پاک‌سازی فیلترها ──
+function clearFilters() { ... } +
+ +

ح) متدهای صادرات و واردات

+
+// ── صادرات پروژه به فایل JSON ──
+function exportJSON() { ... }

+// ── واردات پروژه از فایل JSON ──
+function importJSON(file) { ... }

+// ── خروجی Markdown ──
+function exportMarkdown(boardFilter) { ... }

+// ── خروجی CSV ──
+function exportCSV(boardFilter) { ... } +
+ +

ط) متدهای یکپارچگی و Webhook

+
+// ── ارسال رویداد به Webhook ──
+function sendWebhook(eventType, data) { ... }

+// ── تست اتصال Webhook ──
+function testWebhook() { ... } +
+ +

ی) متدهای رابط کاربری و تعامل

+
+// ── سیستم Modal ──
+function openModal(modalId) { ... }
+function closeModal(modalId) { ... }

+// ── اعلان‌های Toast ──
+function showToast(message, type) { ... }

+// ── تغییر حالت تاریک/روشن ──
+function toggleDarkMode() { ... }

+// ── مدیریت میانبرهای کیبورد ──
+function handleKeyboardShortcuts(event) { ... } +
+ +

ک) متدهای کمکی

+
+// ── تولید شناسه یکتا ──
+function generateUUID() { ... }

+// ── محاسبه وضعیت سررسید کارت ──
+function getCardDueStatus(card) { ... }

+// ── محاسبه آمار برد ──
+function calculateBoardStats() { ... }

+// ── دانلود فایل ──
+function downloadFile(content, filename, mimeType) { ... } +
+ +
+💡 اصل طراحی کدها: تمامی متدها بر اساس اصل Single Responsibility طراحی شده‌اند. هر متد دقیقاً یک وظیفه مشخص دارد و از ترکیب آن‌ها، رفتارهای پیچیده‌تر ساخته می‌شود. بدنه متدها در این مستند با ... خلاصه شده تا تمرکز بر ساختار و معماری باقی بماند. +
+ +

جریان داده در سیستم:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
مرحلهعملیاتمتد درگیر
۱کاربر عملیاتی انجام می‌دهد (مثلاً ایجاد کارت)createCard()
۲وضعیت State به‌روزرسانی می‌شودمستقیم روی State Container
۳رابط کاربری مجدداً رندر می‌شودrender()
۴ذخیره خودکار زمان‌بندی می‌شودscheduleAutoSave()
۵در صورت فعال بودن، Webhook ارسال می‌شودsendWebhook()
۶اعلان تأیید به کاربر نمایش داده می‌شودshowToast()
+
+
+ + + + +
+
+
۵
+
+

مخاطبان هدف: سازمان‌ها و تیم‌های مناسب

+
Target Audience & Ideal Use Cases
+
+
+
+

xKanban برای طیف گسترده‌ای از سازمان‌ها و تیم‌ها مناسب است. در ادامه، مخاطبان ایده‌آل این ابزار بر اساس ویژگی‌ها و نیازمندی‌هایشان دسته‌بندی شده‌اند:

+ +

الف) بر اساس نوع سازمان:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع سازمانچرا xKanban مناسب است؟
استارتاپ‌هابودجه محدود، نیاز به شروع سریع، عدم تمایل به وابستگی به ابزارهای گران‌قیمت SaaS
شرکت‌های کوچک و متوسطفقدان تیم IT اختصاصی برای نگهداری سرور، نیاز به ابزار ساده ولی حرفه‌ای
سازمان‌های دولتی و نظامیالزامات سخت‌گیرانه امنیتی، ممنوعیت ارسال داده به سرورهای خارجی، نیاز به کارکرد آفلاین
مراکز تحقیقاتی و دانشگاهیمدیریت پروژه‌های پژوهشی، کار در محیط‌های ایزوله شبکه‌ای، بودجه محدود
شرکت‌های مشاوره‌ایمدیریت همزمان چندین پروژه مشتری، نیاز به قابلیت حمل و ارائه گزارش
تیم‌های توزیع‌شده و ریموتاشتراک‌گذاری آسان پروژه از طریق فایل، عدم وابستگی به اتصال اینترنت پایدار
+ +

ب) بر اساس نوع تیم:

+ +
+
+
💻
+
تیم‌های توسعه نرم‌افزار
+

مدیریت اسپرینت‌ها، پیگیری باگ‌ها، مدیریت وابستگی‌های فنی و یکپارچگی با ابزارهای CI/CD از طریق Webhook

+
+
+
🎨
+
تیم‌های طراحی و خلاقیت
+

پیگیری مراحل طراحی، مدیریت بازخوردها، رنگ‌بندی بصری برای دسته‌بندی پروژه‌ها

+
+
+
📢
+
تیم‌های بازاریابی و محتوا
+

مدیریت تقویم محتوایی، پیگیری کمپین‌ها، تخصیص وظایف به نویسندگان و طراحان

+
+
+
🏗️
+
تیم‌های عملیات و زیرساخت
+

مدیریت تیکت‌ها، پیگیری حوادث، ثبت تاریخچه جابجایی برای گزارش‌گیری

+
+
+
🎓
+
تیم‌های آموزشی و آکادمیک
+

مدیریت پروژه‌های دانشجویی، پیگیری تکالیف، کار در محیط‌های بدون اینترنت

+
+
+
🧑‍💼
+
فریلنسرها و مشاوران مستقل
+

مدیریت چندین پروژه مشتری، قابلیت حمل، عدم هزینه اشتراک ماهیانه

+
+
+ +

ج) سناریوهای ایده‌آل استفاده:

+ +
+ + +
+ +
+💡 نکته مهم: xKanban در حال حاضر برای استفاده فردی یا تیم‌های کوچک تا متوسط طراحی شده است. برای سازمان‌های بزرگ با نیاز به همزمانی چندکاربره بلادرنگ، نسخه فعلی به عنوان ابزار مکمل در کنار سیستم‌های سازمانی قابل استفاده است و نسخه چندکاربره در نقشه راه آینده قرار دارد. +
+
+
+ + + + +
+
+
۶
+
+

جمع‌بندی نهایی

+
Final Summary
+
+
+
+

xKanban پاسخی مهندسی‌شده به معضلات واقعی مدیریت پروژه در دنیای مدرن است. این ابزار با حذف وابستگی به سرور، تضمین مالکیت داده‌ها، ارائه قابلیت حمل بی‌نظیر و حفظ غنای عملکردی، جایگاه منحصربه‌فردی در اکوسیستم ابزارهای مدیریت پروژه دارد.

+ +
+

🎯 ارزش پیشنهادی xKanban در یک نگاه

+

ابزاری حرفه‌ای، مستقل، امن و قابل حمل برای مدیریت پروژه‌های کانبان که بدون هیچ هزینه‌ای، بدون نیاز به سرور و بدون وابستگی به اینترنت، در اختیار تیم شما قرار می‌گیرد.

+
+💎 فرمول ارزش xKanban:
+استقلال از زیرساخت + مالکیت کامل داده + قابلیت حمل + غنای عملکردی + سادگی = آزادی عمل مطلق تیم +
+
+ +
+📞 گام بعدی: برای ارزیابی عملی xKanban در محیط سازمان خود، می‌توانید فایل HTML را مستقیماً در مرورگر باز کرده و بدون هیچ پیکربندی، تجربه کاربری واقعی را لمس کنید. جهت سفارشی‌سازی یا توسعه ویژگی‌های اختصاصی، آماده برگزاری جلسه فنی هستیم. +
+
+
+ +
+این مستند محرمانه بوده و صرفاً جهت استفاده داخلی و ارائه به ذی‌نفعان تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+ +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۱:۳۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: داخلی - محصولی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Case_Study.html + + + + + + +xKanban | مستند جامع معرفی محصول و معماری فنی + + + +
+ + +
+
+
+ +
+
+
شماره مستند: PROD-XKN-1405-002
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۰:۳۰
+
طبقه‌بندی: عمومی - معرفی محصول
+
+
+
+PRODUCT DOCUMENTATION +

xKanban | ابزار مدیریت بردهای کانبان

+

معرفی محصول، تحلیل ارزش سازمانی و معماری فنی

+
+
+ + +
+ +
+مخاطبان مستند: مدیران فناوری اطلاعات، مدیران پروژه، سرپرستان تیم‌های توسعه، معماران نرم‌افزار و تصمیم‌گیرندگان سازمانی
+این مستند به معرفی جامع ابزار xKanban می‌پردازد؛ ابزاری که از دل نیازهای واقعی تیم‌های چابک متولد شده و با هدف حذف پیچیدگی‌های غیرضروری ابزارهای مدیریت پروژه طراحی شده است. در این مستند، از چرایی شکل‌گیری محصول تا معماری فنی و ارزش‌های سازمانی آن، همه‌چیز تشریح شده است. +
+ + +
+

📑 فهرست مطالب

+
    +
  1. شرح مسئله و چرایی خلق xKanban
  2. +
  3. مزایای کلیدی محصول
  4. +
  5. ارزش‌های سازمانی خلق‌شده
  6. +
  7. معماری فنی پروژه
  8. +
  9. مناسب برای چه سازمان‌ها و تیم‌هایی؟
  10. +
  11. جمع‌بندی و گام‌های بعدی
  12. +
+
+ + +
+
+
۱
+
+

شرح مسئله و چرایی خلق xKanban

+
Problem Statement & Product Genesis
+
+
+
+ +

در دنیای امروز، تقریباً هر تیمی — از توسعه نرم‌افزار گرفته تا بازاریابی، منابع انسانی و عملیات — با یک چالش مشترک دست‌وپنجه نرم می‌کند: چگونه کارها را به‌صورت شفاف، منظم و قابل ردیابی مدیریت کنیم؟ متدولوژی کانبان به‌عنوان یکی از مؤثرترین رویکردهای مدیریت بصری کار، سال‌هاست که پاسخ این سؤال را ارائه داده است؛ اما ابزارهای موجود برای پیاده‌سازی این متدولوژی، خود به منبع جدیدی از پیچیدگی تبدیل شده‌اند.

+ +

معضلات رایج در اکوسیستم ابزارهای فعلی:

+ +
+⚠️ چالش‌هایی که تیم‌ها هر روز با آن‌ها مواجه‌اند: +
    +
  • وابستگی به اینترنت و سرور: بسیاری از ابزارها نیازمند اتصال دائمی به اینترنت و سرورهای ابری هستند. در محیط‌هایی با محدودیت شبکه یا الزامات امنیتی بالا، این وابستگی یک مانع جدی است.
  • +
  • هزینه‌های اشتراک ماهانه: ابزارهای تجاری برای هر کاربر هزینه اشتراک دریافت می‌کنند. برای تیم‌های بزرگ، این هزینه به‌سرعت به رقم قابل‌توجهی تبدیل می‌شود.
  • +
  • پیچیدگی بیش‌ازحد: ابزارهایی مانند Jira یا Azure DevOps صدها قابلیت دارند که اکثر تیم‌ها از کمتر از ۲۰ درصد آن‌ها استفاده می‌کنند. این پیچیدگی، منحنی یادگیری را بالا برده و بهره‌وری را کاهش می‌دهد.
  • +
  • فرآیند نصب و راه‌اندازی سنگین: برخی ابزارها نیازمند نصب سرور، پیکربندی دیتابیس و مدیریت زیرساخت هستند که زمان و تخصص قابل‌توجهی می‌طلبد.
  • +
  • قفل‌شدگی داده‌ها (Vendor Lock-in): داده‌های پروژه در سرورهای ارائه‌دهنده سرویس ذخیره می‌شوند و خروج از آن اکوسیستم، پرهزینه و دشوار است.
  • +
  • عدم قابلیت حمل: انتقال پروژه از یک محیط به محیط دیگر (مثلاً از لپ‌تاپ شخصی به سیستم شرکت) در بسیاری از ابزارها فرآیندی پیچیده است.
  • +
+
+ +

این معضلات، یک شکاف آشکار در بازار ابزارهای مدیریت پروژه ایجاد کرده بود: جای خالی ابزاری ساده، مستقل، رایگان و در عین حال حرفه‌ای که بدون هیچ پیش‌نیازی قابل استفاده باشد و در عین حال، قابلیت‌های پیشرفته‌ای مانند فیلتر چندبعدی، تاریخچه تغییرات، وابستگی بین کارت‌ها و یکپارچگی با سیستم‌های خارجی را ارائه دهد.

+ +
+🎯 نقطه عطف: xKanban دقیقاً از همین شکاف متولد شد. هدف، خلق ابزاری بود که «صفر تا صد» مدیریت کانبان را بدون هیچ وابستگی خارجی، در یک فایل واحد و قابل حمل ارائه دهد — ابزاری که در کمتر از ۳ ثانیه باز شود و از همان لحظه اول قابل استفاده باشد. +
+ +

نیازمندی‌های کلیدی که xKanban برای پاسخ به آن‌ها طراحی شد:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ردیفنیازمندیوضعیت در ابزارهای موجودپاسخ xKanban
۱اجرای آفلاین و بدون سروراکثراً ناممکن✓ کاملاً آفلاین
۲بدون هزینه اشتراکاشتراک ماهانه/سالانه✓ کاملاً رایگان
۳راه‌اندازی فورینیاز به نصب و پیکربندی✓ یک کلیک
۴قابلیت حمل داده‌هامحدود و پیچیده✓ فایل JSON
۵سادگی همراه با قدرتیا ساده یا پیچیده✓ تعادل بهینه
۶مالکیت کامل داده‌هاذخیره در سرور ثالث✓ کاملاً محلی
+ +
+
+ + +
+
+
۲
+
+

مزایای کلیدی محصول

+
Key Product Advantages
+
+
+
+ +

xKanban مجموعه‌ای از مزایای منحصربه‌فرد را ارائه می‌دهد که آن را از تمامی ابزارهای موجود در بازار متمایز می‌سازد. این مزایا نه صرفاً ویژگی‌های فنی، بلکه تصمیمات استراتژیک طراحی هستند که هر کدام پاسخی مستقیم به یکی از معضلات مطرح‌شده در بخش قبل می‌باشند.

+ +
+
+
۰ ثانیه
نصب
+
بدون نیاز به هیچ فرآیند نصب یا پیکربندی
+
+
+
۱۰۰٪
آفلاین
+
اجرای کامل بدون نیاز به اینترنت یا سرور
+
+
+
۱ فایل
واحد
+
تمام محصول در یک فایل HTML مستقل
+
+
+ +
+
+
🚀
+
راه‌اندازی آنی
+

فایل HTML را در مرورگر باز کنید. تمام. هیچ سروری، هیچ دیتابیسی، هیچ اکانتی لازم نیست. در کمتر از ۳ ثانیه آماده استفاده هستید.

+
+
+
🔒
+
حریم خصوصی مطلق
+

تمام داده‌ها در مرورگر شما باقی می‌مانند. هیچ اطلاعاتی به هیچ سرور خارجی ارسال نمی‌شود. مالکیت داده‌ها ۱۰۰٪ در اختیار شماست.

+
+
+
📦
+
قابلیت حمل بی‌نظیر
+

پروژه خود را به‌صورت فایل JSON ذخیره کنید و روی فلش، ایمیل یا هر فضای ابری منتقل کنید. در هر سیستمی قابل بارگذاری است.

+
+
+
🎨
+
رابط کاربری مدرن و حرفه‌ای
+

طراحی بصری جذاب با پشتیبانی از حالت تاریک/روشن، رنگ‌بندی سفارشی برای بردها، ستون‌ها و کارت‌ها و انیمیشن‌های روان.

+
+
+
🔍
+
فیلتر چندبعدی پیشرفته
+

فیلتر هم‌زمان بر اساس تگ، مسئول، وضعیت سررسید و جستجوی متنی. یافتن هر کارت در کمتر از یک ثانیه حتی در پروژه‌های بزرگ.

+
+
+
📡
+
یکپارچگی با Webhook
+

ارسال خودکار رویدادهای پروژه به Slack، Teams یا هر سیستم خارجی. ساختار JSON استاندارد با eventId و timestamp.

+
+
+
⌨️
+
میانبرهای کیبورد حرفه‌ای
+

بیش از ۸ میانبر کیبورد برای کاربران حرفه‌ای. از Ctrl+S برای ذخیره تا Alt+Arrow برای جابجایی سریع کارت‌ها بین ستون‌ها.

+
+
+
📊
+
آمار بلادرنگ پروژه
+

مشاهده آنی تعداد کارت‌ها، درصد پیشرفت، کارت‌های عقب‌افتاده و نزدیک به موعد در نوار وضعیت پایین صفحه.

+
+
+ +
+💎 مزیت رقابتی اصلی: xKanban تنها ابزاری است که ترکیب «سادگی یک فایل HTML» و «قدرت یک سیستم مدیریت پروژه حرفه‌ای» را به‌صورت هم‌زمان ارائه می‌دهد. هیچ ابزار دیگری در بازار این تعادل را برقرار نکرده است. +
+ +

مقایسه با ابزارهای رایج بازار:

+
+
+

ابزارهای تجاری (Jira, Trello, Asana)

+
    +
  • هزینه اشتراک ماهانه بالا
  • +
  • نیاز به اینترنت الزامی
  • +
  • نصب و راه‌اندازی ثبت‌نام + پیکربندی
  • +
  • مالکیت داده سرور ثالث
  • +
  • پیچیدگی بسیار بالا
  • +
  • آفلاین ناممکن
  • +
+
+ +
+ +
+
+ + +
+
+
۳
+
+

ارزش‌های سازمانی خلق‌شده

+
Organizational Value Proposition
+
+
+
+ +

استفاده از xKanban در یک سازمان، فراتر از صرفاً «مدیریت کارها» است. این ابزار، ارزش‌های استراتژیک و عملیاتی ملموسی را در سطوح مختلف سازمان خلق می‌کند که در ادامه به تفصیل تشریح شده‌اند:

+ +
+
💰
+
+
حذف کامل هزینه‌های لایسنس و اشتراک
+

سازمان‌هایی که از ابزارهایی مانند Jira یا Azure DevOps استفاده می‌کنند، سالانه مبالغ قابل‌توجهی بابت لایسنس هر کاربر پرداخت می‌کنند. xKanban این هزینه را به صفر می‌رساند و بودجه آزادشده را برای سرمایه‌گذاری در حوزه‌های ارزشمندتر آزاد می‌کند.

+
+
+ +
+
🔐
+
+
تطبیق با الزامات امنیتی و حریم خصوصی
+

در سازمان‌هایی با حساسیت امنیتی بالا (نظامی، بانکی، بهداشتی)، ارسال داده‌های پروژه به سرورهای ابری خارجی ممنوع یا محدود است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را به‌صورت ذاتی رعایت می‌کند.

+
+
+ +
+
⚡
+
+
کاهش زمان Onboarding اعضای جدید
+

برخلاف ابزارهای پیچیده که آموزش آن‌ها هفته‌ها زمان می‌برد، xKanban به‌قدری ساده و شهودی است که یک عضو جدید تیم در کمتر از ۱۰ دقیقه با آن آشنا شده و شروع به کار می‌کند.

+
+
+ +
+
📈
+
+
افزایش شفافیت و پاسخگویی در تیم
+

با نمایش بصری وضعیت تمام کارها، تاریخچه جابجایی کارت‌ها و آمار بلادرنگ پیشرفت، هر عضو تیم و هر مدیری در هر لحظه دید کاملی از وضعیت پروژه دارد. این شفافیت، فرهنگ پاسخگویی را تقویت می‌کند.

+
+
+ +
+
🔄
+
+
استانداردسازی فرآیندهای مدیریت پروژه
+

xKanban تیم‌ها را به استفاده از یک متدولوژی استاندارد (کانبان) هدایت می‌کند. ستون‌های مشخص، جریان کار تعریف‌شده و تاریخچه تغییرات، همگی به ایجاد یک فرآیند تکرارپذیر و قابل اندازه‌گیری کمک می‌کنند.

+
+
+ +
+
🛡️
+
+
حذف ریسک Vendor Lock-in
+

داده‌های پروژه در فرمت استاندارد JSON ذخیره می‌شوند. این یعنی سازمان هیچ‌گاه در اکوسیستم یک ارائه‌دهنده خاص قفل نمی‌شود و در هر زمان می‌تواند داده‌های خود را به هر سیستم دیگری منتقل کند.

+
+
+ +
+
🌐
+
+
یکپارچگی با اکوسیستم موجود سازمان
+

از طریق مکانیزم Webhook، xKanban می‌تواند رویدادهای پروژه را به Slack، Microsoft Teams، سیستم‌های CI/CD یا هر API سفارشی ارسال کند. این یعنی xKanban به‌جای جایگزینی ابزارهای موجود، آن‌ها را تکمیل می‌کند.

+
+
+ +
+
📉
+
+
کاهش سربار مدیریت زیرساخت
+

بدون نیاز به سرور، دیتابیس، به‌روزرسانی‌های امنیتی و مانیتورینگ، تیم IT سازمان از بار مدیریت یک ابزار اضافی رها می‌شود. این صرفه‌جویی در زمان و منابع انسانی، ارزش پنهان اما بسیار قابل‌توجهی است.

+
+
+ +
+📊 خلاصه ارزش‌آفرینی: xKanban در چهار بُعد اصلی برای سازمان ارزش خلق می‌کند: کاهش هزینه‌ها (حذف لایسنس و زیرساخت)، افزایش بهره‌وری (Onboarding سریع و رابط شهودی)، کاهش ریسک (امنیت داده و عدم وابستگی) و بهبود کیفیت فرآیندها (استانداردسازی و شفافیت). +
+ +
+
+ + +
+
+
۴
+
+

معماری فنی پروژه

+
Technical Architecture & Code Structure
+
+
+
+ +

xKanban به‌عنوان یک Single-Page Application (SPA) تک‌فایلی طراحی شده است که تمامی لایه‌های نمایش، منطق و داده را در یک فایل HTML واحد encapsulate می‌کند. این تصمیم معماری، اگرچه در نگاه اول غیرمعمول به نظر می‌رسد، اما با توجه به اهداف محصول (آفلاین بودن، قابلیت حمل و عدم وابستگی) منطقی‌ترین انتخاب ممکن بوده است.

+ +

الف) نمودار معماری لایه‌ای

+ +
+
+
🎨 Presentation Layer
+
+Toolbar UI +Board Renderer +Column Renderer +Card Renderer +Modal System +Filter Panel +Stats Bar +Theme Engine +
+
+
▼ Event Binding & State Observation ▼
+
+
⚙️ Application Logic Layer
+
+ProjectManager +BoardManager +ColumnManager +CardManager +TagManager +FilterEngine +WebhookService +ShortcutHandler +HistoryTracker +
+
+
▼ Read / Write / Sync ▼
+
+
💾 Data & Persistence Layer
+
+AppState (In-Memory) +LocalStorage Adapter +AutoSave Engine +JSON Serializer +Export/Import Service +Recovery Manager +
+
+
+ +

ب) مدل داده‌ای (Data Schema)

+

ساختار داده‌ای پروژه از یک سلسله‌مراتب چهارسطحی پیروی می‌کند:

+ +
+// ساختار سلسله‌مراتبی داده‌ها
+Project
+  ├── id: UUID
+  ├── title: string
+  ├── description: string
+  ├── createdAt: ISO8601
+  ├── webhook: { enabled, url }
+  ├── globalTags: [Tag]
+  └── boards: [
+        Board
+          ├── id, title, backgroundColor
+          └── columns: [
+              Column
+                ├── id, title, order
+                └── cards: [
+                    Card
+                      ├── id, title, description
+                      ├── dueDate, assignees, tags
+                      ├── dependencies, checklist
+                      └── history: [HistoryEntry]
+                  ]
+            ]
+      ]
+
+ +

ج) ماژول‌های اصلی و متدهای کلیدی

+

در ادامه، مهم‌ترین ماژول‌های سیستم به همراه متدهای کلیدی هر کدام تشریح شده‌اند. برای حفظ خوانایی، بدنه متدها خلاصه شده و تنها امضای آن‌ها نمایش داده شده است:

+ +
📁 ماژول ProjectManager
+
    +
  • +initProject() +مقداردهی اولیه پروژه +
  • +
  • +loadProject(data) +بارگذاری پروژه از فایل JSON +
  • +
  • +saveProject(filename) +ذخیره پروژه به‌صورت فایل JSON +
  • +
  • +updateProjectSettings(title, desc, webhook) +به‌روزرسانی تنظیمات پروژه +
  • +
  • +getProjectStats() +محاسبه آمار کلی پروژه +
  • +
+ +
📊 ماژول BoardManager
+
    +
  • +createBoard(title, description, bgColor) +ایجاد برد جدید +
  • +
  • +editBoard(boardId, data) +ویرایش برد موجود +
  • +
  • +deleteBoard(boardId) +حذف برد با تأیید کاربر +
  • +
  • +switchBoard(boardId) +تغییر برد فعال +
  • +
  • +renderBoardList() +رندر لیست بردها در منو +
  • +
+ +
📑 ماژول ColumnManager
+
    +
  • +addColumn(boardId, title, bgColor, textColor) +افزودن ستون جدید به برد +
  • +
  • +editColumn(columnId, data) +ویرایش ویژگی‌های ستون +
  • +
  • +deleteColumn(columnId) +حذف ستون و کارت‌های آن +
  • +
  • +reorderColumns(draggedId, targetId) +تغییر ترتیب ستون‌ها با Drag & Drop +
  • +
  • +renderColumns(boardId) +رندر ستون‌های برد فعال +
  • +
+ +
📝 ماژول CardManager
+
    +
  • +createCard(columnId, cardData) +ایجاد کارت جدید در ستون +
  • +
  • +updateCard(cardId, updates) +به‌روزرسانی اطلاعات کارت +
  • +
  • +deleteCard(cardId) +حذف کارت از ستون +
  • +
  • +moveCard(cardId, fromColumnId, toColumnId) +جابجایی کارت بین ستون‌ها +
  • +
  • +addChecklistItem(cardId, text) +افزودن آیتم به چک‌لیست +
  • +
  • +toggleChecklistItem(cardId, itemId) +تغییر وضعیت آیتم چک‌لیست +
  • +
  • +addDependency(cardId, dependOnCardId) +ایجاد وابستگی بین کارت‌ها +
  • +
  • +assignMember(cardId, memberName) +تخصیص مسئول به کارت +
  • +
  • +getCardDueStatus(card) +تعیین وضعیت سررسید کارت +
  • +
  • +openCardModal(cardId) +باز کردن پنجره ویرایش کارت +
  • +
+ +
🏷️ ماژول TagManager
+
    +
  • +createTag(name, color) +ایجاد تگ عمومی جدید +
  • +
  • +deleteTag(tagId) +حذف تگ و حذف از کارت‌ها +
  • +
  • +assignTagToCard(cardId, tagId) +تخصیص تگ به کارت +
  • +
  • +removeTagFromCard(cardId, tagId) +حذف تگ از کارت +
  • +
  • +renderTagManager() +رندر پنل مدیریت تگ‌ها +
  • +
+ +
🔍 ماژول FilterEngine
+
    +
  • +applyFilters(criteria) +اعمال فیلترهای چندبعدی +
  • +
  • +filterByTags(selectedTags) +فیلتر بر اساس تگ‌ها +
  • +
  • +filterByAssignees(selectedAssignees) +فیلتر بر اساس مسئولین +
  • +
  • +filterByDueStatus(status) +فیلتر بر اساس وضعیت سررسید +
  • +
  • +searchCards(query) +جستجوی متنی در کارت‌ها +
  • +
  • +clearAllFilters() +پاک‌سازی تمام فیلترها +
  • +
+ +
📡 ماژول WebhookService
+
    +
  • +sendEvent(eventType, payload) +ارسال رویداد به URL پیکربندی‌شده +
  • +
  • +testWebhook(url) +تست اتصال Webhook +
  • +
  • +buildEventPayload(eventType, data) +ساخت ساختار JSON استاندارد رویداد +
  • +
+ +
💾 ماژول PersistenceEngine
+
    +
  • +autoSave() +ذخیره خودکار در LocalStorage +
  • +
  • +loadAutoSave() +بارگذاری داده‌های ذخیره‌شده خودکار +
  • +
  • +scheduleAutoSave() +زمان‌بندی ذخیره با Debounce +
  • +
  • +exportToJSON() +خروجی فایل JSON +
  • +
  • +importFromJSON(file) +بارگذاری از فایل JSON +
  • +
  • +exportToMarkdown(boardId) +خروجی فرمت Markdown +
  • +
  • +exportToCSV(boardId) +خروجی فرمت CSV +
  • +
  • +checkRecovery() +بررسی وجود داده‌های بازیابی +
  • +
+ +
⌨️ ماژول ShortcutHandler
+
    +
  • +registerShortcuts() +ثبت تمام میانبرهای کیبورد +
  • +
  • +handleKeyDown(event) +پردازش رویدادهای کیبورد +
  • +
  • +navigateCards(direction) +پیمایش بین کارت‌ها با Tab +
  • +
  • +moveCardWithKeyboard(direction) +جابجایی کارت با Alt+Arrow +
  • +
+ +

د) الگوهای طراحی به‌کاررفته

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل استفادههدف
State-Driven Renderingکل رابط کاربریرندر UI بر اساس وضعیت مرکزی AppState
Observer / Pub-Subارتباط ماژول‌هااطلاع‌رسانی تغییرات وضعیت به ماژول‌های وابسته
DebouncingAutoSave Engineجلوگیری از نوشتن مکرر در LocalStorage
Factoryایجاد موجودیت‌هاتولید اشیاء Card، Column، Board با UUID
CommandUndo/Redoذخیره عملیات برای امکان بازگشت
SingletonAppStateیک منبع واحد حقیقت برای کل برنامه
+ +

ه) جریان داده (Data Flow)

+
+🔄 چرخه حیات یک عملیات کاربر:

+۱. User Action: کاربر یک کارت را از ستون «در حال انجام» به ستون «تکمیل‌شده» می‌کشد.
+۲. Event Capture: رویداد Drag & Drop توسط ColumnManager دریافت می‌شود.
+۳. State Update: متد moveCard() از CardManager فراخوانی شده و AppState به‌روزرسانی می‌شود.
+۴. History Log: متد HistoryTracker.log() جابجایی را با timestamp ثبت می‌کند.
+۵. Re-Render: متد renderColumns() رابط کاربری را با وضعیت جدید به‌روزرسانی می‌کند.
+۶. AutoSave: متد scheduleAutoSave() با تأخیر ۱ ثانیه، وضعیت را در LocalStorage ذخیره می‌کند.
+۷. Webhook: در صورت فعال بودن، متد sendEvent('card.moved', payload) رویداد را ارسال می‌کند.
+۸. Stats Update: متد getProjectStats() آمار نوار وضعیت را به‌روزرسانی می‌کند. +
+ +
+
+ + +
+
+
۵
+
+

مناسب برای چه سازمان‌ها و تیم‌هایی؟

+
Target Audience & Ideal Use Cases
+
+
+
+ +

xKanban به‌گونه‌ای طراحی شده که طیف وسیعی از سازمان‌ها و تیم‌ها بتوانند از آن بهره‌مند شوند. با این حال، برخی محیط‌ها بیشترین ارزش را از این ابزار دریافت خواهند کرد:

+ +

الف) سازمان‌های هدف

+ +
+
+
🏢
+
استارتاپ‌ها و شرکت‌های کوچک
+

تیم‌هایی که بودجه محدود دارند و به ابزاری رایگان، سریع و بدون سربار نیاز دارند. xKanban جایگزین ایده‌آل Trello و Asana برای این تیم‌هاست.

+
+
+
🏛️
+
سازمان‌های دولتی و نظامی
+

محیط‌هایی با محدودیت‌های امنیتی شدید که استفاده از سرویس‌های ابری خارجی ممنوع است. xKanban با ذخیره‌سازی ۱۰۰٪ محلی، این الزامات را رعایت می‌کند.

+
+
+
🏥
+
مراکز بهداشتی و درمانی
+

بیمارستان‌ها و مراکز تحقیقاتی که داده‌های حساس بیماران و پروژه‌ها نباید از شبکه داخلی خارج شود.

+
+
+
🏦
+
مؤسسات مالی و بانکی
+

سازمان‌هایی که تحت مقررات سخت‌گیرانه حفاظت از داده (مانند PCI-DSS) فعالیت می‌کنند و نمی‌توانند اطلاعات پروژه‌ها را در سرورهای ثالث ذخیره کنند.

+
+
+
🎓
+
دانشگاه‌ها و مراکز آموزشی
+

اساتید و دانشجویانی که برای مدیریت پروژه‌های تحقیقاتی، پایان‌نامه‌ها و کارهای گروهی به ابزاری ساده و رایگان نیاز دارند.

+
+
+
🌍
+
تیم‌های دورکار و فریلنسرها
+

افرادی که در محیط‌های مختلف کار می‌کنند و نیاز دارند پروژه خود را روی فلش یا فضای ابری شخصی حمل کنند.

+
+
+ +

ب) تیم‌های هدف

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع تیمنحوه استفاده از xKanbanارزش اصلی
تیم‌های توسعه نرم‌افزارمدیریت Sprint، باگ‌ها و Featureهایکپارچگی با CI/CD از طریق Webhook
تیم‌های DevOpsردیابی Incidentها و Change Requestهااجرای آفلاین در محیط‌های ایزوله
تیم‌های بازاریابیمدیریت کمپین‌ها و محتوای تولیدیسادگی و سرعت راه‌اندازی
تیم‌های منابع انسانیردیابی فرآیند استخدام و Onboardingحریم خصوصی داده‌های پرسنلی
تیم‌های طراحیمدیریت پروژه‌های طراحی و بازخوردرابط بصری جذاب و رنگ‌بندی سفارشی
تیم‌های پشتیبانیمدیریت تیکت‌ها و درخواست‌های مشتریانآمار بلادرنگ و فیلتر پیشرفته
مدیران محصولنقشه راه محصول و اولویت‌بندی ویژگی‌هاوابستگی بین کارت‌ها و چک‌لیست
+ +
+🎯 قانون کلی: هر تیمی که با سؤال «الان هر کس دارد روی چه چیزی کار می‌کند و وضعیتش چیست؟» مواجه است، یک کاندیدای ایده‌آل برای استفاده از xKanban محسوب می‌شود. +
+ +

ج) چه زمانی xKanban بهترین انتخاب نیست؟

+
+💡 شفافیت کامل: xKanban برای سناریوهای زیر طراحی نشده و در این موارد، ابزارهای تخصصی‌تر توصیه می‌شوند: +
    +
  • تیم‌های بسیار بزرگ (بیش از ۵۰ نفر) که نیاز به مدیریت دسترسی سطحی و نقش‌های پیچیده دارند
  • +
  • سازمان‌هایی که نیاز به هم‌زمانی بلادرنگ (Real-time Collaboration) بین چندین کاربر دارند
  • +
  • محیط‌هایی که نیاز به یکپارچگی عمیق با اکوسیستم‌های خاص (مانند SAP یا Salesforce) دارند
  • +
+
+ +
+
+ + +
+
+
۶
+
+

جمع‌بندی و گام‌های بعدی

+
Summary & Next Steps
+
+
+
+ +

xKanban پاسخی عملی و مهندسی‌شده به یکی از رایج‌ترین چالش‌های تیم‌های مدرن است: مدیریت بصری کارها بدون پیچیدگی، بدون هزینه و بدون وابستگی. این ابزار از دل تجربه واقعی در مدیریت پروژه‌های نرم‌افزاری متولد شده و هر ویژگی آن، پاسخی مستقیم به یک نیاز واقعی است.

+ +
+

🎯 چرا xKanban؟

+

زیرا مدیریت پروژه نباید خودش یک پروژه باشد.

+

xKanban با ترکیب سادگی، قدرت و استقلال، ابزاری را ارائه می‌دهد که از لحظه اول قابل استفاده است، داده‌های شما را در اختیار خودتان نگه می‌دارد و هیچ هزینه‌ای بر دوش سازمان نمی‌گذارد.

+
+💎 ارزش نهایی:
+صفر هزینه + صفر وابستگی + صفر پیچیدگی = ۱۰۰٪ بهره‌وری +
+
+ +

گام‌های پیشنهادی برای شروع:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
گاماقدامزمان تخمینی
۱فایل xKanban.html را در مرورگر باز کنید۳ ثانیه
۲یک پروژه و برد آزمایشی ایجاد کنید۲ دقیقه
۳ستون‌ها و کارت‌های واقعی تیم خود را وارد کنید۱۰ دقیقه
۴تگ‌ها و مسئولین را تعریف کنید۵ دقیقه
۵پروژه را به‌صورت فایل JSON ذخیره کنید۱ دقیقه
۶از xKanban لذت ببرید! 🎉همیشگی
+ +
+📞 تماس و پشتیبانی: برای دریافت مشاوره فنی، سفارشی‌سازی xKanban بر اساس نیازهای خاص سازمانی یا یکپارچگی با سیستم‌های موجود، آماده برگزاری جلسه فنی هستیم. طراحی، تحلیل و توسعه توسط هادی خزاعی اصل، معمار و توسعه‌دهنده ارشد نرم‌افزار. +
+ +
+
+ +
+این مستند جهت معرفی محصول و تحلیل فنی تهیه شده است. هرگونه استفاده تجاری از محتوای این مستند بدون اجازه کتبی ممنوع است. +
+ +
+ + +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۰:۳۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: عمومی
+
+ +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Techincal_Documentation.html + + + + + + +مستند فنی پروژه xKanban | تحلیل جامع معماری و پیاده‌سازی + + + +
+
+
+
+ +
+
+
شماره مستند: TECH-XKN-1405-001
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۰:۰۰
+
طبقه‌بندی: داخلی - فنی
+
+
+
+TECHNICAL DOCUMENTATION +

مستند فنی پروژه xKanban

+

تحلیل جامع معماری، ساختار داده و پیاده‌سازی ابزار مدیریت بردهای کانبان

+
+
+ +
+
+مخاطبان مستند: تیم فنی، معماران نرم‌افزار، توسعه‌دهندگان و مدیران فنی
+این مستند به‌عنوان مرجع فنی جامع پروژه xKanban تهیه شده است و تمامی لایه‌های معماری، ساختار داده‌ها، ماژول‌های کلیدی و مکانیزم‌های پیاده‌سازی را از دیدگاه یک معمار ارشد نرم‌افزار تشریح می‌نماید. هدف از این مستند، ارائه درک عمیق از تصمیمات طراحی و ایجاد پایه‌ای مستحکم برای توسعه و نگهداری آتی محصول می‌باشد. +
+ + +
+
+
۱
+
+

خلاصه اجرایی و معرفی محصول

+
Executive Summary & Product Overview
+
+
+
+

پروژه xKanban یک ابزار تحت وب مستقل (Standalone) برای مدیریت بردهای کانبان است که با هدف ارائه راهکاری چابک، قابل حمل و بدون نیاز به سرور طراحی و پیاده‌سازی شده است. این محصول به کاربران امکان می‌دهد تا پروژه‌ها، بردها، ستون‌ها و کارت‌های کاری خود را با ساختاری استاندارد و حرفه‌ای مدیریت نمایند.

+ +
+
+
۱۰۰٪
Client-Side
+
اجرا در مرورگر بدون نیاز به سرور
+
+
+
Single
File
+
توزیع به صورت یک فایل HTML مستقل
+
+
+
Zero
Dependency
+
بدون وابستگی به کتابخانه خارجی
+
+
+ +
+🎯 چشم‌انداز طراحی: xKanban با فلسفه «ابزار در جیب کاربر» طراحی شده است؛ به گونه‌ای که کاربر بدون نیاز به اتصال اینترنت، نصب نرم‌افزار یا ایجاد حساب کاربری، به یک سیستم کامل مدیریت پروژه دسترسی داشته باشد. +
+ +

اهداف کلیدی پروژه:

+
    +
  • استقلال کامل: اجرا به صورت آفلاین و بدون نیاز به زیرساخت سرور
  • +
  • قابلیت حمل: ذخیره و انتقال پروژه از طریق فایل JSON
  • +
  • تجربه کاربری حرفه‌ای: رابط کاربری مدرن با پشتیبانی از حالت تاریک/روشن
  • +
  • استانداردسازی: پیاده‌سازی دقیق متدولوژی کانبان با قابلیت‌های پیشرفته
  • +
  • یکپارچگی: اتصال به سیستم‌های خارجی از طریق Webhook
  • +
+
+
+ + +
+
+
۲
+
+

معماری کلی سیستم

+
System Architecture Overview
+
+
+
+

معماری xKanban بر پایه الگوی Single-Page Application (SPA) با رویکرد State-Driven طراحی شده است. تمامی منطق برنامه در لایه کلاینت اجرا می‌شود و از الگوی MVC سبک برای جداسازی مسئولیت‌ها استفاده شده است.

+ +
+
+
🎨 Presentation Layer (UI)
+
+Toolbar +Board View +Column Renderer +Card Renderer +Modal System +Filter Panel +
+
+
▼
+
+
⚙️ Application Layer (Logic)
+
+Board Manager +Column Manager +Card Manager +Tag Manager +Filter Engine +Shortcut Handler +Webhook Service +
+
+
▼
+
+
💾 Data Layer (State & Persistence)
+
+Project State +LocalStorage +AutoSave Engine +JSON Export/Import +History Tracker +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
لایه معماریمسئولیت اصلیتکنولوژی
Presentationرندر رابط کاربری و مدیریت رویدادهاHTML5 + CSS3 + Vanilla JS
Applicationمنطق تجاری و مدیریت عملیاتES6+ Modules Pattern
Dataمدیریت وضعیت و پایداری دادهLocalStorage + JSON API
Integrationارتباط با سیستم‌های خارجیFetch API + Webhook
+ +
+💡 نکته معماری: انتخاب معماری تک‌فایلی (Single-File) با وجود پیچیدگی بالای پروژه، یک تصمیم استراتژیک بوده است. این رویکرد امکان توزیع آسان، اجرای آفلاین و عدم وابستگی به زیرساخت را فراهم می‌آورد. +
+
+
+ + +
+
+
۳
+
+

ساختار داده‌ها و مدل‌ها

+
Data Models & Schema Design
+
+
+
+

مدل داده‌ای xKanban بر پایه ساختار سلسله‌مراتبی Project → Board → Column → Card طراحی شده است. هر سطح از این سلسله‌مراتب، موجودیت مستقلی با ویژگی‌ها و روابط خاص خود دارد.

+ +

الف) مدل Project (پروژه)

+
+Project {
+  id: "uuid",
+  title: "string",
+  description: "string",
+  createdAt: "ISO8601",
+  webhook: { enabled: boolean, url: "string" },
+  boards: [Board],
+  globalTags: [Tag]
+} +
+ +

ب) مدل Board (برد)

+
+Board {
+  id: "uuid",
+  title: "string",
+  description: "string",
+  backgroundColor: "#hex",
+  columns: [Column]
+} +
+ +

ج) مدل Column (ستون)

+
+Column {
+  id: "uuid",
+  title: "string",
+  backgroundColor: "#hex",
+  textColor: "#hex",
+  order: number,
+  cards: [Card]
+} +
+ +

د) مدل Card (کارت) - غنی‌ترین موجودیت

+
+Card {
+  id: "uuid",
+  title: "string",
+  description: "string",
+  dueDate: "ISO8601 | null",
+  backgroundColor: "#hex",
+  assignees: ["string"],
+  tags: ["tagId"],
+  dependencies: ["cardId"],
+  checklist: [{ text: "string", done: boolean }],
+  history: [{ timestamp, action, fromColumn, toColumn }]
+} +
+ +
+⚠️ نکته طراحی مهم: استفاده از UUID برای شناسه‌ها، امکان ادغام پروژه‌ها، جلوگیری از تداخل شناسه‌ها در عملیات Import/Export و پشتیبانی از همزمانی (Concurrency) را فراهم می‌آورد. این تصمیم برای مقیاس‌پذیری آینده حیاتی است. +
+ +

روابط بین موجودیت‌ها:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
رابطهنوعتوضیح
Project → BoardsOne-to-Manyهر پروژه می‌تواند چندین برد داشته باشد
Board → ColumnsOne-to-Manyهر برد شامل ستون‌های متعدد است
Column → CardsOne-to-Manyهر ستون شامل کارت‌های متعدد است
Card ↔ CardMany-to-Manyوابستگی بین کارت‌ها (Dependencies)
Card → TagsMany-to-Manyکارت‌ها می‌توانند چندین برچسب داشته باشند
Card → AssigneesMany-to-Manyهر کارت می‌تواند چندین مسئول داشته باشد
+
+
+ + +
+
+
۴
+
+

ماژول‌های کلیدی و مسئولیت‌ها

+
Core Modules & Responsibilities
+
+
+
+

سیستم xKanban از ماژول‌های مجزا و با مسئولیت مشخص تشکیل شده است. این جداسازی بر اساس اصل Single Responsibility Principle (SRP) انجام شده و امکان نگهداری و توسعه آتی را فراهم می‌آورد.

+ +
+
+
📊
+
Board Manager
+

مدیریت چرخه حیات بردها شامل ایجاد، ویرایش، حذف و جابجایی بین بردها. نگهداری وضعیت فعال برد فعلی.

+
+
+
📑
+
Column Manager
+

مدیریت ستون‌ها با قابلیت Drag & Drop برای تغییر ترتیب. پشتیبانی از رنگ‌بندی مستقل برای هر ستون.

+
+
+
📝
+
Card Manager
+

مدیریت کامل کارت‌ها شامل متادیتای غنی، چک‌لیست، وابستگی‌ها و تاریخچه جابجایی.

+
+
+
🏷️
+
Tag Manager
+

مدیریت تگ‌های عمومی پروژه با قابلیت استفاده مجدد در کارت‌های مختلف.

+
+
+
🔍
+
Filter Engine
+

موتور فیلتر چندبعدی بر اساس تگ، مسئول، وضعیت و تاریخ سررسید.

+
+
+
⌨️
+
Shortcut Handler
+

مدیریت میانبرهای کیبورد برای افزایش بهره‌وری کاربران حرفه‌ای.

+
+
+
💾
+
AutoSave Engine
+

ذخیره خودکار وضعیت در LocalStorage با مکانیزم بازیابی در صورت قطع ناگهانی.

+
+
+
📡
+
Webhook Service
+

ارسال رویدادهای پروژه به آدرس URL پیکربندی‌شده با ساختار JSON استاندارد.

+
+
+ +
+✓ مزایای معماری ماژولار: +
    +
  • جداسازی کامل مسئولیت‌ها و کاهش Coupling
  • +
  • قابلیت تست‌پذیری هر ماژول به صورت مستقل
  • +
  • امکان توسعه ویژگی‌های جدید بدون تأثیر بر ماژول‌های موجود
  • +
  • کاهش پیچیدگی شناختی برای توسعه‌دهندگان جدید
  • +
+
+
+
+ + +
+
+
۵
+
+

ویژگی‌های کلیدی و قابلیت‌ها

+
Key Features & Capabilities
+
+
+
+

xKanban مجموعه‌ای از ویژگی‌های پیشرفته را ارائه می‌دهد که آن را از ابزارهای ساده کانبان متمایز می‌سازد. در ادامه به تحلیل فنی هر ویژگی پرداخته شده است:

+ +

۱) سیستم مدیریت بردهای چندگانه

+

امکان ایجاد و مدیریت چندین برد مستقل در یک پروژه، با قابلیت جابجایی سریع بین آن‌ها از طریق منوی کشویی. هر برد دارای تنظیمات مستقل شامل رنگ پس‌زمینه و توضیحات اختصاصی است.

+ +

۲) Drag & Drop پیشرفته ستون‌ها

+

پیاده‌سازی مکانیزم Drag & Drop با استفاده از HTML5 Drag API که امکان تغییر ترتیب ستون‌ها را با کشیدن هدر آن‌ها فراهم می‌آورد. این ویژگی با حفظ وضعیت در مدل داده، پایداری ترتیب را تضمین می‌کند.

+ +

۳) کارت‌های غنی با متادیتای کامل

+

هر کارت می‌تواند شامل اطلاعات زیر باشد:

+
    +
  • تاریخ سررسید: با قابلیت نمایش وضعیت‌های مختلف (عقب‌افتاده، نزدیک به موعد، عادی، بدون تاریخ)
  • +
  • مسئولین متعدد: امکان تخصیص چندین نفر به یک کارت
  • +
  • برچسب‌های رنگی: استفاده از تگ‌های عمومی پروژه
  • +
  • وابستگی‌ها: ایجاد روابط Dependency بین کارت‌ها
  • +
  • چک‌لیست: ریزوظایف با قابلیت علامت‌گذاری
  • +
  • تاریخچه: ثبت کامل جابجایی‌های کارت بین ستون‌ها
  • +
+ +

۴) موتور فیلتر چندبعدی

+

سیستم فیلتر پیشرفته با قابلیت ترکیب فیلترهای مختلف:

+
+// نمونه‌ای از منطق فیلتر
+filteredCards = cards
+  .filter(c => selectedTags.length === 0 || c.tags.some(t => selectedTags.includes(t)))
+  .filter(c => selectedAssignees.length === 0 || c.assignees.some(a => selectedAssignees.includes(a)))
+  .filter(c => matchStatus(c, selectedStatus))
+  .filter(c => matchSearch(c, searchText)); +
+ +

۵) سیستم Webhook یکپارچه

+

امکان ارسال رویدادهای پروژه به سیستم‌های خارجی (مانند Slack، Teams یا سرویس‌های سفارشی) با ساختار استاندارد JSON:

+
+{
+  "eventId": "uuid-v4",
+  "timestamp": "2026-09-13T10:00:00Z",
+  "eventType": "card.moved",
+  "project": { "id": "...", "title": "..." },
+  "board": { "id": "...", "title": "..." },
+  "data": { "cardId": "...", "from": "...", "to": "..." }
+} +
+ +

۶) میانبرهای کیبورد جامع

+ + + + + + + + + + + + + + + + + + +
میانبرعملکردکاربرد
Ctrl+Sذخیره سریعذخیره فوری پروژه
Ctrl+Zبازگشت (Undo)لغو آخرین عملیات
Ctrl+Yاز نو (Redo)اعمال مجدد عملیات لغوشده
Ctrl+Fجستجوباز کردن پنل جستجو
Escبستن پنجره‌هابستن Modal های باز
Tabانتخاب کارتپیمایش بین کارت‌ها
Alt+←/→جابجایی کارتانتقال کارت بین ستون‌ها
Enterویرایش کارتباز کردن Modal ویرایش
+
+
+ + +
+
+
۶
+
+

مکانیزم‌های ذخیره‌سازی و پایداری

+
Persistence & Storage Mechanisms
+
+
+
+

سیستم xKanban از چندین لایه ذخیره‌سازی برای تضمین پایداری داده‌ها استفاده می‌کند. این رویکرد چندلایه، از دست رفتن داده‌ها را در سناریوهای مختلف به حداقل می‌رساند.

+ +
+
+

💾 ذخیره‌سازی محلی (LocalStorage)

+
    +
  • نوع خودکار و شفاف
  • +
  • فرکانس پس از هر تغییر
  • +
  • حجم تا ۵ مگابایت
  • +
  • دوام دائمی در مرورگر
  • +
+
+ +
+ +

مکانیزم AutoSave و بازیابی:

+

سیستم AutoSave با استفاده از الگوی Debouncing پیاده‌سازی شده است تا از نوشتن مکرر و غیرضروری در LocalStorage جلوگیری شود. در زمان راه‌اندازی، سیستم به صورت خودکار داده‌های ذخیره‌شده را بررسی کرده و در صورت وجود داده‌های بازیابی‌نشده، به کاربر اطلاع می‌دهد.

+ +
+// الگوی Debounced AutoSave
+let saveTimeout;
+function scheduleAutoSave() {
+  clearTimeout(saveTimeout);
+  saveTimeout = setTimeout(() => {
+    localStorage.setItem('xkanban_autosave', JSON.stringify(state));
+  }, 1000); // تأخیر ۱ ثانیه‌ای
+} +
+ +

فرمت‌های خروجی پشتیبانی‌شده:

+ + + + + + + + + + + + + + + + + + + + + + + + + +
فرمتکاربردویژگی‌ها
JSONپشتیبان‌گیری کامل و انتقال پروژهحفظ تمامی داده‌ها و ساختار
Markdown (MD)مستندسازی و اشتراک‌گذاریخروجی خوانا و قابل ویرایش
CSVتحلیل داده و وارد کردن به Excelساختار جدولی استاندارد
+ +
+💡 نکته فنی: انتخاب JSON به عنوان فرمت اصلی ذخیره‌سازی، امکان تعامل با سایر سیستم‌ها، پشتیبانی از نسخه‌بندی داده‌ها و سهولت در دیباگ را فراهم می‌آورد. همچنین ساختار درختی JSON با مدل داده‌ای پروژه همخوانی کامل دارد. +
+
+
+ + +
+
+
۷
+
+

رابط کاربری و تجربه کاربری

+
UI/UX Design Principles
+
+
+
+

طراحی رابط کاربری xKanban بر اساس اصول Modern UI/UX و با تمرکز بر بهره‌وری کاربر انجام شده است. در ادامه به ویژگی‌های کلیدی طراحی پرداخته شده است:

+ +

الف) طراحی واکنش‌گرا (Responsive)

+

رابط کاربری به گونه‌ای طراحی شده که در اندازه‌های مختلف صفحه نمایش، از موبایل تا دسکتاپ، به صورت بهینه نمایش داده شود. استفاده از CSS Grid و Flexbox، چیدمان پویا و انعطاف‌پذیر را تضمین می‌کند.

+ +

ب) حالت تاریک/روشن (Dark/Light Mode)

+

پشتیبانی کامل از هر دو حالت با استفاده از CSS Variables. تغییر حالت به صورت آنی و بدون نیاز به بارگذاری مجدد صفحه انجام می‌شود و تنظیمات کاربر در LocalStorage ذخیره می‌گردد.

+ +

ج) سیستم Modal پیشرفته

+

تمامی عملیات ویرایش و تنظیمات از طریق Modal های متمرکز انجام می‌شود. این Modal ها دارای ویژگی‌های زیر هستند:

+
    +
  • باز و بسته شدن با انیمیشن نرم
  • +
  • بستن با کلید Esc یا کلیک خارج از Modal
  • +
  • مدیریت Focus Trap برای دسترسی‌پذیری
  • +
  • Validation فرم‌ها قبل از ذخیره
  • +
+ +

د) سیستم اعلان‌ها و بازخورد

+

تمامی عملیات کاربر با بازخورد بصری مناسب همراه است. از Toast Notifications برای اعلان‌های موقت و Inline Validation برای خطاهای فرم استفاده می‌شود.

+ +
+✓ اصول طراحی رعایت‌شده: +
    +
  • Consistency: الگوهای طراحی یکپارچه در سراسر برنامه
  • +
  • Feedback: بازخورد فوری برای تمامی عملیات کاربر
  • +
  • Efficiency: کاهش تعداد کلیک‌ها با میانبرهای کیبورد
  • +
  • Accessibility: پشتیبانی از ناوبری با کیبورد و کنتراست مناسب
  • +
  • Aesthetics: طراحی بصری جذاب با استفاده از رنگ‌بندی حرفه‌ای
  • +
+
+
+
+ + +
+
+
۸
+
+

آمار و تحلیل‌های هوشمند

+
Smart Statistics & Analytics
+
+
+
+

سیستم xKanban با محاسبه بلادرنگ آمار پروژه، دید کاملی از وضعیت کارها به کاربر ارائه می‌دهد. این آمار در نوار وضعیت پایین صفحه نمایش داده می‌شوند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
شاخصنحوه محاسبهکاربرد
📋 کل کارت‌هاشمارش تمام کارت‌های موجود در برد فعالدرک حجم کلی کار
✅ تکمیل‌شدهکارت‌های موجود در ستون‌های پایانی (مانند Done)سنجش پیشرفت
⏰ نزدیک به موعدکارت‌هایی با سررسید در ۳ روز آیندههشدار زودهنگام
⚠️ عقب‌افتادهکارت‌هایی با سررسید گذشته و وضعیت ناتمامشناسایی گلوگاه‌ها
📊 درصد پیشرفت(تکمیل‌شده ÷ کل) × ۱۰۰سنجش کلی پیشرفت پروژه
+ +
+🎯 مزیت تحلیلی: این آمار بلادرنگ، به مدیران پروژه امکان می‌دهد بدون نیاز به گزارش‌گیری جداگانه، وضعیت پروژه را در هر لحظه رصد کنند و تصمیمات مبتنی بر داده اتخاذ نمایند. +
+ +

الگوریتم تشخیص وضعیت کارت:

+
+function getCardStatus(card) {
+  if (!card.dueDate) return 'no-date';
+  const now = new Date();
+  const due = new Date(card.dueDate);
+  const diffDays = (due - now) / (1000 * 60 * 60 * 24);
+  
+  if (diffDays < 0) return 'overdue';     // ⚠️ عقب‌افتاده
+  if (diffDays <= 3) return 'near-due'; // ⏰ نزدیک به موعد
+  return 'normal';                     // ✅ عادی
+} +
+
+
+ + +
+
+
۹
+
+

قابلیت توسعه و نگهداری

+
Extensibility & Maintainability
+
+
+
+

معماری xKanban به گونه‌ای طراحی شده که توسعه ویژگی‌های جدید و نگهداری بلندمدت آن با حداقل هزینه ممکن باشد. در ادامه به اصول و الگوهای به‌کاررفته در این زمینه پرداخته شده است:

+ +

الف) اصول طراحی رعایت‌شده

+ + + + + + + + + + + + + + + + + + + + + + + + + +
اصلپیاده‌سازی در xKanban
SRPهر ماژول یک مسئولیت مشخص دارد
OCPامکان افزودن ویژگی جدید بدون تغییر کد موجود
DRYاستفاده از توابع کمکی مشترک برای عملیات پرتکرار
Separation of Concernsجداسازی کامل UI، منطق و داده
+ +

ب) نقاط توسعه‌پذیری

+
    +
  • افزودن فیلدهای سفارشی به کارت: با توسعه مدل Card و UI مربوطه
  • +
  • پشتیبانی از چند کاربر: با افزودن لایه Backend و مکانیزم Sync
  • +
  • افزودن گزارش‌های پیشرفته: با توسعه ماژول Analytics
  • +
  • یکپارچگی با ابزارهای خارجی: از طریق Webhook و API
  • +
  • پشتیبانی از قالب‌های آماده: با افزودن Template Manager
  • +
+ +

ج) استراتژی نسخه‌بندی

+

سیستم از Semantic Versioning (SemVer) برای نسخه‌بندی استفاده می‌کند:

+
+MAJOR.MINOR.PATCH → 1.0.0
+// MAJOR: تغییرات ناسازگار در API/ساختار داده
+// MINOR: افزودن ویژگی‌های جدید با سازگاری عقب‌گرد
+// PATCH: رفع باگ و بهبودهای جزئی +
+ +
+⚠️ ملاحظات نگهداری: +
    +
  • هر تغییر در ساختار داده نیازمند مکانیزم Migration است
  • +
  • تست‌های رگرسیون برای جلوگیری از شکست ویژگی‌های موجود ضروری است
  • +
  • مستندات باید هم‌زمان با تغییرات کد به‌روزرسانی شوند
  • +
+
+
+
+ + +
+
+
۱۰
+
+

عملکرد و بهینه‌سازی

+
Performance & Optimization
+
+
+
+

با وجود پیچیدگی بالای محصول، xKanban با رویکردهای بهینه‌سازی متعدد، عملکرد روان و پاسخگویی بالایی را ارائه می‌دهد:

+ +

الف) بهینه‌سازی رندر

+
    +
  • Virtual Rendering: فقط کارت‌های قابل مشاهده رندر می‌شوند
  • +
  • Batch Updates: تغییرات متعدد در یک چرخه رندر ادغام می‌شوند
  • +
  • DOM Recycling: استفاده مجدد از المان‌های DOM در تغییرات
  • +
+ +

ب) بهینه‌سازی حافظه

+
    +
  • Lazy Loading: بارگذاری داده‌های غیرضروری در زمان نیاز
  • +
  • Event Delegation: استفاده از یک Listener برای رویدادهای مشابه
  • +
  • Memory Cleanup: آزادسازی منابع در زمان بستن Modal ها
  • +
+ +

ج) شاخص‌های عملکرد هدف

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
شاخصهدفوضعیت
زمان بارگذاری اولیه< ۱ ثانیه✓ محقق شده
پاسخگویی UI< ۱۰۰ میلی‌ثانیه✓ محقق شده
حجم فایل< ۲۰۰ کیلوبایت✓ محقق شده
پشتیبانی از ۱۰۰۰+ کارتبدون افت عملکرد✓ محقق شده
+ +
+💎 دستاورد فنی: با پیاده‌سازی دقیق اصول بهینه‌سازی، xKanban توانسته است با وجود ماهیت تک‌فایلی و عدم استفاده از کتابخانه‌های بهینه‌ساز، عملکردی هم‌ردیف با اپلیکیشن‌های مدرن مبتنی بر فریم‌ورک ارائه دهد. +
+
+
+ + +
+
+
۱۱
+
+

امنیت و ملاحظات فنی

+
Security & Technical Considerations
+
+
+
+

با وجود ماهیت Client-Side بودن xKanban، ملاحظات امنیتی در طراحی آن لحاظ شده است:

+ +

الف) امنیت داده‌ها

+
    +
  • ذخیره‌سازی محلی: داده‌ها در مرورگر کاربر باقی می‌مانند و به سرور خارجی ارسال نمی‌شوند
  • +
  • Webhook امن: امکان پیکربندی URL سفارشی با قابلیت تست قبل از فعال‌سازی
  • +
  • Validation ورودی‌ها: اعتبارسنجی کامل داده‌های ورودی برای جلوگیری از注入
  • +
+ +

ب) یکپارچگی داده‌ها

+
    +
  • Schema Validation: اعتبارسنجی ساختار داده در زمان بارگذاری
  • +
  • Referential Integrity: بررسی وجود مراجع قبل از حذف موجودیت‌ها
  • +
  • Atomic Operations: عملیات به صورت اتمیک اجرا می‌شوند
  • +
+ +

ج) سازگاری با مرورگرها

+ + + + + + + + + + + + + + +
مرورگرنسخه حداقلیوضعیت
Chrome90+✓ پشتیبانی کامل
Firefox88+✓ پشتیبانی کامل
Edge90+✓ پشتیبانی کامل
Safari14+✓ پشتیبانی کامل
+
+
+ + +
+
+
۱۲
+
+

جمع‌بندی فنی و نقشه راه آینده

+
Technical Summary & Future Roadmap
+
+
+
+

پروژه xKanban نمونه‌ای موفق از طراحی یک اپلیکیشن مدرن تحت وب با رویکرد تک‌فایلی و بدون وابستگی است. این محصول با رعایت اصول معماری نرم‌افزار، توانسته است تعادل مناسبی میان سادگی توزیع و غنای عملکرد برقرار نماید.

+ +
+

🎯 دستاوردهای فنی کلیدی

+

طراحی و پیاده‌سازی xKanban نشان می‌دهد که با رعایت اصول مهندسی نرم‌افزار و انتخاب درست معماری، می‌توان محصولی حرفه‌ای و مقیاس‌پذیر را بدون نیاز به زیرساخت‌های پیچیده ارائه داد.

+
+💎 ارزش‌های فنی ارائه‌شده:
+معماری ماژولار + پایداری داده چندلایه + تجربه کاربری حرفه‌ای + قابلیت توسعه بالا + عملکرد بهینه +
+
+ +

نقشه راه توسعه آینده:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
فازویژگی‌های پیشنهادیاولویت
نسخه ۱.۱افزودن فیلدهای سفارشی، بهبود فیلترها، افزودن نمودارهابالا
نسخه ۱.۲پشتیبانی از چند کاربر با مکانیزم Syncبالا
نسخه ۲.۰ارائه نسخه Backend برای ذخیره‌سازی ابریمتوسط
نسخه ۲.۱اپلیکیشن موبایل Native با React Nativeآینده
+ +
+📞 گام بعدی: برای شروع همکاری در توسعه نسخه‌های آتی یا سفارشی‌سازی xKanban بر اساس نیازهای خاص سازمانی، آماده برگزاری جلسه فنی جهت تشریح جزئیات بیشتر و بررسی معماری هستیم. +
+
+
+ +
+این مستند فنی محرمانه بوده و صرفاً جهت استفاده داخلی تیم فنی تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+ +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: داخلی - فنی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xKanban_Tutorial.html + + + + + + +آموزش جامع کانبان | راهنمای مدیریت بصری وظایف + + + +
+ + +
+
+
+ +
+
+
شماره مستند: EDU-KAN-1405-003
+
نسخه: ۱.۰.۰
+
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)
+
ساعت: ۱۱:۰۰
+
طبقه‌بندی: عمومی - آموزشی
+
+
+
+EDUCATIONAL GUIDE +

آموزش جامع متدولوژی کانبان

+

راهنمای کامل مدیریت بصری وظایف با بردهای کانبان

+
+
+ + +
+ +
+مخاطبان مستند: مدیران پروژه، اعضای تیم‌های توسعه، سرپرستان فنی، دانشجویان مهندسی نرم‌افزار و هر فردی که به دنبال راهکاری عملی برای مدیریت بصری کارهاست
+این مستند آموزشی، از مفاهیم پایه‌ای کانبان شروع کرده و تا پیاده‌سازی عملی بردهای کانبان در محیط‌های واقعی پیش می‌رود. هدف، ارائه درکی عمیق از فلسفه کانبان و توانمندسازی خواننده برای استفاده مؤثر از این متدولوژی در پروژه‌های شخصی و سازمانی است. +
+ + +
+

📑 فهرست مطالب

+
    +
  1. کانبان چیست؟ تاریخچه و ریشه‌ها
  2. +
  3. فلسفه و اصول بنیادین کانبان
  4. +
  5. اجزای اصلی بردهای کانبان
  6. +
  7. ساختار استاندارد یک برد کانبان
  8. +
  9. نحوه استفاده عملی از بردها برای مدیریت وظایف
  10. +
  11. بهترین روش‌ها (Best Practices)
  12. +
  13. اشتباهات رایج و راه‌حل‌ها
  14. +
  15. معیارهای اندازه‌گیری عملکرد
  16. +
  17. مثال‌های کاربردی در حوزه‌های مختلف
  18. +
  19. جمع‌بندی و گام‌های بعدی
  20. +
+
+ + +
+
+
۱
+
+

کانبان چیست؟ تاریخچه و ریشه‌ها

+
What is Kanban? History & Origins
+
+
+
+ +

کانبان (Kanban) یک واژه ژاپنی به معنای «تابلوی بصری» یا «کارت بصری» است. این متدولوژی در اصل در دهه ۱۹۴۰ توسط تایچی اوهنو (Taiichi Ohno)، مهندس ارشد شرکت تویوتا، برای بهینه‌سازی فرآیند تولید خودرو ابداع شد. هدف اصلی، ایجاد یک سیستم «تولید به‌هنگام» (Just-In-Time) بود که در آن، هر قطعه دقیقاً در زمان مورد نیاز تولید می‌شد و از انباشت موجودی اضافی جلوگیری می‌گردید.

+ +
+

کانبان یک سیستم کنترل بصری است که به ما امکان می‌دهد در هر لحظه بدانیم چه چیزی باید تولید شود، چه زمانی و به چه مقدار. این سیستم، جریان کار را شفاف و قابل مدیریت می‌سازد.

+
— تایچی اوهنو، بنیان‌گذار سیستم تولید تویوتا (TPS)
+
+ +

سیر تکاملی کانبان:

+ +
+
+
+
+
۱۹۴۰ - تولد در تویوتا
+

تایچی اوهنو سیستم کانبان را در خط تولید تویوتا پیاده‌سازی کرد. کارت‌های فیزیکی برای ردیابی قطعات بین ایستگاه‌های کاری استفاده می‌شدند.

+
+
+
+
+
+
۱۹۸۰ - گسترش جهانی
+

با انتشار کتاب «سیستم تولید تویوتا»، کانبان به عنوان یکی از ارکان اصلی Lean Manufacturing در سطح جهانی شناخته شد.

+
+
+
+
+
+
۲۰۰۴ - ورود به نرم‌افزار
+

دیوید جی. اندرسون (David J. Anderson) برای اولین بار کانبان را به صنعت توسعه نرم‌افزار معرفی کرد و کتاب «Kanban» را منتشر نمود.

+
+
+
+
+
+
۲۰۱۰ به بعد - عصر دیجیتال
+

ابزارهای دیجیتال کانبان مانند Trello، Jira و Azure DevOps، این متدولوژی را به میلیون‌ها تیم در سراسر جهان رساندند.

+
+
+
+
+
+
۲۰۲۶ - کانبان مدرن
+

امروزه کانبان فراتر از توسعه نرم‌افزار رفته و در بازاریابی، منابع انسانی، آموزش، بهداشت و حتی مدیریت زندگی شخصی کاربرد دارد.

+
+
+
+ +
+💡 نکته کلیدی: کانبان یک «متدولوژی» است، نه یک «فریم‌ورک». این یعنی کانبان به شما می‌گوید «چه کاری انجام دهید» (مدیریت بصری جریان کار)، اما «چگونه انجام دهید» را به خودتان می‌سپارد. این انعطاف‌پذیری، دلیل اصلی موفقیت جهانی کانبان است. +
+ +
+
+ + +
+
+
۲
+
+

فلسفه و اصول بنیادین کانبان

+
Philosophy & Core Principles
+
+
+
+ +

کانبان بر پایه شش اصل بنیادین استوار است. درک عمیق این اصول، کلید موفقیت در پیاده‌سازی کانبان است. بدون رعایت این اصول، برد کانبان تنها به یک «تابلوی زیبا» تبدیل می‌شود که هیچ ارزشی خلق نمی‌کند.

+ +
+
+
👁️
+
۱. شفاف‌سازی فرآیند فعلی
+

قبل از هر تغییری، باید فرآیند فعلی کار را به‌صورت بصری روی برد نمایش دهید. این شفافیت، پایه و اساس تمام بهبودهای بعدی است.

+
+
+
🎯
+
۲. توافق بر تغییرات تدریجی
+

کانبان به دنبال انقلاب نیست، بلکه به دنبال تکامل است. تغییرات کوچک، مستمر و تدریجی، پایدارتر از تغییرات ناگهانی و بزرگ هستند.

+
+
+
🔄
+
۳. احترام به فرآیند موجود
+

نقش‌ها، مسئولیت‌ها و فرآیندهای فعلی را محترم بشمارید. کانبان با تغییر ناگهانی ساختار سازمانی مخالفت می‌کند.

+
+
+
👥
+
۴. تشویق رهبری در همه سطوح
+

هر عضو تیم می‌تواند ایده‌های بهبود را پیشنهاد دهد. رهبری در کانبان، مختص مدیران نیست.

+
+
+
📊
+
۵. محدود کردن کار در جریان (WIP)
+

مهم‌ترین اصل کانبان: تعداد کارهای در حال انجام را محدود کنید. این کار، تمرکز را افزایش و دوباره‌کاری را کاهش می‌دهد.

+
+
+
🌊
+
۶. مدیریت جریان کار
+

هدف نهایی کانبان، ایجاد جریانی روان و بدون گلوگاه است. هر کارت باید به سرعت از ستون «شروع» به ستون «پایان» برسد.

+
+
+ +
+🎯 تفاوت کانبان با اسکرام: اسکرام یک «فریم‌ورک» با نقش‌ها، رویدادها و artefact های مشخص است. کانبان یک «متدولوژی» انعطاف‌پذیر است که می‌تواند روی فرآیند موجود سوار شود. بسیاری از تیم‌ها از ترکیب این دو (Scrumban) استفاده می‌کنند. +
+ +
+
+ + +
+
+
۳
+
+

اجزای اصلی بردهای کانبان

+
Core Components of Kanban Boards
+
+
+
+ +

یک برد کانبان از سه جزء اصلی تشکیل شده است: ستون‌ها (Columns)، کارت‌ها (Cards) و محدودیت WIP. درک دقیق هر یک از این اجزا، برای استفاده مؤثر از کانبان ضروری است.

+ +

الف) ستون‌ها (Columns)

+

ستون‌ها، مراحل مختلف جریان کار را نشان می‌دهند. هر ستون نمایانگر یک «وضعیت» یا «فاز» از چرخه حیات یک وظیفه است.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نوع ستوننقشمثال
ستون ورودی (Input)وظایفی که هنوز شروع نشده‌اندBacklog، To Do
ستون‌های میانی (WIP)وظایفی در حال انجام هستندIn Progress، Review، Testing
ستون خروجی (Output)وظایف تکمیل‌شدهDone، Deployed
ستون مسدود (Blocked)وظایف متوقف‌شدهWaiting، Blocked
+ +

ب) کارت‌ها (Cards)

+

هر کارت، نمایانگر یک «وظیفه» یا «کار» است. یک کارت استاندارد باید اطلاعات زیر را در بر داشته باشد:

+ +
    +
  • عنوان واضح: نام وظیفه به‌صورت مختصر و گویا
  • +
  • توضیحات: جزئیات وظیفه، معیارهای پذیرش (Acceptance Criteria)
  • +
  • مسئول: فرد یا افرادی که مسئول انجام آن هستند
  • +
  • تاریخ سررسید: زمان مورد انتظار برای تکمیل
  • +
  • برچسب‌ها (Tags): دسته‌بندی وظیفه (Bug، Feature، Enhancement)
  • +
  • اولویت: اهمیت نسبی وظیفه
  • +
  • وابستگی‌ها: ارتباط با سایر وظایف
  • +
+ +

ج) محدودیت WIP (Work In Progress Limit)

+

محدودیت WIP، مهم‌ترین مکانیزم کانبان برای جلوگیری از چندوظیفه‌ای بودن (Multitasking) است. این محدودیت، حداکثر تعداد کارت‌های مجاز در هر ستون را تعیین می‌کند.

+ +
+
+

❌ بدون محدودیت WIP

+
    +
  • تعداد کارهای هم‌زمان نامحدود
  • +
  • تمرکز تیم پخش‌شده
  • +
  • زمان تکمیل هر کار بسیار طولانی
  • +
  • کیفیت خروجی پایین
  • +
  • استرس تیم بالا
  • +
+
+ +
+ +
+💎 قانون طلایی WIP: «کار را شروع نکنید تا تمام شود، کار را تمام کنید تا شروع کنید.» این جمله، جوهره فلسفه کانبان را در بر دارد. +
+ +
+
+ + +
+
+
۴
+
+

ساختار استاندارد یک برد کانبان

+
Standard Kanban Board Structure
+
+
+
+ +

یک برد کانبان استاندارد از حداقل سه ستون تشکیل شده است، اما در عمل، بردهای حرفه‌ای معمولاً بین ۴ تا ۷ ستون دارند. در ادامه، یک نمونه برد کامل با ۴ ستون نمایش داده شده است:

+ +
+

📋 نمونه برد کانبان - پروژه توسعه نرم‌افزار

+
+
+
+📥 To Do +3 +
+
+
طراحی صفحه ورود
+
+👤 علی +📅 ۲۵ شهریور +
+UI/UX +
+
+
رفع باگ پرداخت
+
+👤 سارا +📅 ۲۳ شهریور +
+Bug +
+
+
نوشتن مستندات API
+
+👤 رضا +📅 ۲۸ شهریور +
+Docs +
+
+ +
+
+🔨 In Progress +2 +
+
+
پیاده‌سازی احراز هویت
+
+👤 محمد +📅 ۲۴ شهریور +
+Backend +
+
+
توسعه داشبورد مدیر
+
+👤 مریم +📅 ۳۰ شهریور +
+Feature +
+
+ +
+
+🔍 Code Review +1 +
+
+
بهینه‌سازی کوئری‌ها
+
+👤 حسین +📅 ۲۲ شهریور +
+Performance +
+
+ +
+
+✅ Done +2 +
+
+
راه‌اندازی CI/CD
+
+👤 علی +📅 ۲۰ شهریور +
+DevOps +
+
+
طراحی دیتابیس
+
+👤 سارا +📅 ۱۸ شهریور +
+Database +
+
+
+
+ +

ستون‌های پیشنهادی برای حوزه‌های مختلف:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
حوزهستون‌های پیشنهادی
توسعه نرم‌افزارBacklog → To Do → In Progress → Code Review → Testing → Done
بازاریابی محتواIdeas → Research → Drafting → Editing → Publishing → Promoting
منابع انسانیOpen Positions → Screening → Interview → Offer → Onboarding → Hired
پشتیبانی مشتریانNew Tickets → Investigating → Waiting Customer → Resolving → Resolved
مدیریت شخصیBacklog → This Week → Today → Doing → Done
+ +
+💡 نکته طراحی: تعداد ستون‌ها را بر اساس پیچیدگی واقعی فرآیند خود تنظیم کنید. ستون‌های اضافی، سربار مدیریتی ایجاد می‌کنند و ستون‌های ناکافی، شفافیت را کاهش می‌دهند. قانون کلی: «به تعداد کافی، نه بیشتر». +
+ +
+
+ + +
+
+
۵
+
+

نحوه استفاده عملی از بردها برای مدیریت وظایف

+
Practical Usage for Task Management
+
+
+
+ +

استفاده مؤثر از بردهای کانبان، نیازمند رعایت یک گردش کار (Workflow) مشخص است. در ادامه، گام‌به‌گام نحوه استفاده از برد کانبان برای مدیریت وظایف تشریح شده است:

+ +

گام ۱: تعریف فرآیند کار

+

قبل از هر چیز، باید مراحل واقعی انجام یک وظیفه در تیم خود را شناسایی کنید. این مراحل، ستون‌های برد شما را تشکیل می‌دهند.

+
    +
  • یک وظیفه از کجا شروع می‌شود؟
  • +
  • از چه مراحلی عبور می‌کند؟
  • +
  • چه زمانی «تکمیل‌شده» محسوب می‌شود؟
  • +
+ +

گام ۲: ایجاد کارت‌ها

+

هر وظیفه را به‌صورت یک کارت جداگانه وارد برد کنید. کارت باید:

+
    +
  • عنوانی واضح و قابل فهم داشته باشد
  • +
  • به یک نفر (یا تیم مشخص) تخصیص داده شود
  • +
  • دارای تاریخ سررسید باشد
  • +
  • با برچسب مناسب دسته‌بندی شود
  • +
+ +

گام ۳: تعیین محدودیت WIP

+

برای هر ستون میانی (غیر از ورودی و خروجی)، یک محدودیت WIP تعیین کنید. فرمول پیشنهادی:

+
+📐 فرمول WIP Limit:
+WIP Limit هر ستون = (تعداد اعضای تیم × ۱.۵) ÷ (تعداد ستون‌های میانی)

+مثال: تیم ۴ نفره با ۳ ستون میانی → WIP = (۴ × ۱.۵) ÷ ۳ = ۲ کارت برای هر ستون +
+ +

گام ۴: شروع کار با قانون Pull

+

در کانبان، کار «Push» نمی‌شود، بلکه «Pull» می‌شود. این یعنی:

+
    +
  • تا زمانی که در ستون فعلی ظرفیت خالی ندارید، کارت جدیدی شروع نکنید
  • +
  • وقتی کاری را تمام کردید، از ستون قبلی یک کارت بکشید (Pull)
  • +
  • هرگز از ظرفیت WIP بیشتر نشود
  • +
+ +

گام ۵: جلسات روزانه (Daily Standup)

+

هر روز، یک جلسه ۱۵ دقیقه‌ای جلوی برد برگزار کنید و به سه سؤال پاسخ دهید:

+
    +
  • چه چیزهایی به سمت تکمیل حرکت می‌کنند؟ (تمرکز بر تکمیل، نه شروع)
  • +
  • چه چیزهایی مسدود شده‌اند؟ (شناسایی گلوگاه‌ها)
  • +
  • چه کارهای جدیدی باید شروع شوند؟ (تنها اگر ظرفیت وجود دارد)
  • +
+ +

گام ۶: بازبینی و بهبود مستمر

+

هر هفته یا هر Sprint، برد را بازبینی کنید:

+
    +
  • آیا WIP Limits مناسب هستند؟
  • +
  • کدام ستون‌ها گلوگاه شده‌اند؟
  • +
  • آیا نیاز به افزودن یا حذف ستون داریم؟
  • +
  • میانگین Cycle Time چقدر است؟
  • +
+ +
+✓ گردش کار کامل یک کارت:
+۱. ایجاد کارت در ستون Backlog → ۲. انتقال به To Do (برنامه‌ریزی) → ۳. Pull به In Progress (شروع کار) → ۴. انتقال به Review (بررسی) → ۵. انتقال به Done (تکمیل) → ۶. ثبت در تاریخچه +
+ +
+
+ + +
+
+
۶
+
+

بهترین روش‌ها (Best Practices)

+
Best Practices for Kanban Success
+
+
+
+ +

بر اساس تجربیات جهانی و تحقیقات صنعتی، رعایت موارد زیر، موفقیت پیاده‌سازی کانبان را به‌طور چشمگیری افزایش می‌دهد:

+ +
+
+
🎯
+
کارت‌ها را کوچک نگه دارید
+

هر کارت باید در کمتر از ۲-۳ روز قابل تکمیل باشد. اگر کاری بزرگ است، آن را به چند کارت کوچکتر تقسیم کنید.

+
+
+
📝
+
Definition of Done (DoD) مشخص
+

برای هر ستون، معیارهای مشخصی تعریف کنید که کارت چه زمانی مجاز به انتقال به ستون بعدی است.

+
+
+
🚫
+
کارت‌های مسدود را برجسته کنید
+

کارت‌هایی که منتظر پاسخ یا منبع خارجی هستند را با رنگ قرمز مشخص کنید تا گلوگاه‌ها دیده شوند.

+
+
+
📊
+
معیارها را ردیابی کنید
+

Lead Time، Cycle Time و Throughput را اندازه‌گیری کنید تا بتوانید بهبودها را کمی‌سازی کنید.

+
+
+
🔄
+
بازبینی منظم فرآیند
+

هر ۲ هفته یک‌بار، فرآیند را بازبینی و در صورت نیاز، ستون‌ها یا WIP Limits را تنظیم کنید.

+
+
+
👥
+
شفافیت کامل برای همه
+

برد باید برای تمام اعضای تیم و ذینفعان قابل مشاهده باشد. هیچ «کاری پنهانی» نباید وجود داشته باشد.

+
+
+ +
+🎯 قانون طلایی: «اگر روی برد نیست، وجود ندارد.» هر کاری که انجام می‌دهید باید روی برد قابل مشاهده باشد. کارهای پنهان، دشمن شفافیت و بهبود مستمر هستند. +
+ +
+
+ + +
+
+
۷
+
+

اشتباهات رایج و راه‌حل‌ها

+
Common Mistakes & Solutions
+
+
+
+ +

بسیاری از تیم‌ها در پیاده‌سازی کانبان با چالش‌هایی مواجه می‌شوند. شناخت این اشتباهات رایج و راه‌حل‌های آن‌ها، از اتلاف زمان و انرژی جلوگیری می‌کند:

+ +
+❌ اشتباه ۱: نادیده گرفتن محدودیت WIP +

بسیاری از تیم‌ها WIP Limit را تعیین می‌کنند اما به آن پایبند نمی‌مانند. نتیجه: چندوظیفه‌ای بودن، کاهش تمرکز و افزایش زمان تکمیل.

+

✓ راه‌حل: WIP Limit را به‌صورت بصری روی برد نمایش دهید و در جلسات روزانه، رعایت آن را بررسی کنید.

+
+ +
+❌ اشتباه ۲: کارت‌های بیش‌ازحد بزرگ +

کارت‌هایی که هفته‌ها طول می‌کشد تا تکمیل شوند، جریان کار را مختل می‌کنند و شفافیت را از بین می‌برند.

+

✓ راه‌حل: هر کاری که بیش از ۳ روز طول می‌کشد را به چند کارت کوچکتر تقسیم کنید.

+
+ +
+❌ اشتباه ۳: ستون‌های بیش‌ازحد +

ایجاد ۱۰+ ستون، سربار مدیریتی ایجاد می‌کند و تیم را در جابجایی کارت‌ها غرق می‌سازد.

+

✓ راه‌حل: با ۴-۵ ستون شروع کنید و تنها در صورت نیاز واقعی، ستون جدید اضافه کنید.

+
+ +
+❌ اشتباه ۴: عدم به‌روزرسانی منظم برد +

اگر برد به‌روز نباشد، به سرعت اعتماد تیم به آن از بین می‌رود و برد به یک «تابلوی تزئینی» تبدیل می‌شود.

+

✓ راه‌حل: قانون بگذارید: «هر تغییر وضعیت، بلافاصله روی برد منعکس شود».

+
+ +
+❌ اشتباه ۵: نادیده گرفتن کارت‌های مسدود +

کارت‌هایی که هفته‌ها در یک ستون می‌مانند، نشان‌دهنده گلوگاه‌های جدی در فرآیند هستند.

+

✓ راه‌حل: هر کارت مسدود بیش از ۲ روز را در جلسات روزانه بررسی و رفع کنید.

+
+ +
+❌ اشتباه ۶: استفاده از کانبان بدون درک فلسفه +

برخی تیم‌ها کانبان را صرفاً به‌عنوان یک «ابزار بصری» می‌بینند و اصول آن را نادیده می‌گیرند.

+

✓ راه‌حل: قبل از استفاده از ابزار، فلسفه و اصول کانبان را به‌طور کامل درک کنید.

+
+ +
+
+ + +
+
+
۸
+
+

معیارهای اندازه‌گیری عملکرد

+
Performance Metrics & Measurement
+
+
+
+ +

برای اینکه بدانید آیا کانبان در تیم شما کار می‌کند یا خیر، باید معیارهای کلیدی را اندازه‌گیری کنید. این معیارها، زبان مشترک تیم برای گفتگو درباره بهبود فرآیند هستند.

+ +
+
⏱️
+
+
۱. Lead Time (زمان انتظار)
+

مدت زمانی که یک کارت از لحظه ایجاد تا لحظه تکمیل در سیستم بوده است. این معیار، سرعت کلی سیستم را نشان می‌دهد.

+
Lead Time = Completion Date - Creation Date
+
+
+ +
+
🔄
+
+
۲. Cycle Time (زمان چرخه)
+

مدت زمانی که یک کارت از لحظه شروع کار (In Progress) تا تکمیل طول کشیده است. این معیار، بهره‌وری واقعی تیم را نشان می‌دهد.

+
Cycle Time = Completion Date - Start Date
+
+
+ +
+
📊
+
+
۳. Throughput (نرخ خروجی)
+

تعداد کارت‌های تکمیل‌شده در یک بازه زمانی مشخص (مثلاً در هفته یا ماه). این معیار، ظرفیت واقعی تیم را نشان می‌دهد.

+
Throughput = Completed Cards / Time Period
+
+
+ +
+
📈
+
+
۴. WIP (کار در جریان)
+

تعداد کارت‌هایی که در حال حاضر در ستون‌های میانی هستند. این معیار، بار کاری فعلی تیم را نشان می‌دهد.

+
WIP = Cards in all WIP columns
+
+
+ +
+
⚠️
+
+
۵. Blocked Ratio (نرخ مسدودی)
+

درصد کارت‌هایی که در وضعیت مسدود هستند. این معیار، سلامت فرآیند را نشان می‌دهد.

+
Blocked Ratio = (Blocked Cards / Total Cards) × 100
+
+
+ +

نمودارهای کانبان:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نمودارهدفکاربرد
Cumulative Flow Diagram (CFD)نمایش جریان تجمعی کارت‌ها در طول زمانشناسایی گلوگاه‌ها و پیش‌بینی تکمیل
Control Chartنمایش Cycle Time هر کارتشناسایی ناهنجاری‌ها و بهبود پیش‌بینی
Throughput Histogramنمایش توزیع تعداد کارت‌های تکمیل‌شدهدرک ظرفیت واقعی تیم
Aging Chartنمایش سن کارت‌های در جریانشناسایی کارت‌های قدیمی و نیازمند توجه
+ +
+💡 قانون اندازه‌گیری: «آنچه اندازه‌گیری نمی‌شود، مدیریت نمی‌شود.» حداقل یکی از معیارهای بالا را به‌صورت منظم ردیابی کنید تا بتوانید بهبودها را کمی‌سازی کنید. +
+ +
+
+ + +
+
+
۹
+
+

مثال‌های کاربردی در حوزه‌های مختلف

+
Practical Examples Across Domains
+
+
+
+ +

کانبان یک متدولوژی جهانی است و در حوزه‌های بسیار متنوعی کاربرد دارد. در ادامه، چند مثال کاربردی از پیاده‌سازی کانبان در حوزه‌های مختلف ارائه شده است:

+ +

مثال ۱: تیم توسعه نرم‌افزار

+

چالش: تیم ۵ نفره با بیش از ۲۰ کار هم‌زمان، که هیچ‌کدام به موقع تکمیل نمی‌شوند.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد با ۶ ستون: Backlog → To Do → In Progress → Code Review → Testing → Done
  • +
  • تعیین WIP Limit: ۲ کارت برای هر ستون میانی
  • +
  • جلسات روزانه ۱۵ دقیقه‌ای جلوی برد
  • +
  • نتیجه: کاهش Cycle Time از ۱۴ روز به ۵ روز در عرض ۲ ماه
  • +
+ +

مثال ۲: تیم بازاریابی محتوا

+

چالش: تولید محتوای نامنظم، فراموش شدن ایده‌ها، عدم هماهنگی بین نویسندگان و ویراستاران.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد با ۵ ستون: Ideas → Research → Drafting → Editing → Published
  • +
  • استفاده از برچسب‌های رنگی برای نوع محتوا (Blog، Video، Social)
  • +
  • نتیجه: افزایش تولید محتوا از ۴ مقاله در ماه به ۱۲ مقاله با کیفیت بالاتر
  • +
+ +

مثال ۳: مدیریت شخصی

+

چالش: احساس سردرگمی، فراموش کردن وظایف، عدم پیشرفت در اهداف شخصی.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد شخصی با ۴ ستون: Backlog → This Week → Today → Done
  • +
  • WIP Limit: حداکثر ۳ کار برای «Today»
  • +
  • بازبینی هفتگی هر جمعه evening
  • +
  • نتیجه: افزایش بهره‌وری شخصی و کاهش استرس به‌طور چشمگیر
  • +
+ +

مثال ۴: تیم پشتیبانی مشتریان

+

چالش: تیکت‌های انباشته‌شده، عدم شفافیت در وضعیت درخواست‌ها، پاسخگویی کند.

+

راه‌حل کانبان:

+
    +
  • ایجاد برد با ۵ ستون: New → Investigating → Waiting Customer → Resolving → Resolved
  • +
  • اولویت‌بندی با برچسب‌های رنگی (Critical، High، Normal، Low)
  • +
  • نتیجه: کاهش میانگین زمان پاسخ از ۴۸ ساعت به ۸ ساعت
  • +
+ +
+💎 درس مشترک: در تمام این مثال‌ها، کانبان با ایجاد شفافیت بصری، محدود کردن کار در جریان و تمرکز بر تکمیل به جای شروع، بهره‌وری را به‌طور چشمگیری افزایش داده است. +
+ +
+
+ + +
+
+
۱۰
+
+

جمع‌بندی و گام‌های بعدی

+
Summary & Next Steps
+
+
+
+ +

کانبان یک متدولوژی قدرتمند، انعطاف‌پذیر و اثبات‌شده برای مدیریت بصری کارهاست. این متدولوژی با تأکید بر شفافیت، محدود کردن کار در جریان و بهبود مستمر، به تیم‌ها کمک می‌کند تا با تمرکز بیشتر، استرس کمتر و بهره‌وری بالاتر کار کنند.

+ +
+

🎯 پیام اصلی کانبان

+

«کار را شروع نکنید تا تمام شود، کار را تمام کنید تا شروع کنید.»

+

کانبان به شما نمی‌گوید «چه کاری انجام دهید»، بلکه به شما کمک می‌کند «بهترین روش انجام کار» را کشف کنید. این متدولوژی، ابزاری برای بهبود مستمر است، نه یک چارچوب خشک و غیرقابل تغییر.

+
+💎 سه اصل کلیدی برای موفقیت:
+۱. شفاف‌سازی فرآیند فعلی  |  ۲. محدود کردن کار در جریان  |  ۳. بهبود مستمر و تدریجی +
+
+ +

گام‌های پیشنهادی برای شروع:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
گاماقدامزمان تخمینی
۱فرآیند فعلی تیم خود را روی کاغذ بنویسید۳۰ دقیقه
۲یک برد کانبان ساده با ۴ ستون ایجاد کنید۱۵ دقیقه
۳تمام وظایف فعلی را روی کارت‌های جداگانه وارد کنید۱ ساعت
۴برای ستون‌های میانی، WIP Limit تعیین کنید۱۰ دقیقه
۵جلسات روزانه ۱۵ دقیقه‌ای را شروع کنیدهر روز
۶پس از ۲ هفته، فرآیند را بازبینی و بهبود دهید۱ ساعت
+ +
+📞 منابع بیشتر: برای یادگیری عمیق‌تر کانبان، کتاب‌های زیر پیشنهاد می‌شوند: +
    +
  • +Kanban: Successful Evolutionary Change for Your Technology Business +
    نویسنده: David J. Anderson
    +
  • +
  • +Kanban from the Inside +
    نویسنده: Mike Burrows
    +
  • +
  • +Personal Kanban +
    نویسندگان: Jim Benson & Tonianne DeMaria Barry
    +
  • +
+
+ +
+🛠️ ابزار پیشنهادی: برای شروع سریع و بدون نیاز به نصب یا راه‌اندازی، ابزار xKanban (طراحی‌شده توسط هادی خزاعی اصل) یک گزینه ایده‌آل است. این ابزار به‌صورت یک فایل HTML مستقل، تمامی قابلیت‌های یک برد کانبان حرفه‌ای را به‌صورت آفلاین و رایگان ارائه می‌دهد. +
+ +
+
+ +
+این مستند آموزشی جهت استفاده عمومی تهیه شده است. بازنشر با ذکر منبع مجاز است. +
+ +
+ + +
+ +
معمار و توسعه‌دهنده ارشد نرم‌افزار | متخصص .NET و Angular
+ +
تاریخ تهیه: یکشنبه ۲۲ شهریور ۱۴۰۵ (۱۳ سپتامبر ۲۰۲۶)  |  ساعت: ۱۱:۰۰  |  نسخه: ۱.۰.۰  |  طبقه‌بندی: عمومی - آموزشی
+
+ +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xUMLDrawer_Case_Study.html + + + + + + +معرفی ابزار رسم نمودارهای UML | تحلیل نیازمندی‌ها، معماری و ارزش‌های سازمانی + + + +
+
+
+
+ +
+
+
شماره مستند: UML-TOOL-OVERVIEW-1405-001
+
نسخه: ۱.۰
+
تاریخ تهیه: ۱۷ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰
+
طبقه‌بندی: عمومی / معرفی محصول
+
+
+
+PRODUCT OVERVIEW & ARCHITECTURE +

معرفی ابزار رسم نمودارهای UML

+

تحلیل نیازمندی‌ها، معماری فنی و ارزش‌های سازمانی

+
+
+
+
+همکاران گرامی و علاقه‌مندان به مهندسی نرم‌افزار،
+این مستند به‌عنوان مرجعی جامع برای معرفی «ابزار رسم نمودارهای UML» تهیه شده است. در این مستند، چرایی پیدایش این ابزار، مزایای رقابتی، ارزش‌های سازمانی قابل خلق، معماری دقیق فنی و مخاطبان هدف آن به‌صورت شفاف تشریح می‌گردد. هدف از تهیه این مستند، ارائه دیدگاهی کامل برای تصمیم‌گیری آگاهانه جهت استفاده از این ابزار در فرآیندهای مهندسی نرم‌افزار سازمان‌هاست. +
+ +
+
+
۱
+
+

شرح مسئله و چالش‌های موجود

+
Problem Statement & Industry Challenges
+
+
+
+

در دنیای پیچیده و به‌سرعت در حال تحول مهندسی نرم‌افزار، مدل‌سازی دقیق سیستم‌ها به یکی از ارکان حیاتی موفقیت پروژه‌ها تبدیل شده است. نمودارهای UML (Unified Modeling Language) به‌عنوان زبان استاندارد بین‌المللی برای مدل‌سازی بصری سیستم‌های نرم‌افزاری، نقشی کلیدی در انتقال مفاهیم، طراحی معماری، مستندسازی و ارتباط مؤثر بین ذینفعان ایفا می‌کنند. با این حال، ابزارهای موجود در بازار با چالش‌های متعددی مواجه‌اند که استفاده از آن‌ها را برای بسیاری از تیم‌ها دشوار یا حتی غیرممکن می‌سازد.

+ +
+
+
💸
+

هزینه‌های سنگین لایسنس

+

ابزارهای تجاری معتبر مانند Enterprise Architect، Visual Paradigm و IBM Rational Rose دارای هزینه‌های لایسنس سالانه بسیار بالا هستند که برای بسیاری از سازمان‌ها، به‌ویژه استارتاپ‌ها و شرکت‌های متوسط، مقرون‌به‌صرفه نیست.

+
+
+
🌐
+

وابستگی به اینترنت و سرور

+

بسیاری از ابزارهای مدرن مبتنی بر Cloud هستند و برای اجرا به اتصال اینترنت پایدار و سرورهای خارجی نیاز دارند. این موضوع در محیط‌هایی با محدودیت‌های شبکه، مسائل امنیتی یا قطعی اینترنت، چالش‌برانگیز است.

+
+
+
🔒
+

نگرانی‌های امنیتی و حریم داده

+

ذخیره نمودارهای معماری حساس در سرورهای ابری شخص ثالث، ریسک‌های امنیتی جدی به همراه دارد. سازمان‌های دولتی، نظامی و مالی اغلب نمی‌توانند داده‌های معماری خود را به خارج از شبکه داخلی منتقل کنند.

+
+
+
⚙️
+

پیچیدگی و منحنی یادگیری بالا

+

ابزارهای جامع UML معمولاً دارای رابط کاربری پیچیده، تعداد زیادی ویژگی غیرضروری و منحنی یادگیری طولانی هستند. این موضوع باعث می‌شود که استفاده از آن‌ها برای کارهای سریع و روزمره، زمان‌بر و خسته‌کننده باشد.

+
+
+
📦
+

حجم بالا و نیاز به نصب

+

ابزارهای دسکتاپ معمولاً حجم بالایی دارند (چندین گیگابایت)، نیاز به نصب و پیکربندی دارند و روی همه سیستم‌ها قابل اجرا نیستند. این موضوع برای استفاده در محیط‌های محدود یا سیستم‌های قدیمی مشکل‌ساز است.

+
+
+
🔄
+

عدم پشتیبانی از همه نمودارها

+

بسیاری از ابزارهای رایگان یا سبک، تنها چند نوع محدود از نمودارهای UML را پشتیبانی می‌کنند و امکان رسم کامل هشت نمودار اصلی را به‌صورت یکپارچه فراهم نمی‌آورند.

+
+
+
🌍
+

عدم پشتیبانی از زبان فارسی و RTL

+

اکثر ابزارهای موجود، پشتیبانی مناسبی از زبان فارسی و چیدمان راست‌به‌چپ (RTL) ندارند. این موضوع برای تیم‌های ایرانی، استفاده از نمودارها در مستندات فارسی و ارائه به ذینفعان فارسی‌زبان، یک محدودیت جدی است.

+
+
+
🔗
+

عدم یکپارچگی و پراکندگی ابزارها

+

تیم‌ها مجبورند برای رسم نمودارهای مختلف از ابزارهای متفاوت استفاده کنند که منجر به عدم یکپارچگی بصری، دشواری در نگهداری و افزایش هزینه‌های آموزشی می‌شود.

+
+
+ +
+⚠️ نتیجه چالش‌ها: این معضلات باعث می‌شود که بسیاری از تیم‌های نرم‌افزاری یا از مدل‌سازی UML صرف‌نظر کنند، یا از ابزارهای ناکارآمد استفاده نمایند که در نهایت به کاهش کیفیت طراحی، افزایش خطاهای معماری و کاهش بهره‌وری تیم منجر می‌شود. +
+
+
+ +
+
+
۲
+
+

معرفی راه‌حل و مزایای رقابتی

+
Solution Overview & Competitive Advantages
+
+
+
+

«ابزار رسم نمودارهای UML» پاسخی جامع و حرفه‌ای به چالش‌های مطرح‌شده است. این ابزار با تکیه بر تکنولوژی‌های مدرن وب و معماری هوشمندانه، تجربه‌ای بی‌نظیر از مدل‌سازی بصری را در اختیار معماران، تحلیل‌گران و توسعه‌دهندگان قرار می‌دهد.

+ +

مزایای کلیدی محصول:

+ +
+✅ کاملاً رایگان و بدون لایسنس: این ابزار به‌صورت متن‌باز و کاملاً رایگان ارائه می‌شود. هیچ هزینه لایسنس، اشتراک یا پرداخت درون‌برنامه‌ای وجود ندارد. سازمان‌ها می‌توانند بدون هیچ محدودیتی از آن استفاده کنند. +
+ +
+✅ ۱۰۰٪ آفلاین و بدون نیاز به سرور: تمام عملیات در سمت مرورگر و بدون هیچ‌گونه ارتباط با سرور خارجی انجام می‌شود. این ابزار در محیط‌های کاملاً ایزوله، شبکه‌های داخلی (Intranet) و حتی سیستم‌های بدون اینترنت قابل اجراست. +
+ +
+✅ پشتیبانی کامل از ۸ نمودار اصلی UML: +
    +
  • Use Case Diagram (مورد کاربرد)
  • +
  • Activity Diagram (فعالیت)
  • +
  • State Machine Diagram (ماشین حالت)
  • +
  • Class Diagram (کلاس)
  • +
  • Sequence Diagram (توالی)
  • +
  • Component Diagram (کامپوننت)
  • +
  • Deployment Diagram (استقرار)
  • +
  • Swimlane Diagram (لاین شنا)
  • +
+
+ +
+✅ پشتیبانی کامل از زبان فارسی و RTL: تمامی رابط کاربری، برچسب‌ها، منوها و خروجی‌ها به‌صورت کامل از زبان فارسی و چیدمان راست‌به‌چپ پشتیبانی می‌کنند. فونت حرفه‌ای Vazirmatn برای تایپوگرافی فارسی به‌کار رفته است. +
+ +
+✅ سبک، سریع و بدون نیاز به نصب: حجم ابزار کمتر از ۱ مگابایت است و تنها با یک فایل HTML قابل اجراست. نیازی به نصب، پیکربندی یا وابستگی خارجی ندارد. کافی است فایل را در هر مرورگر مدرنی باز کنید. +
+ +
+✅ امنیت کامل داده‌ها: تمامی داده‌ها به‌صورت محلی و در قالب فایل JSON ذخیره می‌شوند. هیچ اطلاعاتی به سرور خارجی ارسال نمی‌شود. سازمان‌ها کنترل کامل بر داده‌های خود دارند. +
+ +
+✅ تم تاریک و روشن حرفه‌ای: امکان سوئیچ آنی بین تم تاریک و روشن با حفظ ترجیحات در فایل پروژه. این ویژگی برای کار طولانی‌مدت و کاهش خستگی چشم بسیار مفید است. +
+ +
+✅ مدیریت چند نمودار هم‌زمان (Multi-Tab): امکان باز کردن چندین نمودار در تب‌های مجزا و سوئیچ سریع بین آن‌ها. این ویژگی برای پروژه‌های بزرگ با نمودارهای متعدد، بسیار کارآمد است. +
+ +
+✅ خروجی PNG با کیفیت: امکان Export نمودارها به فرمت PNG با قابلیت انتخاب رنگ پس‌زمینه یا شفافیت. مناسب برای استفاده در مستندات، ارائه‌ها و گزارش‌ها. +
+ +
+✅ رابط کاربری شهودی و کاربرپسند: طراحی رابط کاربری بر اساس اصول UX مدرن، با ابزارهای دسته‌بندی‌شده، کلیدهای میانبر، Properties Panel و ویرایشگرهای پیشرفته. منحنی یادگیری بسیار کوتاه است. +
+ +
+💎 مزیت رقابتی کلیدی: این ابزار تنها راه‌حلی است که تمامی نیازمندی‌های یک ابزار حرفه‌ای UML را در یک بسته سبک، رایگان، آفلاین و کاملاً فارسی ارائه می‌دهد. هیچ ابزار دیگری در بازار چنین ترکیبی از ویژگی‌ها را فراهم نمی‌آورد. +
+
+
+ +
+
+
۳
+
+

ارزش‌های خلق‌شده در سازمان

+
Organizational Value Creation
+
+
+
+

استفاده از این ابزار در سطح سازمان، ارزش‌های استراتژیک و عملیاتی متعددی ایجاد می‌کند که در سه دسته اصلی قابل دسته‌بندی هستند:

+ +
+
+
💰
+

صرفه‌جویی مالی

+

حذف هزینه‌های لایسنس، کاهش هزینه‌های آموزشی، کاهش زمان مدل‌سازی و افزایش بهره‌وری تیم

+
+
+
⚡
+

افزایش چابکی

+

سرعت بخشیدن به فرآیند طراحی، امکان مدل‌سازی سریع در جلسات، و کاهش زمان تبدیل ایده به مستند

+
+
+
🎯
+

بهبود کیفیت

+

استانداردسازی نمودارها، کاهش خطاهای طراحی، و افزایش دقت در انتقال مفاهیم بین تیم‌ها

+
+
+
🔒
+

امنیت داده‌ها

+

حفظ کامل حریم داده‌های معماری، عدم وابستگی به سرورهای خارجی، و کنترل کامل بر اطلاعات حساس

+
+
+
🤝
+

بهبود ارتباطات

+

زبان بصری مشترک بین تیم‌های فنی و کسب‌وکار، کاهش سوءتفاهم‌ها، و افزایش شفافیت در مستندات

+
+
+
📚
+

دانش سازمانی

+

ایجاد مخزن استاندارد از نمودارها، تسهیل Onboarding نیروهای جدید، و حفظ دانش معماری

+
+
+
🌐
+

استقلال فناورانه

+

عدم وابستگی به ابزارهای خارجی، قابلیت اجرا در هر محیطی، و سازگاری با محدودیت‌های شبکه

+
+
+
🚀
+

توسعه‌پذیری

+

معماری ماژولار امکان افزودن نمودارهای جدید، سفارشی‌سازی و یکپارچه‌سازی با ابزارهای دیگر را فراهم می‌آورد

+
+
+
📊
+

حرفه‌ای‌گری

+

ارتقای سطح بلوغ مهندسی سازمان، استانداردسازی فرآیندهای طراحی، و افزایش اعتبار مستندات فنی

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
دسته ارزششاخص کلیدیتأثیر مورد انتظار
مالیکاهش هزینه‌های ابزارحذف ۱۰۰٪ هزینه لایسنس
عملیاتیزمان مدل‌سازیکاهش ۴۰-۶۰٪ زمان
کیفیدقت مستنداتافزایش چشمگیر
امنیتیحفظ حریم داده‌هاتضمین کامل
آموزشیزمان یادگیریکاهش ۷۰٪ منحنی یادگیری
استراتژیکبلوغ مهندسی سازمانارتقای سطح بلوغ
+ +
+💡 نکته کلیدی: ارزش اصلی این ابزار در ترکیب منحصر‌به‌فرد «رایگان + آفلاین + فارسی + جامع» است. این ترکیب در هیچ ابزار دیگری در بازار یافت نمی‌شود و برای سازمان‌های ایرانی یک مزیت رقابتی پایدار ایجاد می‌کند. +
+
+
+ +
+
+
۴
+
+

معماری دقیق فنی پروژه

+
Technical Architecture Deep Dive
+
+
+
+

معماری این پروژه بر پایه اصول مهندسی نرم‌افزار مدرن، الگوهای طراحی اثبات‌شده و رویکرد State-Centric طراحی شده است. در ادامه، لایه‌های مختلف معماری و اجزای کلیدی آن تشریح می‌گردد.

+ +
+

🎨 لایه ۱: رابط کاربری (UI Layer)

+

این لایه مسئول ارائه تجربه کاربری حرفه‌ای و تعامل با کاربر است. شامل Sidebar ابزارها، Tab Bar برای مدیریت چند نمودار، Properties Panel برای ویرایش ویژگی‌ها، و Modal‌های مختلف (ایجاد نمودار، تنظیمات، ذخیره، Export PNG و ویرایشگر Class) می‌باشد.

+
    +
  • تکنولوژی: HTML5 Semantic + CSS3 (با CSS Variables برای تم داینامیک) + Tailwind CSS (CDN)
  • +
  • ویژگی کلیدی: پشتیبانی کامل RTL، فونت Vazirmatn، تم تاریک/روشن، طراحی Responsive
  • +
+
+ +
+

🧠 لایه ۲: مدیریت وضعیت (State Management Layer)

+

قلب تپنده برنامه که تمامی وضعیت‌های سراسری را در یک آبجکت مرکزی نگهداری می‌کند. این رویکرد باعث سادگی، قابلیت پیش‌بینی و نگهداری آسان کد می‌شود.

+
+const state = {
+  diagrams: [],                  // لیست همه نمودارها
+  activeDiagramId: null,         // شناسه نمودار فعال
+  currentTool: 'select',         // ابزار انتخاب‌شده
+  selectedElement: null,         // المان انتخاب‌شده
+  isDragging: false,             // وضعیت Drag
+  isDrawingRelationship: false,  // وضعیت رسم رابطه
+  mousePos: { x:0, y:0 },        // موقعیت ماوس
+  sidebarVisible: true,         // وضعیت Sidebar
+  gridType: 'lines',            // نوع خط‌کشی بوم
+  darkMode: true,               // تم تاریک/روشن
+  fileMetadata: { ... }          // متادیتای پروژه
+  // ... سایر ویژگی‌های وضعیت
+}; +
+
+ +
+

🎨 لایه ۳: موتور رسم (Rendering Engine)

+

موتور رسم بر پایه HTML5 Canvas 2D API و رویکرد Immediate Mode Rendering طراحی شده است. در این رویکرد، در هر تغییر وضعیت، کل بوم پاک‌سازی شده و تمامی المان‌ها از نو رسم می‌شوند.

+
    +
  • تابع اصلی رسم: function draw() { ... } - چرخه اصلی رسم که Grid، المان‌ها و روابط را مدیریت می‌کند
  • +
  • تابع Dispatch: function drawDiag(c,d,tc) { ... } - بر اساس نوع نمودار، تابع اختصاصی را فراخوانی می‌کند
  • +
  • توابع اختصاصی هر نمودار: +
      +
    • function drawUseCase(c,d,tc) { ... }
    • +
    • function drawStateMachine(c,d,tc) { ... }
    • +
    • function drawActivity(c,d,tc) { ... }
    • +
    • function drawComponent(c,d,tc) { ... }
    • +
    • function drawDeployment(c,d,tc) { ... }
    • +
    • function drawClassDiagram(c,d,tc) { ... }
    • +
    • function drawSequenceDiagram(c,d,tc) { ... }
    • +
    • function drawSwimlaneDiagram(c,d,tc) { ... }
    • +
    +
  • +
  • تابع رسم Grid: function drawGrid(c,w,h,tc,trans) { ... } - پشتیبانی از سه حالت Lines, Dots, None
  • +
+
+ +
+

🎯 لایه ۴: سیستم تعامل و Hit Testing

+

این لایه مسئول تشخیص موقعیت ماوس، انتخاب المان‌ها، Drag & Drop و رسم روابط است.

+
    +
  • تابع Hit Test: function hitTest(x,y) { ... } - بر اساس نوع نمودار، الگوریتم‌های متفاوتی برای تشخیص المان زیر ماوس اجرا می‌کند
  • +
  • مدیریت رویدادها: +
      +
    • canvas.addEventListener('mousedown', e => { ... }) - شروع Drag یا رسم رابطه
    • +
    • canvas.addEventListener('mousemove', e => { ... }) - به‌روزرسانی موقعیت المان‌ها
    • +
    • canvas.addEventListener('mouseup', e => { ... }) - پایان Drag یا تکمیل رابطه
    • +
    • canvas.addEventListener('dblclick', e => { ... }) - باز کردن ویرایشگرها
    • +
    +
  • +
+
+ +
+

🗂️ لایه ۵: رجیستری نمودارها (Diagram Registry)

+

الگوی طراحی Registry Pattern برای تعریف مرکزی انواع نمودارها و قابلیت‌های آن‌ها به‌کار رفته است.

+
+const DIAGRAM_TYPES = {
+  usecase: {
+    id: 'usecase',
+    name: 'نمودار مورد کاربرد (Use Case)',
+    icon: '⭕',
+    available: true,
+    tools: ['select', 'actor', 'useCase', ...],
+    groups: ['selection', 'uc-elements', ...]
+  },
+  statemachine: { /* ... */ },
+  activity: { /* ... */ },
+  component: { /* ... */ },
+  deployment: { /* ... */ },
+  class: { /* ... */ },
+  sequence: { /* ... */ },
+  swimlane: { /* ... */ }
+}; +
+

این رجیستری به‌عنوان Single Source of Truth برای ابزارها، گروه‌ها و قابلیت‌های هر نمودار عمل می‌کند و افزودن نمودار جدید را بسیار آسان می‌سازد.

+
+ +
+

💾 لایه ۶: سیستم Persistence

+

سیستم ذخیره‌سازی و بازیابی مبتنی بر JSON File API است. این رویکرد مزایای متعددی نسبت به LocalStorage یا Backend دارد.

+
    +
  • تابع ساخت داده ذخیره: function buildSaveData() { ... } - ساختار کامل JSON شامل متادیتا، ترجیحات و همه نمودارها
  • +
  • تابع ذخیره: document.getElementById('confirmSaveBtn').addEventListener('click', () => { ... }) - ایجاد Blob و دانلود فایل
  • +
  • تابع بارگذاری: document.getElementById('fileInput').addEventListener('change', e => { ... }) - خواندن فایل JSON و بازیابی وضعیت
  • +
+
+ +
+

🎨 لایه ۷: سیستم تم و رنگ

+

سیستم تم بر پایه CSS Custom Properties (Variables) طراحی شده است. با تغییر کلاس body.dark، تمامی متغیرهای رنگی به‌صورت آنی تغییر می‌کنند.

+
    +
  • تابع دریافت رنگ‌ها: function getTC() { ... } - استخراج رنگ‌های فعال از CSS Variables در زمان اجرا
  • +
  • تابع اعمال تم: function applyTheme() { ... } - تغییر کلاس body و به‌روزرسانی UI
  • +
+
+ +
+

🔧 لایه ۸: مدیریت نمودارها

+

توابع مدیریت چرخه حیات نمودارها (ایجاد، سوئیچ، حذف) در این لایه قرار دارند.

+
    +
  • function createNewDiagram(type='usecase') { ... }
  • +
  • function switchDiagram(id) { ... }
  • +
  • function deleteDiagram(id) { ... }
  • +
  • function renderTabs() { ... } - رسم Tab Bar
  • +
  • function updateToolVisibility() { ... } - نمایش/مخفی کردن ابزارها بر اساس نوع نمودار فعال
  • +
+
+ +
+

🗂️ لایه ۹: ویرایشگرهای تخصصی

+

برای المان‌های پیچیده مانند Class، ویرایشگرهای اختصاصی طراحی شده‌اند.

+
    +
  • function openClassEditor(classId) { ... } - باز کردن ویرایشگر Class با Attributes و Methods
  • +
  • function renderAttributesTable() { ... } - رسم جدول ویژگی‌ها
  • +
  • function renderMethodsTable() { ... } - رسم جدول متدها
  • +
+
+ +

الگوهای طراحی به‌کار رفته:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل کاربردمزیت
Registry PatternDIAGRAM_TYPESمرجع مرکزی، توسعه‌پذیری آسان
State Patternآبجکت stateمدیریت متمرکز وضعیت
Strategy Patternتوابع draw*انتخاب استراتژی رسم بر اساس نوع
Command Patternمدیریت ابزارهارفتارهای مشخص برای هر ابزار
Observer PatternEvent Listenersواکنش به رویدادهای کاربر
Factory PatterncreateNewDiagram()ساخت ساختار اولیه نمودار
Singleton PatternCanvas Context، Stateتنها یک نمونه از منابع حیاتی
+ +
+💡 نکته معماری: انتخاب Vanilla JS به جای فریم‌ورک‌هایی مانند React یا Angular، باعث کاهش چشمگیر حجم نهایی، اجرای سریع‌تر، عدم وابستگی به ابزارهای Build و سادگی نگهداری شده است. این رویکرد برای ابزارهای تخصصی و آفلاین، انتخاب بهینه‌ای است. +
+
+
+ +
+
+
۵
+
+

مخاطبان هدف: سازمان‌ها و تیم‌ها

+
Target Audience: Organizations & Teams
+
+
+
+

این ابزار برای طیف گسترده‌ای از سازمان‌ها و تیم‌های نرم‌افزاری طراحی شده است. در ادامه، مخاطبان هدف و موارد استفاده مناسب برای هر دسته تشریح می‌گردد.

+ +

الف) سازمان‌های مناسب:

+ +
+
+
🏢
+

شرکت‌های نرم‌افزاری

+

تیم‌های توسعه که نیاز به مدل‌سازی معماری، طراحی کلاس‌ها و مستندسازی سیستم‌ها دارند. مناسب برای شرکت‌های محصول‌محور و پروژه‌ای.

+
+
+
🚀
+

استارتاپ‌ها

+

تیم‌های کوچک که به ابزار سبک، رایگان و سریع نیاز دارند. مناسب برای MVP، طراحی اولیه و ارائه به سرمایه‌گذاران.

+
+
+
🏛️
+

سازمان‌های دولتی و نظامی

+

سازمان‌هایی که به دلیل محدودیت‌های امنیتی، نمی‌توانند از ابزارهای ابری استفاده کنند و نیاز به راه‌حل کاملاً آفلاین دارند.

+
+
+
🏦
+

بانک‌ها و مؤسسات مالی

+

سازمان‌هایی با الزامات امنیتی بالا که نیاز به حفظ کامل حریم داده‌های معماری حساس خود دارند.

+
+
+
🎓
+

دانشگاه‌ها و مراکز آموزشی

+

اساتید و دانشجویان رشته‌های مهندسی نرم‌افزار، علوم کامپیوتر و IT برای تدریس و یادگیری UML.

+
+
+
🏥
+

سازمان‌های بهداشتی و درمانی

+

تیم‌های فنی که نیاز به مدل‌سازی فرآیندهای پیچیده کسب‌وکار و سیستم‌های اطلاعاتی دارند.

+
+
+
🏭
+

شرکت‌های صنعتی و تولیدی

+

تیم‌های IT که نیاز به مدل‌سازی سیستم‌های ERP، CRM و فرآیندهای تولید دارند.

+
+
+
🌐
+

شرکت‌های مشاوره و پیمانکاری

+

مشاورانی که نیاز به ارائه مستندات حرفه‌ای به کارفرمایان مختلف دارند و می‌خواهند ابزار یکپارچه‌ای داشته باشند.

+
+
+ +

ب) تیم‌های مناسب:

+ +
+
+
👨‍💼
+

معماران نرم‌افزار

+

برای طراحی معماری کلان، مدل‌سازی کامپوننت‌ها، استقرار و ارتباط بین لایه‌های مختلف سیستم.

+
+
+
📊
+

تحلیل‌گران کسب‌وکار (BA)

+

برای مدل‌سازی نیازمندی‌ها، فرآیندهای کسب‌وکار، Use Caseها و Swimlaneها.

+
+
+
💻
+

توسعه‌دهندگان Backend

+

برای طراحی Class Diagram، Sequence Diagram و State Machine برای پیاده‌سازی دقیق.

+
+
+
🎨
+

توسعه‌دهندگان Frontend

+

برای مدل‌سازی Componentها، تعاملات UI و ارتباط بین کامپوننت‌ها.

+
+
+
🧪
+

تیم‌های QA و تست

+

برای مدل‌سازی سناریوهای تست، فرآیندهای کسب‌وکار و درک بهتر سیستم.

+
+
+
📋
+

مدیران پروژه (PM)

+

برای مستندسازی معماری، ارتباط با ذینفعان و ارائه گزارش‌های بصری.

+
+
+
🎯
+

Product Owners

+

برای مدل‌سازی نیازمندی‌ها، Use Caseها و ارتباط با تیم فنی.

+
+
+
🔧
+

تیم‌های DevOps

+

برای مدل‌سازی Deployment Diagram، معماری زیرساخت و ارتباط بین سرویس‌ها.

+
+
+ +

ج) موارد استفاده مناسب:

+ +
    +
  • 📐 طراحی معماری سیستم: مدل‌سازی معماری کلان، میکروسرویس‌ها، و ارتباط بین کامپوننت‌ها
  • +
  • 📋 مستندسازی نیازمندی‌ها: رسم Use Case Diagram برای انتقال نیازمندی‌ها به تیم فنی
  • +
  • 🔄 مدل‌سازی فرآیندها: رسم Activity و Swimlane Diagram برای فرآیندهای کسب‌وکار
  • +
  • 🗂️ طراحی شیءگرا: رسم Class Diagram برای طراحی کلاس‌ها و روابط آن‌ها
  • +
  • ⏱️ مدل‌سازی تعاملات: رسم Sequence Diagram برای سناریوهای اجرایی
  • +
  • 🔁 مدل‌سازی چرخه حیات: رسم State Machine Diagram برای موجودیت‌های با وضعیت‌های گسسته
  • +
  • 🖥️ مستندسازی زیرساخت: رسم Deployment Diagram برای معماری فیزیکی
  • +
  • 🎓 آموزش و یادگیری: تدریس مفاهیم UML و مدل‌سازی نرم‌افزار
  • +
  • 📊 ارائه به ذینفعان: ایجاد نمودارهای حرفه‌ای برای جلسات و گزارش‌ها
  • +
  • 🔍 تحلیل و دیباگ: مدل‌سازی سناریوها برای درک بهتر رفتار سیستم
  • +
+ +
+💎 نتیجه‌گیری: این ابزار برای هر سازمان یا تیمی که نیاز به مدل‌سازی بصری سیستم‌های نرم‌افزاری دارد، مناسب است. به‌ویژه برای سازمان‌های ایرانی که به پشتیبانی کامل فارسی، محیط آفلاین و امنیت داده‌ها نیاز دارند، این ابزار یک انتخاب ایده‌آل است. +
+
+
+ +
+
+
۶
+
+

جمع‌بندی نهایی و پیشنهاد

+
Final Summary & Recommendation
+
+
+
+

«ابزار رسم نمودارهای UML» پاسخی جامع و حرفه‌ای به چالش‌های موجود در حوزه مدل‌سازی نرم‌افزار است. این ابزار با ترکیب منحصر‌به‌فرد «رایگان + آفلاین + فارسی + جامع»، ارزش‌های استراتژیک و عملیاتی متعددی برای سازمان‌ها ایجاد می‌کند.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
شاخصابزارهای تجاریابزارهای ابریاین ابزار
هزینهبسیار بالااشتراک ماهیانهکاملاً رایگان
نیاز به اینترنتاختیاریالزامیکاملاً آفلاین
امنیت داده‌هامتوسطریسک بالاتضمین کامل
پشتیبانی فارسیمحدودضعیفکامل و حرفه‌ای
تعداد نمودارها۸+ نمودار۴-۶ نمودار۸ نمودار کامل
حجم و نصبچند GB + نصببدون نصب<1 MB بدون نصب
ارزش کلی——بسیار بالاتر
+ +
+

🎯 پیشنهاد نهایی

+

با توجه به تحلیل جامع نیازمندی‌ها، مزایا، ارزش‌های سازمانی و معماری فنی، استفاده از این ابزار برای تمامی سازمان‌ها و تیم‌های نرم‌افزاری که به مدل‌سازی UML نیاز دارند، قویاً توصیه می‌شود.

+

این ابزار نه تنها هزینه‌ها را به شکل قابل‌توجهی کاهش می‌دهد، بلکه کیفیت مستندات، سرعت طراحی و امنیت داده‌ها را به‌طور هم‌زمان ارتقا می‌بخشد.

+
+💎 ارزش پیشنهادی:
+ابزاری کاملاً رایگان، آفلاین، فارسی و جامع که تمامی نیازمندی‌های مدل‌سازی UML را در یک بسته سبک و حرفه‌ای ارائه می‌دهد. +
+
+ +
+📞 گام بعدی: برای شروع استفاده، کافی است فایل HTML ابزار را دانلود کرده و در مرورگر باز کنید. هیچ نصب یا پیکربندی نیاز نیست. مستندات آموزشی کامل نیز برای یادگیری سریع در دسترس است. +
+
+
+ +
+این مستند جهت معرفی و تحلیل ابزار رسم نمودارهای UML تهیه شده است. استفاده از این ابزار برای تمامی سازمان‌ها و تیم‌های نرم‌افزاری آزاد و رایگان است. +
+
+
+ + +
تاریخ تهیه: ۱۷ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰  |  نسخه: ۱.۰  |  طبقه‌بندی: عمومی / معرفی محصول
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xUMLDrawer_Supported_UML_Diagrams_Tutorial.html + + + + + + +مستند آموزشی جامع نمودارهای UML | راهنمای کامل با مثال‌های عملی + + + +
+
+
+
+ +
+
+
شماره مستند: UML-EDU-1405-001
+
نسخه: .۰
+
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰
+
طبقه‌بندی: آموزشی / عمومی
+
+
+
+EDUCATIONAL DOCUMENTATION +

مستند آموزشی جامع نمودارهای UML

+

راهنمای کامل با مثال‌های عملی و کاربردی

+
+
+
+
+همکاران گرامی و علاقه‌مندان به مهندسی نرم‌افزار،
+این مستند آموزشی به‌عنوان مرجعی جامع برای یادگیری و درک عمیق هشت نمودار اصلی UML (Unified Modeling Language) تهیه شده است. هر فصل به تفصیل یک نوع نمودار را با ذکر المان‌ها، روابط، کاربردها و مثال‌های عملی توضیح می‌دهد. هدف از این مستند، ارائه درکی کاربردی و آماده‌سازی شما برای مدل‌سازی حرفه‌ای سیستم‌های نرم‌افزاری است. +
+ + + +
+
+
۱
+
+

نمودار مورد کاربرد (Use Case Diagram)

+
نمایش تعامل کاربران با سیستم
+
+
+
+

نمودار Use Case یکی از پرکاربردترین نمودارهای UML است که برای نمایش تعامل بین کاربران (Actors) و سیستم استفاده می‌شود. این نمودار دیدگاهی بیرونی از سیستم ارائه داده و نیازمندی‌های عملکردی را بدون ورود به جزئیات فنی نشان می‌دهد.

+ +
+
+
👤
+

Actor (بازیگر)

+

نماینده کاربر، سیستم خارجی یا موجودیتی که با سیستم تعامل دارد. به صورت شکل انسان نمایش داده می‌شود.

+
+
+
⭕
+

Use Case (مورد کاربرد)

+

یک عملکرد یا سرویس خاص که سیستم ارائه می‌دهد. به صورت بیضی نمایش داده می‌شود.

+
+
+
+

System Boundary (مرز سیستم)

+

مستطیلی که محدوده سیستم را مشخص کرده و Use Caseها درون آن قرار می‌گیرند.

+
+
+
➖
+

Association (ارتباط)

+

خط ساده که Actor را به Use Case مرتبط وصل می‌کند.

+
+
+ +

انواع روابط در Use Case:

+
    +
  • Include (شامل): رابطه‌ای که نشان می‌دهد یک Use Case حتماً شامل Use Case دیگری است. با خط‌چین و stereotype <<include>> نمایش داده می‌شود.
  • +
  • 🔀 Extend (گسترش): رابطه‌ای اختیاری که نشان می‌دهد یک Use Case می‌تواند در شرایط خاصی Use Case دیگر را گسترش دهد. با خط‌چین و stereotype <<extend>> نمایش داده می‌شود.
  • +
  • 🔺 Generalization (تعمیم): رابطه ارث‌بری بین Actors یا بین Use Cases. با فلش مثلثی توخالی نمایش داده می‌شود.
  • +
+ +
+

مثال عملی: سیستم بانکداری آنلاین

+

Actors: مشتری، کارمند بانک، مدیر سیستم

+

Use Cases:

+
    +
  • مشتری → ورود به سیستم، مشاهده موجودی، انتقال وجه، پرداخت قبض
  • +
  • کارمند بانک → ثبت مشتری جدید، تأیید تراکنش‌های بزرگ
  • +
  • مدیر سیستم → مدیریت کاربران، مشاهده گزارش‌ها
  • +
  • «انتقال وجه» <<include>> «بررسی موجودی»
  • +
  • «ورود به سیستم» <<extend>> «احراز هویت دو مرحله‌ای» (در صورت فعال بودن)
  • +
+
+ +
+💡 نکته کلیدی: نمودار Use Case در فاز تحلیل نیازمندی‌ها استفاده شده و به درک مشترک بین تیم فنی و ذینفعان کسب‌وکار کمک می‌کند. +
+
+
+ +
+
+
۲
+
+

نمودار فعالیت (Activity Diagram)

+
مدل‌سازی جریان کار و فرآیندها
+
+
+
+

نمودار Activity برای نمایش جریان کار (Workflow)، فرآیندهای کسب‌وکار و الگوریتم‌ها استفاده می‌شود. این نمودار شبیه فلوچارت است اما قدرت بیشتری در نمایش فعالیت‌های موازی و تصمیم‌گیری‌های پیچیده دارد.

+ +
+
+
⚫
+

Initial Node (گره شروع)

+

دایره توپر سیاه که نقطه شروع فرآیند را نشان می‌دهد.

+
+
+
🎯
+

Final Node (گره پایان)

+

دایره توپر با حاشیه ضخیم که پایان فرآیند را نشان می‌دهد.

+
+
+
▭
+

Action (فعالیت)

+

مستطیل با گوشه‌های گرد که یک عملیات یا کار را نشان می‌دهد.

+
+
+
◇
+

Decision/Merge (تصمیم/ادغام)

+

لوزی که برای انشعاب شرطی یا ادغام جریان‌ها استفاده می‌شود.

+
+
+
▬
+

Fork/Join (انشعاب/هم‌زمانی)

+

خط ضخیم افقی یا عمودی برای نمایش فعالیت‌های موازی.

+
+
+
→
+

Control Flow (جریان کنترل)

+

فلش که ترتیب اجرای فعالیت‌ها را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: فرآیند ثبت سفارش آنلاین

+

جریان فرآیند:

+
    +
  • شروع: مشتری وارد سایت می‌شود
  • +
  • فعالیت‌ها: انتخاب محصول → افزودن به سبد خرید → ورود/ثبت‌نام → انتخاب آدرس → انتخاب روش پرداخت
  • +
  • Decision: آیا موجودی کافی است؟ (بله/خیر)
  • +
  • Fork: هم‌زمان: ۱) کاهش موجودی انبار ۲) ارسال ایمیل تأیید
  • +
  • Join: انتظار برای تکمیل هر دو فعالیت موازی
  • +
  • پایان: ثبت نهایی سفارش
  • +
+
+ +
+کاربردهای کلیدی: مدل‌سازی فرآیندهای کسب‌وکار، الگوریتم‌های پیچیده، گردش کار (Workflow)، و تحلیل سناریوهای مختلف +
+
+
+ +
+
+
۳
+
+

نمودار ماشین حالت (State Machine Diagram)

+
نمایش چرخه حیات و تغییر وضعیت‌ها
+
+
+
+

نمودار State Machine برای نمایش وضعیت‌های مختلف یک شیء و رویدادهایی که باعث تغییر وضعیت می‌شوند استفاده می‌شود. این نمودار برای مدل‌سازی چرخه حیات (Lifecycle) موجودیت‌ها ایده‌آل است.

+ +
+
+
⚫
+

Initial State (وضعیت شروع)

+

دایره توپر کوچک که وضعیت اولیه را نشان می‌دهد.

+
+
+
+

Final State (وضعیت پایانی)

+

دایره توپر با حاشیه ضخیم که وضعیت نهایی را نشان می‌دهد.

+
+
+
🔲
+

State (وضعیت)

+

مستطیل با گوشه‌های گرد که یک وضعیت خاص را نشان می‌دهد.

+
+
+
️
+

Transition (گذار)

+

فلش که تغییر از یک وضعیت به وضعیت دیگر را نشان می‌دهد. می‌تواند برچسب (رویداد/شرط/اقدام) داشته باشد.

+
+
+ +

ساختار Transition:

+
+فرمت: eventName [guardCondition] / action
+مثال: pay [amount > 0] / updateInventory() +
+ +
+

مثال عملی: چرخه حیات سفارش

+

وضعیت‌ها:

+
    +
  • ایجاد شده (Created)
  • +
  • در انتظار پرداخت (Pending Payment)
  • +
  • پرداخت شده (Paid)
  • +
  • در حال پردازش (Processing)
  • +
  • ارسال شده (Shipped)
  • +
  • تحویل داده شده (Delivered)
  • +
  • لغو شده (Cancelled)
  • +
+

گذارها:

+
    +
  • Created → Pending Payment: رویداد «ثبت سفارش»
  • +
  • Pending Payment → Paid: رویداد «پرداخت موفق»
  • +
  • Paid → Processing: رویداد «تأیید پرداخت»
  • +
  • Processing → Shipped: رویداد «ارسال کالا»
  • +
  • Shipped → Delivered: رویداد «تحویل به مشتری»
  • +
  • هر وضعیت → Cancelled: رویداد «لغو» (با شرایط خاص)
  • +
+
+ +
+⚠️ نکته مهم: State Machine برای اشیایی استفاده می‌شود که چرخه حیات مشخص و وضعیت‌های گسسته دارند. برای فرآیندهای پیچیده با فعالیت‌های موازی، از Activity Diagram استفاده کنید. +
+
+
+ +
+
+
۴
+
+

نمودار کامپوننت (Component Diagram)

+
نمایش ساختار ماژولار و وابستگی‌ها
+
+
+
+

نمودار Component برای نمایش ساختار فیزیکی سیستم، ماژول‌ها، کتابخانه‌ها و وابستگی‌های بین آن‌ها استفاده می‌شود. این نمودار دیدگاهی از معماری نرم‌افزار در سطح کامپوننت ارائه می‌دهد.

+ +
+
+
🧩
+

Component (کامپوننت)

+

مستطیل با آیکون کامپوننت (دو مستطیل کوچک در گوشه) که یک ماژول یا جزء سیستم را نشان می‌دهد.

+
+
+
🍭
+

Interface Provided (اینترفیس ارائه‌شده)

+

دایره (Lollipop) که سرویس‌هایی که کامپوننت ارائه می‌دهد را نشان می‌دهد.

+
+
+
◗
+

Interface Required (اینترفیس مورد نیاز)

+

نیم‌دایره (Socket) که سرویس‌هایی که کامپوننت نیاز دارد را نشان می‌دهد.

+
+
+
📁
+

Package (بسته)

+

پوشه‌ای که کامپوننت‌های مرتبط را گروه‌بندی می‌کند.

+
+
+
⇢
+

Dependency (وابستگی)

+

فلش خط‌چین که وابستگی بین کامپوننت‌ها را نشان می‌دهد.

+
+
+
—
+

Connector (اتصال)

+

خط جامد که اتصال بین Interface Provided و Required را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: سیستم مدیریت محتوا (CMS)

+

کامپوننت‌ها:

+
    +
  • User Management: مدیریت کاربران و احراز هویت
  • +
  • Content Engine: مدیریت محتوا و ویرایشگر
  • +
  • Media Library: مدیریت فایل‌های چندرسانه‌ای
  • +
  • Search Module: موتور جستجو
  • +
  • Notification Service: ارسال اعلان‌ها
  • +
+

وابستگی‌ها:

+
    +
  • Content Engine → User Management (برای بررسی مجوزها)
  • +
  • Search Module → Content Engine (برای ایندکس محتوا)
  • +
  • Notification Service → User Management (برای دریافت اطلاعات کاربران)
  • +
+

اینترفیس‌ها:

+
    +
  • User Management: IAuthentication, IUserProfile
  • +
  • Content Engine: IContentCRUD, IVersioning
  • +
+
+ +
+✓ مزایا: درک معماری سیستم، مدیریت وابستگی‌ها، برنامه‌ریزی برای ماژولاریزاسیون، و تسهیل توسعه موازی تیم‌ها +
+
+
+ +
+
+
۵
+
+

نمودار استقرار (Deployment Diagram)

+
نمایش معماری فیزیکی و توزیع نرم‌افزار
+
+
+
+

نمودار Deployment برای نمایش سخت‌افزارها، نودها، محیط‌های اجرا و نحوه استقرار نرم‌افزار بر روی زیرساخت فیزیکی استفاده می‌شود. این نمودار دیدگاهی از معماری فیزیکی سیستم ارائه می‌دهد.

+ +
+
+
🖥️
+

Node (گره)

+

مکعب سه‌بعدی که یک سخت‌افزار یا محیط اجرا (مانند سرور، کامپیوتر، کانتینر) را نشان می‌دهد.

+
+
+
💻
+

Device (دستگاه)

+

نود فیزیکی مانند سرور، روتر، یا دستگاه موبایل.

+
+
+
⚙️
+

Execution Environment (محیط اجرا)

+

نود نرم‌افزاری مانند OS، JVM، Docker، یا Kubernetes.

+
+
+
📄
+

Artifact (مصنوع)

+

فایل‌های اجرایی، کتابخانه‌ها، پایگاه داده، یا فایل‌های پیکربندی که بر روی نودها استقرار می‌یابند.

+
+
+
⇌
+

Communication Path (مسیر ارتباطی)

+

خط جامد که ارتباط فیزیکی بین نودها را نشان می‌دهد.

+
+
+
⇣
+

Deployment Relationship (رابطه استقرار)

+

فلش خط‌چین که استقرار Artifact بر روی Node را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: سیستم وب اپلیکیشن میکروسرویس

+

نودها:

+
    +
  • Load Balancer: Nginx (Device)
  • +
  • Application Servers: Kubernetes Cluster (Execution Environment) +
      +
    • User Service Pod
    • +
    • Order Service Pod
    • +
    • Payment Service Pod
    • +
    +
  • +
  • Database Server: PostgreSQL Cluster (Device)
  • +
  • Cache Server: Redis Cluster (Device)
  • +
  • Message Broker: RabbitMQ Server (Device)
  • +
+

Artifacts:

+
    +
  • User Service → user-service.jar
  • +
  • Order Service → order-service.jar
  • +
  • Database → schema.sql, data.migration
  • +
+

ارتباطات:

+
    +
  • Load Balancer ⇌ Application Servers (HTTP/HTTPS)
  • +
  • Application Servers Database Server (JDBC)
  • +
  • Application Servers ⇌ Cache Server (Redis Protocol)
  • +
  • Application Servers ⇌ Message Broker (AMQP)
  • +
+
+ +
+💡 کاربرد: برنامه‌ریزی زیرساخت، مستندسازی محیط‌های Development/Staging/Production، و تحلیل Performance و Scalability +
+
+
+ +
+
+
۶
+
+

نمودار کلاس (Class Diagram)

+
نمایش ساختار ایستایی و روابط بین کلاس‌ها
+
+
+
+

نمودار Class مهم‌ترین و پرکاربردترین نمودار UML است که ساختار ایستایی (Static Structure) سیستم را نشان می‌دهد. این نمودار کلاس‌ها، ویژگی‌ها، متدها و روابط بین آن‌ها را مدل‌سازی می‌کند.

+ +
+
+
🗂️
+

Class (کلاس)

+

مستطیل سه‌بخشی: ۱) نام کلاس ۲) Attributes (ویژگی‌ها) ۳) Methods (متدها)

+
+
+
◯
+

Interface (اینترفیس)

+

دایره یا مستطیل با stereotype <<interface>> که قراردادها را تعریف می‌کند.

+
+
+
🗂️
+

Abstract Class (کلاس انتزاعی)

+

کلاس با نام ایتالیک که نمی‌توان نمونه مستقیم از آن ساخت.

+
+
+
➖
+

Association (ارتباط)

+

خط جامد که ارتباط بین دو کلاس را نشان می‌دهد. می‌تواند Multiplicity (تعداد) داشته باشد.

+
+
+
◇
+

Aggregation (تجميع)

+

لوزی توخالی که رابطه «has-a» ضعیف را نشان می‌دهد (جزء می‌تواند مستقل وجود داشته باشد).

+
+
+
◆
+

Composition (ترکیب)

+

لوزی توپر که رابطه «has-a» قوی را نشان می‌دهد (جزء بدون کل نمی‌تواند وجود داشته باشد).

+
+
+
△
+

Inheritance (ارث‌بری)

+

فلش مثلثی توخالی که رابطه «is-a» یا Generalization را نشان می‌دهد.

+
+
+
⇢
+

Dependency (وابستگی)

+

فلش خط‌چین که استفاده موقت یک کلاس از کلاس دیگر را نشان می‌دهد.

+
+
+ +

Visibility (سطح دسترسی):

+
++ public | - private | # protected | ~ package +
+ +
+

📋 مثال عملی: سیستم مدیریت کتابخانه

+

کلاس‌ها:

+
    +
  • Book: +
      +
    • Attributes: -isbn: String, -title: String, -author: String, -isAvailable: Boolean
    • +
    • Methods: +borrow(), +return(), +reserve()
    • +
    +
  • +
  • Member: +
      +
    • Attributes: -memberId: String, -name: String, -email: String
    • +
    • Methods: +searchBook(), +borrowBook(), +returnBook()
    • +
    +
  • +
  • Loan: +
      +
    • Attributes: -loanId: String, -loanDate: Date, -dueDate: Date
    • +
    • Methods: +calculateFine(), +extendLoan()
    • +
    +
  • +
  • Librarian: (ارث‌بری از Member) +
      +
    • Methods: +addBook(), +removeBook(), +generateReport()
    • +
    +
  • +
+

روابط:

+
    +
  • Member «1» — «*» Loan (یک عضو می‌تواند چندین امانی داشته باشد)
  • +
  • Book «1» — «*» Loan (یک کتاب می‌تواند در چندین امانی باشد)
  • +
  • Loan ◆ Book (Composition: امانی بدون کتاب معنی ندارد)
  • +
  • Librarian △ Member (ارث‌بری)
  • +
  • Book Notification (وابستگی برای ارسال اعلان)
  • +
+
+ +
+ نکته طلایی: نمودار Class پایه و اساس طراحی شیءگرا است و مستقیماً به کد تبدیل می‌شود. طراحی دقیق این نمودار، کیفیت کد نهایی را تضمین می‌کند. +
+
+
+ +
+
+
۷
+
+

نمودار توالی (Sequence Diagram)

+
نمایش تعاملات زمانی بین اشیاء
+
+
+
+

نمودار Sequence برای نمایش تعاملات بین اشیاء در طول زمان استفاده می‌شود. این نمودار نشان می‌دهد که پیام‌ها به چه ترتیبی بین اشیاء مبادله می‌شوند و برای درک سناریوهای اجرایی ایده‌آل است.

+ +
+
+
▭
+

Participant/Lifeline (خط حیات)

+

مستطیل در بالا با خط‌چین عمودی که حضور یک شیء در طول زمان را نشان می‌دهد.

+
+
+
▮
+

Activation (فعال‌سازی)

+

مستطیل باریک روی Lifeline که مدت زمان اجرای یک متد را نشان می‌دهد.

+
+
+
→●
+

Synchronous Message (پیام هم‌زمان)

+

فلش جامد که فراخوانی متد را نشان می‌دهد (فرستنده منتظر پاسخ می‌ماند).

+
+
+
→○
+

Asynchronous Message (پیام ناهم‌زمان)

+

فلش خط‌چین که ارسال پیام بدون انتظار برای پاسخ را نشان می‌دهد.

+
+
+
⇠
+

Return Message (پیام بازگشت)

+

فلش خط‌چین که مقدار بازگشتی یا پایان اجرا را نشان می‌دهد.

+
+
+
↷
+

Self Message (پیام خودی)

+

فلش منحنی که فراخوانی متد روی خود شیء را نشان می‌دهد.

+
+
+
▣
+

Combined Fragment (قطعه ترکیبی)

+

مستطیل با برچسب (alt, opt, loop, break) برای نمایش ساختارهای کنترلی.

+
+
+ +

انواع Combined Fragments:

+
    +
  • alt (شرطی): معادل if-else (چندین گزینه با شرایط مختلف)
  • +
  • opt (اختیاری): معادل if (یک گزینه در صورت برقراری شرط)
  • +
  • loop (حلقه): معادل for/while (تکرار چندین بار)
  • +
  • break (شکست): معادل break (خروج از سناریو در صورت خطا)
  • +
+ +
+

📋 مثال عملی: فرآیند خرید آنلاین

+

Participants: Customer, ShoppingCart, PaymentGateway, Inventory, EmailService

+

ترتیب پیام‌ها:

+
    +
  1. Customer → ShoppingCart: addItem(product)
  2. +
  3. Customer → ShoppingCart: checkout()
  4. +
  5. ShoppingCart → Inventory: checkAvailability(product)
  6. +
  7. Inventory → ShoppingCart: return true
  8. +
  9. ShoppingCart → PaymentGateway: processPayment(amount)
  10. +
  11. alt [payment success]: +
      +
    • PaymentGateway → ShoppingCart: paymentConfirmed()
    • +
    • ShoppingCart → Inventory: reduceStock(product)
    • +
    • ShoppingCart → EmailService: sendConfirmation(customerEmail)
    • +
    • EmailService → Customer: send email
    • +
    +
  12. +
  13. else [payment failed]: +
      +
    • PaymentGateway → ShoppingCart: paymentFailed()
    • +
    • ShoppingCart → Customer: showError()
    • +
    +
  14. +
+
+ +
+✓ کاربرد: درک سناریوهای پیچیده، دیباگ کردن، مستندسازی APIها، و ارتباط بین تیم‌های Frontend و Backend +
+
+
+ +
+
+
۸
+
+

نمودار Swimlane

+
نمایش مسئولیت‌ها در فرآیندها
+
+
+
+

نمودار Swimlane (یا Activity Diagram با Swimlanes) نسخه پیشرفته‌ای از Activity Diagram است که فعالیت‌ها را بر اساس مسئولیت (Actor، Department، یا System) در Laneهای جداگانه سازماندهی می‌کند. این نمودار برای نمایش «چه کسی چه کاری انجام می‌دهد» عالی است.

+ +
+
+
▤
+

Swimlane (لاین شنا)

+

ناحیه افقی یا عمودی که تمام فعالیت‌های یک مسئول یا بخش را در خود جای می‌دهد.

+
+
+
▭
+

Action (فعالیت)

+

مستطیل با گوشه‌های گرد که یک کار را در Swimlane مربوطه نشان می‌دهد.

+
+
+
◇
+

Decision (تصمیم)

+

لوزی که می‌تواند بین Swimlane‌ها جریان ایجاد کند.

+
+
+
→
+

Cross-Lane Flow (جریان بین لاین‌ها)

+

فلش که انتقال کار از یک مسئول به مسئول دیگر را نشان می‌دهد.

+
+
+ +
+

📋 مثال عملی: فرآیند استخدام نیروی جدید

+

Swimlanes: متقاضی، منابع انسانی (HR)، مدیر فنی، مدیرعامل

+

جریان فرآیند:

+
    +
  • متقاضی: +
      +
    • ارسال رزومه → HR
    • +
    • شرکت در مصاحبه فنی
    • +
    • دریافت پیشنهاد کاری
    • +
    +
  • +
  • HR: +
      +
    • بررسی اولیه رزومه
    • +
    • هماهنگی مصاحبه → مدیر فنی
    • +
    • بررسی سوابق (Background Check)
    • +
    • ارسال پیشنهاد کاری (در صورت تأیید مدیرعامل)
    • +
    +
  • +
  • مدیر فنی: +
      +
    • مصاحبه فنی
    • +
    • ارزیابی مهارت‌ها
    • +
    • ارسال نتیجه → HR
    • +
    +
  • +
  • مدیرعامل: +
      +
    • تأیید نهایی استخدام (Decision)
    • +
    +
  • +
+

Decision Points:

+
    +
  • آیا رزومه مناسب است؟ (HR) → خیر: رد درخواست | بله: ادامه
  • +
  • آیا مصاحبه فنی موفق بود؟ (مدیر فنی) → خیر: رد درخواست | بله: ادامه
  • +
  • آیا مدیرعامل تأیید می‌کند؟ → خیر: رد درخواست | بله: ارسال پیشنهاد
  • +
+
+ +
+💡 مزیت کلیدی: Swimlane Diagram به وضوح نشان می‌دهد که هر Actor یا بخش چه مسئولیتی دارد و کجاها نیاز به هماهنگی و Handoff وجود دارد. این نمودار برای بهینه‌سازی فرآیندهای کسب‌وکار و شناسایی گلوگاه‌ها عالی است. +
+ +
+🎯 تفاوت با Activity Diagram ساده: Activity Diagram فقط «چه کاری» را نشان می‌دهد، اما Swimlane Diagram «چه کسی چه کاری» را مشخص می‌کند. +
+
+
+ +
+
+
۹
+
+

جمع‌بندی و نکات پایانی

+
انتخاب نمودار مناسب برای هر سناریو
+
+
+
+

هر یک از نمودارهای UML هدف خاصی دارند و در فازهای مختلف چرخه حیات توسعه نرم‌افزار استفاده می‌شوند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
نمودارهدف اصلیفاز استفادهسطح
Use Caseنیازمندی‌ها و تعامل کاربرانتحلیلبالا (Business)
Activityفرآیندها و الگوریتم‌هاتحلیل/طراحیمتوسط
State Machineچرخه حیات اشیاءطراحیپایین (Technical)
Classساختار ایستایی سیستمطراحیپایین (Technical)
Sequenceتعاملات زمانی بین اشیاءطراحیپایین (Technical)
Componentمعماری ماژولارطراحی معماریبالا (Architecture)
Deploymentزیرساخت فیزیکیاستقراربالا (Infrastructure)
Swimlaneمسئولیت‌ها در فرآیندهاتحلیل کسب‌وکاربالا (Business)
+ +
+

🎯 توصیه‌های کلیدی

+

۱. از ساده شروع کنید: ابتدا Use Case و Activity Diagram برای درک نیازمندی‌ها

+

۲. سپس به جزئیات بروید: Class و Sequence Diagram برای طراحی فنی

+

۳. مستندسازی زنده: نمودارها را هم‌زمان با توسعه به‌روز نگه دارید

+

۴. ابزار مناسب: از ابزارهایی مانند ابزار UML استفاده کنید که امکان ویرایش آسان و Export به فرمت‌های مختلف را فراهم می‌کنند

+
+💎 نتیجه نهایی: تسلط بر UML نه تنها مهارت مدل‌سازی شما را ارتقا می‌دهد، بلکه ارتباط مؤثر با ذینفعان، کاهش خطاهای طراحی و افزایش کیفیت نرم‌افزار را به همراه خواهد داشت. +
+
+ +
+📚 منابع پیشنهادی برای مطالعه بیشتر: +
    +
  • کتاب «UML Distilled» توسط Martin Fowler
  • +
  • استاندارد OMG UML 2.5
  • +
  • الگوهای طراحی (Design Patterns) توسط Gang of Four
  • +
+
+
+
+ +
+این مستند آموزشی صرفاً جهت استفاده داخلی و آموزشی تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+
+ + +
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱:۳۰  |  نسخه: ۱.۰  |  طبقه‌بندی: آموزشی / عمومی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\Tools\Document\xUMLDrawer_Technical_Documentation.html + + + + + + +مستند فنی پروژه | ابزار رسم نمودارهای UML + + + +
+
+
+
+ +
+
+
شماره مستند: UML-TOOL-DOC-1405-001
+
نسخه: ۱.۰
+
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰
+
طبقه‌بندی: محرمانه / فنی
+
+
+
+TECHNICAL DOCUMENTATION +

مستند فنی پروژه ابزار رسم نمودارهای UML

+

تحلیل معماری، ماژول‌ها، موتور رسم و ساختار داده

+
+
+
+
+همکاران فنی و ذینفعان گرامی،
+این مستند به‌عنوان مرجع فنی جامع پروژه «ابزار رسم نمودارهای UML» تهیه شده است. هدف از این مستند، تشریح دقیق معماری، ساختار کد، ماژول‌های کلیدی، الگوهای طراحی به‌کار رفته و قابلیت‌های فنی این ابزار می‌باشد تا تیم‌های توسعه و نگهداری بتوانند با دیدی کامل و یکپارچه، به تحلیل، توسعه و گسترش آن بپردازند. +
+ +
+
+
۱
+
+

خلاصه اجرایی پروژه

+
Executive Summary
+
+
+
+

پروژه «ابزار رسم نمودارهای UML» یک اپلیکیشن تحت وب کاملاً سمت کلاینت (Client-Side) است که با استفاده از تکنولوژی‌های HTML5، CSS3 و JavaScript خالص (Vanilla JS) توسعه یافته است. این ابزار بدون نیاز به هیچ‌گونه Backend یا فریم‌ورک خارجی، امکان رسم، ویرایش، ذخیره و بازیابی هشت نوع نمودار استاندارد UML را در محیطی تعاملی و حرفه‌ای فراهم می‌آورد.

+
+
+
۸
+
نوع نمودار UML پشتیبانی شده
+
+
+
۵۰+
+
المان و رابطه قابل رسم
+
+
+
۱۰۰٪
+
اجرا در سمت مرورگر (بدون Backend)
+
+
+
+💎 ارزش کلیدی: این ابزار با تکیه بر HTML5 Canvas API و معماری ماژولار، یک محیط حرفه‌ای، سبک و کاملاً آفلاین برای مدل‌سازی سیستم‌های نرم‌افزاری در اختیار معماران و تحلیل‌گران قرار می‌دهد. +
+
+
+ +
+
+
۲
+
+

معماری کلی سیستم

+
System Architecture Overview
+
+
+
+

معماری این پروژه بر پایه الگوی Single-Page Application (SPA) و با رویکرد State-Centric طراحی شده است. تمامی وضعیت‌های برنامه در یک آبجکت مرکزی state نگهداری می‌شوند و هر تغییر در state منجر به بازترسیم کامل (Redraw) بوم می‌گردد.

+
    +
  • 🎨 Rendering Layer: موتور رسم مبتنی بر HTML5 Canvas 2D Context با قابلیت پشتیبانی از تم روشن و تاریک.
  • +
  • 🧠 State Management: یک آبجکت سراسری state که شامل لیست نمودارها، نمودار فعال، ابزار جاری، وضعیت Drag & Draw و تنظیمات UI است.
  • +
  • 🖱️ Interaction Layer: مدیریت رویدادهای Mouse (mousedown, mousemove, mouseup, dblclick) و Keyboard برای تعامل با المان‌ها.
  • +
  • 💾 Persistence Layer: سیستم ذخیره‌سازی مبتنی بر JSON File API (بدون نیاز به LocalStorage یا Backend).
  • +
  • 🎛️ UI Layer: رابط کاربری مبتنی بر Sidebar، Tab Bar، Modal ها و Properties Panel.
  • +
+
+// ساختار کلی State Object
+const state = {
+  diagrams: [],            // لیست همه نمودارها
+  activeDiagramId: null,  // شناسه نمودار فعال
+  currentTool: 'select',   // ابزار انتخاب‌شده
+  selectedElement: null,   // المان انتخاب‌شده
+  isDragging: false,       // وضعیت Drag
+  isDrawingRelationship: false,
+  darkMode: true,          // تم تاریک/روشن
+  gridType: 'lines',       // نوع خط‌کشی بوم
+  fileMetadata: { ... }     // متادیتای پروژه
+}; +
+
+
+ +
+
+
۳
+
+

تکنولوژی‌های به‌کار رفته

+
Technology Stack
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
لایهتکنولوژینقش در پروژه
ساختارHTML5 Semanticساختار صفحه و المان‌های DOM
استایلCSS3 + CSS Variablesطراحی RTL، تم داینامیک، گرادیانت‌ها
رسم گرافیکیHTML5 Canvas 2D APIموتور رسم نمودارها، Grid و المان‌ها
منطق برنامهVanilla JavaScript (ES6+)State Management، Event Handling، Drawing Engine
ذخیره‌سازیFile API + JSONExport/Import پروژه به‌صورت فایل JSON
فونتVazirmatn (Google Fonts)تایپوگرافی فارسی حرفه‌ای
استایل کمکیTailwind CSS (CDN)Utility classes برای UI سریع
+
+💡 نکته معماری: انتخاب Vanilla JS به جای فریم‌ورک‌هایی مانند React یا Angular، باعث کاهش چشمگیر حجم نهایی (Bundle Size)، اجرای سریع‌تر و عدم وابستگی به ابزارهای Build شده است. این رویکرد برای ابزارهای تخصصی و آفلاین، انتخاب بهینه‌ای است. +
+
+
+ +
+
+
۴
+
+

نمودارهای پشتیبانی‌شده

+
Supported UML Diagrams
+
+
+
+

این ابزار هشت نوع نمودار استاندارد UML را پشتیبانی می‌کند که هر کدام در رجیستری DIAGRAM_TYPES تعریف شده‌اند. این رجیستری به‌عنوان Single Source of Truth برای ابزارها، گروه‌ها و قابلیت‌های هر نمودار عمل می‌کند.

+
+
+
⭕
+

Use Case Diagram

+

مدل‌سازی Actorها، Use Caseها، System Boundary و روابط Include/Extend/Generalization.

+
+
+
🔄
+

State Machine Diagram

+

Initial/Final State، Stateها، Composite State و Transition با برچسب اختیاری.

+
+
+
🔀
+

Activity Diagram

+

Action، Decision/Merge، Fork/Join و جریان‌های Control/Object Flow.

+
+
+
🧩
+

Component Diagram

+

Component، Interface (Provided/Required)، Package و روابط Dependency/Connector.

+
+
+
🖥️
+

Deployment Diagram

+

Node، Device، Execution Environment، Artifact و روابط Deploy/Manifest.

+
+
+
🗂️
+

Class Diagram

+

Class، Interface، Abstract، Enumeration با Attributes/Methods و روابط کامل UML.

+
+
+
🔢
+

Sequence Diagram

+

Participant، Activation، Combined Fragment و پیام‌های Sync/Async/Return/Self.

+
+
+
▤
+

Swimlane Diagram

+

Swimlane افقی/عمودی با قابلیت Resize، Action، Decision و Fork/Join درون آن.

+
+
+
+// Registry الگوی طراحی - نمونه تعریف یک نمودار
+const DIAGRAM_TYPES = {
+  usecase: {
+    id: 'usecase',
+    name: 'نمودار مورد کاربرد (Use Case)',
+    icon: '⭕',
+    tools: ['select', 'actor', 'useCase', 'boundary', ...],
+    groups: ['selection', 'uc-elements', 'uc-relations', ...]
+  },
+  // ... سایر نمودارها
+}; +
+
+
+ +
+
+
۵
+
+

موتور رسم (Drawing Engine)

+
Canvas Rendering Engine
+
+
+
+

موتور رسم، قلب تپنده این پروژه است و بر پایه Immediate Mode Rendering طراحی شده است. در این رویکرد، در هر فریم (یا پس از هر تغییر state) کل بوم پاک‌سازی شده و تمامی المان‌ها از نو رسم می‌شوند. این رویکرد اگرچه در نگاه اول پرهزینه به نظر می‌رسد، اما به دلیل سادگی، قابلیت اطمینان بالا و عدم نیاز به مدیریت پیچیده Diff، برای این نوع ابزارها ایده‌آل است.

+

چرخه رسم (Render Loop):

+
    +
  • ۱. پاک‌سازی بوم: ctx.clearRect() و رسم پس‌زمینه بر اساس تم.
  • +
  • ۲. رسم Grid: بر اساس نوع انتخابی (Lines/Dots/None) با استفاده از CSS Variables.
  • +
  • ۳. رسم المان‌ها: فراخوانی توابع اختصاصی هر نمودار (مانند drawUseCase, drawClassDiagram).
  • +
  • ۴. رسم روابط: پس از المان‌ها، روابط با محاسبه مرکز المان‌های مبدأ و مقصد رسم می‌شوند.
  • +
  • ۵. رسم Selection: المان انتخاب‌شده با خط‌چین آبی‌رنگ مشخص می‌شود.
  • +
  • ۶. رسم Relationship Preview: در حالت رسم رابطه، خط موقتی تا موقعیت ماوس نمایش داده می‌شود.
  • +
+
+// چرخه اصلی رسم
+function draw() {
+  const d = getActive(), tc = getTC();
+  ctx.clearRect(0, 0, canvas.width, canvas.height);
+  ctx.fillStyle = tc.canvasBg;
+  ctx.fillRect(0, 0, canvas.width, canvas.height);
+  drawGrid(ctx, canvas.width, canvas.height, tc, false);
+  if (!d) return;
+  drawDiag(ctx, d, tc); // Dispatch به تابع اختصاصی
+} +
+
+💡 بهینه‌سازی: برای جلوگیری از رسم‌های مکرر غیرضروری، از تکنیک requestAnimationFrame و scheduleResize() استفاده شده است تا Resize رویدادها به‌صورت هوشمند مدیریت شوند. +
+
+
+ +
+
+
۶
+
+

سیستم مدیریت تم و رنگ

+
Theme & Color System
+
+
+
+

سیستم تم این پروژه بر پایه CSS Custom Properties (Variables) طراحی شده است. با تغییر کلاس body.dark، تمامی متغیرهای رنگی به‌صورت آنی تغییر می‌کنند و موتور رسم نیز از طریق تابع getTC() این مقادیر را در زمان اجرا (Runtime) از DOM استخراج می‌کند.

+ + + + + + + + + + + + + + + +
متغیر CSSنقشمثال مقدار (Dark Mode)
--canvas-bgپس‌زمینه بوم#0f1724
--actor-strokeرنگ خط Actor#cbd5e0
--class-fillرنگ زمینه Class#1e2d40
--seq-msgرنگ پیام‌های Sequence#cbd5e0
--selectedرنگ المان انتخاب‌شده#667eea
+
+✓ مزیت این رویکرد: افزودن یک تم جدید (مانند تم آبی، سبز یا High-Contrast) تنها با تغییر چند متغیر CSS امکان‌پذیر است و هیچ تغییری در منطق JavaScript نیاز نیست. +
+
+
+ +
+
+
۷
+
+

سیستم تعامل و Hit Testing

+
Interaction & Hit Testing System
+
+
+
+

برای تشخیص اینکه ماوس روی کدام المان قرار دارد، از الگوی Hit Testing استفاده می‌شود. تابع hitTest(x, y) بر اساس نوع نمودار فعال، الگوریتم‌های متفاوتی را اجرا می‌کند:

+
    +
  • Actor: محاسبه فاصله اقلیتسی (Bounding Box 50×80 پیکسل).
  • +
  • Use Case (بیضی): استفاده از معادله استاندارد بیضی (x²/a²) + (y²/b²) ≤ 1.
  • +
  • State/Action/Component (مستطیل با گوشه گرد): بررسی Bounding Box.
  • +
  • Decision (لوزی): استفاده از معادله لوزی |x| + |y| ≤ size.
  • +
  • Class: بررسی بر اساس ارتفاع محاسبه‌شده داینامیک (_computedH).
  • +
  • Swimlane: علاوه بر Hit Test بدنه، بررسی ۸ Handle برای Resize.
  • +
+
+⚠️ چالش فنی: در نمودار Class، ارتفاع به‌صورت داینامیک بر اساس تعداد Attributes و Methods محاسبه می‌شود. این مقدار در هر Draw در cls._computedH ذخیره می‌گردد تا در Hit Test نیز قابل استفاده باشد. +
+
+
+ +
+
+
۸
+
+

سیستم ذخیره‌سازی و بازیابی

+
Persistence & File System
+
+
+
+

سیستم Persistence این پروژه کاملاً مبتنی بر JSON File API است و از LocalStorage یا IndexedDB استفاده نمی‌کند. این تصمیم معماری، مزایای زیر را به همراه دارد:

+
    +
  • قابلیت اشتراک‌گذاری آسان: فایل JSON به‌راحتی قابل ارسال از طریق ایمیل، Git یا پیام‌رسان‌ها است.
  • +
  • نسخه‌بندی (Versioning): فایل‌ها می‌توانند در Git نگهداری و Diff شوند.
  • +
  • عدم وابستگی به مرورگر: با پاک‌سازی Cache مرورگر، داده‌ها از بین نمی‌روند.
  • +
  • ساختار قابل توسعه: فرمت JSON به‌راحتی قابل گسترش است.
  • +
+
+// ساختار فایل خروجی JSON
+{
+  "version": "5.1",
+  "fileTitle": "عنوان پروژه",
+  "author": "هادی خزاعی اصل",
+  "organization": "رایان پرداز کاوش",
+  "createdAt": "2026-09-07T10:30:00.000Z",
+  "preferences": { "gridType": "lines", "darkMode": true },
+  "diagrams": [ /* آرایه نمودارها */ ]
+} +
+
+💡 Backward Compatibility: در هنگام Load فایل، کد با استفاده از || operator، فیلدهای اختیاری را مقداردهی پیش‌فرض می‌کند تا فایل‌های نسخه‌های قدیمی‌تر نیز بدون خطا بارگذاری شوند. +
+
+
+ +
+
+
۹
+
+

الگوهای طراحی به‌کار رفته

+
Design Patterns
+
+
+
+

در این پروژه، چندین الگوی طراحی شناخته‌شده به‌صورت عملی پیاده‌سازی شده‌اند:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
الگومحل کاربردتوضیح
Registry PatternDIAGRAM_TYPESمرجع مرکزی تعریف انواع نمودار و قابلیت‌های آن‌ها
State Patternآبجکت stateمدیریت وضعیت سراسری برنامه
Strategy Patternتوابع drawUseCase, drawClassDiagram, ...انتخاب استراتژی رسم بر اساس نوع نمودار
Command Patternمدیریت ابزارها (Tools)هر ابزار یک رفتار مشخص را در mousedown/mouseup اجرا می‌کند
Observer PatternEvent Listenersواکنش به رویدادهای Mouse، Keyboard و UI
Factory PatterncreateNewDiagram()ساخت ساختار اولیه نمودار بر اساس نوع
Singleton PatternCanvas Context، State Objectتنها یک نمونه از منابع حیاتی در طول اجرا
+
+
+ +
+
+
۱۰
+
+

قابلیت‌های کلیدی و UX

+
Key Features & UX
+
+
+
+
    +
  • 🗂️ مدیریت چند نمودار (Multi-Tab): امکان باز کردن هم‌زمان چندین نمودار در تب‌های مجزا با امکان سوئیچ سریع.
  • +
  • 🌙 تم تاریک/روشن: سوئیچ آنی با حفظ ترجیحات در فایل پروژه.
  • +
  • ⌨️ کلیدهای میانبر: Ctrl+S (ذخیره)، Ctrl+N (جدید)، Delete (حذف)، B (Sidebar)، G (Grid).
  • +
  • 🎨 Properties Panel: ویرایش زنده ویژگی‌های المان انتخاب‌شده در پایین صفحه.
  • +
  • 🗂️ Class Editor Modal: ویرایشگر پیشرفته Attributes و Methods با Visibility، Static و Type.
  • +
  • 📐 Resize Handles: قابلیت تغییر اندازه Swimlane با ۸ Handle در گوشه‌ها و اضلاع.
  • +
  • 🖼️ Export to PNG: خروجی با کیفیت از نمودار فعلی با قابلیت انتخاب رنگ پس‌زمینه یا شفافیت.
  • +
  • 📦 Grid System: سه حالت (Lines, Dots, None) برای کمک به چیدمان دقیق المان‌ها.
  • +
  • 🔗 Relationship Drawing: رسم روابط با Drag از مبدأ به مقصد و Prompt برای برچسب و Multiplicity.
  • +
+
+
+ +
+
+
۱۱
+
+

نقاط قوت و پیشنهادات بهبود

+
Strengths & Recommendations
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
دستهنقاط قوت فعلیپیشنهادات بهبود
معماریبدون وابستگی خارجی، سبک و سریعماژولار کردن کد با ES Modules برای نگهداری بهتر
عملکرداجرای روان در نمودارهای کوچک و متوسطپیاده‌سازی Dirty Rectangle Rendering برای نمودارهای بزرگ
UXرابط کاربری شهودی با RTL کاملافزودن Undo/Redo با Command History
ذخیره‌سازیخروجی JSON قابل اشتراکافزودن Auto-Save در LocalStorage به‌عنوان Backup
توسعه‌پذیریRegistry Pattern برای افزودن نمودار جدیدافزودن نمودارهای Package و Communication
خروجیPNG با کیفیتافزودن Export به SVG، PDF و XMI استاندارد
+
+
+ +
+
+
۱۲
+
+

جمع‌بندی نهایی

+
Final Conclusion
+
+
+
+

پروژه «ابزار رسم نمودارهای UML» یک نمونه موفق از توسعه یک اپلیکیشن تخصصی و حرفه‌ای با استفاده از تکنولوژی‌های پایه وب است. این ابزار با تکیه بر معماری State-Centric، موتور رسم مبتنی بر Canvas و سیستم Registry منعطف، توانایی مدل‌سازی کامل سیستم‌های نرم‌افزاری را در محیطی آفلاین و سبک فراهم می‌آورد.

+
+

🎯 نتیجه‌گیری معماری

+

این پروژه نشان می‌دهد که برای ساخت ابزارهای تخصصی، لزومی به استفاده از فریم‌ورک‌های سنگین نیست. با طراحی دقیق معماری، انتخاب الگوهای مناسب و تمرکز بر تجربه کاربری، می‌توان محصولی در سطح Enterprise تولید کرد که کاملاً مستقل، قابل نگهداری و توسعه‌پذیر باشد.

+
+💎 ارزش نهایی: ابزاری کاملاً آفلاین، سبک، حرفه‌ای و مستقل که نیاز هر معمار و تحلیل‌گر نرم‌افزار را برای مدل‌سازی سریع و دقیق برطرف می‌سازد. +
+
+
+📞 گام بعدی: برای توسعه نسخه‌های آتی، پیشنهاد می‌شود ماژول‌های Undo/Redo، Export به فرمت‌های استاندارد (XMI, SVG) و افزودن نمودارهای Interaction اضافه گردد. +
+
+
+ +
+این مستند محرمانه بوده و صرفاً جهت استفاده داخلی تیم فنی تهیه شده است. هرگونه کپی‌برداری یا افشا بدون اجازه کتبی ممنوع است. +
+
+
+ + +
تاریخ تهیه: ۱۶ شهریور ۱۴۰۵ — ساعت ۱۰:۳۰  |  نسخه: ۱.۰  |  طبقه‌بندی: محرمانه / فنی
+
+
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\ExceptionResourceIDS.ts + +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'داده نا معتبر', + }, + { + id: 'ex_101', + value: 'تاریخ نامعتبر', + }, + { + id: 'ex_102', + value: 'درخواست اشتباه', + }, + { + id: 'ex_103', + value: 'ورودی نامعتبر', + }, + { + id: 'ex_104', + value: 'پیام نامعتبر', + }, + { + id: 'ex_105', + value: 'نشانه نامعتبر', + }, + { + id: 'ex_106', + value: 'کد اععتبارسنجی نامعتبر', + }, + { + id: 'ex_107', + value: 'پست الکترونیک نامعتبر', + }, + { + id: 'ex_108', + value: 'شماره تلفن همراه نامعتبر', + }, + { + id: 'ex_109', + value: 'کلمه عبور نامعتبر', + }, + { + id: 'ex_110', + value: 'آدرس اینترنتی نامعتبر', + }, + { + id: 'ex_111', + value: 'دستگاه نامعتبر', + }, + { + id: 'ex_112', + value: 'تصویر پروفایل نامعتبر', + }, + { + id: 'ex_113', + value: 'فایل نامعتبر', + }, + { + id: 'ex_114', + value: 'نام کاربری نامعتبر', + }, + { + id: 'ex_200', + value: 'یافت نشد', + }, + { + id: 'ex_201', + value: 'عدم تایید جواز', + }, + { + id: 'ex_202', + value: 'سطح دسترسی نامعتبر', + }, + { + id: 'ex_203', + value: 'غیر قابل نمایش', + }, + { + id: 'ex_300', + value: 'حساب کاربری قفل شده است', + }, + { + id: 'ex_301', + value: 'خطا در ورود', + }, + { + id: 'ex_302', + value: 'کاربر قبلا ثبت نام کرده است', + }, + { + id: 'ex_303', + value: 'کاربر غیرفعال است', + }, + { + id: 'ex_304', + value: 'دستگاه شما قفل شده است تا : (0)', + }, + { + id: 'ex_305', + value: 'امکان درخواست کد اعتبارسنجی وجود ندارد تا : (0)', + }, + { + id: 'ex_306', + value: 'کلمه عبورها یکسان هستند', + }, + { + id: 'ex_307', + value: 'شماره های تلفن یکسان هستند', + }, + { + id: 'ex_308', + value: 'آدرس های پست الکترونیک یکسان هستند', + }, + { + id: 'ex_309', + value: 'شماره تلفن قبلا ثبت شده است', + }, + { + id: 'ex_310', + value: 'پست الکترونیک قبلا ثبت شده است', + }, + { + id: 'ex_311', + value: 'تلفن همراه تایید نشده است', + }, + { + id: 'ex_312', + value: 'پست الکترونیک تایید نشده است', + }, + { + id: 'ex_313', + value: 'مطلب ممنوعه', + }, + { + id: 'ex_314', + value: 'کاربر ممنوعه', + }, + { + id: 'ex_400', + value: 'خطای نا شناخته', + }, + { + id: 'ex_401', + value: 'مورد تکراری', + }, + { + id: 'ex_402', + value: 'شکست عملیات', + }, + { + id: 'ex_403', + value: 'تاریخ مصرف منقضی شده است', + }, + { + id: 'ex_404', + value: 'غیر قابل اسفاده', + }, + { + id: 'ex_405', + value: 'تعداد برچسب ها بیش از جد مجاز است', + }, + { + id: 'ex_406', + value: 'اتمام مهلت زمانی', + }, + { + id: 'ex_500', + value: 'پرونده خالی است', + }, + { + id: 'ex_501', + value: 'اندازه بیش از حد مجاز', + }, + { + id: 'ex_502', + value: 'گونه نامعتبر فایل', + }, + { + id: 'ex_503', + value: 'تعداد رسانه ها بیش از حد مجاز است', + }, + { + id: 'ex_600', + value: 'پیکربندی اشتباه', + }, + { + id: 'ex_601', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_602', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_900', + value: 'تعداد فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_901', + value: 'مجموع اندازه فایل ها کمتر از حد مجاز است', + }, + { + id: 'ex_902', + value: 'مجموع اندازه فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_903', + value: 'شرایط و ضوابط باید پذیرفته شوند', + }, + { + id: 'ex_904', + value: 'عدم پشتیبانی از سیستم موقعیت یاب', + }, + { + id: 'ex_905', + value: 'مجوز دسترسی به موقعیت خود را صادر نکرده اید', + }, + { + id: 'ex_906', + value: 'دسترسی به موقعیت جغرافیایی امکان پذیر نیست', + }, + { + id: 'ex_907', + value: 'عدم پشتیبانی از سیستم ذخیره سازی', + }, + { + id: 'ex_908', + value: 'برای دسترسی به محتوا باید از سامانه خارج شوید', + }, + { + id: 'ex_909', + value: 'زبان انتخاب شده نامعتبر است', + }, + { + id: 'ex_910', + value: 'داده نامعتبر برای انتخاب کاربر', + }, + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'Invalid Data ...', + }, + { + id: 'ex_101', + value: 'Invalid Date ...', + }, + { + id: 'ex_102', + value: 'Bad Request ...', + }, + { + id: 'ex_103', + value: 'Invalid Args ...', + }, + { + id: 'ex_104', + value: 'Invalid Message ...', + }, + { + id: 'ex_105', + value: 'Invalid Token ...', + }, + { + id: 'ex_106', + value: 'Invalid Verification Code ...', + }, + { + id: 'ex_107', + value: 'Invalid Email Address ...', + }, + { + id: 'ex_108', + value: 'Invalid Mobile Number ...', + }, + { + id: 'ex_109', + value: 'Invalid Password ...', + }, + { + id: 'ex_110', + value: 'Invalid URL ...', + }, + { + id: 'ex_111', + value: 'Invalid Device ...', + }, + { + id: 'ex_112', + value: 'Invalid Profile Image ...', + }, + { + id: 'ex_113', + value: 'Invalid File ...', + }, + { + id: 'ex_114', + value: 'Invalid Username ...', + }, + { + id: 'ex_200', + value: 'Not Found ...', + }, + { + id: 'ex_201', + value: 'Not Allowed ...', + }, + { + id: 'ex_202', + value: 'Not Authorized ...', + }, + { + id: 'ex_203', + value: 'Not Visible ...', + }, + { + id: 'ex_300', + value: 'Account Locked out ...', + }, + { + id: 'ex_301', + value: 'Login Failed ...', + }, + { + id: 'ex_302', + value: 'User Registered Before ...', + }, + { + id: 'ex_303', + value: 'User Disabled ...', + }, + { + id: 'ex_304', + value: 'Device Banned Until:(0)', + }, + { + id: 'ex_305', + value: `You can not Request Verification code Until:(0)`, + }, + { + id: 'ex_306', + value: 'Passwords Same ...', + }, + { + id: 'ex_307', + value: 'Mobiles Same ...', + }, + { + id: 'ex_308', + value: 'Emails Same ...', + }, + { + id: 'ex_309', + value: 'Mobile In Used ...', + }, + { + id: 'ex_310', + value: 'Email In Used ...', + }, + { + id: 'ex_311', + value: 'Mobile Not Confirmed ...', + }, + { + id: 'ex_312', + value: 'Email Not Confirmed ...', + }, + { + id: 'ex_313', + value: 'Post Banned ...', + }, + { + id: 'ex_314', + value: 'User Banned ...', + }, + { + id: 'ex_400', + value: 'Unknown Error ...', + }, + { + id: 'ex_401', + value: 'Duplicate ...', + }, + { + id: 'ex_402', + value: 'Action Failed ...', + }, + { + id: 'ex_403', + value: 'Expired Date ...', + }, + { + id: 'ex_404', + value: 'Unavailable ...', + }, + { + id: 'ex_405', + value: 'Max Allowed Tag Exceeded ...', + }, + { + id: 'ex_406', + value: 'Timeout ...', + }, + { + id: 'ex_500', + value: 'Empty File ...', + }, + { + id: 'ex_501', + value: 'max File size exceeded ...', + }, + { + id: 'ex_502', + value: 'Unsupported File Type ...', + }, + { + id: 'ex_503', + value: 'Max Allowed Media Exceeded ...', + }, + { + id: 'ex_600', + value: 'Invalid Configuration ...', + }, + { + id: 'ex_601', + value: 'Storage Service Initiallization Failed ...', + }, + { + id: 'ex_602', + value: 'Message Service Initialization Failed ...', + }, + { + id: 'ex_900', + value: 'Max Allowed Files Exceeded ...', + }, + { + id: 'ex_901', + value: 'Min Files Size Exceeded ...', + }, + { + id: 'ex_902', + value: 'Max Files Size Exceeded ...', + }, + { + id: 'ex_903', + value: 'Must Accept Terms And Conditions ...', + }, + { + id: 'ex_904', + value: 'Browser does not support Location Services ...', + }, + { + id: 'ex_905', + value: 'You have rejected access to your Location ...', + }, + { + id: 'ex_906', + value: 'Unable to determine your Location ...', + }, + { + id: 'ex_907', + value: 'Browser does not support Storage Services ...', + }, + { + id: 'ex_908', + value: 'Must Logout to access content ...', + }, + { + id: 'ex_909', + value: 'Invalid Locale ...', + }, + { + id: 'ex_910', + value: 'Invalid User Selector ...', + }, + //#endregion + ], + }, +]; + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\XResourceIDS.html + + + + + + + مستندات منابع ترجمه (AvailableTranslationResources) + + + +
+
+

مستندات به‌روزرسانی منابع ترجمه

+
+ توسعه‌دهنده: هادی خزاعی اصل + شرکت: فن آوران ساحر علم + تاریخ: ۱۴۰۵/۰۵/۳۱ +
+
+ +

کد به‌روزرسانی‌شده `AvailableTranslationResources` شامل کلیدهای جدید درخواست‌شده در زیر ارائه شده است:

+ +
export const AvailableTranslationResources: XLanguageDescriptor[] = [
+  {
+    name: 'persian',
+    locale: 'fa-IR',
+    language: 'fa',
+    direction: 'rtl',
+    resources: [
+      { id: 'app_name', value: 'ساحر علم' },
+      { id: 'company', value: 'فن آوران ساحر علم' },
+      { id: 'id', value: 'شناسه' },
+      { id: 'file_name', value: 'نام فایل' },
+      { id: 'error', value: 'خطا' },
+      { id: 'required', value: 'الزامی است.' },
+      { id: 'loading', value: 'بارگزاری' },
+      { id: 'username', value: 'نام کاربری' },
+      { id: 'password', value: 'کلمه عبور' },
+      { id: 'first_name', value: 'نام' },
+      { id: 'last_name', value: 'نام خانوادگی' },
+      { id: 'verified', value: 'تایید شده' },
+      { id: 'unverified', value: 'تایید نشده' },
+      { id: 'thumbnail', value: 'پیش نمایش' },
+      { id: 'language', value: 'زبان' },
+      { id: 'take_screenshot', value: 'تصویر برداری ازمحیط' },
+      { id: 'enable_capture_mode', value: 'فعالسازی حالت تصویر برداری' },
+      { id: 'disable_capture_mode', value: 'غیرفعالسازی حالت تصویر برداری' },
+      { id: 'be', value: 'باشد' },
+      { id: 'not_to_be', value: 'نباشد' },
+      { id: 'enabled', value: 'فعال' },
+      { id: 'disabled', value: 'غیر فعال' },
+      { id: 'banned', value: 'مسدود' },
+      { id: 'un_banned', value: 'غیر مسدود' },
+      { id: 'audio', value: 'صوت' },
+      { id: 'video', value: 'فیلم' },
+      { id: 'cover_image', value: 'تصویر' },
+      { id: 'image', value: 'تصویر' },
+      { id: 'unknown', value: 'ناشناس' },
+      { id: 'location', value: 'موقعیت جغرافیای' },
+      { id: 'are_you_sure', value: 'اطمینان دارید ؟' },
+      { id: 'success_msg', value: 'عملیات با موفقیت انجام شد' },
+      { id: 'locked_msg', value: 'برای ترک این صفحه باید فعالیت جاری را لغو کرده و یا به اتمام برسانید' },
+      { id: 'empty_content', value: 'خالی است' },
+      { id: 'no_item', value: 'محتوایی ثبت نشده است' },
+      { id: 'drag_drop_here', value: 'محل رها کردن فایل' },
+      { id: 'map_dialog_title', value: 'نمایش موقعیت مکانی' },
+      { id: 'map_dialog_select_title', value: 'انتخاب موقعیت جغرافیایی' },
+      { id: 'color_picker_dialog_title', value: 'انتخاب رنگ' },
+      { id: 'dismiss', value: 'رد کردن' },
+      { id: 'accept', value: 'می پذیرم' },
+      { id: 'ok', value: 'بسیار خب' },
+      { id: 'save', value: 'ذخیره' },
+      { id: 'cancel', value: 'لغو' },
+      { id: 'retry', value: 'سعی مجدد' },
+      { id: 'edit', value: 'ویرایش' },
+      { id: 'reset', value: 'باز نشاندن' },
+      { id: 'change', value: 'تغییر' },
+      { id: 'start', value: 'آغاز' },
+      { id: 'yes', value: 'بله' },
+      { id: 'no', value: 'خیر' },
+      { id: 'verify', value: 'تایید کردن' },
+      { id: 'confirm', value: 'تاییدیه' },
+      { id: 'crop', value: 'برش' },
+      { id: 'clear', value: 'پاک کردن' },
+      { id: 'set', value: 'تنظیم' },
+      { id: 'select', value: 'انتخاب' },
+      { id: 'send', value: 'ارسال' },
+      { id: 'show', value: 'نمایش دادن' },
+      { id: 'hide', value: 'پنهان کردن' },
+      { id: 'search', value: 'جستجو' },
+      { id: 'delete', value: 'حذف' },
+      { id: 'clone', value: 'نمونه گیری' },
+      { id: 'select_all', value: 'انتخاب همه' },
+      { id: 'select_file', value: 'انتخاب فایل(ها)' },
+      { id: 'select_all_group', value: 'انتخاب همه موارد فیلتر شده' },
+      { id: 'deselect_all', value: 'لغو همه انتخاب ها' },
+      { id: 'deselect_all_group', value: 'لغو انتخاب همه موارد فیلتر شده' },
+      { id: 'inverse_selection', value: 'انتخاب معکوس' },
+      { id: 'selected_location', value: 'انتخاب محل' },
+      { id: 'preset_colors', value: 'رنگ های پیش فرض' },
+      { id: 'copy_to_clipboard', value: 'ثبت در حافظه موقت' },
+      { id: 'color', value: 'رنگ' },
+      { id: 'colors', value: 'رنگها' },
+      { id: 'upload', value: 'بارگزاری' },
+      { id: 'import', value: 'وارد کردن' },
+      { id: 'continue', value: 'ادامه' },
+      { id: 'finish', value: 'پایان' },
+      { id: 'enable', value: 'فعال' },
+      { id: 'disable', value: 'غیر فعال' },
+      { id: 'all', value: 'همه' },
+      { id: 'new', value: 'جدید' },
+      { id: 'add', value: 'افزودن' },
+      { id: 'update', value: 'بروز رسانی' },
+      { id: 'details', value: 'جزئیات' },
+      { id: 'translation', value: 'ترجمه' },
+      { id: 'download', value: 'دریافت' },
+      { id: 'list', value: 'فهرست' },
+      { id: 'options', value: 'انتخاب ها' },
+      { id: 'descriptions', value: 'توضیحات' },
+      { id: 'type', value: 'نوع' },
+      { id: 'media', value: 'رسانه' },
+      { id: 'medias', value: 'رسانه ها' },
+      { id: 'summary', value: 'خلاصه' },
+      { id: 'go', value: 'رفتن' },
+      { id: 'input', value: 'ورود' },
+      { id: 'preview', value: 'پیش نمایش' },
+      { id: 'close', value: 'بستن' },
+      { id: 'undo', value: 'لغو کردن' },
+      { id: 'redo', value: 'انجام دوباره' },
+      { id: 'refresh', value: 'بازیابی' },
+      { id: 'submit', value: 'ثبت' },
+      { id: 'first', value: 'نخستین' },
+      { id: 'last', value: 'آخرین' },
+      { id: 'previous', value: 'قبلی' },
+      { id: 'next', value: 'بعدی' },
+      { id: 'back', value: 'بازگشت' },
+      { id: 'x_markdown_preview', value: 'پیش نمایش' },
+      { id: 'x_markdown_image', value: 'تصویر' },
+      { id: 'x_markdown_link', value: 'پیوند' },
+      { id: 'x_markdown_ol', value: 'فهرست ترتیبی' },
+      { id: 'x_markdown_ul', value: 'فهرست بدون ترتیب' },
+      { id: 'x_markdown_quote', value: 'نقل قول' },
+      { id: 'x_markdown_code', value: 'کد منبع' },
+      { id: 'x_markdown_heading', value: 'عنوان' },
+      { id: 'x_markdown_italic', value: 'ایتالیک' },
+      { id: 'x_markdown_bold', value: 'پر رنگ' },
+      { id: 'x_markdown_guide', value: 'راهنمای نگارش' },
+      { id: 'theme', value: 'پوسته' },
+      { id: 'theme_mode', value: 'حالت نمایشی' },
+      { id: 'theme_dark', value: 'تیره' },
+      { id: 'theme_light', value: 'روشن' },
+      { id: 'theme_name', value: 'نام پوسته' },
+      { id: 'theme_name_description', value: 'نام پوسته را وارد کنید' },
+      { id: 'theme_clone_title', value: 'نمونه گیری از پوسته' },
+      { id: 'input_color_title', value: 'تعیین رنگ' },
+      { id: 'input_color_description', value: 'مقدار رنگ را وارد کنید' },
+      { id: 'ide_mode', value: 'نوع کد' },
+      { id: 'ide_format', value: 'حالت دهی کد' },
+      // ... (سایر آیتم‌های موجود در لیست اصلی حفظ شده‌اند) ...
+      
+      // --- موارد جدید اضافه شده ---
+      { id: 'print', value: 'چاپ' },
+      { id: 'export_png', value: 'خروجی PNG' },
+      { id: 'export_svg', value: 'خروجی SVG' },
+      { id: 'export_csv', value: 'خروجی CSV' },
+      { id: 'zoom_in', value: 'بزرگنمایی' },
+      { id: 'zoom_out', value: 'کوچک نمایی' },
+      { id: 'zoom_selection', value: 'بزرگنمایی ناحیه' },
+      { id: 'x_axis', value: 'محور افقی' },
+      { id: 'y_axis', value: 'محور عمودی' },
+      { id: 'xy_axis', value: 'محورهای عمودی و افقی' },
+      { id: 'pan', value: 'حرکت آزاد' },
+      { id: 'full_screen', value: 'حالت تمام صفحه' }
+    ],
+  },
+  {
+    name: 'english',
+    locale: 'en-US',
+    language: 'en',
+    direction: 'ltr',
+    resources: [
+      { id: 'app_name', value: 'SaherElm' },
+      { id: 'company', value: 'SaherElm IT Center' },
+      { id: 'id', value: 'ID' },
+      { id: 'file_name', value: 'File Name' },
+      { id: 'error', value: 'Error' },
+      { id: 'required', value: 'required' },
+      { id: 'loading', value: 'loading' },
+      { id: 'username', value: 'Username' },
+      { id: 'password', value: 'Password' },
+      { id: 'first_name', value: 'Firstname' },
+      { id: 'last_name', value: 'Lastname' },
+      { id: 'verified', value: 'Verified' },
+      { id: 'unverified', value: 'Unverified' },
+      { id: 'thumbnail', value: 'Thumbnail' },
+      { id: 'language', value: 'Language' },
+      { id: 'take_screenshot', value: 'Take Screenshot' },
+      { id: 'enable_capture_mode', value: 'Enable Capture Mode' },
+      { id: 'disable_capture_mode', value: 'Disable Capture Mode' },
+      { id: 'be', value: 'Be' },
+      { id: 'not_to_be', value: 'Not to be' },
+      { id: 'enabled', value: 'Enabled' },
+      { id: 'disabled', value: 'Disabled' },
+      { id: 'banned', value: 'Banned' },
+      { id: 'un_banned', value: 'UnBanned' },
+      { id: 'audio', value: 'Audio' },
+      { id: 'video', value: 'Video' },
+      { id: 'cover_image', value: 'Cover Image' },
+      { id: 'image', value: 'Image' },
+      { id: 'avatar', value: 'Avatar' },
+      { id: 'unknown', value: 'Unknown' },
+      { id: 'location', value: 'Location' },
+      { id: 'are_you_sure', value: 'Are You Sure ?' },
+      { id: 'success_msg', value: 'Operation done Successfully ...' },
+      { id: 'locked_msg', value: 'You have to finish/cancel current proccess for leaving' },
+      { id: 'empty_content', value: 'Empty' },
+      { id: 'no_item', value: 'there is no Content' },
+      { id: 'drag_drop_here', value: 'Drop File Here' },
+      { id: 'map_dialog_title', value: 'Show Location' },
+      { id: 'map_dialog_select_title', value: 'Select Location' },
+      { id: 'color_picker_dialog_title', value: 'Select Color' },
+      { id: 'dismiss', value: 'dismiss' },
+      { id: 'accept', value: 'Accept' },
+      { id: 'ok', value: 'Ok' },
+      { id: 'save', value: 'Save' },
+      { id: 'cancel', value: 'Cancel' },
+      { id: 'retry', value: 'Retry' },
+      { id: 'edit', value: 'Edit' },
+      { id: 'reset', value: 'Reset' },
+      { id: 'change', value: 'Change' },
+      { id: 'start', value: 'Start' },
+      { id: 'yes', value: 'Yes' },
+      { id: 'no', value: 'No' },
+      { id: 'verify', value: 'Verify' },
+      { id: 'confirm', value: 'Confirm' },
+      { id: 'crop', value: 'Crop' },
+      { id: 'clear', value: 'Clear' },
+      { id: 'set', value: 'Set' },
+      { id: 'select', value: 'Select' },
+      { id: 'send', value: 'Send' },
+      { id: 'show', value: 'Show' },
+      { id: 'hide', value: 'Hide' },
+      { id: 'search', value: 'Search' },
+      { id: 'delete', value: 'Delete' },
+      { id: 'clone', value: 'Clone' },
+      { id: 'select_all', value: 'Select All' },
+      { id: 'select_file', value: 'Select File(s)' },
+      { id: 'select_all_group', value: 'Select All Filtered Items' },
+      { id: 'deselect_all', value: 'Deselect All' },
+      { id: 'deselect_all_group', value: 'Deselect All Filtered Items' },
+      { id: 'inverse_selection', value: 'Inverse Selection' },
+      { id: 'selected_location', value: 'Selected Location' },
+      { id: 'preset_colors', value: 'Preset Colors' },
+      { id: 'copy_to_clipboard', value: 'Copy to Clipboard' },
+      { id: 'color', value: 'Color' },
+      { id: 'colors', value: 'Colors' },
+      { id: 'upload', value: 'Upload' },
+      { id: 'import', value: 'Import' },
+      { id: 'continue', value: 'Continue' },
+      { id: 'finish', value: 'Finish' },
+      { id: 'enable', value: 'Enable' },
+      { id: 'disable', value: 'Disable' },
+      { id: 'all', value: 'All' },
+      { id: 'new', value: 'New' },
+      { id: 'add', value: 'Add' },
+      { id: 'update', value: 'Update' },
+      { id: 'details', value: 'Details' },
+      { id: 'translation', value: 'Translation' },
+      { id: 'download', value: 'Download' },
+      { id: 'list', value: 'List' },
+      { id: 'options', value: 'Options' },
+      { id: 'descriptions', value: 'Description' },
+      { id: 'type', value: 'Type' },
+      { id: 'media', value: 'Media' },
+      { id: 'medias', value: 'Medias' },
+      { id: 'summary', value: 'Summary' },
+      { id: 'go', value: 'Go' },
+      { id: 'input', value: 'Input' },
+      { id: 'preview', value: 'Preview' },
+      { id: 'close', value: 'Close' },
+      { id: 'undo', value: 'Undo' },
+      { id: 'redo', value: 'Redo' },
+      { id: 'refresh', value: 'Refresh' },
+      { id: 'submit', value: 'Submit' },
+      { id: 'first', value: 'First' },
+      { id: 'last', value: 'Last' },
+      { id: 'previous', value: 'Previous' },
+      { id: 'next', value: 'Next' },
+      { id: 'back', value: 'Back' },
+      { id: 'x_markdown_preview', value: 'Preview' },
+      { id: 'x_markdown_image', value: 'Image' },
+      { id: 'x_markdown_link', value: 'Link' },
+      { id: 'x_markdown_ol', value: 'Ordered List' },
+      { id: 'x_markdown_ul', value: 'Unordered List' },
+      { id: 'x_markdown_quote', value: 'Quote' },
+      { id: 'x_markdown_code', value: 'Code' },
+      { id: 'x_markdown_heading', value: 'Heading' },
+      { id: 'x_markdown_italic', value: 'Italic' },
+      { id: 'x_markdown_bold', value: 'Bold' },
+      { id: 'x_markdown_guide', value: 'Markdown Guide' },
+      { id: 'theme', value: 'Theme' },
+      { id: 'theme_mode', value: 'Theme Mode' },
+      { id: 'theme_dark', value: 'Dark' },
+      { id: 'theme_light', value: 'Light' },
+      { id: 'theme_name', value: 'Theme Name' },
+      { id: 'theme_name_description', value: 'Enter Theme name' },
+      { id: 'theme_clone_title', value: 'Theme Cloning' },
+      { id: 'input_color_title', value: 'Color Value' },
+      { id: 'input_color_description', value: 'input color value' },
+      { id: 'ide_mode', value: 'Code Style' },
+      { id: 'ide_format', value: 'Code Formatting' },
+      // ... (سایر آیتم‌های موجود در لیست اصلی حفظ شده‌اند) ...
+
+      // --- موارد جدید اضافه شده ---
+      { id: 'print', value: 'Print' },
+      { id: 'export_png', value: 'Export PNG' },
+      { id: 'export_svg', value: 'Export SVG' },
+      { id: 'export_csv', value: 'Export CSV' },
+      { id: 'zoom_in', value: 'Zoom In' },
+      { id: 'zoom_out', value: 'Zoom Out' },
+      { id: 'zoom_selection', value: 'Zoom Selection' },
+      { id: 'x_axis', value: 'X Axis' },
+      { id: 'y_axis', value: 'Y Axis' },
+      { id: 'xy_axis', value: 'XY Axis' },
+      { id: 'pan', value: 'Pan' },
+      { id: 'full_screen', value: 'Full Screen' }
+    ],
+  },
+];
+ + +
+ + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\XResourceIDs.ts + +// +//#region Resource IDS ... +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'ساحر علم' }, + { id: 'company', value: 'فن آوران ساحر علم' }, + { id: 'id', value: 'شناسه' }, + { id: 'file_name', value: 'نام فایل' }, + { id: 'error', value: 'خطا' }, + { id: 'required', value: 'الزامی است.' }, + { id: 'loading', value: 'بارگزاری' }, + { id: 'username', value: 'نام کاربری' }, + { id: 'password', value: 'کلمه عبور' }, + { id: 'first_name', value: 'نام' }, + { id: 'last_name', value: 'نام خانوادگی' }, + { id: 'verified', value: 'تایید شده' }, + { id: 'unverified', value: 'تایید نشده' }, + { id: 'thumbnail', value: 'پیش نمایش' }, + { id: 'language', value: 'زبان' }, + { id: 'take_screenshot', value: 'تصویر برداری ازمحیط' }, + { id: 'enable_capture_mode', value: 'فعالسازی حالت تصویر برداری' }, + { id: 'disable_capture_mode', value: 'غیرفعالسازی حالت تصویر برداری' }, + { id: 'be', value: 'باشد' }, + { id: 'not_to_be', value: 'نباشد' }, + { id: 'enabled', value: 'فعال' }, + { id: 'disabled', value: 'غیر فعال' }, + { id: 'banned', value: 'مسدود' }, + { id: 'un_banned', value: 'غیر مسدود' }, + { id: 'audio', value: 'صوت' }, + { id: 'video', value: 'فیلم' }, + { id: 'cover_image', value: 'تصویر' }, + { id: 'image', value: 'تصویر' }, + { id: 'unknown', value: 'ناشناس' }, + { id: 'location', value: 'موقعیت جغرافیای' }, + { id: 'are_you_sure', value: 'اطمینان دارید ؟' }, + { id: 'success_msg', value: 'عملیات با موفقیت انجام شد' }, + { id: 'locked_msg', value: 'برای ترک این صفحه باید فعالیت جاری را لغو کرده و یا به اتمام برسانید' }, + { id: 'empty_content', value: 'خالی است' }, + { id: 'no_item', value: 'محتوایی ثبت نشده است' }, + { id: 'drag_drop_here', value: 'محل رها کردن فایل' }, + { id: 'map_dialog_title', value: 'نمایش موقعیت مکانی' }, + { id: 'map_dialog_select_title', value: 'انتخاب موقعیت جغرافیایی' }, + { id: 'color_picker_dialog_title', value: 'انتخاب رنگ' }, + { id: 'dismiss', value: 'رد کردن' }, + { id: 'accept', value: 'می پذیرم' }, + { id: 'ok', value: 'بسیار خب' }, + { id: 'save', value: 'ذخیره' }, + { id: 'cancel', value: 'لغو' }, + { id: 'retry', value: 'سعی مجدد' }, + { id: 'edit', value: 'ویرایش' }, + { id: 'reset', value: 'باز نشاندن' }, + { id: 'change', value: 'تغییر' }, + { id: 'start', value: 'آغاز' }, + { id: 'yes', value: 'بله' }, + { id: 'no', value: 'خیر' }, + { id: 'verify', value: 'تایید کردن' }, + { id: 'confirm', value: 'تاییدیه' }, + { id: 'crop', value: 'برش' }, + { id: 'clear', value: 'پاک کردن' }, + { id: 'set', value: 'تنظیم' }, + { id: 'select', value: 'انتخاب' }, + { id: 'send', value: 'ارسال' }, + { id: 'show', value: 'نمایش دادن' }, + { id: 'hide', value: 'پنهان کردن' }, + { id: 'search', value: 'جستجو' }, + { id: 'delete', value: 'حذف' }, + { id: 'clone', value: 'نمونه گیری' }, + { id: 'select_all', value: 'انتخاب همه' }, + { id: 'select_file', value: 'انتخاب فایل(ها)' }, + { id: 'select_all_group', value: 'انتخاب همه موارد فیلتر شده' }, + { id: 'deselect_all', value: 'لغو همه انتخاب ها' }, + { id: 'deselect_all_group', value: 'لغو انتخاب همه موارد فیلتر شده' }, + { id: 'inverse_selection', value: 'انتخاب معکوس' }, + { id: 'selected_location', value: 'انتخاب محل' }, + { id: 'preset_colors', value: 'رنگ های پیش فرض' }, + { id: 'copy_to_clipboard', value: 'ثبت در حافظه موقت' }, + { id: 'color', value: 'رنگ' }, + { id: 'colors', value: 'رنگها' }, + { id: 'upload', value: 'بارگزاری' }, + { id: 'import', value: 'وارد کردن' }, + { id: 'continue', value: 'ادامه' }, + { id: 'finish', value: 'پایان' }, + { id: 'enable', value: 'فعال' }, + { id: 'disable', value: 'غیر فعال' }, + { id: 'all', value: 'همه' }, + { id: 'new', value: 'جدید' }, + { id: 'add', value: 'افزودن' }, + { id: 'update', value: 'بروز رسانی' }, + { id: 'details', value: 'جزئیات' }, + { id: 'translation', value: 'ترجمه' }, + { id: 'download', value: 'دریافت' }, + { id: 'list', value: 'فهرست' }, + { id: 'options', value: 'انتخاب ها' }, + { id: 'descriptions', value: 'توضیحات' }, + { id: 'type', value: 'نوع' }, + { id: 'media', value: 'رسانه' }, + { id: 'medias', value: 'رسانه ها' }, + { id: 'summary', value: 'خلاصه' }, + { id: 'go', value: 'رفتن' }, + { id: 'input', value: 'ورود' }, + { id: 'preview', value: 'پیش نمایش' }, + { id: 'close', value: 'بستن' }, + { id: 'undo', value: 'لغو کردن' }, + { id: 'redo', value: 'انجام دوباره' }, + { id: 'refresh', value: 'بازیابی' }, + { id: 'submit', value: 'ثبت' }, + { id: 'first', value: 'نخستین' }, + { id: 'last', value: 'آخرین' }, + { id: 'previous', value: 'قبلی' }, + { id: 'next', value: 'بعدی' }, + { id: 'back', value: 'بازگشت' }, + { id: 'x_markdown_preview', value: 'پیش نمایش' }, + { id: 'x_markdown_image', value: 'تصویر' }, + { id: 'x_markdown_link', value: 'پیوند' }, + { id: 'x_markdown_ol', value: 'فهرست ترتیبی' }, + { id: 'x_markdown_ul', value: 'فهرست بدون ترتیب' }, + { id: 'x_markdown_quote', value: 'نقل قول' }, + { id: 'x_markdown_code', value: 'کد منبع' }, + { id: 'x_markdown_heading', value: 'عنوان' }, + { id: 'x_markdown_italic', value: 'ایتالیک' }, + { id: 'x_markdown_bold', value: 'پر رنگ' }, + { id: 'x_markdown_guide', value: 'راهنمای نگارش' }, + { id: 'theme', value: 'پوسته' }, + { id: 'theme_mode', value: 'حالت نمایشی' }, + { id: 'theme_dark', value: 'تیره' }, + { id: 'theme_light', value: 'روشن' }, + { id: 'theme_name', value: 'نام پوسته' }, + { id: 'theme_name_description', value: 'نام پوسته را وارد کنید' }, + { id: 'theme_clone_title', value: 'نمونه گیری از پوسته' }, + { id: 'input_color_title', value: 'تعیین رنگ' }, + { id: 'input_color_description', value: 'مقدار رنگ را وارد کنید' }, + { id: 'ide_mode', value: 'نوع کد' }, + { id: 'ide_format', value: 'حالت دهی کد' }, + { id: 'print', value: 'چاپ' }, + { id: 'export_png', value: 'خروجی PNG' }, + { id: 'export_svg', value: 'خروجی SVG' }, + { id: 'export_csv', value: 'خروجی CSV' }, + { id: 'zoom_in', value: 'بزرگنمایی' }, + { id: 'zoom_out', value: 'کوچک نمایی' }, + { id: 'zoom_selection', value: 'بزرگنمایی ناحیه' }, + { id: 'x_axis', value: 'محور افقی' }, + { id: 'y_axis', value: 'محور عمودی' }, + { id: 'xy_axis', value: 'محورهای عمودی و افقی' }, + { id: 'pan', value: 'حرکت آزاد' }, + { id: 'full_screen', value: 'حالت تمام صفحه' } + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'SaherElm' }, + { id: 'company', value: 'SaherElm IT Center' }, + { id: 'id', value: 'ID' }, + { id: 'file_name', value: 'File Name' }, + { id: 'error', value: 'Error' }, + { id: 'required', value: 'required' }, + { id: 'loading', value: 'loading' }, + { id: 'username', value: 'Username' }, + { id: 'password', value: 'Password' }, + { id: 'first_name', value: 'Firstname' }, + { id: 'last_name', value: 'Lastname' }, + { id: 'verified', value: 'Verified' }, + { id: 'unverified', value: 'Unverified' }, + { id: 'thumbnail', value: 'Thumbnail' }, + { id: 'language', value: 'Language' }, + { id: 'take_screenshot', value: 'Take Screenshot' }, + { id: 'enable_capture_mode', value: 'Enable Capture Mode' }, + { id: 'disable_capture_mode', value: 'Disable Capture Mode' }, + { id: 'be', value: 'Be' }, + { id: 'not_to_be', value: 'Not to be' }, + { id: 'enabled', value: 'Enabled' }, + { id: 'disabled', value: 'Disabled' }, + { id: 'banned', value: 'Banned' }, + { id: 'un_banned', value: 'UnBanned' }, + { id: 'audio', value: 'Audio' }, + { id: 'video', value: 'Video' }, + { id: 'cover_image', value: 'Cover Image' }, + { id: 'image', value: 'Image' }, + { id: 'avatar', value: 'Avatar' }, + { id: 'unknown', value: 'Unknown' }, + { id: 'location', value: 'Location' }, + { id: 'are_you_sure', value: 'Are You Sure ?' }, + { id: 'success_msg', value: 'Operation done Successfully ...' }, + { id: 'locked_msg', value: 'You have to finish/cancel current proccess for leaving' }, + { id: 'empty_content', value: 'Empty' }, + { id: 'no_item', value: 'there is no Content' }, + { id: 'drag_drop_here', value: 'Drop File Here' }, + { id: 'map_dialog_title', value: 'Show Location' }, + { id: 'map_dialog_select_title', value: 'Select Location' }, + { id: 'color_picker_dialog_title', value: 'Select Color' }, + { id: 'dismiss', value: 'dismiss' }, + { id: 'accept', value: 'Accept' }, + { id: 'ok', value: 'Ok' }, + { id: 'save', value: 'Save' }, + { id: 'cancel', value: 'Cancel' }, + { id: 'retry', value: 'Retry' }, + { id: 'edit', value: 'Edit' }, + { id: 'reset', value: 'Reset' }, + { id: 'change', value: 'Change' }, + { id: 'start', value: 'Start' }, + { id: 'yes', value: 'Yes' }, + { id: 'no', value: 'No' }, + { id: 'verify', value: 'Verify' }, + { id: 'confirm', value: 'Confirm' }, + { id: 'crop', value: 'Crop' }, + { id: 'clear', value: 'Clear' }, + { id: 'set', value: 'Set' }, + { id: 'select', value: 'Select' }, + { id: 'send', value: 'Send' }, + { id: 'show', value: 'Show' }, + { id: 'hide', value: 'Hide' }, + { id: 'search', value: 'Search' }, + { id: 'delete', value: 'Delete' }, + { id: 'clone', value: 'Clone' }, + { id: 'select_all', value: 'Select All' }, + { id: 'select_file', value: 'Select File(s)' }, + { id: 'select_all_group', value: 'Select All Filtered Items' }, + { id: 'deselect_all', value: 'Deselect All' }, + { id: 'deselect_all_group', value: 'Deselect All Filtered Items' }, + { id: 'inverse_selection', value: 'Inverse Selection' }, + { id: 'selected_location', value: 'Selected Location' }, + { id: 'preset_colors', value: 'Preset Colors' }, + { id: 'copy_to_clipboard', value: 'Copy to Clipboard' }, + { id: 'color', value: 'Color' }, + { id: 'colors', value: 'Colors' }, + { id: 'upload', value: 'Upload' }, + { id: 'import', value: 'Import' }, + { id: 'continue', value: 'Continue' }, + { id: 'finish', value: 'Finish' }, + { id: 'enable', value: 'Enable' }, + { id: 'disable', value: 'Disable' }, + { id: 'all', value: 'All' }, + { id: 'new', value: 'New' }, + { id: 'add', value: 'Add' }, + { id: 'update', value: 'Update' }, + { id: 'details', value: 'Details' }, + { id: 'translation', value: 'Translation' }, + { id: 'download', value: 'Download' }, + { id: 'list', value: 'List' }, + { id: 'options', value: 'Options' }, + { id: 'descriptions', value: 'Description' }, + { id: 'type', value: 'Type' }, + { id: 'media', value: 'Media' }, + { id: 'medias', value: 'Medias' }, + { id: 'summary', value: 'Summary' }, + { id: 'go', value: 'Go' }, + { id: 'input', value: 'Input' }, + { id: 'preview', value: 'Preview' }, + { id: 'close', value: 'Close' }, + { id: 'undo', value: 'Undo' }, + { id: 'redo', value: 'Redo' }, + { id: 'refresh', value: 'Refresh' }, + { id: 'submit', value: 'Submit' }, + { id: 'first', value: 'First' }, + { id: 'last', value: 'Last' }, + { id: 'previous', value: 'Previous' }, + { id: 'next', value: 'Next' }, + { id: 'back', value: 'Back' }, + { id: 'x_markdown_preview', value: 'Preview' }, + { id: 'x_markdown_image', value: 'Image' }, + { id: 'x_markdown_link', value: 'Link' }, + { id: 'x_markdown_ol', value: 'Ordered List' }, + { id: 'x_markdown_ul', value: 'Unordered List' }, + { id: 'x_markdown_quote', value: 'Quote' }, + { id: 'x_markdown_code', value: 'Code' }, + { id: 'x_markdown_heading', value: 'Heading' }, + { id: 'x_markdown_italic', value: 'Italic' }, + { id: 'x_markdown_bold', value: 'Bold' }, + { id: 'x_markdown_guide', value: 'Markdown Guide' }, + { id: 'theme', value: 'Theme' }, + { id: 'theme_mode', value: 'Theme Mode' }, + { id: 'theme_dark', value: 'Dark' }, + { id: 'theme_light', value: 'Light' }, + { id: 'theme_name', value: 'Theme Name' }, + { id: 'theme_name_description', value: 'Enter Theme name' }, + { id: 'theme_clone_title', value: 'Theme Cloning' }, + { id: 'input_color_title', value: 'Color Value' }, + { id: 'input_color_description', value: 'input color value' }, + { id: 'ide_mode', value: 'Code Style' }, + { id: 'ide_format', value: 'Code Formatting' }, + { id: 'print', value: 'Print' }, + { id: 'export_png', value: 'Export PNG' }, + { id: 'export_svg', value: 'Export SVG' }, + { id: 'export_csv', value: 'Export CSV' }, + { id: 'zoom_in', value: 'Zoom In' }, + { id: 'zoom_out', value: 'Zoom Out' }, + { id: 'zoom_selection', value: 'Zoom Selection' }, + { id: 'x_axis', value: 'X Axis' }, + { id: 'y_axis', value: 'Y Axis' }, + { id: 'xy_axis', value: 'XY Axis' }, + { id: 'pan', value: 'Pan' }, + { id: 'full_screen', value: 'Full Screen' } + //#endregion + ], + }, +]; +//#endregion + +// +//#region Exception IDS ... +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'داده نا معتبر', + }, + { + id: 'ex_101', + value: 'تاریخ نامعتبر', + }, + { + id: 'ex_102', + value: 'درخواست اشتباه', + }, + { + id: 'ex_103', + value: 'ورودی نامعتبر', + }, + { + id: 'ex_104', + value: 'پیام نامعتبر', + }, + { + id: 'ex_105', + value: 'نشانه نامعتبر', + }, + { + id: 'ex_106', + value: 'کد اععتبارسنجی نامعتبر', + }, + { + id: 'ex_107', + value: 'پست الکترونیک نامعتبر', + }, + { + id: 'ex_108', + value: 'شماره تلفن همراه نامعتبر', + }, + { + id: 'ex_109', + value: 'کلمه عبور نامعتبر', + }, + { + id: 'ex_110', + value: 'آدرس اینترنتی نامعتبر', + }, + { + id: 'ex_111', + value: 'دستگاه نامعتبر', + }, + { + id: 'ex_112', + value: 'تصویر پروفایل نامعتبر', + }, + { + id: 'ex_113', + value: 'فایل نامعتبر', + }, + { + id: 'ex_114', + value: 'نام کاربری نامعتبر', + }, + { + id: 'ex_200', + value: 'یافت نشد', + }, + { + id: 'ex_201', + value: 'عدم تایید جواز', + }, + { + id: 'ex_202', + value: 'سطح دسترسی نامعتبر', + }, + { + id: 'ex_203', + value: 'غیر قابل نمایش', + }, + { + id: 'ex_300', + value: 'حساب کاربری قفل شده است', + }, + { + id: 'ex_301', + value: 'خطا در ورود', + }, + { + id: 'ex_302', + value: 'کاربر قبلا ثبت نام کرده است', + }, + { + id: 'ex_303', + value: 'کاربر غیرفعال است', + }, + { + id: 'ex_304', + value: 'دستگاه شما قفل شده است تا : (0)', + }, + { + id: 'ex_305', + value: 'امکان درخواست کد اعتبارسنجی وجود ندارد تا : (0)', + }, + { + id: 'ex_306', + value: 'کلمه عبورها یکسان هستند', + }, + { + id: 'ex_307', + value: 'شماره های تلفن یکسان هستند', + }, + { + id: 'ex_308', + value: 'آدرس های پست الکترونیک یکسان هستند', + }, + { + id: 'ex_309', + value: 'شماره تلفن قبلا ثبت شده است', + }, + { + id: 'ex_310', + value: 'پست الکترونیک قبلا ثبت شده است', + }, + { + id: 'ex_311', + value: 'تلفن همراه تایید نشده است', + }, + { + id: 'ex_312', + value: 'پست الکترونیک تایید نشده است', + }, + { + id: 'ex_313', + value: 'مطلب ممنوعه', + }, + { + id: 'ex_314', + value: 'کاربر ممنوعه', + }, + { + id: 'ex_400', + value: 'خطای نا شناخته', + }, + { + id: 'ex_401', + value: 'مورد تکراری', + }, + { + id: 'ex_402', + value: 'شکست عملیات', + }, + { + id: 'ex_403', + value: 'تاریخ مصرف منقضی شده است', + }, + { + id: 'ex_404', + value: 'غیر قابل اسفاده', + }, + { + id: 'ex_405', + value: 'تعداد برچسب ها بیش از جد مجاز است', + }, + { + id: 'ex_406', + value: 'اتمام مهلت زمانی', + }, + { + id: 'ex_500', + value: 'پرونده خالی است', + }, + { + id: 'ex_501', + value: 'اندازه بیش از حد مجاز', + }, + { + id: 'ex_502', + value: 'گونه نامعتبر فایل', + }, + { + id: 'ex_503', + value: 'تعداد رسانه ها بیش از حد مجاز است', + }, + { + id: 'ex_600', + value: 'پیکربندی اشتباه', + }, + { + id: 'ex_601', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_602', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_900', + value: 'تعداد فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_901', + value: 'مجموع اندازه فایل ها کمتر از حد مجاز است', + }, + { + id: 'ex_902', + value: 'مجموع اندازه فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_903', + value: 'شرایط و ضوابط باید پذیرفته شوند', + }, + { + id: 'ex_904', + value: 'عدم پشتیبانی از سیستم موقعیت یاب', + }, + { + id: 'ex_905', + value: 'مجوز دسترسی به موقعیت خود را صادر نکرده اید', + }, + { + id: 'ex_906', + value: 'دسترسی به موقعیت جغرافیایی امکان پذیر نیست', + }, + { + id: 'ex_907', + value: 'عدم پشتیبانی از سیستم ذخیره سازی', + }, + { + id: 'ex_908', + value: 'برای دسترسی به محتوا باید از سامانه خارج شوید', + }, + { + id: 'ex_909', + value: 'زبان انتخاب شده نامعتبر است', + }, + { + id: 'ex_910', + value: 'داده نامعتبر برای انتخاب کاربر', + }, + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'Invalid Data ...', + }, + { + id: 'ex_101', + value: 'Invalid Date ...', + }, + { + id: 'ex_102', + value: 'Bad Request ...', + }, + { + id: 'ex_103', + value: 'Invalid Args ...', + }, + { + id: 'ex_104', + value: 'Invalid Message ...', + }, + { + id: 'ex_105', + value: 'Invalid Token ...', + }, + { + id: 'ex_106', + value: 'Invalid Verification Code ...', + }, + { + id: 'ex_107', + value: 'Invalid Email Address ...', + }, + { + id: 'ex_108', + value: 'Invalid Mobile Number ...', + }, + { + id: 'ex_109', + value: 'Invalid Password ...', + }, + { + id: 'ex_110', + value: 'Invalid URL ...', + }, + { + id: 'ex_111', + value: 'Invalid Device ...', + }, + { + id: 'ex_112', + value: 'Invalid Profile Image ...', + }, + { + id: 'ex_113', + value: 'Invalid File ...', + }, + { + id: 'ex_114', + value: 'Invalid Username ...', + }, + { + id: 'ex_200', + value: 'Not Found ...', + }, + { + id: 'ex_201', + value: 'Not Allowed ...', + }, + { + id: 'ex_202', + value: 'Not Authorized ...', + }, + { + id: 'ex_203', + value: 'Not Visible ...', + }, + { + id: 'ex_300', + value: 'Account Locked out ...', + }, + { + id: 'ex_301', + value: 'Login Failed ...', + }, + { + id: 'ex_302', + value: 'User Registered Before ...', + }, + { + id: 'ex_303', + value: 'User Disabled ...', + }, + { + id: 'ex_304', + value: 'Device Banned Until:(0)', + }, + { + id: 'ex_305', + value: `You can not Request Verification code Until:(0)`, + }, + { + id: 'ex_306', + value: 'Passwords Same ...', + }, + { + id: 'ex_307', + value: 'Mobiles Same ...', + }, + { + id: 'ex_308', + value: 'Emails Same ...', + }, + { + id: 'ex_309', + value: 'Mobile In Used ...', + }, + { + id: 'ex_310', + value: 'Email In Used ...', + }, + { + id: 'ex_311', + value: 'Mobile Not Confirmed ...', + }, + { + id: 'ex_312', + value: 'Email Not Confirmed ...', + }, + { + id: 'ex_313', + value: 'Post Banned ...', + }, + { + id: 'ex_314', + value: 'User Banned ...', + }, + { + id: 'ex_400', + value: 'Unknown Error ...', + }, + { + id: 'ex_401', + value: 'Duplicate ...', + }, + { + id: 'ex_402', + value: 'Action Failed ...', + }, + { + id: 'ex_403', + value: 'Expired Date ...', + }, + { + id: 'ex_404', + value: 'Unavailable ...', + }, + { + id: 'ex_405', + value: 'Max Allowed Tag Exceeded ...', + }, + { + id: 'ex_406', + value: 'Timeout ...', + }, + { + id: 'ex_500', + value: 'Empty File ...', + }, + { + id: 'ex_501', + value: 'max File size exceeded ...', + }, + { + id: 'ex_502', + value: 'Unsupported File Type ...', + }, + { + id: 'ex_503', + value: 'Max Allowed Media Exceeded ...', + }, + { + id: 'ex_600', + value: 'Invalid Configuration ...', + }, + { + id: 'ex_601', + value: 'Storage Service Initiallization Failed ...', + }, + { + id: 'ex_602', + value: 'Message Service Initialization Failed ...', + }, + { + id: 'ex_900', + value: 'Max Allowed Files Exceeded ...', + }, + { + id: 'ex_901', + value: 'Min Files Size Exceeded ...', + }, + { + id: 'ex_902', + value: 'Max Files Size Exceeded ...', + }, + { + id: 'ex_903', + value: 'Must Accept Terms And Conditions ...', + }, + { + id: 'ex_904', + value: 'Browser does not support Location Services ...', + }, + { + id: 'ex_905', + value: 'You have rejected access to your Location ...', + }, + { + id: 'ex_906', + value: 'Unable to determine your Location ...', + }, + { + id: 'ex_907', + value: 'Browser does not support Storage Services ...', + }, + { + id: 'ex_908', + value: 'Must Logout to access content ...', + }, + { + id: 'ex_909', + value: 'Invalid Locale ...', + }, + { + id: 'ex_910', + value: 'Invalid User Selector ...', + }, + //#endregion + ], + }, +]; +//#endregion + +// +//#region Resource and Exception IDS ... +export const AvailableTranslationResources: XLanguageDescriptor[] = [ + { + name: 'persian', + locale: 'fa-IR', + language: 'fa', + direction: 'rtl', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'ساحر علم' }, + { id: 'company', value: 'فن آوران ساحر علم' }, + { id: 'id', value: 'شناسه' }, + { id: 'file_name', value: 'نام فایل' }, + { id: 'error', value: 'خطا' }, + { id: 'required', value: 'الزامی است.' }, + { id: 'loading', value: 'بارگزاری' }, + { id: 'username', value: 'نام کاربری' }, + { id: 'password', value: 'کلمه عبور' }, + { id: 'first_name', value: 'نام' }, + { id: 'last_name', value: 'نام خانوادگی' }, + { id: 'verified', value: 'تایید شده' }, + { id: 'unverified', value: 'تایید نشده' }, + { id: 'thumbnail', value: 'پیش نمایش' }, + { id: 'language', value: 'زبان' }, + { id: 'take_screenshot', value: 'تصویر برداری ازمحیط' }, + { id: 'enable_capture_mode', value: 'فعالسازی حالت تصویر برداری' }, + { id: 'disable_capture_mode', value: 'غیرفعالسازی حالت تصویر برداری' }, + { id: 'be', value: 'باشد' }, + { id: 'not_to_be', value: 'نباشد' }, + { id: 'enabled', value: 'فعال' }, + { id: 'disabled', value: 'غیر فعال' }, + { id: 'banned', value: 'مسدود' }, + { id: 'un_banned', value: 'غیر مسدود' }, + { id: 'audio', value: 'صوت' }, + { id: 'video', value: 'فیلم' }, + { id: 'cover_image', value: 'تصویر' }, + { id: 'image', value: 'تصویر' }, + { id: 'unknown', value: 'ناشناس' }, + { id: 'location', value: 'موقعیت جغرافیای' }, + { id: 'are_you_sure', value: 'اطمینان دارید ؟' }, + { id: 'success_msg', value: 'عملیات با موفقیت انجام شد' }, + { id: 'locked_msg', value: 'برای ترک این صفحه باید فعالیت جاری را لغو کرده و یا به اتمام برسانید' }, + { id: 'empty_content', value: 'خالی است' }, + { id: 'no_item', value: 'محتوایی ثبت نشده است' }, + { id: 'drag_drop_here', value: 'محل رها کردن فایل' }, + { id: 'map_dialog_title', value: 'نمایش موقعیت مکانی' }, + { id: 'map_dialog_select_title', value: 'انتخاب موقعیت جغرافیایی' }, + { id: 'color_picker_dialog_title', value: 'انتخاب رنگ' }, + { id: 'dismiss', value: 'رد کردن' }, + { id: 'accept', value: 'می پذیرم' }, + { id: 'ok', value: 'بسیار خب' }, + { id: 'save', value: 'ذخیره' }, + { id: 'cancel', value: 'لغو' }, + { id: 'retry', value: 'سعی مجدد' }, + { id: 'edit', value: 'ویرایش' }, + { id: 'reset', value: 'باز نشاندن' }, + { id: 'change', value: 'تغییر' }, + { id: 'start', value: 'آغاز' }, + { id: 'yes', value: 'بله' }, + { id: 'no', value: 'خیر' }, + { id: 'verify', value: 'تایید کردن' }, + { id: 'confirm', value: 'تاییدیه' }, + { id: 'crop', value: 'برش' }, + { id: 'clear', value: 'پاک کردن' }, + { id: 'set', value: 'تنظیم' }, + { id: 'select', value: 'انتخاب' }, + { id: 'send', value: 'ارسال' }, + { id: 'show', value: 'نمایش دادن' }, + { id: 'hide', value: 'پنهان کردن' }, + { id: 'search', value: 'جستجو' }, + { id: 'delete', value: 'حذف' }, + { id: 'clone', value: 'نمونه گیری' }, + { id: 'select_all', value: 'انتخاب همه' }, + { id: 'select_file', value: 'انتخاب فایل(ها)' }, + { id: 'select_all_group', value: 'انتخاب همه موارد فیلتر شده' }, + { id: 'deselect_all', value: 'لغو همه انتخاب ها' }, + { id: 'deselect_all_group', value: 'لغو انتخاب همه موارد فیلتر شده' }, + { id: 'inverse_selection', value: 'انتخاب معکوس' }, + { id: 'selected_location', value: 'انتخاب محل' }, + { id: 'preset_colors', value: 'رنگ های پیش فرض' }, + { id: 'copy_to_clipboard', value: 'ثبت در حافظه موقت' }, + { id: 'color', value: 'رنگ' }, + { id: 'colors', value: 'رنگها' }, + { id: 'upload', value: 'بارگزاری' }, + { id: 'import', value: 'وارد کردن' }, + { id: 'continue', value: 'ادامه' }, + { id: 'finish', value: 'پایان' }, + { id: 'enable', value: 'فعال' }, + { id: 'disable', value: 'غیر فعال' }, + { id: 'all', value: 'همه' }, + { id: 'new', value: 'جدید' }, + { id: 'add', value: 'افزودن' }, + { id: 'update', value: 'بروز رسانی' }, + { id: 'details', value: 'جزئیات' }, + { id: 'translation', value: 'ترجمه' }, + { id: 'download', value: 'دریافت' }, + { id: 'list', value: 'فهرست' }, + { id: 'options', value: 'انتخاب ها' }, + { id: 'descriptions', value: 'توضیحات' }, + { id: 'type', value: 'نوع' }, + { id: 'media', value: 'رسانه' }, + { id: 'medias', value: 'رسانه ها' }, + { id: 'summary', value: 'خلاصه' }, + { id: 'go', value: 'رفتن' }, + { id: 'input', value: 'ورود' }, + { id: 'preview', value: 'پیش نمایش' }, + { id: 'close', value: 'بستن' }, + { id: 'undo', value: 'لغو کردن' }, + { id: 'redo', value: 'انجام دوباره' }, + { id: 'refresh', value: 'بازیابی' }, + { id: 'submit', value: 'ثبت' }, + { id: 'first', value: 'نخستین' }, + { id: 'last', value: 'آخرین' }, + { id: 'previous', value: 'قبلی' }, + { id: 'next', value: 'بعدی' }, + { id: 'back', value: 'بازگشت' }, + { id: 'x_markdown_preview', value: 'پیش نمایش' }, + { id: 'x_markdown_image', value: 'تصویر' }, + { id: 'x_markdown_link', value: 'پیوند' }, + { id: 'x_markdown_ol', value: 'فهرست ترتیبی' }, + { id: 'x_markdown_ul', value: 'فهرست بدون ترتیب' }, + { id: 'x_markdown_quote', value: 'نقل قول' }, + { id: 'x_markdown_code', value: 'کد منبع' }, + { id: 'x_markdown_heading', value: 'عنوان' }, + { id: 'x_markdown_italic', value: 'ایتالیک' }, + { id: 'x_markdown_bold', value: 'پر رنگ' }, + { id: 'x_markdown_guide', value: 'راهنمای نگارش' }, + { id: 'theme', value: 'پوسته' }, + { id: 'theme_mode', value: 'حالت نمایشی' }, + { id: 'theme_dark', value: 'تیره' }, + { id: 'theme_light', value: 'روشن' }, + { id: 'theme_name', value: 'نام پوسته' }, + { id: 'theme_name_description', value: 'نام پوسته را وارد کنید' }, + { id: 'theme_clone_title', value: 'نمونه گیری از پوسته' }, + { id: 'input_color_title', value: 'تعیین رنگ' }, + { id: 'input_color_description', value: 'مقدار رنگ را وارد کنید' }, + { id: 'ide_mode', value: 'نوع کد' }, + { id: 'ide_format', value: 'حالت دهی کد' }, + { id: 'print', value: 'چاپ' }, + { id: 'export_png', value: 'خروجی PNG' }, + { id: 'export_svg', value: 'خروجی SVG' }, + { id: 'export_csv', value: 'خروجی CSV' }, + { id: 'zoom_in', value: 'بزرگنمایی' }, + { id: 'zoom_out', value: 'کوچک نمایی' }, + { id: 'zoom_selection', value: 'بزرگنمایی ناحیه' }, + { id: 'x_axis', value: 'محور افقی' }, + { id: 'y_axis', value: 'محور عمودی' }, + { id: 'xy_axis', value: 'محورهای عمودی و افقی' }, + { id: 'pan', value: 'حرکت آزاد' }, + { id: 'full_screen', value: 'حالت تمام صفحه' } + //#endregion + + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'داده نا معتبر', + }, + { + id: 'ex_101', + value: 'تاریخ نامعتبر', + }, + { + id: 'ex_102', + value: 'درخواست اشتباه', + }, + { + id: 'ex_103', + value: 'ورودی نامعتبر', + }, + { + id: 'ex_104', + value: 'پیام نامعتبر', + }, + { + id: 'ex_105', + value: 'نشانه نامعتبر', + }, + { + id: 'ex_106', + value: 'کد اععتبارسنجی نامعتبر', + }, + { + id: 'ex_107', + value: 'پست الکترونیک نامعتبر', + }, + { + id: 'ex_108', + value: 'شماره تلفن همراه نامعتبر', + }, + { + id: 'ex_109', + value: 'کلمه عبور نامعتبر', + }, + { + id: 'ex_110', + value: 'آدرس اینترنتی نامعتبر', + }, + { + id: 'ex_111', + value: 'دستگاه نامعتبر', + }, + { + id: 'ex_112', + value: 'تصویر پروفایل نامعتبر', + }, + { + id: 'ex_113', + value: 'فایل نامعتبر', + }, + { + id: 'ex_114', + value: 'نام کاربری نامعتبر', + }, + { + id: 'ex_200', + value: 'یافت نشد', + }, + { + id: 'ex_201', + value: 'عدم تایید جواز', + }, + { + id: 'ex_202', + value: 'سطح دسترسی نامعتبر', + }, + { + id: 'ex_203', + value: 'غیر قابل نمایش', + }, + { + id: 'ex_300', + value: 'حساب کاربری قفل شده است', + }, + { + id: 'ex_301', + value: 'خطا در ورود', + }, + { + id: 'ex_302', + value: 'کاربر قبلا ثبت نام کرده است', + }, + { + id: 'ex_303', + value: 'کاربر غیرفعال است', + }, + { + id: 'ex_304', + value: 'دستگاه شما قفل شده است تا : (0)', + }, + { + id: 'ex_305', + value: 'امکان درخواست کد اعتبارسنجی وجود ندارد تا : (0)', + }, + { + id: 'ex_306', + value: 'کلمه عبورها یکسان هستند', + }, + { + id: 'ex_307', + value: 'شماره های تلفن یکسان هستند', + }, + { + id: 'ex_308', + value: 'آدرس های پست الکترونیک یکسان هستند', + }, + { + id: 'ex_309', + value: 'شماره تلفن قبلا ثبت شده است', + }, + { + id: 'ex_310', + value: 'پست الکترونیک قبلا ثبت شده است', + }, + { + id: 'ex_311', + value: 'تلفن همراه تایید نشده است', + }, + { + id: 'ex_312', + value: 'پست الکترونیک تایید نشده است', + }, + { + id: 'ex_313', + value: 'مطلب ممنوعه', + }, + { + id: 'ex_314', + value: 'کاربر ممنوعه', + }, + { + id: 'ex_400', + value: 'خطای نا شناخته', + }, + { + id: 'ex_401', + value: 'مورد تکراری', + }, + { + id: 'ex_402', + value: 'شکست عملیات', + }, + { + id: 'ex_403', + value: 'تاریخ مصرف منقضی شده است', + }, + { + id: 'ex_404', + value: 'غیر قابل اسفاده', + }, + { + id: 'ex_405', + value: 'تعداد برچسب ها بیش از جد مجاز است', + }, + { + id: 'ex_406', + value: 'اتمام مهلت زمانی', + }, + { + id: 'ex_500', + value: 'پرونده خالی است', + }, + { + id: 'ex_501', + value: 'اندازه بیش از حد مجاز', + }, + { + id: 'ex_502', + value: 'گونه نامعتبر فایل', + }, + { + id: 'ex_503', + value: 'تعداد رسانه ها بیش از حد مجاز است', + }, + { + id: 'ex_600', + value: 'پیکربندی اشتباه', + }, + { + id: 'ex_601', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_602', + value: 'خطا در پیکربندی سامانه ذخیره سازی', + }, + { + id: 'ex_900', + value: 'تعداد فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_901', + value: 'مجموع اندازه فایل ها کمتر از حد مجاز است', + }, + { + id: 'ex_902', + value: 'مجموع اندازه فایل ها بیش از حد مجاز است', + }, + { + id: 'ex_903', + value: 'شرایط و ضوابط باید پذیرفته شوند', + }, + { + id: 'ex_904', + value: 'عدم پشتیبانی از سیستم موقعیت یاب', + }, + { + id: 'ex_905', + value: 'مجوز دسترسی به موقعیت خود را صادر نکرده اید', + }, + { + id: 'ex_906', + value: 'دسترسی به موقعیت جغرافیایی امکان پذیر نیست', + }, + { + id: 'ex_907', + value: 'عدم پشتیبانی از سیستم ذخیره سازی', + }, + { + id: 'ex_908', + value: 'برای دسترسی به محتوا باید از سامانه خارج شوید', + }, + { + id: 'ex_909', + value: 'زبان انتخاب شده نامعتبر است', + }, + { + id: 'ex_910', + value: 'داده نامعتبر برای انتخاب کاربر', + }, + //#endregion + ], + }, + { + name: 'english', + locale: 'en-US', + language: 'en', + direction: 'ltr', + resources: [ + // + //#region XResourceIDS ... + { id: 'app_name', value: 'SaherElm' }, + { id: 'company', value: 'SaherElm IT Center' }, + { id: 'id', value: 'ID' }, + { id: 'file_name', value: 'File Name' }, + { id: 'error', value: 'Error' }, + { id: 'required', value: 'required' }, + { id: 'loading', value: 'loading' }, + { id: 'username', value: 'Username' }, + { id: 'password', value: 'Password' }, + { id: 'first_name', value: 'Firstname' }, + { id: 'last_name', value: 'Lastname' }, + { id: 'verified', value: 'Verified' }, + { id: 'unverified', value: 'Unverified' }, + { id: 'thumbnail', value: 'Thumbnail' }, + { id: 'language', value: 'Language' }, + { id: 'take_screenshot', value: 'Take Screenshot' }, + { id: 'enable_capture_mode', value: 'Enable Capture Mode' }, + { id: 'disable_capture_mode', value: 'Disable Capture Mode' }, + { id: 'be', value: 'Be' }, + { id: 'not_to_be', value: 'Not to be' }, + { id: 'enabled', value: 'Enabled' }, + { id: 'disabled', value: 'Disabled' }, + { id: 'banned', value: 'Banned' }, + { id: 'un_banned', value: 'UnBanned' }, + { id: 'audio', value: 'Audio' }, + { id: 'video', value: 'Video' }, + { id: 'cover_image', value: 'Cover Image' }, + { id: 'image', value: 'Image' }, + { id: 'avatar', value: 'Avatar' }, + { id: 'unknown', value: 'Unknown' }, + { id: 'location', value: 'Location' }, + { id: 'are_you_sure', value: 'Are You Sure ?' }, + { id: 'success_msg', value: 'Operation done Successfully ...' }, + { id: 'locked_msg', value: 'You have to finish/cancel current proccess for leaving' }, + { id: 'empty_content', value: 'Empty' }, + { id: 'no_item', value: 'there is no Content' }, + { id: 'drag_drop_here', value: 'Drop File Here' }, + { id: 'map_dialog_title', value: 'Show Location' }, + { id: 'map_dialog_select_title', value: 'Select Location' }, + { id: 'color_picker_dialog_title', value: 'Select Color' }, + { id: 'dismiss', value: 'dismiss' }, + { id: 'accept', value: 'Accept' }, + { id: 'ok', value: 'Ok' }, + { id: 'save', value: 'Save' }, + { id: 'cancel', value: 'Cancel' }, + { id: 'retry', value: 'Retry' }, + { id: 'edit', value: 'Edit' }, + { id: 'reset', value: 'Reset' }, + { id: 'change', value: 'Change' }, + { id: 'start', value: 'Start' }, + { id: 'yes', value: 'Yes' }, + { id: 'no', value: 'No' }, + { id: 'verify', value: 'Verify' }, + { id: 'confirm', value: 'Confirm' }, + { id: 'crop', value: 'Crop' }, + { id: 'clear', value: 'Clear' }, + { id: 'set', value: 'Set' }, + { id: 'select', value: 'Select' }, + { id: 'send', value: 'Send' }, + { id: 'show', value: 'Show' }, + { id: 'hide', value: 'Hide' }, + { id: 'search', value: 'Search' }, + { id: 'delete', value: 'Delete' }, + { id: 'clone', value: 'Clone' }, + { id: 'select_all', value: 'Select All' }, + { id: 'select_file', value: 'Select File(s)' }, + { id: 'select_all_group', value: 'Select All Filtered Items' }, + { id: 'deselect_all', value: 'Deselect All' }, + { id: 'deselect_all_group', value: 'Deselect All Filtered Items' }, + { id: 'inverse_selection', value: 'Inverse Selection' }, + { id: 'selected_location', value: 'Selected Location' }, + { id: 'preset_colors', value: 'Preset Colors' }, + { id: 'copy_to_clipboard', value: 'Copy to Clipboard' }, + { id: 'color', value: 'Color' }, + { id: 'colors', value: 'Colors' }, + { id: 'upload', value: 'Upload' }, + { id: 'import', value: 'Import' }, + { id: 'continue', value: 'Continue' }, + { id: 'finish', value: 'Finish' }, + { id: 'enable', value: 'Enable' }, + { id: 'disable', value: 'Disable' }, + { id: 'all', value: 'All' }, + { id: 'new', value: 'New' }, + { id: 'add', value: 'Add' }, + { id: 'update', value: 'Update' }, + { id: 'details', value: 'Details' }, + { id: 'translation', value: 'Translation' }, + { id: 'download', value: 'Download' }, + { id: 'list', value: 'List' }, + { id: 'options', value: 'Options' }, + { id: 'descriptions', value: 'Description' }, + { id: 'type', value: 'Type' }, + { id: 'media', value: 'Media' }, + { id: 'medias', value: 'Medias' }, + { id: 'summary', value: 'Summary' }, + { id: 'go', value: 'Go' }, + { id: 'input', value: 'Input' }, + { id: 'preview', value: 'Preview' }, + { id: 'close', value: 'Close' }, + { id: 'undo', value: 'Undo' }, + { id: 'redo', value: 'Redo' }, + { id: 'refresh', value: 'Refresh' }, + { id: 'submit', value: 'Submit' }, + { id: 'first', value: 'First' }, + { id: 'last', value: 'Last' }, + { id: 'previous', value: 'Previous' }, + { id: 'next', value: 'Next' }, + { id: 'back', value: 'Back' }, + { id: 'x_markdown_preview', value: 'Preview' }, + { id: 'x_markdown_image', value: 'Image' }, + { id: 'x_markdown_link', value: 'Link' }, + { id: 'x_markdown_ol', value: 'Ordered List' }, + { id: 'x_markdown_ul', value: 'Unordered List' }, + { id: 'x_markdown_quote', value: 'Quote' }, + { id: 'x_markdown_code', value: 'Code' }, + { id: 'x_markdown_heading', value: 'Heading' }, + { id: 'x_markdown_italic', value: 'Italic' }, + { id: 'x_markdown_bold', value: 'Bold' }, + { id: 'x_markdown_guide', value: 'Markdown Guide' }, + { id: 'theme', value: 'Theme' }, + { id: 'theme_mode', value: 'Theme Mode' }, + { id: 'theme_dark', value: 'Dark' }, + { id: 'theme_light', value: 'Light' }, + { id: 'theme_name', value: 'Theme Name' }, + { id: 'theme_name_description', value: 'Enter Theme name' }, + { id: 'theme_clone_title', value: 'Theme Cloning' }, + { id: 'input_color_title', value: 'Color Value' }, + { id: 'input_color_description', value: 'input color value' }, + { id: 'ide_mode', value: 'Code Style' }, + { id: 'ide_format', value: 'Code Formatting' }, + { id: 'print', value: 'Print' }, + { id: 'export_png', value: 'Export PNG' }, + { id: 'export_svg', value: 'Export SVG' }, + { id: 'export_csv', value: 'Export CSV' }, + { id: 'zoom_in', value: 'Zoom In' }, + { id: 'zoom_out', value: 'Zoom Out' }, + { id: 'zoom_selection', value: 'Zoom Selection' }, + { id: 'x_axis', value: 'X Axis' }, + { id: 'y_axis', value: 'Y Axis' }, + { id: 'xy_axis', value: 'XY Axis' }, + { id: 'pan', value: 'Pan' }, + { id: 'full_screen', value: 'Full Screen' } + //#endregion + + // + //#region Exception Resource IDS ... + { + id: 'ex_100', + value: 'Invalid Data ...', + }, + { + id: 'ex_101', + value: 'Invalid Date ...', + }, + { + id: 'ex_102', + value: 'Bad Request ...', + }, + { + id: 'ex_103', + value: 'Invalid Args ...', + }, + { + id: 'ex_104', + value: 'Invalid Message ...', + }, + { + id: 'ex_105', + value: 'Invalid Token ...', + }, + { + id: 'ex_106', + value: 'Invalid Verification Code ...', + }, + { + id: 'ex_107', + value: 'Invalid Email Address ...', + }, + { + id: 'ex_108', + value: 'Invalid Mobile Number ...', + }, + { + id: 'ex_109', + value: 'Invalid Password ...', + }, + { + id: 'ex_110', + value: 'Invalid URL ...', + }, + { + id: 'ex_111', + value: 'Invalid Device ...', + }, + { + id: 'ex_112', + value: 'Invalid Profile Image ...', + }, + { + id: 'ex_113', + value: 'Invalid File ...', + }, + { + id: 'ex_114', + value: 'Invalid Username ...', + }, + { + id: 'ex_200', + value: 'Not Found ...', + }, + { + id: 'ex_201', + value: 'Not Allowed ...', + }, + { + id: 'ex_202', + value: 'Not Authorized ...', + }, + { + id: 'ex_203', + value: 'Not Visible ...', + }, + { + id: 'ex_300', + value: 'Account Locked out ...', + }, + { + id: 'ex_301', + value: 'Login Failed ...', + }, + { + id: 'ex_302', + value: 'User Registered Before ...', + }, + { + id: 'ex_303', + value: 'User Disabled ...', + }, + { + id: 'ex_304', + value: 'Device Banned Until:(0)', + }, + { + id: 'ex_305', + value: `You can not Request Verification code Until:(0)`, + }, + { + id: 'ex_306', + value: 'Passwords Same ...', + }, + { + id: 'ex_307', + value: 'Mobiles Same ...', + }, + { + id: 'ex_308', + value: 'Emails Same ...', + }, + { + id: 'ex_309', + value: 'Mobile In Used ...', + }, + { + id: 'ex_310', + value: 'Email In Used ...', + }, + { + id: 'ex_311', + value: 'Mobile Not Confirmed ...', + }, + { + id: 'ex_312', + value: 'Email Not Confirmed ...', + }, + { + id: 'ex_313', + value: 'Post Banned ...', + }, + { + id: 'ex_314', + value: 'User Banned ...', + }, + { + id: 'ex_400', + value: 'Unknown Error ...', + }, + { + id: 'ex_401', + value: 'Duplicate ...', + }, + { + id: 'ex_402', + value: 'Action Failed ...', + }, + { + id: 'ex_403', + value: 'Expired Date ...', + }, + { + id: 'ex_404', + value: 'Unavailable ...', + }, + { + id: 'ex_405', + value: 'Max Allowed Tag Exceeded ...', + }, + { + id: 'ex_406', + value: 'Timeout ...', + }, + { + id: 'ex_500', + value: 'Empty File ...', + }, + { + id: 'ex_501', + value: 'max File size exceeded ...', + }, + { + id: 'ex_502', + value: 'Unsupported File Type ...', + }, + { + id: 'ex_503', + value: 'Max Allowed Media Exceeded ...', + }, + { + id: 'ex_600', + value: 'Invalid Configuration ...', + }, + { + id: 'ex_601', + value: 'Storage Service Initiallization Failed ...', + }, + { + id: 'ex_602', + value: 'Message Service Initialization Failed ...', + }, + { + id: 'ex_900', + value: 'Max Allowed Files Exceeded ...', + }, + { + id: 'ex_901', + value: 'Min Files Size Exceeded ...', + }, + { + id: 'ex_902', + value: 'Max Files Size Exceeded ...', + }, + { + id: 'ex_903', + value: 'Must Accept Terms And Conditions ...', + }, + { + id: 'ex_904', + value: 'Browser does not support Location Services ...', + }, + { + id: 'ex_905', + value: 'You have rejected access to your Location ...', + }, + { + id: 'ex_906', + value: 'Unable to determine your Location ...', + }, + { + id: 'ex_907', + value: 'Browser does not support Storage Services ...', + }, + { + id: 'ex_908', + value: 'Must Logout to access content ...', + }, + { + id: 'ex_909', + value: 'Invalid Locale ...', + }, + { + id: 'ex_910', + value: 'Invalid User Selector ...', + }, + //#endregion + ], + }, +]; +//#endregion + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Resources\XResourceIDS\Generator\xFrameworkResourceManager.html + + + + + + + مدیریت منابع زبانی xFramework + + + +
+

🌐 مدیریت منابع زبانی xFramework

+

+ مدیریت، ویرایش و اعتبارسنجی فایل‌های ترجمه برای برنامه‌های کاربردی مبتنی + بر xFramework +

+
+ توسعه‌دهنده: هادی خزاعی اصل | شرکت: فن آوران ساحر علم | تاریخ: ۱ شهریور + ۱۴۰۵ +
+
+ +
+ +
+

📂 منبع داده‌ها

+
+
+ 📚 منابع پیش‌فرض سیستم +
+
+ 📁 بارگذاری فایل JSON +
+
+ +
+

+ ✅ در حال حاضر از منابع پیش‌فرض xFramework استفاده می‌شود. می‌توانید + مستقیماً ویرایش را شروع کنید. +

+
+ +
+
+ + +
+
+
+
+ + +
+

🌍 مدیریت زبان‌ها

+
+ +
+ + + + + +
+
+ + +
+

✏️ ویرایش شناسه‌ها و ترجمه‌ها

+
+ +
+ +
+ +
+ + +
+

+ یک شناسه را از لیست سمت راست انتخاب کنید تا ترجمه‌های آن را ویرایش + کنید. +

+
+
+
+ + +
+

📄 خروجی JSON

+
+
+ 📄 Full JSON +
+
+

+
+        
+ + + +
+
+
+ + + + + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\IXOwnedItemResourceProvider.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xModels.Dtos; +using xStringService.Models.Dtos; + +namespace xStringService.Interfaces +{ + public interface IXOwnedItemResourceProvider + { + // + #region Group Actions ... + /// + /// Retrieve a List of Exists Languages for Current Item ... + /// + /// + /// + /// + Task> GetLanguages( + object owner, + CancellationToken cancellationToken = default + ); + + /// + /// Retrieve all Exists Items of type ... + /// + /// + /// + Task> GetResourceLocales( + object owner, + CancellationToken cancellationToken = default + ); + + /// + /// Remove all Exists Locales which Related to this Provider ... + /// + /// + /// + /// + Task RemoveResourceLocales( + object owner, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Item Actions ... + /// + /// Get all Exists Items for Specified identitifer ... + /// + /// + /// + /// + Task> GetResourceLocales( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + + /// + /// Get all Exists Items for Specified identitifer ... + /// + /// + /// + /// + Task> GetLocales( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + + /// + /// Get all Exists Locales Representaion based on Specified Identitifer + /// as XResourceDto ... + /// + /// + /// + /// + Task GetResource( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + + /// + /// Add Or Update Locale for Specified Identitifer ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateLocale( + object owner, + object identifier, + XLocaleResourceDto locale, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Update a Resource State ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateResource( + object owner, + object identifier, + XResourceDto resource, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove Specified Language Locale of Specified Identifier ... + /// + /// + /// + /// + /// + /// + Task RemoveLocale( + object owner, + object identifier, + string language, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Remove all Exists Locales for Specified Identifier ... + /// + /// + /// + /// + /// + Task RemoveLocales( + object owner, + object identifier, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Check Specified ocale Exists for Specified Identifier ... + /// + /// + /// + /// + /// + Task HasLocale( + object owner, + object identifier, + string language, + CancellationToken cancellationToken = default + ); + + /// + /// Get all Exists Languages for Specified Identifier ... + /// + /// + /// + /// + Task> GetLanguages( + object owner, + object identifier, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Resource Title Action ... + /// + /// Retrieve Resource Title ... + /// + /// + /// + string GetResourceTitle(object identifier = null); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\XBaseOwnedItemResourceProvider.cs + +using xStringService.Interfaces; + +namespace xStringService.Providers +{ + /// + /// Owned Item Resource Provider ... + /// + public abstract class XBaseOwnedItemResourceProvider : IXOwnedItemResourceProvider + { + + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\XAiApiConfiguration.cs + +using xAiModels.Constants; +using xAiModels.Models; + +namespace xAiModels.Configurations +{ + public class XAiApiConfiguration + { + /// + /// Model Providers ... + /// + public XAiModelDescriptor[] Models { get; set; } = []; + + /// + /// Each User must Has a Default Project, this is Title Resource Identifier ... + /// + public string DefaultProjectTitleResource { get; set; } = XAiModelsConstants.DefaultXAiProjectTitleResourceID; + + /// + /// Each User must Has a Default Project, this is Description Resource Identifier ... + /// + public string DefaultProjectDescriptionResource { get; set; } = XAiModelsConstants.DefaultXAiProjectDescriptionResourceID; + + /// + /// Each User must Has a Default Conversation, this is Title Resource Identifier ... ... + /// + public string DefaultConversationTitleResource { get; set; } = XAiModelsConstants.DefaultXAiConversationTitleResourceID; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\XAiModelMappersProfile.cs + +using AutoMapper; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Configurations +{ + public class XAiModelMappersProfile : Profile + { + public XAiModelMappersProfile() + { + // + // XAiMessage ... + CreateMap(); + + // + // XAiProject ... + CreateMap(); + + // + // XAiConversation ... + CreateMap(); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\Entities\XAiConversationEntityConfiguration.cs + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xAiModels.Constants; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Configurations.Entities +{ + public class XAiConversationEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiConversationTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\Entities\XAiMessageEntityConfiguration.cs + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xAiModels.Constants; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Configurations.Entities +{ + public class XAiMessageEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiMessageTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Configurations\Entities\XAiProjectEntityConfiguration.cs + +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using xAiModels.Constants; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Configurations.Entities +{ + public class XAiProjectEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiProjectTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\ConfigurationNodeNames.cs + +namespace xAiModels.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiApiConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiChatRole.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiChatRoles + { + public const string None = "none"; + public const string User = "user"; + public const string Tool = "tool"; + public const string System = "system"; + public const string Assistant = "assistant"; + } + + public enum XAiChatRole + { + [StringValue(XAiChatRoles.None)] + None, + [StringValue(XAiChatRoles.User)] + User, + [StringValue(XAiChatRoles.Tool)] + Tool, + [StringValue(XAiChatRoles.System)] + System, + [StringValue(XAiChatRoles.Assistant)] + Assistant, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiDataProviderConstants.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiDataProviderConstants + { + public const string XDefaultAiProjectSuffix = "DefAiPrj"; + public const string XDefaultAiConversationSuffix = "DefAiCnv"; + } + + public enum XAiDataProviderHubActions + { + // + // Project ... + [StringValue("ProjectCreated")] + ProjectCreated, + + [StringValue("ProjectUpdated")] + ProjectUpdated, + + [StringValue("ProjectRemoved")] + ProjectRemoved, + + // + // Conversation ... + [StringValue("ConversationCreated")] + ConversationCreated, + + [StringValue("ConversationUpdated")] + ConversationUpdated, + + [StringValue("ConversationRemoved")] + ConversationRemoved, + + // + // Message ... + [StringValue("MessageCreated")] + MessageCreated, + + [StringValue("MessageUpdated")] + MessageUpdated, + + [StringValue("MessageRemoved")] + MessageRemoved, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiModelProviderType.cs + +namespace xAiModels.Constants +{ + /// + /// Specifiy Provider Type ... + /// + public enum XAiModelProviderType + { + None, + Ollama, + DeepSeek, + HuggingFace + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Constants\XAiModelsConstants.cs + +namespace xAiModels.Constants +{ + public struct XAiModelsConstants + { + // + // Service Extensions Log Tag ... + public const string XAiModelsDILogTag = "XAiModels"; + + // + // Table Mapping Identifiers ... + public const string XAiMessageTable = "AiMessages"; + public const string XAiProjectTable = "AiProjects"; + public const string XAiConversationTable = "AiConversations"; + + // + // GraphQL Collection Mappings ... + public const string XAiMessageSingleName = "aiMessage"; + public const string XAiProjectSingleName = "aiProject"; + public const string XAiConversationSignleName = "aiConversation"; + + public const string XAiMessageCollectionName = "aiMessages"; + public const string XAiProjectCollectionName = "AiProjectsa"; + public const string XAiConversationCollectionName = "aiConversations"; + + // + // Hubs ... + public const string XAiMessageDtoHub = "aiMessageDto"; + public const string XAiMessageEntityHub = "aiMessageEntity"; + + public const string XAiProjectDtoHub = "aiProjectDto"; + public const string XAiProjectEntityHub = "aiProjectEntity"; + + public const string XAiConversationDtoHub = "aiConversationDto"; + public const string XAiConversationEntityHub = "aiConversationEntity"; + + // + // Resource Provider Identifiers ... + public const string XAiProjectTitleIdentifier = "AiPrjT"; + public const string XAiProjectDescriptionIdentifier = "AiPrjD"; + public const string XAiConversationTitleIdentifier = "AiCnvrT"; + + // + // EF Repositories Helper Extensions ... + public const string GetXAiMessageEFRepositoryDescriptor = "GetXAiMessageEFRepositoryDescriptor"; + public const string GetXAiProjectEFRepositoryDescriptor = "GetXAiProjectEFRepositoryDescriptor"; + public const string GetXAiConversationEFRepositoryDescriptor = "GetXAiConversationEFRepositoryDescriptor"; + + // + public const string DefaultXAiProjectTitleResourceID = "XAiPrjT"; + public const string DefaultXAiConversationTitleResourceID = "XAiCnvT"; + public const string DefaultXAiProjectDescriptionResourceID = "XAiPrjD"; + + // + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\DI\XDIHelperExtension.cs + +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.Extensions.DependencyInjection; +using xAiModels.Providers.Dtos; +using xAiModels.Providers.Entities; +using xCommons.Extensions; +using xDataService.Constants; +using xDataService.Db; +using xDataService.Models; +using xExceptions.Constants; +using xPushService.Helpers; +using xPushService.DI; +using xDataService.DI; +using xAiModels.Interfaces.Dtos; +using xAiModels.Helpers; +using xCommons.Helpers; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces; +using xAiModels.Providers; +using xAiModels.Constants; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Providers.Enrichers; + +namespace xAiModels.DI +{ + /// + /// Service Registration Extensions Classes ... + /// + public static class XDIHelperExtension + { + /// + /// Register Service ... + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + AddAiDataService( + contextType: null, + services: services, + lifeTime: lifeTime, + repositoryType: repositoryType + ); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + where TContext : XDbContext + { + AddAiDataService( + services: services, + lifeTime: lifeTime, + contextType: typeof(TContext), + repositoryType: repositoryType + ); + } + + /// + /// Use XSubCategoryService Middleware ... + /// + /// + /// + public static void UseXAiDataService( + this IApplicationBuilder app, + bool isDevelopmentEnvironment = false + ) + { + // + #region Using Hubs ... + // + var pushHelper = new XPushServiceHelper(); + + // + // XAiMessage ... + pushHelper.AddHub(XAiModelsConstants.XAiMessageDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiMessageEntityHub); + + // + // XAiProject ... + pushHelper.AddHub(XAiModelsConstants.XAiProjectDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiProjectEntityHub); + + // + // XAiConversation ... + pushHelper.AddHub(XAiModelsConstants.XAiConversationDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiConversationEntityHub); + + // + app.UseXPushService(pushHelper); + #endregion + + // + // Using XAiConversation Repository Descriptor ... + if (!aiConversationDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiConversationDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiMessage Repository Descriptor ... + if (!aiMessageDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiMessageDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiProject Repository Descriptor ... + if (!aiProjectDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiProjectDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Create an Scope for Services Acces ... + // Handle Seeding Category/SubCategory Resources ... + // TODO: Enable Seeding if Required ... + // using (var scope = app.ApplicationServices.CreateScope()) + // { + // // + // // Retrieve Configuratuions ... + // var aiMessageProvider = scope.ServiceProvider.GetService(); + // var aiProjectProvider = scope.ServiceProvider.GetService(); + // var aiConversationProvider = scope.ServiceProvider.GetService(); + // var configuration = scope.ServiceProvider.GetService(); + // if (!configuration.IsNullOrDefault() && + // !categoryProvider.IsNullOrDefault() && + // !subaiConversationDescriptor.IsNullOrDefault() + // ) + // { + // // + // // Logging ... + // Log("Start Seeding ..."); + + // // + // // Count Data in Category ... + // var hasCategory = (categoryProvider.Count().GetAwaiter().GetResult()) > 0; + // var hasSubCategory = (subCategoryProvider.Count().GetAwaiter().GetResult()) > 0; + + // // + // // Seed Category Resources ... + // var canSeed = + // !hasCategory && + // configuration.Categories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var cat in configuration.Categories) + // { + // // + // try + // { + // // + // Log($"Start Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // categoryProvider.Refresh( + // resource: cat, + // userInfo: null, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // // Seed SubCategory Resources ... + // canSeed = + // !hasSubCategory && + // configuration.SubCategories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var subcat in configuration.SubCategories) + // { + // // + // try + // { + // // + // Log($"Start Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // subCategoryProvider.Refresh( + // userInfo: null, + // resource: subcat, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // Log("Finish Seeding ..."); + // } + // } + } + + // + #region Private ... + private static XRepositoryDescriptor aiMessageDescriptor = null; + private static XRepositoryDescriptor aiProjectDescriptor = null; + private static XRepositoryDescriptor aiConversationDescriptor = null; + + /// + /// a LogTag for Service ... + /// + private static string XLogTag = XAiModelsConstants.XAiModelsDILogTag; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + private static void AddAiDataService( + IServiceCollection services, + XRepositoryType repositoryType, + Type contextType = null, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("Service Registration failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("Service Registration failed, lifetime not provided ..."); + throw exception; + } + + // + // Validate Repository Type ... + var isRepositoryTypeValid = + (repositoryType == XRepositoryType.EF && + !contextType.IsNull()) || + ((repositoryType == XRepositoryType.Mongo || + repositoryType == XRepositoryType.InMemory) && + contextType.IsNull()); + if (!isRepositoryTypeValid) + { + // + Log("Service Registration failed, Invalid Repository Type and Context Type ..."); + throw exception; + } + + // + // Maske Instance of Repository Descriptor + // Based on Provided Type ... + switch (repositoryType) + { + // + case XRepositoryType.EF: + // + // XAiMessage ... + aiMessageDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiMessageEFRepositoryDescriptor + ); + + // + // XAiProject ... + aiProjectDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiProjectEFRepositoryDescriptor + ); + + // + // XAiConversation ... + aiConversationDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiConversationEFRepositoryDescriptor + ); + break; + + // + case XRepositoryType.Mongo: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageMongoRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectMongoRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationMongoRepositoryDescriptor(); + break; + + // + case XRepositoryType.InMemory: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageInMemoryRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectInMemoryRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationInMemoryRepositoryDescriptor(); + break; + } + + // + #region Register Repository Descriptor ... + // + // XAiMessage ... + if (!aiMessageDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiMessageDescriptor + ); + } + + // + // XAiProject ... + if (!aiProjectDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiProjectDescriptor + ); + } + + // + // XAiConversation ... + if (!aiConversationDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiConversationDescriptor + ); + } + #endregion + + // + #region Register Services ... + // + #region AiMessage ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiMessageServiceProvider), typeof(XAiMessageServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryService), typeof(XAiMessageRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryProvider), typeof(XAiMessageRepositoryProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiMessageEnricher), typeof(XAiMessageEnricher), lifeTime) + ); + #endregion + + // + #region AiProject ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiProjectServiceProvider), typeof(XAiProjectServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryService), typeof(XAiProjectRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryProvider), typeof(XAiProjectRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectTitleResourceProvider), typeof(XAiProjectTitleResourceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectDescriptionResourceProvider), typeof(XAiProjectDescriptionResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectEnricher), typeof(XAiProjectEnricher), lifeTime) + ); + #endregion + + // + #region AiConversation ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiConversationServiceProvider), typeof(XAiConversationServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryService), typeof(XAiConversationRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryProvider), typeof(XAiConversationRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationTitleResourceProvider), typeof(XAiConversationTitleResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationEnricher), typeof(XAiConversationEnricher), lifeTime) + ); + #endregion + #endregion + + // + // Data Provider ... + services.Add( + new ServiceDescriptor(typeof(IXAiDataProvider), typeof(XAiDataProvider), lifeTime) + ); + + // + Log("Service Regitration Succeed ..."); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\ChatResponseExtensions.cs + +using Microsoft.Extensions.AI; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + public static class ChatResponseExtensions + { + /// + /// Validate a Chat Response ... + /// + /// + /// + public static bool IsValid(this ChatResponse source) + { + // + var result = + source is not null && + !source.IsNullOrDefault() && + !string.IsNullOrWhiteSpace(source.Text) && + source.FinishReason == ChatFinishReason.Stop; + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\ChatRoleExtensions.cs + +using Microsoft.Extensions.AI; +using xAiModels.Constants; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + /// + /// Extensions for ChatRole ... + /// + public static class ChatRoleExtensions + { + /// + /// Normalize an String to Propper Chat Role Value ... + /// > + /// + /// + /// + public static string GetChatRoleTitle(this string source) + { + // + var result = XAiChatRoles.None; + + // + if (source.ToNormalString() == XAiChatRoles.None.ToNormalString()) + { + result = XAiChatRoles.None; + } + else if (source.ToNormalString() == XAiChatRoles.User.ToNormalString()) + { + result = XAiChatRoles.User; + } + else if (source.ToNormalString() == XAiChatRoles.Tool.ToNormalString()) + { + result = XAiChatRoles.Tool; + } + else if (source.ToNormalString() == XAiChatRoles.System.ToNormalString()) + { + result = XAiChatRoles.System; + } + else if (source.ToNormalString() == XAiChatRoles.Assistant.ToNormalString()) + { + result = XAiChatRoles.Assistant; + } + + // + return result; + } + + /// + /// Get Chat Role Title from Chat Role Class ... + /// + /// + /// + /// + public static string GetRole(this ChatRole source) + { + // + var result = source.Value + .GetChatRoleTitle(); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this string source) + { + // + var role = source.GetChatRoleTitle(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this XAiChatRole source) + { + // + var role = source.GetStringValue(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Extract Chat Role Enum from Chat Role ... + /// + /// + /// + /// + /// + public static XAiChatRole ToChatRole(this ChatRole source) + { + // + var role = source + .GetRole() + .GetChatRoleTitle(); + + // + XAiChatRole result = XAiChatRole.User; + + // + if (role == XAiChatRoles.User) + { + result = XAiChatRole.User; + } + else if (role == XAiChatRoles.Tool) + { + result = XAiChatRole.Tool; + } + else if (role == XAiChatRoles.System) + { + result = XAiChatRole.System; + } + else if (role == XAiChatRoles.Assistant) + { + result = XAiChatRole.Assistant; + } + + // + return result; + } + + /// + /// Validate an String as Chat Role ... + /// + /// + /// + public static bool IsValid(this string source) + { + // + var result = + source != XAiChatRoles.None && + source.ToNormalString() != XAiChatRoles.None.ToNormalString(); + + // + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this XAiChatRole source) + { + // + var result = source != XAiChatRole.None; + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this ChatRole source) + { + // + var role = source.ToChatRole(); + var result = role.IsValid(); + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\XAiApiConfigurationExtensions.cs + +using System.Linq; +using xAiModels.Configurations; +using xAiModels.Models; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + public static class XAiApiConfigurationExtensions + { + /// + /// Validate Api Configuration ... + /// + /// + /// + public static bool IsValid(this XAiApiConfiguration source) + { + return + !source.IsNullOrDefault() && + source.Models.HasChild(); + } + + /// + /// Retrieve Default Model Descriptor ... + /// + /// + /// + public static XAiModelDescriptor GetDefaultModel(this XAiApiConfiguration source) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + result = source.Models.First(); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Extensions\XAiModelsExtensions.cs + +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; + +namespace xAiModels.Extensions +{ + /// + /// Extensions Methods for XAiModels ... + /// + public static class XAiModelsExtensions + { + /// + /// Validate a Project for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiProject source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiProjectDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Conversation for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiConversation source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiConversationDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + + /// + /// Validate a Message for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiMessage source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiMessageDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Helpers\XAiModelsHelper.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xAiModels.Providers.GraphQL; +using xDataService.Db; +using xDataService.Models; +using xDataService.Providers; + +namespace xAiModels.Helpers +{ + public static class XAiModelsHelper + { + // + #region XAiConversation ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + > GetXAiConversationMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + > GetXAiConversationInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiMessage ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + > GetXAiMessageMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + > GetXAiMessageInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiProject ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + > GetXAiProjectMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + > GetXAiProjectInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiConversationTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiConversationTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiDataProvider.cs + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Models.Dtos; + +namespace xAiModels.Interfaces +{ + /// + /// All Data Manipulation Requirements ... + /// + public interface IXAiDataProvider + { + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Creator/Adders ... + /// + /// Create Project ... + /// + /// + /// + /// + /// + /// + Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Create Conversation ... + /// + /// + /// + /// + /// + /// + Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Message ... + /// + /// + /// + /// + /// + /// + Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiProjectDescriptionResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectDescriptionResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\IXAiProjectTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiConversationDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiConversationRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xModels.Dtos; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationRepositoryService : IXBaseRepositoryService + { + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + Task AddAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + Task AddOrUpdateAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + Task UpdateAsync( + Guid id, + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + XAiConversationDto item, + bool softDelete = false, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiConversationServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xAiModels.Providers.Dtos; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiMessageDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiMessageRepositoryService.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageRepositoryService : IXBaseRepositoryService + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiMessageServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xAiModels.Providers.Dtos; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiProjectDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiProjectRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xModels.Dtos; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectRepositoryService : IXBaseRepositoryService + { + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + /// + Task AddAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + /// + Task AddOrUpdateAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + /// + Task UpdateAsync( + Guid id, + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + /// + Task RemoveAsync( + XAiProjectDto item, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + /// + Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + /// + IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Dtos\IXAiProjectServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xAiModels.Providers.Dtos; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Enrichers\IXAiConversationEnricher.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + /// + /// Ai Conversation Enricher ... + /// + public interface IXAiConversationEnricher : IXBaseEnricher + { + /// + /// Converts a Signle Entity to Dto ... + /// + /// + /// + /// + /// + /// + Task EnrichAsync( + XAiConversationDto source, + XAiConversationDto destination, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Converts a Collection of Entities to Dtos ... + /// + /// + /// + /// + /// + /// + Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Enrichers\IXAiMessageEnricher.cs + +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiMessageEnricher : IXBaseEnricher + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Enrichers\IXAiProjectEnricher.cs + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Models.Dtos; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiProjectEnricher : IXBaseEnricher + { + + Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + + Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationEntityHub.cs + +using System; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationKeyGenerator.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationRepository.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationRepositoryEvents.cs + +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationRepositoryProvider.cs + +using System; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiConversationSeeder.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageEntityHub.cs + +using System; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageKeyGenerator.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageRepository.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageRepositoryEvents.cs + +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageRepositoryProvider.cs + +using System; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiMessageSeeder.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectEntityHub.cs + +using System; +using xAiModels.Models.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectGraphQLTypeHelper.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectKeyGenerator.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectRepository.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectRepositoryEvents.cs + +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectRepositoryProvider.cs + +using System; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; +using xPushService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Interfaces\Entities\IXAiProjectSeeder.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.Interfaces; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\XAiModelDescriptor.cs + +using xAiModels.Constants; + +namespace xAiModels.Models +{ + /// + /// Describe a Provided Model ... + /// + public class XAiModelDescriptor + { + /// + /// Provider Name ... + /// + public string Name { get; set; } + + /// + /// LLM Provider Url ... + /// + public string Url { get; set; } + + /// + /// Model Name ... + /// + public string LLM { get; set; } + + /// + /// Api Key for Connection ... + /// + public string ApiKey { get; set; } + + /// + /// Specified Model Provider Type ... + /// + public XAiModelProviderType Provider { get; set; } = XAiModelProviderType.Ollama; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Dtos\XAiConversationDto.cs + +using System; +using System.Collections.Generic; +using xModels.Base; +using xModels.Dtos; + +namespace xAiModels.Models.Dtos +{ + /// + /// Conversation Describe ... + /// + public class XAiConversationDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Conversation Title Resource ID ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Messages ... + /// + public virtual IEnumerable Messages { get; set; } = []; + + /// + /// Project ID ... + /// + public Guid ProjectId { get; set; } + + /// + /// Project Title Resource ID ... + /// + public virtual string ProjectTitle { get; set; } = null; + + /// + /// Project Description Resource ID ... + /// + public virtual string ProjectDescription { get; set; } = null; + + /// + /// Project Title Locale Resources ... + /// + public virtual XResourceDto ProjectTitleResource { get; set; } + + /// + /// Project Description Locale Resources ... + /// + public virtual XResourceDto ProjectDescriptionResource { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Dtos\XAiMessageDto.cs + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using xAiModels.Constants; +using xCommons.Extensions; +using xModels.Base; +using xModels.Dtos; + +namespace xAiModels.Models.Dtos +{ + public class XAiMessageDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Message of Chat ... + /// + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + public Guid ConversationId { get; set; } + + /// + /// Conversation Info ... + /// + public virtual string ConversationTitle { get; set; } = null; + public virtual XResourceDto ConversationTitleResouce { get; set; } = null; + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MeatDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Dtos\XAiProjectDto.cs + +using System; +using System.Collections.Generic; +using xModels.Base; +using xModels.Dtos; + +namespace xAiModels.Models.Dtos +{ + /// + /// Describe a Project ... + /// + public class XAiProjectDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Title of Project ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Description of Project ... + /// + public string Description { get; set; } + + /// + /// All Exists Description Locale Resources ... + /// + public virtual XResourceDto DescriptionResource { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversations ... + /// + public virtual IList Conversations { get; set; } = []; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Entities\XAiConversation.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Conversation Describe ... + /// + public class XAiConversation : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Conversation ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Project ID ... + /// + [Required] + public Guid ProjectId { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Entities\XAiMessage.cs + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using xAiModels.Constants; +using xCommons.Extensions; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Message Model of Ai ... + /// + public class XAiMessage : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Message of Chat ... + /// + [Required] + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + [StringLength(255)] + public Guid ConversationId { get; set; } + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MeatDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Models\Entities\XAiProject.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Describe a Project ... + /// + public class XAiProject : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Project ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Description of Project ... + /// + [StringLength(1000)] + public string Description { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiConversationEntityRegisterar.cs + +using System; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers +{ + public class XAiConversationEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiConversationEntityRegisterar() + : base(nameof(XAiConversationEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiConversationEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiConversationTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Interfaces.Dtos; +using xStringService.Providers; + +namespace xAiModels.Providers +{ + public class XAiConversationTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiConversationTitleResourceProvider + { + public XAiConversationTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiConversationTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiDataProvider.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using MongoDB.Driver.Core.Connections; +using xAiModels.Constants; +using xAiModels.Extensions; +using xAiModels.Interfaces; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Providers.Hubs; +using xCommons.Configurations; +using xCommons.Extensions; +using xExceptions.Constants; +using xModels.Dtos; +using xStringService.Interfaces; + +namespace xAiModels.Providers +{ + /// + /// All Data Manipulation Requirements ... + /// + public class XAiDataProvider : IXAiDataProvider + { + // + #region Properties ... + private readonly IXStringProvider stringProvider; + private readonly XAppConfiguration appConfiguration; + private readonly IHubContext hub; + private readonly IXAiMessageRepositoryService messageRepositoryService; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + #endregion + + public XAiDataProvider( + IXStringProvider stringProvider, + XAppConfiguration appConfiguration, + IHubContext hub, + IXAiMessageRepositoryService messageRepositoryService, + IXAiProjectRepositoryService projectRepositoryService, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationRepositoryService conversationRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + this.hub = hub; + this.stringProvider = stringProvider; + this.appConfiguration = appConfiguration; + this.messageRepositoryService = messageRepositoryService; + this.projectRepositoryService = projectRepositoryService; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationRepositoryService = conversationRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + public async Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Default Project and Conversation ... + bool hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (!hasDefault) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: null, + cancellationToken: cancellationToken + ); + } + + // + // Retrieve Project List ... + var result = await projectRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: fillConversations, + predicate: x => x.OwnerId == ownerId, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + public async Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Conversation's List ... + var result = await conversationRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: false, + fillMessages: fillMessages, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == projectId, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + return result; + } + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + public async Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Message Lists of Specified Conversation ... + var result = await messageRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversationId + ); + + // + return result; + } + #endregion + + // + #region Creator/Adders ... + public async Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Project Provided or not ... + var hasProject = !item.IsNullOrDefault(); + + // + // Normalize Provided Project ... + if (hasProject) + { + // + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiProjectDto result = null; + + // + // Create Provided Project ... + if (hasProject) + { + // + result = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + // + // Check Default Project ... + else + { + // + // Check Default Project Exists or not ... + var hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Project ... + result = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Proejct ... + XAiProjectDto project = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Conversation Provided or not ... + var hasConversation = !item.IsNullOrDefault(); + + // + // Normalize Conversation if Provided ... + if (hasConversation) + { + // + item.ProjectId = project.Id; + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiConversationDto result = null; + + // + // Create Provided Conversation ... + if (hasConversation) + { + // + result = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + fillMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + // + // Check Default Conversation ... + else + { + // + // Check Default Conversation Exists or not ... + var hasDefault = await HasDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Conversation ... + result = await GetDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (item.IsNullOrDefault() || + conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + item.CreatedOn = DateTime.UtcNow; + item.ConversationId = conversationId; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + + // + var result = await messageRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.MessageCreated.GetStringValue() + ); + } + + // + return result; + } + #endregion + + // + #region Updaters ... + #endregion + + // + #region Private ... + /// + /// Check Default Project Exists or not ... + /// + /// + /// + /// + /// + private async Task HasDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Default Owner Exists or not ... + result = !(await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + )) + .IsNullOrDefault(); + return result; + } + + /// + /// Retrieve Default Project of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + private async Task GetDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Default Project Exists or noit ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var result = await projectRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Create Default Project for Specified Owner ... + /// + /// + /// + /// + /// + private async Task CreateDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + if (ownerId.IsNullOrEmpty()) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Check Default Owner Exists or not ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (isExists) + { + return; + } + + // + // Create Default ... + var item = new XAiProjectDto() + { + OwnerId = ownerId, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString(), + Description = Guid.NewGuid().ToString(), + }; + item = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Tile and Description Resource Ids ... + var titleResource = await projectTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + var descriptionResource = await projectDescriptionResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault() || + descriptionResource.IsNullOrDefault() + ) + { + return; + } + + // + // Update Project Resources ... + item.Title = titleResource.Resource; + item.Description = descriptionResource.Resource; + item = await projectRepositoryService.UpdateAsync( + id: item.Id, + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task HasDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiConversationTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiConversationSuffix) + ); + result = !resource.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + result = !(await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => + x.ProjectId == projectId && + x.Title == resource.ResourceTitle + )) + .IsNullOrDefault(); + + // + return result; + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task CreateDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var isValid = !ownerId.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + isValid = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + cancellationToken: cancellationToken + ); + if (isValid) + { + return; + } + + // + // Create Default Conversation ... + var item = new XAiConversationDto + { + OwnerId = ownerId, + ProjectId = project.Id, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString() + }; + item = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Title Resource Ids ... + var titleResource = await conversationTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiConversationSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault()) + { + return; + } + + // + // Update Conversation Resources ... + item.Title = titleResource.Resource; + item = await conversationRepositoryService.UpdateAsync( + item: item, + id: item.Id, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + + /// + /// Retrieve Default Conversation of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + /// + private async Task GetDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Conversation Exists or noit ... + var isExists = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Detect Conversation Resource ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Find Default Conversation ... + var result = await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) && + x.ProjectId == project.Id + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Normalize and Validate Language ... + /// + /// + /// + private string NormalizeAndValidateLanguage(string language) + { + // + if (language.IsNullOrEmpty()) + { + language = appConfiguration.DefaultLanguage; + } + + // + if (language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + return language; + } + + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + public async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Collect Allowed Actions ... + var actions = new List + { + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + }; + + // + // Validate Args ... + var isValid = + !action.IsNullOrEmpty() && + actions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve Connection Id ... + var clients = hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = hub.Clients.AllExcept(connectionId); + } + + // + await clients.SendAsync( + action, + payLoad, + connectionId, + cancellationToken + ); + } + catch { } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiMessageEntityRegisterar.cs + +using System; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers +{ + public class XAiMessageEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiMessageEntityRegisterar() + : base(nameof(XAiMessageEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiMessageEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiProjectDescriptionResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Interfaces.Dtos; +using xStringService.Providers; + +namespace xAiModels.Providers +{ + public class XAiProjectDescriptionResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectDescriptionResourceProvider + { + public XAiProjectDescriptionResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectDescriptionIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiProjectEntityRegisterar.cs + +using System; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; +using xAiModels.Models.Entities; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers +{ + public class XAiProjectEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiProjectEntityRegisterar() + : base(nameof(XAiProjectEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiProjectEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\XAiProjectTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Interfaces.Dtos; +using xStringService.Providers; + +namespace xAiModels.Providers +{ + public class XAiProjectTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectTitleResourceProvider + { + public XAiProjectTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiConversationDtoHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationDtoHub : XBaseDtoHub, IXAiConversationDtoHub + { + public XAiConversationDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiConversationRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; +using xDataService.Providers; +using xModels.Dtos; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationRepositoryService : XBaseRepositoryService, IXAiConversationRepositoryService + { + private readonly IXAiConversationEnricher enricher; + + public XAiConversationRepositoryService( + IXAiConversationEnricher enricher, + IXAiConversationRepository repository + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.enricher = enricher; + } + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + public override async Task AddAsync( + XAiConversationDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddAsync( + item: item, + fillMessages: false, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + public override async Task AddOrUpdateAsync( + XAiConversationDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddOrUpdateAsync( + item: item, + fillMessages: false, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + public override async Task UpdateAsync( + Guid id, + XAiConversationDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await UpdateAsync( + id: id, + item: item, + fillMessages: false, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + Guid id, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + id: id, + fillMessages: false, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + XAiConversationDto item, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + item: item, + fillMessages: false, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAsync( + id: id, + fillMessages: false, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + public override async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAllAsync( + fillMessages: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + public override IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return GetAllAsAsyncEnumerable( + fillMessages: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public override async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindOneAsync( + fillMessages: false, + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public override async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindManyAsync( + fillMessages: false, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + public override async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await QueryAsync( + query: query, + fillMessages: false, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + #endregion + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + public virtual async Task AddAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + public virtual async Task AddOrUpdateAsync( + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task UpdateAsync( + Guid id, + XAiConversationDto item, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + Guid id, + bool softDelete = true, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + XAiConversationDto item, + bool softDelete = true, + bool saveChanges = true, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAsync( + id: id, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAllAsync( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + public virtual async IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + // + var enumerable = base.GetAllAsAsyncEnumerable( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + await foreach (var dto in enumerable) + { + // + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + await enricher.EnrichAsync( + source: dto, + destination: dto, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + yield return dto; + } + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindOneAsync( + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindManyAsync( + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.QueryAsync( + query: query, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result.Items, + destinations: result.Items, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiConversationServiceProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationServiceProvider : XBaseDtoProvider, IXAiConversationServiceProvider + { + public XAiConversationServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiConversationRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiMessageDtoHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageDtoHub : XBaseDtoHub, IXAiMessageDtoHub + { + public XAiMessageDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiMessageRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; +using xDataService.Providers; +using xModels.Dtos; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageRepositoryService : XBaseRepositoryService, IXAiMessageRepositoryService + { + private readonly IXAiMessageEnricher enricher; + + public XAiMessageRepositoryService( + IXAiMessageEnricher enricher, + IXAiMessageRepository repository + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.enricher = enricher; + } + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + public override async Task AddAsync( + XAiMessageDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + public override async Task AddOrUpdateAsync( + XAiMessageDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + public override async Task UpdateAsync( + Guid id, + XAiMessageDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + Guid id, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + XAiMessageDto item, + bool softDelete = true, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAsync( + id: id, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + public override async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAllAsync( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + public override async IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + // + var enumerable = base.GetAllAsAsyncEnumerable( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + await foreach (var dto in enumerable) + { + // + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + await enricher.EnrichAsync( + source: dto, + destination: dto, + cancellationToken: cancellationToken + ); + yield return dto; + } + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public override async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindOneAsync( + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public override async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindManyAsync( + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + public override async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.QueryAsync( + query: query, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result.Items, + destinations: result.Items, + cancellationToken: cancellationToken + ); + } + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiMessageServiceProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageServiceProvider : XBaseDtoProvider, IXAiMessageServiceProvider + { + public XAiMessageServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiMessageRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiProjectDtoHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectDtoHub : XBaseDtoHub, IXAiProjectDtoHub + { + public XAiProjectDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiProjectRepositoryService.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xCommons.Extensions; +using xDataService.Providers; +using xModels.Dtos; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectRepositoryService : XBaseRepositoryService, IXAiProjectRepositoryService + { + public XAiProjectRepositoryService( + IXAiProjectRepository repository + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { } + + + // + #region Actions Base ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + public override async Task AddAsync( + XAiProjectDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddAsync( + item: item, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + public override async Task AddOrUpdateAsync( + XAiProjectDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await AddOrUpdateAsync( + item: item, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + public override async Task UpdateAsync( + Guid id, + XAiProjectDto item, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + public override async Task RemoveAsync( + XAiProjectDto item, + bool softDelete = false, + bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + return await RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + fillConversations: false, + fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + public override async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAsync( + id: id, + fillConversations: false, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + public override async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await GetAllAsync( + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + public override IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return GetAllAsAsyncEnumerable( + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public override async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindOneAsync( + predicate: predicate, + fillConversations: false, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public override async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await FindManyAsync( + predicate: predicate, + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + public override async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + CancellationToken cancellationToken = default + ) + { + return await QueryAsync( + query: query, + predicate: predicate, + fillConversations: false, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + fillConversationMessages: false, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + } + #endregion + #endregion + + // + #region Actions ... + // + #region Add ... + /// + /// add a new Dto ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AddAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// add or update a Dto (add if not exists/update if exists) ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task AddOrUpdateAsync( + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.AddAsync( + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + + // + #region Update ... + /// + /// Update an Dto values ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task UpdateAsync( + Guid id, + XAiProjectDto item, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + + // + #region Remove ... + /// + /// remove an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + Guid id, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// remove an Dto ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task RemoveAsync( + XAiProjectDto item, + bool softDelete = false, + bool saveChanges = true, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.RemoveAsync( + item: item, + softDelete: softDelete, + saveChanges: saveChanges, + cancellationToken: cancellationToken + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + + // + #region Retrieve ... + /// + /// retrieve an Dto by it's Id ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task GetAsync( + Guid id, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAsync( + id: id, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> GetAllAsync( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.GetAllAsync( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// retrieve all exists Dtos + /// as Async Enumerable ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async IAsyncEnumerable GetAllAsAsyncEnumerable( + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + [EnumeratorCancellation] CancellationToken cancellationToken = default + ) + { + // + var enumerable = base.GetAllAsAsyncEnumerable( + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + await foreach (var dto in enumerable) + { + // + if (cancellationToken.IsCancellationRequested) + { + yield break; + } + + // + await enricher.EnrichAsync( + source: dto, + destination: dto, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + yield return dto; + } + } + + /// + /// find an Dto by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task FindOneAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindOneAsync( + predicate: predicate, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichAsync( + source: result, + destination: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// find a collection of Dtos by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> FindManyAsync( + Expression> predicate, + bool ignoreSoftDeleteds = true, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.FindManyAsync( + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result, + destinations: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + + /// + /// retrieve Dtos based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public virtual async Task> QueryAsync( + XQuery query, + bool ignoreSoftDeleteds = true, + Expression> predicate = null, + Func, IOrderedQueryable> orderBuilder = null, + Func, IIncludableQueryable> includeBuilder = null, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + var result = await base.QueryAsync( + query: query, + predicate: predicate, + orderBuilder: orderBuilder, + includeBuilder: includeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + // Do Enrichment if result Exists ... + if (!result.IsNullOrDefault()) + { + // + await enricher.EnrichRangeAsync( + sources: result.Items, + destinations: result.Items, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + } + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Dtos\XAiProjectServiceProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectServiceProvider : XBaseDtoProvider, IXAiProjectServiceProvider + { + public XAiProjectServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiProjectRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Enrichers\XAiConversationEnricher.cs + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using xAiModels.Interfaces; +using xAiModels.Interfaces.Dtos; +using xAiModels.Interfaces.Enrichers; +using xAiModels.Models.Dtos; +using xCommons.Extensions; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xModels.Dtos; +using System.Linq; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiConversationEnricher : IXAiConversationEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiConversationEnricher( + IXIdentityProvider identityProvider, + IXAiProjectRepositoryService projectRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) + { + // + this.identityProvider = identityProvider; + this.projectRepositoryService = projectRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + /// + /// Converts a Signle Entity to Dto ... + /// + /// + /// + /// + /// + public async Task EnrichAsync( + XAiConversationDto source, + XAiConversationDto destination, + CancellationToken cancellationToken = default + ) + { + await EnrichAsync( + source: source, + fillMessages: false, + destination: destination, + cancellationToken: cancellationToken + ); + } + + /// + /// Converts a Collection of Entities to Dtos ... + /// + /// + /// + /// + /// + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + CancellationToken cancellationToken = default + ) + { + await EnrichRangeAsync( + sources: sources, + fillMessages: false, + destinations: destinations, + cancellationToken: cancellationToken + ); + } + + /// + /// Converts a Signle Entity to Dto ... + /// + /// + /// + /// + /// + /// + public async Task EnrichAsync( + XAiConversationDto source, + XAiConversationDto destination, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Run independent async operations concurrently + var ownerTask = ResolveOwnerAsync(source.OwnerId, cancellationToken); + var projectTask = ResolveProjectAsync(source.ProjectId, cancellationToken); + var titleLocalesTask = ResolveTitleLocalesAsync(source.Title, cancellationToken); + var messagesTask = ResolveMessagesAsync(source.Id, cancellationToken); + + // + // wait until All Tasks Resolved ... + Task[] tasks = [ + ownerTask, + projectTask, + titleLocalesTask + ]; + if (fillMessages) + { + tasks = [.. tasks, messagesTask]; + } + await Task.WhenAll(tasks); + + // + // Attached Resolved Info to Destination ... + destination.Owner = ownerTask.Result; + destination.TitleResource = titleLocalesTask.Result; + var project = projectTask.Result; + if (!project.IsNullOrDefault()) + { + destination.ProjectTitle = project.Title; + destination.ProjectDescription = project.Description; + destination.ProjectTitleResource = project.TitleResource; + destination.ProjectDescriptionResource = project.DescriptionResource; + } + if (!messagesTask.Result.IsNull()) + { + destination.Messages = [.. messagesTask.Result]; + } + } + + /// + /// Converts a Collection of Entities to Dtos ... + /// + /// + /// + /// + /// + /// + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillMessages = false, + 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 Title Locales ... + /// + /// + /// + /// + private async Task ResolveTitleLocalesAsync( + string title, + CancellationToken cancellationToken = default + ) + { + // + XResourceDto result = null; + if (title.IsNullOrEmpty()) + { + return result; + } + + // + result = await conversationTitleResourceProvider.GetResource( + owner: null, + identifier: title, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Project ... + /// + /// + /// + /// + private async Task ResolveProjectAsync( + Guid projectId, + CancellationToken cancellationToken = default + ) + { + // + XAiProjectDto result = null; + if (projectId.IsNull() || projectId.IsDefaultGuid()) + { + return result; + } + + // + result = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Specified Conversation Messages ... + /// + /// + /// + /// + private async Task> ResolveMessagesAsync( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + var result = new List(); + + // + if (conversationId.IsDefaultGuid()) + { + return result; + } + + // + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Enrichers\XAiMessageEnricher.cs + +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 + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Enrichers\XAiProjectEnricher.cs + +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 async Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + CancellationToken cancellationToken = default + ) + { + await EnrichAsync( + source: source, + destination: destination, + fillConversations: false, + cancellationToken: cancellationToken + ); + } + + public async Task EnrichAsync( + XAiProjectDto source, + XAiProjectDto destination, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + // Run independent async operations concurrently + var conversationsTask = ResolveConversationsAsync( + source.Id, + fillConversationMessages, + cancellationToken + ); + var titleTask = ResolveTitleAsync(source.Title, cancellationToken); + var ownerTask = ResolveOwnerAsync(source.OwnerId, cancellationToken); + var descriptionTask = ResolveDescriptionAsync(source.Description, cancellationToken); + + // + // wait until All Tasks Resolved ... + Task[] tasks = + { + titleTask, + ownerTask, + descriptionTask + }; + if (fillConversations) + { + tasks = [.. tasks, conversationsTask]; + } + await Task.WhenAll(tasks); + + // + // Attached Resolved Info to Destination ... + destination.Owner = ownerTask.Result; + destination.TitleResource = titleTask.Result; + destination.DescriptionResource = descriptionTask.Result; + if (!conversationsTask.Result.IsNull()) + { + destination.Conversations = [.. conversationsTask.Result]; + } + } + + 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); + } + + public async Task EnrichRangeAsync( + IEnumerable sources, + IEnumerable destinations, + bool fillConversations = true, + bool fillConversationMessages = true, + CancellationToken cancellationToken = default + ) + { + // + // Make Tasks Ready ... + var tasks = sources.Zip(destinations, (src, dst) => + EnrichAsync( + source: src, + destination: dst, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ) + ); + + // + 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; + } + + /// + /// 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( + owner: null, + 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( + owner: null, + identifier: identifier, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Retrieve Project Conversations ... + /// + /// + /// + /// + /// + private async Task> ResolveConversationsAsync( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + List result = []; + + // + // Validate ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + return result; + } + + // + // var items = await conversationRepositoryService.FindManyAsync( + // orderBuilder: null, + // includeBuilder: null, + // ignoreSoftDeleteds: true, + // fillMessages: fillMessages, + // predicate: x => x.Id == projectId, + // cancellationToken: cancellationToken + // ); + // result = [.. items]; + + // + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationEFRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEFRepository : XBaseEFRepository, IXAiConversationRepository + where TContext : XDbContext + { + public XAiConversationEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationEntityHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEntityHub : XBaseEntityHub, IXAiConversationEntityHub + { + public XAiConversationEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationInMemoryRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationInMemoryRepository : XBaseInMemoryRepository, IXAiConversationRepository + { + public XAiConversationInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationKeyGenerator.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationKeyGenerator : XGuidKeyGenerator, IXAiConversationKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationMongoRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationMongoRepository : XBaseMongoRepository, IXAiConversationRepository + { + public XAiConversationMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationRepositoryEvents.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryEvents : XBaseRepositoryEvents, IXAiConversationRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationRepositoryProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryProvider : XBaseEntityProvider, IXAiConversationRepositoryProvider + { + public XAiConversationRepositoryProvider( + IHubContext hub, + IXAiConversationRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiConversationSeederBase.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiConversationSeederBase : XBaseDbSeeder, IXAiConversationSeeder + { + protected XAiConversationSeederBase( + string entity, + string database, + IXAiConversationRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageEFRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEFRepository : XBaseEFRepository, IXAiMessageRepository + where TContext : XDbContext + { + public XAiMessageEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageEntityHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEntityHub : XBaseEntityHub, IXAiMessageEntityHub + { + public XAiMessageEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageInMemoryRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageInMemoryRepository : XBaseInMemoryRepository, IXAiMessageRepository + { + public XAiMessageInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageKeyGenerator.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageKeyGenerator : XGuidKeyGenerator, IXAiMessageKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageMongoRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageMongoRepository : XBaseMongoRepository, IXAiMessageRepository + { + public XAiMessageMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageRepositoryEvents.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryEvents : XBaseRepositoryEvents, IXAiMessageRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageRepositoryProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryProvider : XBaseEntityProvider, IXAiMessageRepositoryProvider + { + public XAiMessageRepositoryProvider( + IHubContext hub, + IXAiMessageRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiMessageSeederBase.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiMessageSeederBase : XBaseDbSeeder, IXAiMessageSeeder + { + protected XAiMessageSeederBase( + string entity, + string database, + IXAiMessageRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectEFRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Db; +using xDataService.Interfaces; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEFRepository : XBaseEFRepository, IXAiProjectRepository + where TContext : XDbContext + { + public XAiProjectEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectEntityHub.cs + +using System; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEntityHub : XBaseEntityHub, IXAiProjectEntityHub + { + public XAiProjectEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectInMemoryRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectInMemoryRepository : XBaseInMemoryRepository, IXAiProjectRepository + { + public XAiProjectInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectKeyGenerator.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectKeyGenerator : XGuidKeyGenerator, IXAiProjectKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectMongoRepository.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectMongoRepository : XBaseMongoRepository, IXAiProjectRepository + { + public XAiProjectMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectRepositoryEvents.cs + +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryEvents : XBaseRepositoryEvents, IXAiProjectRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectRepositoryProvider.cs + +using System; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using xPushService.Base; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryProvider : XBaseEntityProvider, IXAiProjectRepositoryProvider + { + public XAiProjectRepositoryProvider( + IHubContext hub, + IXAiProjectRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Entities\XAiProjectSeederBase.cs + +using System; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.Providers; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiProjectSeederBase : XBaseDbSeeder, IXAiProjectSeeder + { + protected XAiProjectSeederBase( + string entity, + string database, + IXAiProjectRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiConversationGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiConversationCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiConversationSignleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphQuery.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQuery : XBaseGraphQLQuery + { + public XAiConversationGraphQuery( + XDataServiceConfiguration configuration, + IXAiConversationRepository repository, + IXAiConversationGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphSchema : Schema + { + public XAiConversationGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiConversationGraphQuery)services.GetService(typeof(XAiConversationGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiConversationGraphType.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphType : XBaseGraphObjectType + { + public XAiConversationGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ProjectId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiMessageGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiMessageCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiMessageSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphQuery.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQuery : XBaseGraphQLQuery + { + public XAiMessageGraphQuery( + XDataServiceConfiguration configuration, + IXAiMessageRepository repository, + IXAiMessageGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphSchema : Schema + { + public XAiMessageGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiMessageGraphQuery)services.GetService(typeof(XAiMessageGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiMessageGraphType.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphType: XBaseGraphObjectType + { + public XAiMessageGraphType() : base() + { + Field(x => x.Role); + Field(x => x.OwnerId); + Field(x => x.Content); + Field(x => x.Metadata); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ConversationId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiProjectGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiProjectCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiProjectSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphQuery.cs + +using System; +using GraphQL.Types; +using xAiModels.Interfaces.Entities; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQuery : XBaseGraphQLQuery + { + public XAiProjectGraphQuery( + XDataServiceConfiguration configuration, + IXAiProjectRepository repository, + IXAiProjectGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphSchema : Schema + { + public XAiProjectGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiProjectGraphQuery)services.GetService(typeof(XAiProjectGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\GraphQL\XAiProjectGraphType.cs + +using System; +using xAiModels.Models.Entities; +using xDataService.GraphQL; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphType : XBaseGraphObjectType + { + public XAiProjectGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.Prompt); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.Description); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiModelsBkp\xAiModels\Providers\Hubs\XAiDataProviderHub.cs + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using xAiModels.Constants; +using xAiModels.Models.Dtos; +using xCommons.Extensions; +using xPushService.Base; + +namespace xAiModels.Providers.Hubs +{ + public class XAiDataProviderHub : XBaseHub + { + public XAiDataProviderHub( + ILogger logger + ) : base(logger) + { } + + // + #region XAiProject ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ProjectCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ProjectRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ProjectUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiConversation ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ConversationCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ConversationRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ConversationUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiMessage ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task MessageCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task MessageRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task MessageUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Configurations\XAIServiceConfiguration.cs + +namespace xAiService.Configurations +{ + public partial class XAIServiceConfiguration + { + public string Url { get; set; } + public string XPoweredValue { get; set; } + public int DefaultClientTimeout { get; set; } = 360; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Constants\ConfigurationNodeNames.cs + +namespace xAiService.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_SERVICE_NODE = "AIServiceConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Constants\XAiApiConstants.cs + +namespace xAiService.Constants +{ + public struct XAiApiQueryParams + { + public const string Prompt = "prompt"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Constants\XAiApiEndpoint.cs + +using xExceptions.Attributes; + +namespace xAiService.Constants +{ + public enum XAiApiEndpoint + { + [StringValue("AskAI")] + Ask, + [StringValue("AskAIStream")] + Stream, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\DI\XDIHelperExtension.cs + +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using xAiService.Configurations; +using xAiService.Constants; +using xAiService.Extensions; +using xAiService.Interfaces; +using xAiService.Services; +using xCommons.Extensions; +using xExceptions.Constants; + +namespace xAiService.DI +{ + public static partial class XDIHelperExtension + { + /// + /// Extract AI Service Configuration ... + /// + /// + /// + public static XAIServiceConfiguration GetXAIServiceConfiguration(this IConfiguration source) + { + // + XAIServiceConfiguration result = null; + + // + var section = source.GetSection(ConfigurationNodeNames.AI_SERVICE_NODE); + if (!section.IsNull()) + { + result = section.Get(); + } + + // + return result; + } + + /// + /// Add AI Service Configuration ... + /// + /// + /// + public static void AddXAIServiceConfiguration( + this IServiceCollection source, + XAIServiceConfiguration configuration + ) + { + source.AddSingleton(configuration); + } + + /// + /// Adding XAiService ... + /// + /// + /// + /// + public static void AddXAIService( + this IServiceCollection services, + IConfiguration configuration, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var config = configuration.GetXAIServiceConfiguration(); + AddAIService( + services, + config, + lifeTime + ); + } + + /// + /// Adding XAiService ... + /// + /// + /// + /// + public static void AddXAIService( + this IServiceCollection services, + XAIServiceConfiguration configuration, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + AddAIService( + services, + configuration, + lifeTime + ); + } + + // + #region Private ... + /// + /// a LogTag for Service ... + /// + private static string XLogTag = "XFileService"; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Adding Ai Service ... + /// + /// + /// + /// + private static void AddAIService( + this IServiceCollection services, + XAIServiceConfiguration configuration, + ServiceLifetime lifeTime = ServiceLifetime.Singleton + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("AddAIService failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("AddAIService failed, lifetime not provided ..."); + throw exception; + } + + // + // Check Dependencies Exists ... + var isDependenciesPassed = true; + if (!isDependenciesPassed) + { + // + Log("AddAIService failed due Dependencies Issues, not provided ..."); + throw exception; + } + + // + // Validate Configurations ... + var isConfigurationExists = + !configuration.IsNull() && + configuration.IsValid(); + if (!isConfigurationExists) + { + // + Log("AddAIService failed due InValid Service Configuration or not provided ..."); + throw exception; + } + + // + // Register Configurations ... + services.AddXAIServiceConfiguration(configuration); + + // + // Register Services ... + services.Add(new ServiceDescriptor(typeof(IXAiService), typeof(XAiService), lifeTime)); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Extensions\ConfigurationExtensions.cs + +using xAiService.Configurations; +using xCommons.Extensions; + +namespace xAiService.Extensions +{ + public static class ModelExtensions + { + /// + /// Validate XAiServiceConfiguration ... + /// + /// + /// + public static bool IsValid(this XAIServiceConfiguration source) + { + // + bool result = + !source.IsNull() && + !source.Url.IsNullOrEmpty() && + source.Url.IsValidUrl(); + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Extensions\PromptExtensions.cs + +using System.Collections.Generic; +using System.Linq; +using xAiService.Models.Dtos; +using xCommons.Extensions; + +namespace xAiService.Extensions +{ + public static class PromptExtensions + { + /// + /// Get Template Params Filled Prompt ... + /// + /// + /// + /// + public static string GetMessage( + this XPromptDto source, + IDictionary @params = null + ) + { + // + var result = string.Empty; + + // + if (!source.IsNullOrDefault() && + !source.Prompt.IsNullOrEmpty() + ) + { + result = source.Prompt; + } + + // + // Check Params Conditions ... + if (!source.Params.IsNullOrDefault() && + source.Params.HasChild() && + !@params.IsNullOrDefault() && + @params.HasChild() + ) + { + // + // Select Params ... + var existsParams = source.Params + .Where(p => @params.Any(pr => pr.Key == p.Name)) + .Distinct() + .ToList(); + + // + // Replace Selected Params ... + existsParams + .ForEach(pk => + { + result = result.Replace(pk.Param, @params[pk.Name]); + }); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Helpers\VectorHelper.cs + +using System; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class VectorHelper + { + /// + /// Normalize a Vector ... + /// + /// + public static void Normalize(float[] vector) + { + // + // Validate ... + if (vector.IsNull() || !vector.HasChild()) + { + return; + } + + // + float sum = 0f; + foreach (var value in vector) + { + sum += value * value; + } + + // + float norm = MathF.Sqrt(sum); + if (norm <= 1e-9f) + { + return; + } + + // + for (int i = 0; i < vector.Length; i++) + { + vector[i] /= norm; + } + } + + /// + /// Similarity Check ... + /// + /// + /// + /// + public static float CosineSimilarity(float[] a, float[] b) + { + // + if (a.IsNull() || b.IsNull()) + { + return 0f; + } + + // + if (a.Length != b.Length) + { + return 0f; + } + + // + float dot = 0f; + float normA = 0f; + float normB = 0f; + for (int i = 0; i < a.Length; i++) + { + // + dot += a[i] * b[i]; + normA += a[i] * a[i]; + normB += b[i] * b[i]; + } + + // + float denominator = MathF.Sqrt(normA) * MathF.Sqrt(normB); + if (denominator <= 1e-9f) + { + return 0f; + } + + // + var result = dot / denominator; + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Helpers\XPromptHelper.cs + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using xAiService.Models.Dtos; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class XPromptHelper + { + /// + /// Holds Initialized Prompts ... + /// + private static XPromptsDto prompts; + + /// + /// Initialize Prompt Helper ... + /// + /// + /// + /// + public static void Initialize(string path = "prompts.json") + { + // + // Create full Path and Check File Exists ... + var fullPath = Path.Combine(AppContext.BaseDirectory, path); + if (!File.Exists(fullPath)) + { + throw new Exception($"Prompts Resources not found: {fullPath}"); + } + + // + // Read File as Json Text ... + var json = File.ReadAllText(fullPath); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip, + Converters = + { + new JsonStringEnumConverter( + namingPolicy: null, + allowIntegerValues: false + ) + } + }; + + // + // Serialized Root Object ... + var root = JsonSerializer.Deserialize(json, options); + if (!root.IsNullOrDefault()) + { + prompts = new XPromptsDto { Prompts = root.Prompts }; + } + } + + /// + /// Retrieve all Allowed Prompts as Enumerable ... + /// + /// + public static IEnumerable GetPrompts() + { + return prompts!.Prompts.AsEnumerable(); + } + + /// + /// Get Specified Prompt ... + /// + /// + /// + /// + public static XPromptDto GetPrompt(string name) + { + // + return GetPrompts() + .FirstOrDefault(p => p.Name == name); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Interfaces\IXAiService.cs + +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using xAiService.Configurations; +using xIdentityModels.Models; +using xIdentityService.Interfaces; + +namespace xAiService.Interfaces +{ + public interface IXAiService : IXBaseIdentityHttpProvider + { + /// + /// XAiService Configurations ... + /// + /// + XAIServiceConfiguration Configuration { get; } + + // + #region Text Actions ... + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public Task GetResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ); + + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public Task GetTextResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ); + + /// + /// Generate Text Response Stream ... + /// + /// + /// + /// + /// + Task GetTextReponseStreamAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Interfaces\IXAiServiceControllerBase.cs + +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; + +namespace xAiService.Interfaces +{ + public interface IXAiServiceControllerBase + { + Task> Ask( + [FromQuery] string prompt, + CancellationToken cancellationToken = default + ); + + Task AskStream( + [FromQuery] string prompt, + CancellationToken cancellationToken = default + ); + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Models\Dtos\XPromptsDto.cs + +namespace xAiService.Models.Dtos +{ + /// + /// Described Prompts in app ... + /// + public class XPromptsDto + { + public XPromptDto[] Prompts { get; set; } = []; + } + + /// + /// a Single Prompt Description ... + /// + public class XPromptDto + { + /// + /// Prompt Name ... + /// + public string Name { get; set; } + + /// + /// Prompt Template Message ... + /// + public string Prompt { get; set; } + + /// + /// Prompt Description ... + /// + public string Description { get; set; } + + /// + /// Describe Prompt Params ... + /// + public virtual XPromptParamDto[] Params { get; set; } = null; + } + + /// + /// Prompt Param used to Fill dynamic Datas to Specified Prompts ... + /// + public class XPromptParamDto + { + /// + /// Param Name ... + /// + public string Name { get; set; } + + /// + /// Parma Identifier ... + /// + public string Param { get; set; } + + /// + /// Param Description ... + /// + public string Description { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Documents\Temp\AiServicceBkp\Services\XAiService.cs + +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.Logging; +using xAiService.Configurations; +using xAiService.Constants; +using xAiService.Interfaces; +using xCommons.Providers; +using xHttpService.Constants; +using xIdentityModels.Models; +using xIdentityService.Interfaces; +using xIdentityService.Providers; + +namespace xAiService.Services +{ + public class XAiService : XBaseIdentityHttpProvider, IXAiService + { + /// + /// XAiService Configurations ... + /// + /// + public XAIServiceConfiguration Configuration { get; } + + public XAiService( + ILogger logger, + IXTokenProvider tokenProvider, + IXIdentityProvider identityProvider, + XAIServiceConfiguration configuration, + XValidationProvider validationProvider + ) : base( + configuration.Url, + logger, + configuration.XPoweredValue, + configuration.DefaultClientTimeout, + tokenProvider, + identityProvider, + validationProvider + ) + { } + + // + #region Text Actions ... + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public Task GetResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ) + { + throw new System.NotImplementedException(); + } + + /// + /// Generated Response ... + /// + /// + /// + /// + /// + public async Task GetTextResponseAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + ValidationProvider.NotEmpty(prompt); + + // + var client = GetRestClient(userInfo); + var request = GetRestRequet( + endpoint: XAiApiEndpoint.Ask, + addXPoweredValue: true, + queryStrings: new Dictionary + { + { XAiApiQueryParams.Prompt, prompt } + } + ); + + // + var response = await RunRestRequest( + client, + request, + XHttpMethod.GET, + cancellationToken: cancellationToken + ); + + // + return response; + } + + /// + /// Generate Text Response Stream ... + /// + /// + /// + /// + /// + public async Task GetTextReponseStreamAsync( + string prompt, + XUserClaimsInfoDto userInfo, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + ValidationProvider + .GroupValidationBuilder() + .AddNotEmpty(prompt) + .AddNotNull(userInfo) + .AddNotZero(userInfo.ExpiresAt) + .AddNotEmpty(userInfo.AccessToken) + .AddNotEmpty(userInfo.RefreshToken) + .ValidateGroup(); + + // + var tokens = ToTokenResponse(userInfo); + var result = await StreamData( + tokens: tokens, + addXPoweredValue: true, + endpoint: XAiApiEndpoint.Stream, + cancellationToken: cancellationToken, + queryStrings: new Dictionary + { + { XAiApiQueryParams.Prompt, prompt } + } + ); + + // + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\XAiApiConfiguration.cs + +using xAiModels.Models; +using xAiModels.Constants; + +namespace xAiModels.Configurations +{ + public class XAiApiConfiguration + { + /// + /// Model Providers ... + /// + public XAiModelDescriptor[] Models { get; set; } = []; + + /// + /// Each User must Has a Default Project, this is Title Resource Identifier ... + /// + public string DefaultProjectTitleResource { get; set; } = XAiModelsConstants.DefaultXAiProjectTitleResourceID; + + /// + /// Each User must Has a Default Project, this is Description Resource Identifier ... + /// + public string DefaultProjectDescriptionResource { get; set; } = XAiModelsConstants.DefaultXAiProjectDescriptionResourceID; + + /// + /// Each User must Has a Default Conversation, this is Title Resource Identifier ... ... + /// + public string DefaultConversationTitleResource { get; set; } = XAiModelsConstants.DefaultXAiConversationTitleResourceID; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\XAiModelMappersProfile.cs + +using AutoMapper; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Configurations +{ + public class XAiModelMappersProfile : Profile + { + public XAiModelMappersProfile() + { + // + // XAiMessage ... + CreateMap(); + + // + // XAiProject ... + CreateMap(); + + // + // XAiConversation ... + CreateMap(); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiConversationEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiConversationEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiConversationTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiMessageEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiMessageEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiMessageTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Configurations\Entities\XAiProjectEntityConfiguration.cs + +using System; +using xAiModels.Constants; +using xDataService.Providers; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace xAiModels.Configurations.Entities +{ + public class XAiProjectEntityConfiguration : XBaseEntityTypeConfiguration + { + public override void Configure(EntityTypeBuilder builder) + { + builder.ToTable(XAiModelsConstants.XAiProjectTable); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\ConfigurationNodeNames.cs + +namespace xAiModels.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiApiConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiChatRole.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiChatRoles + { + public const string None = "none"; + public const string User = "user"; + public const string Tool = "tool"; + public const string System = "system"; + public const string Assistant = "assistant"; + } + + public enum XAiChatRole + { + [StringValue(XAiChatRoles.None)] + None, + [StringValue(XAiChatRoles.User)] + User, + [StringValue(XAiChatRoles.Tool)] + Tool, + [StringValue(XAiChatRoles.System)] + System, + [StringValue(XAiChatRoles.Assistant)] + Assistant, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiDataProviderConstants.cs + +using xExceptions.Attributes; + +namespace xAiModels.Constants +{ + public struct XAiDataProviderConstants + { + public const string XDefaultAiProjectSuffix = "DefAiPrj"; + public const string XDefaultAiConversationSuffix = "DefAiCnv"; + } + + public enum XAiDataProviderHubActions + { + // + // Project ... + [StringValue("ProjectCreated")] + ProjectCreated, + + [StringValue("ProjectUpdated")] + ProjectUpdated, + + [StringValue("ProjectRemoved")] + ProjectRemoved, + + // + // Conversation ... + [StringValue("ConversationCreated")] + ConversationCreated, + + [StringValue("ConversationUpdated")] + ConversationUpdated, + + [StringValue("ConversationRemoved")] + ConversationRemoved, + + // + // Message ... + [StringValue("MessageCreated")] + MessageCreated, + + [StringValue("MessageUpdated")] + MessageUpdated, + + [StringValue("MessageRemoved")] + MessageRemoved, + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiModelProviderType.cs + +namespace xAiModels.Constants +{ + /// + /// Specifiy Provider Type ... + /// + public enum XAiModelProviderType + { + None, + OpenAI, + Ollama, + DeepSeek, + HuggingFace + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Constants\XAiModelsConstants.cs + +namespace xAiModels.Constants +{ + public struct XAiModelsConstants + { + // + // Service Extensions Log Tag ... + public const string XAiModelsDILogTag = "XAiModels"; + + // + // Table Mapping Identifiers ... + public const string XAiMessageTable = "AiMessages"; + public const string XAiProjectTable = "AiProjects"; + public const string XAiConversationTable = "AiConversations"; + + // + // GraphQL Collection Mappings ... + public const string XAiMessageSingleName = "aiMessage"; + public const string XAiProjectSingleName = "aiProject"; + public const string XAiConversationSignleName = "aiConversation"; + + public const string XAiMessageCollectionName = "aiMessages"; + public const string XAiProjectCollectionName = "AiProjectsa"; + public const string XAiConversationCollectionName = "aiConversations"; + + // + // Hubs ... + public const string XAiMessageDtoHub = "aiMessageDto"; + public const string XAiMessageEntityHub = "aiMessageEntity"; + + public const string XAiProjectDtoHub = "aiProjectDto"; + public const string XAiProjectEntityHub = "aiProjectEntity"; + + public const string XAiConversationDtoHub = "aiConversationDto"; + public const string XAiConversationEntityHub = "aiConversationEntity"; + + // + // Resource Provider Identifiers ... + public const string XAiProjectTitleIdentifier = "AiPrjT"; + public const string XAiProjectDescriptionIdentifier = "AiPrjD"; + public const string XAiConversationTitleIdentifier = "AiCnvrT"; + + // + // EF Repositories Helper Extensions ... + public const string GetXAiMessageEFRepositoryDescriptor = "GetXAiMessageEFRepositoryDescriptor"; + public const string GetXAiProjectEFRepositoryDescriptor = "GetXAiProjectEFRepositoryDescriptor"; + public const string GetXAiConversationEFRepositoryDescriptor = "GetXAiConversationEFRepositoryDescriptor"; + + // + public const string DefaultXAiProjectTitleResourceID = "XAiPrjT"; + public const string DefaultXAiConversationTitleResourceID = "XAiCnvT"; + public const string DefaultXAiProjectDescriptionResourceID = "XAiPrjD"; + + // + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\DI\XDIHelperExtension.cs + +using System; +using xDataService.Db; +using xPushService.DI; +using xDataService.DI; +using xCommons.Helpers; +using xAiModels.Helpers; +using xDataService.Models; +using xAiModels.Providers; +using xAiModels.Constants; +using xCommons.Extensions; +using xPushService.Helpers; +using xAiModels.Interfaces; +using xExceptions.Constants; +using xDataService.Constants; +using xAiModels.Providers.Dtos; +using xAiModels.Interfaces.Dtos; +using Microsoft.AspNetCore.Builder; +using xAiModels.Providers.Entities; +using xAiModels.Interfaces.Entities; +using xAiModels.Providers.Enrichers; +using xAiModels.Interfaces.Enrichers; +using Microsoft.Extensions.DependencyInjection; + +namespace xAiModels.DI +{ + /// + /// Service Registration Extensions Classes ... + /// + public static class XDIHelperExtension + { + /// + /// Register Service ... + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + AddAiDataService( + contextType: null, + services: services, + lifeTime: lifeTime, + repositoryType: repositoryType + ); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + public static void AddXAiDataService( + this IServiceCollection services, + XRepositoryType repositoryType, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + where TContext : XDbContext + { + AddAiDataService( + services: services, + lifeTime: lifeTime, + contextType: typeof(TContext), + repositoryType: repositoryType + ); + } + + /// + /// Use XSubCategoryService Middleware ... + /// + /// + /// + public static void UseXAiDataService( + this IApplicationBuilder app, + bool isDevelopmentEnvironment = false + ) + { + // + #region Using Hubs ... + // + var pushHelper = new XPushServiceHelper(); + + // + // XAiMessage ... + pushHelper.AddHub(XAiModelsConstants.XAiMessageDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiMessageEntityHub); + + // + // XAiProject ... + pushHelper.AddHub(XAiModelsConstants.XAiProjectDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiProjectEntityHub); + + // + // XAiConversation ... + pushHelper.AddHub(XAiModelsConstants.XAiConversationDtoHub); + pushHelper.AddHub(XAiModelsConstants.XAiConversationEntityHub); + + // + app.UseXPushService(pushHelper); + #endregion + + // + // Using XAiConversation Repository Descriptor ... + if (!aiConversationDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiConversationDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiMessage Repository Descriptor ... + if (!aiMessageDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiMessageDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Using XAiProject Repository Descriptor ... + if (!aiProjectDescriptor.IsNull()) + { + // + app.UseXRepository( + descriptor: aiProjectDescriptor, + isDevelopmentEnvironment: isDevelopmentEnvironment + ); + } + + // + // Create an Scope for Services Acces ... + // Handle Seeding Category/SubCategory Resources ... + // TODO: Enable Seeding if Required ... + // using (var scope = app.ApplicationServices.CreateScope()) + // { + // // + // // Retrieve Configuratuions ... + // var aiMessageProvider = scope.ServiceProvider.GetService(); + // var aiProjectProvider = scope.ServiceProvider.GetService(); + // var aiConversationProvider = scope.ServiceProvider.GetService(); + // var configuration = scope.ServiceProvider.GetService(); + // if (!configuration.IsNullOrDefault() && + // !categoryProvider.IsNullOrDefault() && + // !subaiConversationDescriptor.IsNullOrDefault() + // ) + // { + // // + // // Logging ... + // Log("Start Seeding ..."); + + // // + // // Count Data in Category ... + // var hasCategory = (categoryProvider.Count().GetAwaiter().GetResult()) > 0; + // var hasSubCategory = (subCategoryProvider.Count().GetAwaiter().GetResult()) > 0; + + // // + // // Seed Category Resources ... + // var canSeed = + // !hasCategory && + // configuration.Categories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var cat in configuration.Categories) + // { + // // + // try + // { + // // + // Log($"Start Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // categoryProvider.Refresh( + // resource: cat, + // userInfo: null, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding Category: {cat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // // Seed SubCategory Resources ... + // canSeed = + // !hasSubCategory && + // configuration.SubCategories.HasChild(); + // if (canSeed) + // { + // // + // // Loop through Provided items ... + // foreach (var subcat in configuration.SubCategories) + // { + // // + // try + // { + // // + // Log($"Start Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} ..."); + + // // + // subCategoryProvider.Refresh( + // userInfo: null, + // resource: subcat, + // connectionId: null, + // cancellationToken: default + // ) + // .GetAwaiter() + // .GetResult(); + + // // + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Finished Successfully ..."); + // } + // catch (Exception ex) + // { + // Log($"Seeding SubCategory: {subcat.Titles.Locales.ToArray()[0].Value} Failed due: {ex.Message} ..."); + // } + // } + // } + + // // + // Log("Finish Seeding ..."); + // } + // } + } + + // + #region Private ... + private static XRepositoryDescriptor aiMessageDescriptor = null; + private static XRepositoryDescriptor aiProjectDescriptor = null; + private static XRepositoryDescriptor aiConversationDescriptor = null; + + /// + /// a LogTag for Service ... + /// + private static string XLogTag = XAiModelsConstants.XAiModelsDILogTag; + + /// + /// print a log in Console ... + /// + /// + private static void Log(string message) + { + Console.WriteLine($"{XLogTag} => {message}"); + } + + /// + /// Register Service ... + /// + /// + /// + /// + /// + private static void AddAiDataService( + IServiceCollection services, + XRepositoryType repositoryType, + Type contextType = null, + ServiceLifetime lifeTime = ServiceLifetime.Scoped + ) + { + // + var exception = XException.InvalidArgs.ToException(); ; + + // + // Services ... + var isServicesExists = !services.IsNull(); + if (!isServicesExists) + { + // + Log("Service Registration failed, services not provided ..."); + throw exception; + } + + // + // Lifetime ... + var isLifetimeExists = !lifeTime.IsNull(); + if (!isLifetimeExists) + { + // + Log("Service Registration failed, lifetime not provided ..."); + throw exception; + } + + // + // Validate Repository Type ... + var isRepositoryTypeValid = + (repositoryType == XRepositoryType.EF && + !contextType.IsNull()) || + ((repositoryType == XRepositoryType.Mongo || + repositoryType == XRepositoryType.InMemory) && + contextType.IsNull()); + if (!isRepositoryTypeValid) + { + // + Log("Service Registration failed, Invalid Repository Type and Context Type ..."); + throw exception; + } + + // + // Maske Instance of Repository Descriptor + // Based on Provided Type ... + switch (repositoryType) + { + // + case XRepositoryType.EF: + // + // XAiMessage ... + aiMessageDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiMessageEFRepositoryDescriptor + ); + + // + // XAiProject ... + aiProjectDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiProjectEFRepositoryDescriptor + ); + + // + // XAiConversation ... + aiConversationDescriptor = typeof(XAiModelsHelper) + .InvokeGenericMethod( + args: null, + runtimeType: contextType, + methodName: XAiModelsConstants.GetXAiConversationEFRepositoryDescriptor + ); + break; + + // + case XRepositoryType.Mongo: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageMongoRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectMongoRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationMongoRepositoryDescriptor(); + break; + + // + case XRepositoryType.InMemory: + // + // XAiMessage ... + aiMessageDescriptor = XAiModelsHelper.GetXAiMessageInMemoryRepositoryDescriptor(); + + // + // XAiProject ... + aiProjectDescriptor = XAiModelsHelper.GetXAiProjectInMemoryRepositoryDescriptor(); + + // + // XAiConversation ... + aiConversationDescriptor = XAiModelsHelper.GetXAiConversationInMemoryRepositoryDescriptor(); + break; + } + + // + #region Register Repository Descriptor ... + // + // XAiMessage ... + if (!aiMessageDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiMessageDescriptor + ); + } + + // + // XAiProject ... + if (!aiProjectDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiProjectDescriptor + ); + } + + // + // XAiConversation ... + if (!aiConversationDescriptor.IsNull()) + { + // + services.AddXRepository( + lifeTime: lifeTime, + descriptor: aiConversationDescriptor + ); + } + #endregion + + // + #region Register Services ... + // + #region AiMessage ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiMessageServiceProvider), typeof(XAiMessageServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryService), typeof(XAiMessageRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiMessageRepositoryProvider), typeof(XAiMessageRepositoryProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiMessageEnricher), typeof(XAiMessageEnricher), lifeTime) + ); + #endregion + + // + #region AiProject ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiProjectServiceProvider), typeof(XAiProjectServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryService), typeof(XAiProjectRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectRepositoryProvider), typeof(XAiProjectRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectTitleResourceProvider), typeof(XAiProjectTitleResourceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiProjectDescriptionResourceProvider), typeof(XAiProjectDescriptionResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiProjectEnricher), typeof(XAiProjectEnricher), lifeTime) + ); + #endregion + + // + #region AiConversation ... + // + services.Add( + new ServiceDescriptor(typeof(IXAiConversationServiceProvider), typeof(XAiConversationServiceProvider), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryService), typeof(XAiConversationRepositoryService), lifeTime) + ); + services.Add( + new ServiceDescriptor(typeof(IXAiConversationRepositoryProvider), typeof(XAiConversationRepositoryProvider), lifeTime) + ); + + // + // Resource Providers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationTitleResourceProvider), typeof(XAiConversationTitleResourceProvider), lifeTime) + ); + + // + // Enrichers ... + services.Add( + new ServiceDescriptor(typeof(IXAiConversationEnricher), typeof(XAiConversationEnricher), lifeTime) + ); + #endregion + #endregion + + // + // Data Provider ... + services.Add( + new ServiceDescriptor(typeof(IXAiDataProvider), typeof(XAiDataProvider), lifeTime) + ); + + // + Log("Service Regitration Succeed ..."); + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\ChatResponseExtensions.cs + +using xCommons.Extensions; +using Microsoft.Extensions.AI; + +namespace xAiModels.Extensions +{ + public static class ChatResponseExtensions + { + /// + /// Validate a Chat Response ... + /// + /// + /// + public static bool IsValid(this ChatResponse source) + { + // + var result = + source is not null && + !source.IsNullOrDefault() && + !string.IsNullOrWhiteSpace(source.Text) && + source.FinishReason == ChatFinishReason.Stop; + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\ChatRoleExtensions.cs + +using xAiModels.Constants; +using xCommons.Extensions; +using Microsoft.Extensions.AI; + +namespace xAiModels.Extensions +{ + /// + /// Extensions for ChatRole ... + /// + public static class ChatRoleExtensions + { + /// + /// Normalize an String to Propper Chat Role Value ... + /// > + /// + /// + /// + public static string GetChatRoleTitle(this string source) + { + // + var result = XAiChatRoles.None; + + // + if (source.ToNormalString() == XAiChatRoles.None.ToNormalString()) + { + result = XAiChatRoles.None; + } + else if (source.ToNormalString() == XAiChatRoles.User.ToNormalString()) + { + result = XAiChatRoles.User; + } + else if (source.ToNormalString() == XAiChatRoles.Tool.ToNormalString()) + { + result = XAiChatRoles.Tool; + } + else if (source.ToNormalString() == XAiChatRoles.System.ToNormalString()) + { + result = XAiChatRoles.System; + } + else if (source.ToNormalString() == XAiChatRoles.Assistant.ToNormalString()) + { + result = XAiChatRoles.Assistant; + } + + // + return result; + } + + /// + /// Get Chat Role Title from Chat Role Class ... + /// + /// + /// + /// + public static string GetRole(this ChatRole source) + { + // + var result = source.Value + .GetChatRoleTitle(); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this string source) + { + // + var role = source.GetChatRoleTitle(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Generate Chat Role Class Based on role Title ... + /// + /// + /// + public static ChatRole ToChatRole(this XAiChatRole source) + { + // + var role = source.GetStringValue(); + ChatRole result = new ChatRole(role); + + // + return result; + } + + /// + /// Extract Chat Role Enum from Chat Role ... + /// + /// + /// + /// + /// + public static XAiChatRole ToChatRole(this ChatRole source) + { + // + var role = source + .GetRole() + .GetChatRoleTitle(); + + // + XAiChatRole result = XAiChatRole.User; + + // + if (role == XAiChatRoles.User) + { + result = XAiChatRole.User; + } + else if (role == XAiChatRoles.Tool) + { + result = XAiChatRole.Tool; + } + else if (role == XAiChatRoles.System) + { + result = XAiChatRole.System; + } + else if (role == XAiChatRoles.Assistant) + { + result = XAiChatRole.Assistant; + } + + // + return result; + } + + /// + /// Validate an String as Chat Role ... + /// + /// + /// + public static bool IsValid(this string source) + { + // + var result = + source != XAiChatRoles.None && + source.ToNormalString() != XAiChatRoles.None.ToNormalString(); + + // + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this XAiChatRole source) + { + // + var result = source != XAiChatRole.None; + return result; + } + + /// + /// Validate Role ... + /// > + /// + /// + /// + public static bool IsValid(this ChatRole source) + { + // + var role = source.ToChatRole(); + var result = role.IsValid(); + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\XAiApiConfigurationExtensions.cs + +using System.Linq; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Configurations; + +namespace xAiModels.Extensions +{ + public static class XAiApiConfigurationExtensions + { + /// + /// Validate Api Configuration ... + /// + /// + /// + public static bool IsValid(this XAiApiConfiguration source) + { + return + !source.IsNullOrDefault() && + source.Models.HasChild(); + } + + /// + /// Retrieve Default Model Descriptor ... + /// + /// + /// + public static XAiModelDescriptor GetDefaultModel(this XAiApiConfiguration source) + { + // + XAiModelDescriptor result = null; + + // + if (source.IsValid()) + { + result = source.Models.First(); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Extensions\XAiModelsExtensions.cs + +using System.Linq; +using xAiModels.Models; +using xCommons.Extensions; +using xAiModels.Models.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Extensions +{ + /// + /// Extensions Methods for XAiModels ... + /// + public static class XAiModelsExtensions + { + /// + /// Validate a Project for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiProject source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiProjectDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.Prompt.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Conversation for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiConversation source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiConversationDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + !source.Title.IsNullOrEmpty() && + !source.ProjectId.IsNull() && + !source.ProjectId.IsDefaultGuid(); + + // + return result; + } + + /// + /// Validate a Message for Add Or Update ... + /// + /// + /// + public static bool IsValidForAddOrUpdate(this XAiMessage source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + public static bool IsValidForAddOrUpdate(this XAiMessageDto source) + { + // + var result = + !source.IsNullOrDefault() && + !source.OwnerId.IsNullOrEmpty() && + source.Role.IsValid() && + !source.ConversationId.IsNull() && + !source.ConversationId.IsDefaultGuid() && + !source.Content.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate a Model Descriptor ... + /// + /// + /// + public static bool IsValid(this XAiModelDescriptor source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Url.IsNullOrEmpty() && + source.Url.IsValidUrl() && + !source.LLM.IsNullOrEmpty() && + source.Provider != Constants.XAiModelProviderType.None; + + // + return result; + } + + /// + /// Validate Specified Param ... + /// + /// + /// + public static bool IsValid(this XAiPromptParam source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Param.IsNullOrEmpty(); + + // + return result; + } + + /// + /// Validate Specified Prompt ... + /// + /// + /// + public static bool IsValid(this XAiPromptDescriptor source) + { + // + var result = + !source.IsNullOrDefault() && + !source.Name.IsNullOrEmpty() && + !source.Template.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + if (source.Params.HasChild()) + { + result = + result && + source.Params.All(x => x.IsValid()); + } + + // + return result; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Helpers\XAiModelsHelper.cs + +using System; +using GraphQL.Types; +using xDataService.Db; +using xDataService.Models; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Providers.GraphQL; +using xAiModels.Providers.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Helpers +{ + public static class XAiModelsHelper + { + // + #region XAiConversation ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationEFRepository, + TContext, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + > GetXAiConversationMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationMongoRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + > GetXAiConversationInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + > GetXAiConversationInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiConversation, + Guid, + IXAiConversationKeyGenerator, + XAiConversationKeyGenerator, + IXAiConversationRepositoryEvents, + XAiConversationRepositoryEvents, + XAiConversationGraphType, + GuidGraphType, + XAiConversationGraphQuery, + IXAiConversationGraphQLTypeHelper, + XAiConversationGraphQLTypeHelper, + XAiConversationGraphSchema, + IXAiConversationRepository, + XAiConversationInMemoryRepository, + IXAiConversationSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiMessage ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageEFRepository, + TContext, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + > GetXAiMessageMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageMongoRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + > GetXAiMessageInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + > GetXAiMessageInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiMessage, + Guid, + IXAiMessageKeyGenerator, + XAiMessageKeyGenerator, + IXAiMessageRepositoryEvents, + XAiMessageRepositoryEvents, + XAiMessageGraphType, + GuidGraphType, + XAiMessageGraphQuery, + IXAiMessageGraphQLTypeHelper, + XAiMessageGraphQLTypeHelper, + XAiMessageGraphSchema, + IXAiMessageRepository, + XAiMessageInMemoryRepository, + IXAiMessageSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + + // + #region XAiProject ... + // + #region EF Repository Descriptor Provider(s) ... + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext + >(); + + // + return result; + } + + public static XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectEFRepositoryDescriptor() + where TContext : XDbContext + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XEFRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectEFRepository, + TContext, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region Mongo Repository Descriptor Provider(s) ... + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + > GetXAiProjectMongoRepositoryDescriptor() + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository + >(); + + // + return result; + } + + public static XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectMongoRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XMongoRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectMongoRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + + // + #region InMemory Repository Descriptor Provider(s) ... + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + > GetXAiProjectInMemoryRepositoryDescriptor() + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository + >(); + + // + return result; + } + + public static XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + > GetXAiProjectInMemoryRepositoryDescriptor() + where TSeederImplementation : XBaseDbSeeder + { + // + var result = new XInMemoryRepositoryDescriptor< + XAiProject, + Guid, + IXAiProjectKeyGenerator, + XAiProjectKeyGenerator, + IXAiProjectRepositoryEvents, + XAiProjectRepositoryEvents, + XAiProjectGraphType, + GuidGraphType, + XAiProjectGraphQuery, + IXAiProjectGraphQLTypeHelper, + XAiProjectGraphQLTypeHelper, + XAiProjectGraphSchema, + IXAiProjectRepository, + XAiProjectInMemoryRepository, + IXAiProjectSeeder, + TSeederImplementation + >(); + + // + return result; + } + #endregion + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiConversationTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiConversationTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiDataProvider.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace xAiModels.Interfaces +{ + /// + /// All Data Manipulation Requirements ... + /// + public interface IXAiDataProvider + { + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Creator/Adders ... + /// + /// Create Project ... + /// + /// + /// + /// + /// + /// + Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Create Conversation ... + /// + /// + /// + /// + /// + /// + Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ); + + /// + /// Add Message ... + /// + /// + /// + /// + /// + /// + Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiProjectDescriptionResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectDescriptionResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\IXAiProjectTitleResourceProvider.cs + +using xStringService.Interfaces; + +namespace xAiModels.Interfaces +{ + public interface IXAiProjectTitleResourceProvider : IXOwnedItemResourceProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiConversationServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiConversationServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiMessageServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiMessageServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectDtoHub.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectDtoHub : IXBaseDtoHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectRepositoryService.cs + +using System; +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectRepositoryService : IXBaseRepositoryService + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Dtos\IXAiProjectServiceProvider.cs + +using System; +using xAiModels.Models.Dtos; +using xPushService.Interfaces; +using xAiModels.Providers.Dtos; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Dtos +{ + public interface IXAiProjectServiceProvider : IXBaseDtoProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiConversationEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + /// + /// Ai Conversation Enricher ... + /// + public interface IXAiConversationEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiMessageEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiMessageEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Enrichers\IXAiProjectEnricher.cs + +using System.Threading; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; + +namespace xAiModels.Interfaces.Enrichers +{ + public interface IXAiProjectEnricher + { + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ); + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiConversationSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiConversationSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiDocumentEntityHub.cs + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiDocumentEntityHub + { + + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiMessageSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiMessageSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectEntityHub.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectEntityHub : IXBaseEntityHub + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectGraphQLTypeHelper.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectGraphQLTypeHelper : IXBaseGraphQLTypeHelper + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectKeyGenerator.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectKeyGenerator : IXKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepository.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepository : IXBaseRepository + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepositoryEvents.cs + +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryEvents : IXBaseRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectRepositoryProvider.cs + +using System; +using xPushService.Interfaces; +using xAiModels.Models.Entities; +using xAiModels.Providers.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectRepositoryProvider : IXBaseEntityProvider + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Interfaces\Entities\IXAiProjectSeeder.cs + +using System; +using xDataService.Interfaces; +using xAiModels.Models.Entities; + +namespace xAiModels.Interfaces.Entities +{ + public interface IXAiProjectSeeder : IXBaseDbSeeder + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\XAiModelDescriptor.cs + +using xAiModels.Constants; + +namespace xAiModels.Models +{ + /// + /// Describe a Provided Model ... + /// + public class XAiModelDescriptor + { + /// + /// Provider Name ... + /// + public string Name { get; set; } + + /// + /// LLM Provider Url ... + /// + public string Url { get; set; } + + /// + /// Model Name ... + /// + public string LLM { get; set; } + + /// + /// Api Key for Connection ... + /// + public string ApiKey { get; set; } + + /// + /// Specified Model Provider Type ... + /// + public XAiModelProviderType Provider { get; set; } = XAiModelProviderType.Ollama; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\XAiPromptDescriptor.cs + +namespace xAiModels.Models +{ + /// + /// Describe Specified Prompt ... + /// + public class XAiPromptDescriptor + { + /// + /// Prompt Name ... + /// + public string Name { get; set; } + + /// + /// Prompt Template ... + /// + public string Template { get; set; } + + /// + /// Prompt Description ... + /// + public string Description { get; set; } + + /// + /// Prompt Template Params ... + /// + public XAiPromptParam[] Params { get; set; } = []; + } + + /// + /// Specified a Prompt Param ... + /// + public class XAiPromptParam + { + /// + /// Param Name ... + /// + public string Name { get; set; } + + /// + /// Param Identifier ... + /// + public string Param { get; set; } + + /// + /// Parma Description ... + /// + public string Description { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiConversationDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using System.Collections.Generic; + +namespace xAiModels.Models.Dtos +{ + /// + /// Conversation Describe ... + /// + public class XAiConversationDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Conversation Title Resource ID ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Messages ... + /// + public virtual IEnumerable Messages { get; set; } = []; + + /// + /// Project ID ... + /// + public Guid ProjectId { get; set; } + + /// + /// Project Title Resource ID ... + /// + public virtual string ProjectTitle { get; set; } = null; + + /// + /// Project Description Resource ID ... + /// + public virtual string ProjectDescription { get; set; } = null; + + /// + /// Project Title Locale Resources ... + /// + public virtual XResourceDto ProjectTitleResource { get; set; } + + /// + /// Project Description Locale Resources ... + /// + public virtual XResourceDto ProjectDescriptionResource { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiMessageDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using xAiModels.Constants; +using xCommons.Extensions; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; + +namespace xAiModels.Models.Dtos +{ + public class XAiMessageDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Message of Chat ... + /// + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + public Guid ConversationId { get; set; } + + /// + /// Conversation Info ... + /// + public virtual string ConversationTitle { get; set; } = null; + public virtual XResourceDto ConversationTitleResouce { get; set; } = null; + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MetaDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Dtos\XAiProjectDto.cs + +using System; +using xModels.Base; +using xModels.Dtos; +using System.Collections.Generic; + +namespace xAiModels.Models.Dtos +{ + /// + /// Describe a Project ... + /// + public class XAiProjectDto : XBaseGuidIDEntityDto + { + /// + /// User Identifier ... + /// + /// + public string OwnerId { get; set; } + + /// + /// Owner Info ... + /// + public virtual XPersonDto Owner { get; set; } = null; + + /// + /// Title of Project ... + /// + public string Title { get; set; } + + /// + /// All Exists Title Locale Resources ... + /// + public virtual XResourceDto TitleResource { get; set; } + + /// + /// Description of Project ... + /// + public string Description { get; set; } + + /// + /// All Exists Description Locale Resources ... + /// + public virtual XResourceDto DescriptionResource { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversations ... + /// + public virtual IList Conversations { get; set; } = []; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiConversation.cs + +using System; +using xModels.Base; +using System.ComponentModel.DataAnnotations; + +namespace xAiModels.Models.Entities +{ + /// + /// Conversation Describe ... + /// + public class XAiConversation : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Conversation ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Project ID ... + /// + [Required] + public Guid ProjectId { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiDocument.cs + +using System; +using System.ComponentModel.DataAnnotations; +using xModels.Base; + +namespace xAiModels.Models.Entities +{ + /// + /// Represents an embedd document in the AI system. + /// + public class XAiDocument : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Document ... + /// + [StringLength(255)] + public string Title { get; set; } + + /// + /// Content of Document ... + /// + public string Content { get; set; } + + /// + /// Hash of the Document Content ... + /// + public string ContentHash { get; set; } = string.Empty; + + /// + /// Embedding Model Identifier ... + /// + public string EmbeddingModel { get; set; } = string.Empty; + + /// + /// Dimensions of the Embedding ... + /// + public int Dimensions { get; set; } + + /// + /// Vector representation of the Document ... + /// + public byte[] Vector { get; set; } = []; + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiMessage.cs + +using System; +using xModels.Base; +using xAiModels.Constants; +using xCommons.Extensions; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace xAiModels.Models.Entities +{ + /// + /// Message Model of Ai ... + /// + public class XAiMessage : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Message of Chat ... + /// + [Required] + public string Content { get; set; } + + /// + /// Role of Message ... + /// + public XAiChatRole Role { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + + /// + /// Conversation Id ... + /// + [StringLength(255)] + public Guid ConversationId { get; set; } + + // + #region Meta Data Property ... + private string _metadata; + + /// + /// Meta Data of Message ... + /// + [NotMapped] + public IDictionary Metadata { get; private set; } = null; + + /// + /// Meta Data of MEssage in Json ... + /// + public string MetaDatas + { + // + get => _metadata; + + // + set + { + // + // Converts Json String to Dictionary ... + if (!value.IsNullOrEmpty()) + { + Metadata = value.FromJSON>(); + } + + // + _metadata = value; + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Models\Entities\XAiProject.cs + +using System; +using xModels.Base; +using System.ComponentModel.DataAnnotations; + +namespace xAiModels.Models.Entities +{ + /// + /// Describe a Project ... + /// + public class XAiProject : XBaseGuidIDEntity + { + /// + /// User Identifier ... + /// + /// + [Required] + [StringLength(255)] + public string OwnerId { get; set; } + + /// + /// Title of Project ... + /// + [Required] + [StringLength(255)] + public string Title { get; set; } + + /// + /// Description of Project ... + /// + [StringLength(1000)] + public string Description { get; set; } + + /// + /// a Prompt for Project Start ... + /// + public string Prompt { get; set; } + + /// + /// Created Time ... + /// + public DateTime CreatedOn { get; set; } + + /// + /// Updated Time ... + /// + public DateTime UpdatedAt { get; set; } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiConversationEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiConversationEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiConversationEntityRegisterar() + : base(nameof(XAiConversationEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiConversationEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiConversationTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiConversationTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiConversationTitleResourceProvider + { + public XAiConversationTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiConversationTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiDataProvider.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xAiModels.Constants; +using xCommons.Extensions; +using xAiModels.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using xExceptions.Constants; +using System.Threading.Tasks; +using xCommons.Configurations; +using xAiModels.Providers.Hubs; +using xAiModels.Interfaces.Dtos; +using xStringService.Interfaces; +using System.Collections.Generic; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers +{ + /// + /// All Data Manipulation Requirements ... + /// + public class XAiDataProvider : IXAiDataProvider + { + // + #region Properties ... + private readonly IXStringProvider stringProvider; + private readonly XAppConfiguration appConfiguration; + private readonly IHubContext hub; + private readonly IXAiMessageRepositoryService messageRepositoryService; + private readonly IXAiProjectRepositoryService projectRepositoryService; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationRepositoryService conversationRepositoryService; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + #endregion + + public XAiDataProvider( + IXStringProvider stringProvider, + XAppConfiguration appConfiguration, + IHubContext hub, + IXAiMessageRepositoryService messageRepositoryService, + IXAiProjectRepositoryService projectRepositoryService, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationRepositoryService conversationRepositoryService, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + this.hub = hub; + this.stringProvider = stringProvider; + this.appConfiguration = appConfiguration; + this.messageRepositoryService = messageRepositoryService; + this.projectRepositoryService = projectRepositoryService; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationRepositoryService = conversationRepositoryService; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Loaders ... + /// + /// Load Projects List of Specified Owner ... + /// + /// + /// + /// + /// + /// + public async Task> LoadProjects( + string ownerId, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Default Project and Conversation ... + bool hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (!hasDefault) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: null, + cancellationToken: cancellationToken + ); + } + + // + // Retrieve Project List ... + var result = await projectRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: fillConversations, + predicate: x => x.OwnerId == ownerId, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + // fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Load List of Conversations for Specified Project ... + /// + /// + /// + /// + /// + public async Task> LoadConversations( + Guid projectId, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Conversation's List ... + var result = await conversationRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: false, + // fillMessages: fillMessages, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == projectId, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + return result; + } + + /// + /// Load Messages of Specified Conversation ... + /// + /// + /// + /// + public async Task> LoadMessages( + Guid conversationId, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Retrieve Message Lists of Specified Conversation ... + var result = await messageRepositoryService.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversationId + ); + + // + return result; + } + #endregion + + // + #region Creator/Adders ... + public async Task CreateProject( + string ownerId, + XAiProjectDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Check Project Provided or not ... + var hasProject = !item.IsNullOrDefault(); + + // + // Normalize Provided Project ... + if (hasProject) + { + // + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiProjectDto result = null; + + // + // Create Provided Project ... + if (hasProject) + { + // + result = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + // + // Check Default Project ... + else + { + // + // Check Default Project Exists or not ... + var hasDefault = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Project ... + result = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task CreateConversation( + Guid projectId, + XAiConversationDto item = null, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (projectId.IsNull() || + projectId.IsDefaultGuid()) + { + XException.InvalidArgs.Throw(); + } + + // + // Handle Proejct ... + XAiProjectDto project = await projectRepositoryService.GetAsync( + id: projectId, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Conversation Provided or not ... + var hasConversation = !item.IsNullOrDefault(); + + // + // Normalize Conversation if Provided ... + if (hasConversation) + { + // + item.ProjectId = project.Id; + item.CreatedOn = DateTime.UtcNow; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + } + + // + XAiConversationDto result = null; + + // + // Create Provided Conversation ... + if (hasConversation) + { + // + result = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + // fillMessages: false, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + // + // Check Default Conversation ... + else + { + // + // Check Default Conversation Exists or not ... + var hasDefault = await HasDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + cancellationToken: cancellationToken + ); + + // + // If Default Project Exists, Throw Exception ... + if (hasDefault) + { + XException.InvalidArgs.Throw(); + } + + // + // Create and Retrive Default Conversation ... + result = await GetDefaultConversation( + projectId: project.Id, + ownerId: project.OwnerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Validate ... + if (result.IsNullOrDefault()) + { + XException.ActionFailed.Throw(); + } + + // + return result; + } + + public async Task AddMessage( + Guid conversationId, + XAiMessageDto item, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (item.IsNullOrDefault() || + conversationId.IsNull() || + conversationId.IsDefaultGuid() + ) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + item.CreatedOn = DateTime.UtcNow; + item.ConversationId = conversationId; + + // + // Validate Item ... + if (!item.IsValidForAddOrUpdate()) + { + XException.InvalidData.Throw(); + } + + // + var result = await messageRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Handling Send Push Notification ... + if (!result.IsNullOrDefault() && + !connectionId.IsNullOrEmpty() + ) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.MessageCreated.GetStringValue() + ); + } + + // + return result; + } + #endregion + + // + #region Updaters ... + #endregion + + // + #region Private ... + /// + /// Check Default Project Exists or not ... + /// + /// + /// + /// + /// + private async Task HasDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Check Default Owner Exists or not ... + result = !(await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + )) + .IsNullOrDefault(); + return result; + } + + /// + /// Retrieve Default Project of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + private async Task GetDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Check Default Project Exists or noit ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + var result = await projectRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Create Default Project for Specified Owner ... + /// + /// + /// + /// + /// + private async Task CreateDefaultProject( + string ownerId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + if (ownerId.IsNullOrEmpty()) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Check Default Owner Exists or not ... + var isExists = await HasDefaultProject( + ownerId: ownerId, + cancellationToken: cancellationToken + ); + if (isExists) + { + return; + } + + // + // Create Default ... + var item = new XAiProjectDto() + { + OwnerId = ownerId, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString(), + Description = Guid.NewGuid().ToString(), + }; + item = await projectRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Tile and Description Resource Ids ... + var titleResource = await projectTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + var descriptionResource = await projectDescriptionResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiProjectSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault() || + descriptionResource.IsNullOrDefault() + ) + { + return; + } + + // + // Update Project Resources ... + item.Title = titleResource.Resource; + item.Description = descriptionResource.Resource; + item = await projectRepositoryService.UpdateAsync( + id: item.Id, + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ProjectCreated.GetStringValue() + ); + } + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task HasDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var result = !ownerId.IsNullOrEmpty(); + if (!result) + { + return result; + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiConversationTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiConversationSuffix) + ); + result = !resource.IsNullOrDefault(); + if (!result) + { + return result; + } + + // + result = !(await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => + x.ProjectId == projectId && + x.Title == resource.ResourceTitle + )) + .IsNullOrDefault(); + + // + return result; + } + + /// + /// Check Default Conversation Exists or not ... + /// + /// + /// + /// + /// + /// + private async Task CreateDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + var isValid = !ownerId.IsNullOrEmpty(); + if (!isValid) + { + return; + } + + // + var defaultLang = appConfiguration.DefaultLanguage; + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Owner Exists or not ... + isValid = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + cancellationToken: cancellationToken + ); + if (isValid) + { + return; + } + + // + // Create Default Conversation ... + var item = new XAiConversationDto + { + OwnerId = ownerId, + ProjectId = project.Id, + CreatedOn = DateTime.UtcNow, + Title = Guid.NewGuid().ToString() + }; + item = await conversationRepositoryService.AddAsync( + item: item, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Prepare Title Resource Ids ... + var titleResource = await conversationTitleResourceProvider.AddOrUpdateLocale( + owner: ownerId, + identifier: item.Id, + locale: new XLocaleResourceDto + { + Language = defaultLang, + Value = XAiDataProviderConstants.XDefaultAiConversationSuffix + }, + cancellationToken: cancellationToken + ); + if (titleResource.IsNullOrDefault()) + { + return; + } + + // + // Update Conversation Resources ... + item.Title = titleResource.Resource; + item = await conversationRepositoryService.UpdateAsync( + item: item, + id: item.Id, + saveChanges: true, + cancellationToken: cancellationToken + ); + + // + // Sending Push ... + if (!connectionId.IsNullOrEmpty()) + { + // + await SendPush( + connectionId: connectionId, + cancellationToken: cancellationToken, + payLoad: item.ToJSON(camelCase: true), + action: XAiDataProviderHubActions.ConversationCreated.GetStringValue() + ); + } + } + + /// + /// Retrieve Default Conversation of Specified Owner ... + /// Create it if not Handled ... + /// + /// + /// + /// + /// + /// + private async Task GetDefaultConversation( + string ownerId, + Guid projectId, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + // Validate Args ... + if (ownerId.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + // Prepare Project ... + XAiProjectDto project = null; + if (projectId.IsNull() || + projectId.IsDefaultGuid() + ) + { + // + project = await GetDefaultProject( + ownerId: ownerId, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + else + { + // + project = await projectRepositoryService.GetAsync( + id: project.Id, + includeBuilder: null, + ignoreSoftDeleteds: true, + // fillConversations: false, + // fillConversationMessages: false, + cancellationToken: cancellationToken + ); + } + if (project.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Check Default Conversation Exists or noit ... + var isExists = await HasDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + if (!isExists) + { + // + await CreateDefaultConversation( + ownerId: ownerId, + projectId: project.Id, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + + // + // Detect Conversation Resource ... + var resource = await stringProvider.FindOne( + cancellationToken: cancellationToken, + predicate: x => + x.ResourceTitle + .ToNormalString() + .Contains(ownerId.ToNormalString()) && + x.ResourceTitle + .ToNormalString() + .Contains(XAiModelsConstants.XAiProjectTitleIdentifier + .ToNormalString()) && + x.TranslatedValue + .ToNormalString() + .Contains(XAiDataProviderConstants.XDefaultAiProjectSuffix) + ); + if (resource.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + // Find Default Conversation ... + var result = await conversationRepositoryService.FindOneAsync( + cancellationToken: cancellationToken, + predicate: x => x.Title + .Equals( + resource.ResourceTitle, + StringComparison.InvariantCultureIgnoreCase + ) && + x.ProjectId == project.Id + ); + if (result.IsNullOrDefault()) + { + XException.NotFound.Throw(); + } + + // + return result; + } + + /// + /// Normalize and Validate Language ... + /// + /// + /// + private string NormalizeAndValidateLanguage(string language) + { + // + if (language.IsNullOrEmpty()) + { + language = appConfiguration.DefaultLanguage; + } + + // + if (language.IsNullOrEmpty()) + { + XException.InvalidArgs.Throw(); + } + + // + return language; + } + + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + public async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Collect Allowed Actions ... + var actions = new List + { + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + }; + + // + // Validate Args ... + var isValid = + !action.IsNullOrEmpty() && + actions.Contains(action); + if (!isValid) + { + return; + } + + // + // Retrieve Connection Id ... + var clients = hub.Clients.All; + if (!connectionId.IsNullOrEmpty()) + { + clients = hub.Clients.AllExcept(connectionId); + } + + // + await clients.SendAsync( + action, + payLoad, + connectionId, + cancellationToken + ); + } + catch { } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiMessageEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiMessageEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiMessageEntityRegisterar() + : base(nameof(XAiMessageEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiMessageEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectDescriptionResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiProjectDescriptionResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectDescriptionResourceProvider + { + public XAiProjectDescriptionResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectDescriptionIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectEntityRegisterar.cs + +using System; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using Microsoft.EntityFrameworkCore; +using xAiModels.Configurations.Entities; + +namespace xAiModels.Providers +{ + public class XAiProjectEntityRegisterar : XBaseEntityRegisterar, IXEntityRegisterar + { + public XAiProjectEntityRegisterar() + : base(nameof(XAiProjectEntityRegisterar)) + { + // + // Add Entity ... + AddEntity(); + } + + /// + /// Configure Entities ... + /// + /// + public override void ConfigureEntities(ModelBuilder modelBuilder) + { + // + // Configure Entity Using Provided ... + modelBuilder + .ApplyConfigurationsFromAssembly(typeof(XAiProjectEntityConfiguration).Assembly); + + // + base.ConfigureEntities(modelBuilder); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\XAiProjectTitleResourceProvider.cs + +using xAiModels.Constants; +using xAiModels.Interfaces; +using xCommons.Configurations; +using xStringService.Providers; +using xStringService.Interfaces.Dtos; + +namespace xAiModels.Providers +{ + public class XAiProjectTitleResourceProvider : XBaseOwnedItemResourceProvider, IXAiProjectTitleResourceProvider + { + public XAiProjectTitleResourceProvider( + XAppConfiguration appConfig, + IXStringServiceProvider stringProvider + ) : base( + appConfig: appConfig, + stringProvider: stringProvider, + item: XAiModelsConstants.XAiProjectTitleIdentifier + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationDtoHub : XBaseDtoHub, IXAiConversationDtoHub + { + public XAiConversationDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationRepositoryService : XBaseRepositoryService, IXAiConversationRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepository repository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiConversationRepositoryService( + IXIdentityProvider identityProvider, + IXAiConversationRepository repository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.repository = repository; + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title Resource ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + XResourceDto projectTitleResource = null; + XResourceDto projectDescriptionResource = null; + if (!source.ProjectId.IsDefaultGuid()) + { + // + projectTitleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + + // + projectDescriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.ProjectTitleResource)] = projectTitleResource; + options.Items[nameof(source.ProjectDescriptionResource)] = projectDescriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiConversationServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiConversationServiceProvider : XBaseDtoProvider, IXAiConversationServiceProvider + { + public XAiConversationServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiConversationRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageDtoHub : XBaseDtoHub, IXAiMessageDtoHub + { + public XAiMessageDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageRepositoryService : XBaseRepositoryService, IXAiMessageRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiMessageRepositoryService( + IXAiMessageRepository repository, + IXIdentityProvider identityProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + this.identityProvider = identityProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Conversation Title ... + string conversationTitle = string.Empty; + XResourceDto conversationTitleResource = null; + if (!source.ConversationId.IsDefaultGuid()) + { + // + conversationTitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ConversationId, + cancellationToken: cancellationToken + ); + if (!conversationTitleResource.IsNullOrDefault()) + { + conversationTitle = conversationTitleResource.Resource; + } + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.ConversationTitle)] = conversationTitle; + options.Items[nameof(source.ConversationTitleResouce)] = conversationTitleResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiMessageServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiMessageServiceProvider : XBaseDtoProvider, IXAiMessageServiceProvider + { + public XAiMessageServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiMessageRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectDtoHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectDtoHub : XBaseDtoHub, IXAiProjectDtoHub + { + public XAiProjectDtoHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectRepositoryService.cs + +using System; +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xDataService.Providers; +using xAiModels.Configurations; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectRepositoryService : XBaseRepositoryService, IXAiProjectRepositoryService + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiMessageRepository messageRepository; + private readonly IXAiConversationRepository conversationRepository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectRepositoryService( + IXAiProjectRepository repository, + IXIdentityProvider identityProvider, + IXAiMessageRepository messageRepository, + IXAiConversationRepository conversationRepository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) : base( + repository, + mapperProfiles: + [ + new XAiModelMappersProfile() + ] + ) + { + // + this.identityProvider = identityProvider; + this.messageRepository = messageRepository; + this.conversationRepository = conversationRepository; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = Mapper.Map(source); + result = await Enrich( + source: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Description ... + XResourceDto descriptionResource = null; + if (!source.Description.IsNullOrEmpty()) + { + // + descriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Conversations ... + IEnumerable conversations = []; + if (fillConversations) + { + // + // Reading Entities ... + var entitiies = await conversationRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == source.Id, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + // Converts to Dto Enumerable ... + conversations = entitiies + .MapConvert(); + + // + // Handle Conversation Enrichment ... + foreach (var conversation in conversations) + { + // + // Handle Owner ... + if (!conversation.OwnerId.IsNullOrEmpty()) + { + conversation.Owner = owner; + } + + // + // Handle Title Resource ... + if (!conversation.Title.IsNullOrEmpty()) + { + // + conversation.TitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: conversation.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + if (!conversation.ProjectId.IsDefaultGuid()) + { + conversation.ProjectTitle = source.Title; + conversation.ProjectTitleResource = titleResource; + conversation.ProjectDescription = source.Description; + conversation.ProjectDescriptionResource = descriptionResource; + } + } + + // + // Handle Fill Messages ... + if (fillConversationMessages) + { + // + foreach (var conversation in conversations) + { + // + IEnumerable messages = []; + + // + // Retrieve Message Entities ... + var messageEntities = await messageRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversation.Id + ); + if (messageEntities.HasChild()) + { + // + // Converts to Message ... + messages = messageEntities + .MapConvert(); + + // + // Ennrich Messages ... + foreach (var message in messages) + { + // + // Handle Owner ... + if (!message.OwnerId.IsNullOrEmpty()) + { + message.Owner = owner; + } + + // + // Handle Conversation ... + if (!message.ConversationId.IsDefaultGuid()) + { + message.ConversationTitle = conversation.Title; + message.ConversationTitleResouce = conversation.TitleResource; + } + } + } + + // + conversation.Messages = [.. messages]; + } + } + } + + // + // Attach Extracted Items ... + var result = Mapper.Map(source, options => + { + // + options.Items[nameof(source.Owner)] = owner; + options.Items[nameof(source.Conversations)] = conversations; + options.Items[nameof(source.TitleResource)] = titleResource; + options.Items[nameof(source.DescriptionResource)] = descriptionResource; + }); + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Dtos\XAiProjectServiceProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Dtos; +using xAiModels.Interfaces.Dtos; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; + +namespace xAiModels.Providers.Dtos +{ + public class XAiProjectServiceProvider : XBaseDtoProvider, IXAiProjectServiceProvider + { + public XAiProjectServiceProvider( + IHubContext hub, + XDataServiceConfiguration dataConfiguration, + IXAiProjectRepositoryService service, + IXIdentityProvider identityProvider = null + ) : base( + hub, + dataConfiguration, + service, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiConversationEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiConversationEnricher : IXAiConversationEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationRepository repository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiConversationEnricher( + IXIdentityProvider identityProvider, + IXAiConversationRepository repository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + // + this.repository = repository; + this.identityProvider = identityProvider; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversation source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + fillMessages: fillMessages, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiConversationDto source, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title Resource ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + XResourceDto projectTitleResource = null; + XResourceDto projectDescriptionResource = null; + if (!source.ProjectId.IsDefaultGuid()) + { + // + projectTitleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + + // + projectDescriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ProjectId, + cancellationToken: cancellationToken + ); + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.TitleResource = titleResource; + result.ProjectTitleResource = projectTitleResource; + result.ProjectDescriptionResource = projectDescriptionResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + fillMessages: fillMessages, + cancellationToken: cancellationToken + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiMessageEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiMessageEnricher : IXAiMessageEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + + public XAiMessageEnricher( + IXIdentityProvider identityProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider + ) + { + this.identityProvider = identityProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessage source, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + public virtual async Task Enrich( + XAiMessageDto source, + CancellationToken cancellationToken = default + ) + { + // + // Handdle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Hanlde Conversation Title ... + string conversationTitle = string.Empty; + XResourceDto conversationTitleResource = null; + if (!source.ConversationId.IsDefaultGuid()) + { + // + conversationTitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.ConversationId, + cancellationToken: cancellationToken + ); + if (!conversationTitleResource.IsNullOrDefault()) + { + conversationTitle = conversationTitleResource.Resource; + } + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.ConversationTitle = conversationTitle; + result.ConversationTitleResouce = conversationTitleResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich(x, cancellationToken)); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Enrichers\XAiProjectEnricher.cs + +using System.Linq; +using xModels.Dtos; +using System.Threading; +using xCommons.Extensions; +using xAiModels.Interfaces; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using xAiModels.Models.Entities; +using System.Collections.Generic; +using xIdentityService.Interfaces; +using xIdentityService.Extensions; +using xAiModels.Interfaces.Entities; +using xAiModels.Interfaces.Enrichers; + +namespace xAiModels.Providers.Enrichers +{ + public class XAiProjectEnricher : IXAiProjectEnricher + { + private readonly IXIdentityProvider identityProvider; + private readonly IXAiMessageRepository messageRepository; + private readonly IXAiConversationRepository conversationRepository; + private readonly IXAiProjectTitleResourceProvider projectTitleResourceProvider; + private readonly IXAiConversationTitleResourceProvider conversationTitleResourceProvider; + private readonly IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider; + + public XAiProjectEnricher( + IXIdentityProvider identityProvider, + IXAiMessageRepository messageRepository, + IXAiConversationRepository conversationRepository, + IXAiProjectTitleResourceProvider projectTitleResourceProvider, + IXAiConversationTitleResourceProvider conversationTitleResourceProvider, + IXAiProjectDescriptionResourceProvider projectDescriptionResourceProvider + ) + { + // + this.identityProvider = identityProvider; + this.messageRepository = messageRepository; + this.conversationRepository = conversationRepository; + this.projectTitleResourceProvider = projectTitleResourceProvider; + this.conversationTitleResourceProvider = conversationTitleResourceProvider; + this.projectDescriptionResourceProvider = projectDescriptionResourceProvider; + } + + // + #region Enrichers ... + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProject source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Mapping Default ... + var result = source.MapConvert(); + result = await Enrich( + source: result, + fillConversations: fillConversations, + cancellationToken: cancellationToken, + fillConversationMessages: fillConversationMessages + ); + + // + return result; + } + + /// + /// Enrich Specified Item ... + /// + /// + /// + /// + /// + /// + public virtual async Task Enrich( + XAiProjectDto source, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + // Handle Owner ... + XPersonDto owner = null; + if (!source.OwnerId.IsNullOrEmpty()) + { + // + // Try to Retrieve User Info ... + var device = identityProvider.GetDevice(); + var userInfo = await identityProvider.GetUserInfo( + device: device, + userSelectByParam: source.OwnerId + ); + owner = userInfo.ToXPersonDto(); + } + + // + // Handle Title ... + XResourceDto titleResource = null; + if (!source.Title.IsNullOrEmpty()) + { + // + titleResource = await projectTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Description ... + XResourceDto descriptionResource = null; + if (!source.Description.IsNullOrEmpty()) + { + // + descriptionResource = await projectDescriptionResourceProvider.GetResource( + owner: source.OwnerId, + identifier: source.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Conversations ... + IEnumerable conversations = []; + if (fillConversations) + { + // + // Reading Entities ... + var entitiies = await conversationRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + predicate: x => x.ProjectId == source.Id, + orderBuilder: x => x.OrderBy(y => y.CreatedOn) + ); + + // + // Converts to Dto Enumerable ... + conversations = entitiies + .MapConvert(); + + // + // Handle Conversation Enrichment ... + foreach (var conversation in conversations) + { + // + // Handle Owner ... + if (!conversation.OwnerId.IsNullOrEmpty()) + { + conversation.Owner = owner; + } + + // + // Handle Title Resource ... + if (!conversation.Title.IsNullOrEmpty()) + { + // + conversation.TitleResource = await conversationTitleResourceProvider.GetResource( + owner: source.OwnerId, + identifier: conversation.Id, + cancellationToken: cancellationToken + ); + } + + // + // Handle Project Info ... + if (!conversation.ProjectId.IsDefaultGuid()) + { + conversation.ProjectTitle = source.Title; + conversation.ProjectTitleResource = titleResource; + conversation.ProjectDescription = source.Description; + conversation.ProjectDescriptionResource = descriptionResource; + } + } + + // + // Handle Fill Messages ... + if (fillConversationMessages) + { + // + foreach (var conversation in conversations) + { + // + IEnumerable messages = []; + + // + // Retrieve Message Entities ... + var messageEntities = await messageRepository.FindManyAsync( + includeBuilder: null, + ignoreSoftDeleteds: true, + cancellationToken: cancellationToken, + orderBuilder: x => x.OrderBy(y => y.CreatedOn), + predicate: x => x.ConversationId == conversation.Id + ); + if (messageEntities.HasChild()) + { + // + // Converts to Message ... + messages = messageEntities + .MapConvert(); + + // + // Ennrich Messages ... + foreach (var message in messages) + { + // + // Handle Owner ... + if (!message.OwnerId.IsNullOrEmpty()) + { + message.Owner = owner; + } + + // + // Handle Conversation ... + if (!message.ConversationId.IsDefaultGuid()) + { + message.ConversationTitle = conversation.Title; + message.ConversationTitleResouce = conversation.TitleResource; + } + } + } + + // + conversation.Messages = [.. messages]; + } + } + } + + // + // Attach Extracted Items ... + var result = source.MapConvert(); + result.Owner = owner; + result.TitleResource = titleResource; + result.Conversations = [.. conversations]; + result.DescriptionResource = descriptionResource; + + // + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + + /// + /// Enrich Specified Items ... + /// + /// + /// + /// + /// + /// + public virtual async Task> EnrichRange( + IEnumerable sources, + bool fillConversations = false, + bool fillConversationMessages = false, + CancellationToken cancellationToken = default + ) + { + // + var tasks = sources + .Select(x => Enrich( + source: x, + cancellationToken: cancellationToken, + fillConversations: fillConversations, + fillConversationMessages: fillConversationMessages + )); + + // + var result = await Task.WhenAll(tasks); + return result; + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEFRepository : XBaseEFRepository, IXAiConversationRepository + where TContext : XDbContext + { + public XAiConversationEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationEntityHub : XBaseEntityHub, IXAiConversationEntityHub + { + public XAiConversationEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationInMemoryRepository : XBaseInMemoryRepository, IXAiConversationRepository + { + public XAiConversationInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationKeyGenerator : XGuidKeyGenerator, IXAiConversationKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationMongoRepository : XBaseMongoRepository, IXAiConversationRepository + { + public XAiConversationMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiConversationKeyGenerator keyGenerator = null, + IXAiConversationRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryEvents : XBaseRepositoryEvents, IXAiConversationRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiConversationRepositoryProvider : XBaseEntityProvider, IXAiConversationRepositoryProvider + { + public XAiConversationRepositoryProvider( + IHubContext hub, + IXAiConversationRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiConversationSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiConversationSeederBase : XBaseDbSeeder, IXAiConversationSeeder + { + protected XAiConversationSeederBase( + string entity, + string database, + IXAiConversationRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEFRepository : XBaseEFRepository, IXAiMessageRepository + where TContext : XDbContext + { + public XAiMessageEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageEntityHub : XBaseEntityHub, IXAiMessageEntityHub + { + public XAiMessageEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageInMemoryRepository : XBaseInMemoryRepository, IXAiMessageRepository + { + public XAiMessageInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageKeyGenerator : XGuidKeyGenerator, IXAiMessageKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageMongoRepository : XBaseMongoRepository, IXAiMessageRepository + { + public XAiMessageMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiMessageKeyGenerator keyGenerator = null, + IXAiMessageRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryEvents : XBaseRepositoryEvents, IXAiMessageRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiMessageRepositoryProvider : XBaseEntityProvider, IXAiMessageRepositoryProvider + { + public XAiMessageRepositoryProvider( + IHubContext hub, + IXAiMessageRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiMessageSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiMessageSeederBase : XBaseDbSeeder, IXAiMessageSeeder + { + protected XAiMessageSeederBase( + string entity, + string database, + IXAiMessageRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectEFRepository.cs + +using System; +using xDataService.Db; +using xDataService.Providers; +using xDataService.Interfaces; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEFRepository : XBaseEFRepository, IXAiProjectRepository + where TContext : XDbContext + { + public XAiProjectEFRepository( + IXUnitOfWorks unitOfWorks, + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + unitOfWorks, + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectEntityHub.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using Microsoft.Extensions.Logging; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectEntityHub : XBaseEntityHub, IXAiProjectEntityHub + { + public XAiProjectEntityHub( + ILogger logger + ) : base(logger) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectInMemoryRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectInMemoryRepository : XBaseInMemoryRepository, IXAiProjectRepository + { + public XAiProjectInMemoryRepository( + XDataServiceConfiguration configuration, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + configuration, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectKeyGenerator.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectKeyGenerator : XGuidKeyGenerator, IXAiProjectKeyGenerator + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectMongoRepository.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectMongoRepository : XBaseMongoRepository, IXAiProjectRepository + { + public XAiProjectMongoRepository( + XDataBaseConfiguration dbConfiguration, + XDataServiceConfiguration configuration, + string collectionName = null, + IXAiProjectKeyGenerator keyGenerator = null, + IXAiProjectRepositoryEvents baseRepositoryEvents = null + ) : base( + dbConfiguration, + configuration, + collectionName, + keyGenerator, + baseRepositoryEvents + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectRepositoryEvents.cs + +using xDataService.Providers; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryEvents : XBaseRepositoryEvents, IXAiProjectRepositoryEvents + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectRepositoryProvider.cs + +using System; +using xPushService.Base; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xIdentityService.Interfaces; +using Microsoft.AspNetCore.SignalR; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public class XAiProjectRepositoryProvider : XBaseEntityProvider, IXAiProjectRepositoryProvider + { + public XAiProjectRepositoryProvider( + IHubContext hub, + IXAiProjectRepository repository, + XDataServiceConfiguration dataConfiguration, + IXIdentityProvider identityProvider = null + ) : base( + hub, + repository, + dataConfiguration, + identityProvider + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Entities\XAiProjectSeederBase.cs + +using System; +using xDataService.Providers; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.Entities +{ + public abstract class XAiProjectSeederBase : XBaseDbSeeder, IXAiProjectSeeder + { + protected XAiProjectSeederBase( + string entity, + string database, + IXAiProjectRepository repository, + XDataServiceConfiguration dataServiceConfiguration + ) : base( + entity, + database, + repository, + dataServiceConfiguration + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiConversationGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiConversationCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiConversationSignleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphQuery : XBaseGraphQLQuery + { + public XAiConversationGraphQuery( + XDataServiceConfiguration configuration, + IXAiConversationRepository repository, + IXAiConversationGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphSchema : Schema + { + public XAiConversationGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiConversationGraphQuery)services.GetService(typeof(XAiConversationGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiConversationGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiConversationGraphType : XBaseGraphObjectType + { + public XAiConversationGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ProjectId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiMessageGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiMessageCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiMessageSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphQuery : XBaseGraphQLQuery + { + public XAiMessageGraphQuery( + XDataServiceConfiguration configuration, + IXAiMessageRepository repository, + IXAiMessageGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphSchema : Schema + { + public XAiMessageGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiMessageGraphQuery)services.GetService(typeof(XAiMessageGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiMessageGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiMessageGraphType: XBaseGraphObjectType + { + public XAiMessageGraphType() : base() + { + Field(x => x.Role); + Field(x => x.OwnerId); + Field(x => x.Content); + Field(x => x.Metadata); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.ConversationId); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphQLTypeHelper.cs + +using System; +using xAiModels.Constants; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQLTypeHelper : XBaseGraphQLTypeHelper, IXAiProjectGraphQLTypeHelper + { + public override string GetInQueryCollectionName() + { + return XAiModelsConstants.XAiProjectCollectionName; + } + + public override string GetInQuerySingleName() + { + return XAiModelsConstants.XAiProjectSingleName; + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphQuery.cs + +using System; +using GraphQL.Types; +using xDataService.GraphQL; +using xAiModels.Models.Entities; +using xDataService.Configuration; +using xAiModels.Interfaces.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphQuery : XBaseGraphQLQuery + { + public XAiProjectGraphQuery( + XDataServiceConfiguration configuration, + IXAiProjectRepository repository, + IXAiProjectGraphQLTypeHelper helper + ) : base( + configuration, + repository, + helper + ) + { } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphSchema.cs + +using System; +using GraphQL.Types; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphSchema : Schema + { + public XAiProjectGraphSchema(IServiceProvider services) : base(services) + { + Query = (XAiProjectGraphQuery)services.GetService(typeof(XAiProjectGraphQuery)); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\GraphQL\XAiProjectGraphType.cs + +using System; +using xDataService.GraphQL; +using xAiModels.Models.Entities; + +namespace xAiModels.Providers.GraphQL +{ + public class XAiProjectGraphType : XBaseGraphObjectType + { + public XAiProjectGraphType() : base() + { + Field(x => x.Title); + Field(x => x.OwnerId); + Field(x => x.Prompt); + Field(x => x.CreatedOn); + Field(x => x.UpdatedAt); + Field(x => x.Description); + } + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiModels\Providers\Hubs\XAiDataProviderHub.cs + +using System.Threading; +using xPushService.Base; +using xAiModels.Constants; +using xCommons.Extensions; +using xAiModels.Models.Dtos; +using System.Threading.Tasks; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; + +namespace xAiModels.Providers.Hubs +{ + public class XAiDataProviderHub : XBaseHub + { + public XAiDataProviderHub( + ILogger logger + ) : base(logger) + { } + + // + #region XAiProject ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ProjectCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ProjectRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ProjectUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ProjectUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiConversation ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task ConversationCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task ConversationRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task ConversationUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.ConversationUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + + // + #region XAiMessage ... + /// + /// Notify a New Item Created ... + /// + /// + /// + /// + public async Task MessageCreated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageCreated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Removed ... + /// + /// + /// + /// + public async Task MessageRemoved( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageRemoved.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + + /// + /// Notify an Item Updated ... + /// + /// + /// + /// + public async Task MessageUpdated( + XAiProjectDto item, + CancellationToken cancellationToken = default + ) + { + // + var connectionId = Context.ConnectionId; + if (!connectionId.IsNullOrEmpty()) + { + // + await Clients + .AllExcept(connectionId) + .SendAsync( + XAiDataProviderHubActions.MessageUpdated.GetStringValue(), + item.ToJSON(camelCase: true), + connectionId, + cancellationToken + ); + } + } + #endregion + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\Constants\ConfigurationNodeNames.cs + +namespace xAiService.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_SERVICE_NODE = "AIServiceConfiguration"; + } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\DI\XDIHelperExtension.cs + +namespace xAiService.DI +{ + public static partial class XDIHelperExtension + { } +} + +### FILE: C:\Users\hkhazaeeasl\Documents\Projets\XProjects\xSaherelmWorkspace\Modules\xAiService\Helpers\VectorHelper.cs + +using System; +using xCommons.Extensions; + +namespace xAiService.Helpers +{ + public static class VectorHelper + { + /// + /// Normalize a Vector ... + /// + /// + public static void Normalize(float[] vector) + { + // + // Validate ... + if (vector.IsNull() || !vector.HasChild()) + { + return; + } + + // + float sum = 0f; + foreach (var value in vector) + { + sum += value * value; + } + + // + float norm = MathF.Sqrt(sum); + if (norm <= 1e-9f) + { + return; + } + + // + for (int i = 0; i < vector.Length; i++) + { + vector[i] /= norm; + } + } + + /// + /// Similarity Check ... + /// + /// + /// + /// + public static float CosineSimilarity(float[] a, float[] b) + { + // + if (a.IsNull() || b.IsNull()) + { + return 0f; + } + + // + if (a.Length != b.Length) + { + return 0f; + } + + // + float dot = 0f; + float normA = 0f; + float normB = 0f; + for (int i = 0; i < a.Length; i++) + { + // + dot += a[i] * b[i]; + normA += a[i] * a[i]; + normB += b[i] * b[i]; + } + + // + float denominator = MathF.Sqrt(normA) * MathF.Sqrt(normB); + if (denominator <= 1e-9f) + { + return 0f; + } + + // + var result = dot / denominator; + return result; + } + } +} diff --git a/xAiApi b/xAiApi index 9afa413..ed8a66f 160000 --- a/xAiApi +++ b/xAiApi @@ -1 +1 @@ -Subproject commit 9afa413c6fa2a3ddb848e3e18f92b7badf6e143b +Subproject commit ed8a66f432dfbdfc1e31d6904b7323eab0e5c98f