From a4bcde599457accf1abe9a00369f4b1f4d18aeb3 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 15 Aug 2026 10:49:08 +0330 Subject: [PATCH] last ... --- Constants/ConfigurationNodeNames.cs | 7 ++ Constants/XAiApiConstants.cs | 1 + Controllers/DefaultAiController.cs | 27 ++++++ Controllers/XAiServiceControllerBase.cs | 72 +++++++++++++++ DI/XDIHelperExtension.cs | 87 +++++++++++++++++++ Extensions/XModelsExtensions.cs | 2 +- ...AIApiServiceBase.cs => IXAiServiceBase.cs} | 2 +- Interfaces/IXAiServiceControllerBase.cs | 21 +++++ Interfaces/IXDefaultAiService.cs | 5 ++ Program.cs | 6 -- Providers/XAIServiceBase.cs | 6 +- Providers/XDefaultAiService.cs | 21 +++++ Startup.cs | 20 +++++ appsettings.Development.json | 19 ++++ 14 files changed, 285 insertions(+), 11 deletions(-) create mode 100644 Constants/ConfigurationNodeNames.cs create mode 100644 Controllers/DefaultAiController.cs create mode 100644 Controllers/XAiServiceControllerBase.cs create mode 100644 DI/XDIHelperExtension.cs rename Interfaces/{IXAIApiServiceBase.cs => IXAiServiceBase.cs} (97%) create mode 100644 Interfaces/IXAiServiceControllerBase.cs create mode 100644 Interfaces/IXDefaultAiService.cs create mode 100644 Providers/XDefaultAiService.cs diff --git a/Constants/ConfigurationNodeNames.cs b/Constants/ConfigurationNodeNames.cs new file mode 100644 index 0000000..49f630c --- /dev/null +++ b/Constants/ConfigurationNodeNames.cs @@ -0,0 +1,7 @@ +namespace xAiApi.Constants +{ + public partial struct ConfigurationNodeNames + { + public const string AI_API_NODE = "AiAPiConfiguration"; + } +} \ No newline at end of file diff --git a/Constants/XAiApiConstants.cs b/Constants/XAiApiConstants.cs index 3dc5c59..419b278 100644 --- a/Constants/XAiApiConstants.cs +++ b/Constants/XAiApiConstants.cs @@ -8,6 +8,7 @@ namespace xAiApi.Constants public const string XAiApiMigrationsAssemblyIdentifier = "xAiApi"; // + public const string XDILogTag = "XAiApi"; public const string XAiApiIntroductionPromptName = "Introduction"; } } \ No newline at end of file diff --git a/Controllers/DefaultAiController.cs b/Controllers/DefaultAiController.cs new file mode 100644 index 0000000..828f2a5 --- /dev/null +++ b/Controllers/DefaultAiController.cs @@ -0,0 +1,27 @@ +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 + ) + { } + } +} \ No newline at end of file diff --git a/Controllers/XAiServiceControllerBase.cs b/Controllers/XAiServiceControllerBase.cs new file mode 100644 index 0000000..ce7d8a3 --- /dev/null +++ b/Controllers/XAiServiceControllerBase.cs @@ -0,0 +1,72 @@ +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; + } + } + } +} \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs new file mode 100644 index 0000000..9ec3901 --- /dev/null +++ b/DI/XDIHelperExtension.cs @@ -0,0 +1,87 @@ +using System; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using xAiApi.Configurations; +using xAiApi.Constants; +using xAiApi.Extensions; +using xCommons.Extensions; +using xExceptions.Constants; + +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 + } +} \ No newline at end of file diff --git a/Extensions/XModelsExtensions.cs b/Extensions/XModelsExtensions.cs index 779ea3f..22e92b2 100644 --- a/Extensions/XModelsExtensions.cs +++ b/Extensions/XModelsExtensions.cs @@ -186,7 +186,7 @@ namespace xAiApi.Extensions /// public static string GetPrompt( this XAiApiConfiguration source, - string name, + string name = null, IDictionary @params = null ) { diff --git a/Interfaces/IXAIApiServiceBase.cs b/Interfaces/IXAiServiceBase.cs similarity index 97% rename from Interfaces/IXAIApiServiceBase.cs rename to Interfaces/IXAiServiceBase.cs index 5799066..01b9b4d 100644 --- a/Interfaces/IXAIApiServiceBase.cs +++ b/Interfaces/IXAiServiceBase.cs @@ -10,7 +10,7 @@ namespace xAiApi.Interfaces /// /// Describe a Base Service Actions of any Ai Based Services ... /// - public interface IXAIServiceBase : IDisposable + public interface IXAiServiceBase : IDisposable { /// /// Base Method for Communicate with LLM ... diff --git a/Interfaces/IXAiServiceControllerBase.cs b/Interfaces/IXAiServiceControllerBase.cs new file mode 100644 index 0000000..fe26abf --- /dev/null +++ b/Interfaces/IXAiServiceControllerBase.cs @@ -0,0 +1,21 @@ +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 + ); + } +} \ No newline at end of file diff --git a/Interfaces/IXDefaultAiService.cs b/Interfaces/IXDefaultAiService.cs new file mode 100644 index 0000000..1bc6a1f --- /dev/null +++ b/Interfaces/IXDefaultAiService.cs @@ -0,0 +1,5 @@ +namespace xAiApi.Interfaces +{ + public interface IXDefaultAiService : IXAiServiceBase + { } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs index ef7f973..d93697e 100644 --- a/Program.cs +++ b/Program.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; namespace xAiApi { diff --git a/Providers/XAIServiceBase.cs b/Providers/XAIServiceBase.cs index 49b11ea..d109b27 100644 --- a/Providers/XAIServiceBase.cs +++ b/Providers/XAIServiceBase.cs @@ -17,7 +17,7 @@ using OllamaSharp; namespace xAiApi.Providers { - public abstract class XAIServiceBase : IXAIServiceBase + public abstract class XAIServiceBase : IXAiServiceBase { private readonly IXAiDataProvider dataProvider; private readonly ILogger logger; @@ -273,7 +273,7 @@ namespace xAiApi.Providers // Preparing Introduction Prompt ... var introductionPrompt = new ChatMessage( ChatRole.System, - PromptHelper.GetIntroductionPrompt().Prompt + configuration.GetPrompt() ); // @@ -307,7 +307,7 @@ namespace xAiApi.Providers // Preparing Introduction Prompt ... var introductionPrompt = new ChatMessage( ChatRole.System, - PromptHelper.GetIntroductionPrompt().Prompt + configuration.GetPrompt() ); // diff --git a/Providers/XDefaultAiService.cs b/Providers/XDefaultAiService.cs new file mode 100644 index 0000000..7adf00c --- /dev/null +++ b/Providers/XDefaultAiService.cs @@ -0,0 +1,21 @@ +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 + ) + { } + } +} \ No newline at end of file diff --git a/Startup.cs b/Startup.cs index c362289..c154949 100644 --- a/Startup.cs +++ b/Startup.cs @@ -26,6 +26,11 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using IdentityModel.AspNetCore.OAuth2Introspection; using xPushService.Helpers; +using xAiApi.DI; +using xExceptions.Constants; +using xAiApi.Interfaces; +using xAiApi.Providers; +using xAiModels.DI; namespace xAiApi { @@ -169,6 +174,21 @@ namespace xAiApi 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(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) diff --git a/appsettings.Development.json b/appsettings.Development.json index 691295f..986b937 100644 --- a/appsettings.Development.json +++ b/appsettings.Development.json @@ -35,6 +35,25 @@ "ThumbQuality": 72, "MaxFileSize": 41943040 }, + "AiAPiConfiguration": { + "Models": [ + { + "ApiKey": "", + "Name": "Gemma", + "LLM": "gemma3:1b", + "Provider": "Ollama", + "Url": "http://localhost:11434" + } + ], + "Prompts": [ + { + "Name": "Introduction", + "Template": "your name is xSaherElmAi, you are a professional ai assistant which develped by SaherElm IT Center", + "Description": "", + "Params": [] + } + ] + }, "Logging": { "LogLevel": { "Default": "Information",