diff --git a/AI/DI/AIExtensions.cs b/AI/DI/AIExtensions.cs
new file mode 100644
index 0000000..7ab2e5e
--- /dev/null
+++ b/AI/DI/AIExtensions.cs
@@ -0,0 +1,27 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using xAiApi.AI.Interfaces;
+using xAiApi.AI.Services;
+
+namespace xAiApi.AI.DI
+{
+ public static class AIExtensions
+ {
+ ///
+ /// Register AI Services ...
+ ///
+ ///
+ public static void AddXAIServices(this IServiceCollection services)
+ {
+ //
+ services.AddSingleton();
+ }
+
+ ///
+ /// Use AI Service Middlewares ...
+ ///
+ ///
+ public static void UseXAIServices(this IApplicationBuilder builder)
+ { }
+ }
+}
\ No newline at end of file
diff --git a/AI/Interfaces/IXAIService.cs b/AI/Interfaces/IXAIService.cs
new file mode 100644
index 0000000..cbade33
--- /dev/null
+++ b/AI/Interfaces/IXAIService.cs
@@ -0,0 +1,28 @@
+using System.Threading.Tasks;
+using Microsoft.Extensions.AI;
+
+namespace xAiApi.AI.Interfaces
+{
+ public interface IXAIService
+ {
+ IChatClient TextGenreatorClient { get; }
+ IChatClient ImageGenreatorClient { get; }
+
+ //
+ #region Actions ...
+ ///
+ /// Generated Text ...
+ ///
+ ///
+ ///
+ Task GetTextResponseAsync(string prompt);
+
+ ///
+ /// Generated Response ...
+ ///
+ ///
+ ///
+ Task GetResponseAsync(string prompt);
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/AI/Services/XAIService.cs b/AI/Services/XAIService.cs
new file mode 100644
index 0000000..1e4a593
--- /dev/null
+++ b/AI/Services/XAIService.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.Extensions.AI;
+using OllamaSharp;
+using xAiApi.AI.Interfaces;
+using xCommons.Extensions;
+using xExceptions.Constants;
+
+namespace xAiApi.AI.Services
+{
+ public class XAIService : IXAIService
+ {
+ //
+ public IChatClient TextGenreatorClient { get; }
+ public IChatClient ImageGenreatorClient { get; }
+
+ public XAIService()
+ {
+ //
+ // here we are Initialize Text Generator Model ...
+ TextGenreatorClient = new OllamaApiClient(
+ new Uri("http://localhost:11434"),
+ "gemma3:1b"
+ );
+ }
+
+ //
+ #region Actions ...
+ ///
+ /// Generated Response ...
+ ///
+ ///
+ ///
+ public async Task GetResponseAsync(string prompt)
+ {
+ //
+ // Validate ...
+ var isValid = !prompt.IsNullOrEmpty();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Generate Response ...
+ var result = await TextGenreatorClient
+ .GetResponseAsync(prompt);
+
+ //
+ return result;
+ }
+
+ ///
+ /// Generated Text ...
+ ///
+ ///
+ ///
+ public async Task GetTextResponseAsync(string prompt)
+ {
+ //
+ var response = await GetResponseAsync(prompt);
+ return response.Text;
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Controllers/OSController.cs b/Controllers/OSController.cs
new file mode 100644
index 0000000..ed9acc7
--- /dev/null
+++ b/Controllers/OSController.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using xAiApi.Helpers;
+using xCommons.Configurations;
+using xCommons.Controllers;
+using xCommons.Extensions;
+using xCommons.Providers;
+using xIdentityHelper;
+
+namespace xAiApi.Controllers
+{
+ public class OSController : XBaseController
+ {
+ public OSController(
+ ILogger logger,
+ XAppConfiguration appConfiguration,
+ XValidationProvider validationProvider
+ ) : base(
+ logger,
+ appConfiguration,
+ validationProvider
+ )
+ { }
+
+ //
+ #region Actions ...
+ ///
+ /// Get OS Type ...
+ ///
+ ///
+ [HttpGet("OSType")]
+ [Authorize(Policy = XPolicies.Admin)]
+ public ActionResult GetOSType()
+ {
+ //
+ // Do ...
+ try
+ {
+ //
+ var osType = XOsHelper.GetOSType();
+ var result = osType.GetStringValue();
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+
+ ///
+ /// Get OS Description ...
+ ///
+ ///
+ [HttpGet("OSDescription")]
+ [Authorize(Policy = XPolicies.Admin)]
+ public ActionResult GetOSDescription()
+ {
+ //
+ // Do ...
+ try
+ {
+ //
+ var result = XOsHelper.GetOSDescription();
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Controllers/V1/AIController.cs b/Controllers/V1/AIController.cs
new file mode 100644
index 0000000..e666888
--- /dev/null
+++ b/Controllers/V1/AIController.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using xAiApi.AI.Interfaces;
+using xAiApi.Base;
+using xCommons.Configurations;
+using xCommons.Providers;
+using xIdentityService.Interfaces;
+
+namespace xAiApi.Controllers.V1
+{
+ public class AIController : XIBaseV1Controller
+ {
+ private readonly IXAIService aiService;
+
+ public AIController(
+ IXAIService aiService,
+ ILogger logger,
+ XAppConfiguration appConfiguration,
+ IXIdentityProvider identityProvider,
+ XValidationProvider validationProvider
+ ) : base(
+ logger,
+ appConfiguration,
+ identityProvider,
+ validationProvider
+ )
+ {
+ this.aiService = aiService;
+ }
+
+ //
+ #region Actions ...
+ [AllowAnonymous]
+ [HttpGet("AskAI")]
+ public async Task> AskAI(
+ [FromQuery] string prompt
+ )
+ {
+ //
+ // Do ...
+ try
+ {
+ //
+ var result = await aiService
+ .GetTextResponseAsync(prompt);
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Controllers/V1/OllamaController.cs b/Controllers/V1/OllamaController.cs
new file mode 100644
index 0000000..0810ab8
--- /dev/null
+++ b/Controllers/V1/OllamaController.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+using xAiApi.Base;
+using xAiApi.Helpers;
+using xCommons.Configurations;
+using xCommons.Providers;
+using xIdentityHelper;
+using xIdentityService.Interfaces;
+
+namespace xAiApi.Controllers.V1
+{
+ public class OllamaController : XIBaseV1Controller
+ {
+ public OllamaController(
+ ILogger logger,
+ XAppConfiguration appConfiguration,
+ IXIdentityProvider identityProvider,
+ XValidationProvider validationProvider
+ ) : base(
+ logger,
+ appConfiguration,
+ identityProvider,
+ validationProvider
+ )
+ { }
+
+ //
+ #region Actions ...
+ ///
+ /// Retrieve Ollama Version ...
+ ///
+ ///
+ [HttpGet("Version")]
+ [Authorize(Policy = XPolicies.Admin)]
+ public async Task> GetVersion()
+ {
+ //
+ // Do ...
+ try
+ {
+ //
+ var result = await XOllamaHelper.GetVersion();
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+
+ ///
+ /// Retrieve a List of Available models ...
+ ///
+ ///
+ [HttpGet("Models")]
+ [Authorize(Policy = XPolicies.Admin)]
+ public async Task>> GetModels()
+ {
+ //
+ // Do ...
+ try
+ {
+ //
+ var result = await XOllamaHelper.GetModels();
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+
+ ///
+ /// Find a model ...
+ ///
+ ///
+ [HttpGet("FindModel")]
+ [Authorize(Policy = XPolicies.Admin)]
+ public async Task>> FindModel(
+ [FromQuery]
+ string model
+ )
+ {
+ //
+ // Do ...
+ try
+ {
+ //
+ var result = await XOllamaHelper.FindModel(model);
+
+ //
+ return Ok(result);
+ }
+ catch (Exception ex)
+ {
+ //
+ var result = GetExceptionActionResult(ex);
+ return result;
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Helpers/XOllamaHelper.cs b/Helpers/XOllamaHelper.cs
new file mode 100644
index 0000000..c4da791
--- /dev/null
+++ b/Helpers/XOllamaHelper.cs
@@ -0,0 +1,145 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using xCommons.Extensions;
+
+namespace xAiApi.Helpers
+{
+ public class XOllamaHelper
+ {
+ ///
+ /// Get Version ...
+ ///
+ ///
+ public static async Task GetVersion()
+ {
+ //
+ var cmd = "ollama";
+ var args = "--version";
+ var cmdResult = await XOsHelper.Execute(cmd, args);
+
+ //
+ var result =
+ cmdResult.Error.IsNullOrEmpty()
+ ? cmdResult.Result
+ : cmdResult.Error;
+
+ //
+ result = result.Replace("\n", "");
+
+ //
+ return result;
+ }
+
+ ///
+ /// Get Exists Models ...
+ ///
+ ///
+ public static async Task> GetModels()
+ {
+ //
+ var cmd = "ollama";
+ var args = "list";
+ var cmdResult = await XOsHelper.Execute(cmd, args);
+
+ //
+ var cmdResultText =
+ cmdResult.Error.IsNullOrEmpty()
+ ? cmdResult.Result
+ : cmdResult.Error;
+
+ //
+ var cmdResultList = cmdResultText
+ .Split("\n")
+ .ToList();
+ if (cmdResultList.Count > 0)
+ {
+ cmdResultList.RemoveAt(0);
+ }
+
+ //
+ var result = new List();
+ if (cmdResultList.Count > 0)
+ {
+ //
+ cmdResultList
+ .ForEach(i =>
+ {
+ //
+ if (!i.IsNullOrEmpty())
+ {
+ //
+ var d = i.Split(" ");
+ if (d.Length > 0)
+ {
+ result.Add(d[0]);
+ }
+ }
+ });
+ }
+
+ //
+ return result;
+ }
+
+ ///
+ /// Check Specified Model Exists ...
+ ///
+ ///
+ ///
+ public static async Task HasModel(string model)
+ {
+ //
+ var result = !model.IsNullOrEmpty();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ var models = await GetModels();
+ result = models.HasChild();
+ if (!result)
+ {
+ return result;
+ }
+
+ //
+ result = models
+ .Any(n => n == model || n.ToNormalString().Contains(model.ToNormalString()));
+ return result;
+ }
+
+ ///
+ /// Search Available Models ...
+ ///
+ ///
+ ///
+ public static async Task> FindModel(string model)
+ {
+ //
+ var result = new List();
+
+ //
+ if (model.IsNullOrEmpty())
+ {
+ return result;
+ }
+
+ //
+ var models = await GetModels();
+ if (!models.HasChild())
+ {
+ return result;
+ }
+
+ //
+ result = models
+ .Where(n => n == model || n.ToNormalString().Contains(model.ToNormalString()))
+ .ToList();
+
+ //
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Helpers/XOsHelper.cs b/Helpers/XOsHelper.cs
new file mode 100644
index 0000000..900903c
--- /dev/null
+++ b/Helpers/XOsHelper.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using xCommons.Extensions;
+using xExceptions.Attributes;
+using xExceptions.Constants;
+
+namespace xAiApi.Helpers
+{
+ ///
+ /// Several OS Type ...
+ ///
+ public enum XOSType
+ {
+ [StringValue("Unknown")]
+ XUnknown,
+
+ [StringValue("Mac")]
+ XMacOs,
+
+ [StringValue("Linux")]
+ XLinux,
+
+ [StringValue("Windows")]
+ XWindows,
+
+ [StringValue("FreeBSD")]
+ XFreeBSD,
+ }
+
+ ///
+ /// OS Command Execution Result ...
+ ///
+ public class XOSCMDResult
+ {
+ ///
+ /// Execution Result ...
+ ///
+ ///
+ public string Result { get; set; }
+
+ ///
+ /// Execution Error ...
+ ///
+ ///
+ public string Error { get; set; }
+ }
+
+ public static class XOsHelper
+ {
+ ///
+ /// Retrieve OS Type ...
+ ///
+ ///
+ public static XOSType GetOSType()
+ {
+ //
+ XOSType result = XOSType.XUnknown;
+
+ //
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ result = XOSType.XMacOs;
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ result = XOSType.XLinux;
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ result = XOSType.XWindows;
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
+ {
+ result = XOSType.XFreeBSD;
+ }
+
+ //
+ return result;
+ }
+
+ ///
+ /// Retrieve OS Description ...
+ ///
+ ///
+ public static string GetOSDescription()
+ {
+ //
+ var result = RuntimeInformation.OSDescription;
+ return result;
+ }
+
+ ///
+ /// Execute an Specified Command ...
+ ///
+ /// Specified Command
+ /// Command Arguments
+ ///
+ public static async Task Execute(
+ string cmd,
+ string args
+ )
+ {
+ //
+ var result = new XOSCMDResult
+ {
+ Error = "Unknown",
+ };
+
+ //
+ try
+ {
+ //
+ // Validate CMD ...
+ var isValid = !cmd.IsNullOrEmpty();
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ // Validate OS Type ...
+ XOSType osType = GetOSType();
+ isValid = osType != XOSType.XUnknown;
+ if (!isValid)
+ {
+ XException.InvalidArgs.Throw();
+ }
+
+ //
+ ProcessStartInfo psi = new ProcessStartInfo();
+
+ //
+ psi.FileName = cmd;
+ psi.Arguments = args;
+ psi.UseShellExecute = false;
+ psi.RedirectStandardError = true;
+ psi.RedirectStandardOutput = true;
+
+ //
+ Process process = Process.Start(psi);
+
+ //
+ // Read the output
+ string output = process.StandardOutput.ReadToEnd();
+ string error = process.StandardError.ReadToEnd();
+
+ //
+ await process.WaitForExitAsync();
+
+ //
+ result = new XOSCMDResult
+ {
+ Error = error,
+ Result = output,
+ };
+ }
+ catch (Exception ex)
+ {
+ result.Error = ex.Message;
+ }
+
+ //
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Startup.cs b/Startup.cs
index 294ce8f..4b46c20 100644
--- a/Startup.cs
+++ b/Startup.cs
@@ -27,6 +27,7 @@ using xAiApi.DI;
using xAiApi.Data.Helpers;
using xAiApi.Data;
using xAiApi.Data.Seeder;
+using xAiApi.AI.DI;
// using xApi.Extensions;
// using xDataHelper;
// using xDataHelper.DbSeeder;
@@ -201,6 +202,10 @@ namespace xAiApi
};
});
#endregion
+
+ //
+ // Register AI Service ...
+ services.AddXAIServices();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
@@ -263,6 +268,10 @@ namespace xAiApi
//
// Use xGraphQL Middleware ...
app.UseXGraphQL(withPlayground: withPlayground);
+
+ //
+ // Use AI Services ...
+ app.UseXAIServices();
}
}
}
\ No newline at end of file
diff --git a/xAiApi.csproj b/xAiApi.csproj
index 6d917b9..da9bf91 100644
--- a/xAiApi.csproj
+++ b/xAiApi.csproj
@@ -29,6 +29,8 @@
+
+