This commit is contained in:
2026-04-10 17:41:01 +03:30
parent 523ad16b3c
commit e4ddceafa0
11 changed files with 416 additions and 50 deletions
+29
View File
@@ -0,0 +1,29 @@
namespace xAiApi.AI.Configuration
{
public class XAiApiConfiguration
{
/// <summary>
/// AI Provider Client URL ...
/// </summary>
/// <value></value>
public string Url { get; set; }
/// <summary>
/// Text Generator Model Name ...
/// </summary>
/// <value></value>
public string TextModel { get; set; }
/// <summary>
/// Code Generator Model Name ...
/// </summary>
/// <value></value>
public string CodeModel { get; set; }
/// <summary>
/// Image Generator Model Name ...
/// </summary>
/// <value></value>
public string ImageModel { get; set; }
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace xAiApi.AI.Constants
{
public partial struct ConfigurationNodeNames
{
public const string AI_API_SERVICE_NODE = "AiApiServiceConfiguration";
}
}
+7 -2
View File
@@ -11,9 +11,10 @@ namespace xAiApi.AI.DI
/// Register AI Services ...
/// </summary>
/// <param name="services"></param>
public static void AddXAIServices(this IServiceCollection services)
public static void AddXAIServices(
this IServiceCollection services
)
{
//
services.AddSingleton<IXAIService, XAIService>();
}
@@ -23,5 +24,9 @@ namespace xAiApi.AI.DI
/// <param name="builder"></param>
public static void UseXAIServices(this IApplicationBuilder builder)
{ }
//
#region Private ...
#endregion
}
}
@@ -0,0 +1,70 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using xAiApi.AI.Configuration;
using xAiApi.AI.Constants;
using xCommons.Extensions;
namespace xAiApi.AI.Extensions
{
public static class XAiApiConfigurationExtension
{
/// <summary>
/// Extract Configuration ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static XAiApiConfiguration GetXAiApiConfiguration(this IConfiguration source)
{
//
var section = source.GetSection(ConfigurationNodeNames.AI_API_SERVICE_NODE);
var result = section.Get<XAiApiConfiguration>();
//
return result;
}
/// <summary>
/// Add XAiApiConfiguration ...
/// </summary>
/// <param name="source"></param>
/// <param name="configuration"></param>
public static void AddXAiApiConfiguration(
this IServiceCollection source,
XAiApiConfiguration configuration
)
{
//
if (!configuration.IsValid())
{
return;
}
//
source.AddSingleton(configuration);
}
/// <summary>
/// Validate XAiApiConfiguration ...
/// </summary>
/// <param name="configuration"></param>
/// <returns></returns>
public static bool IsValid(this XAiApiConfiguration configuration)
{
//
var result =
!configuration.IsNull() &&
!configuration.Url.IsNullOrEmpty() &&
configuration.Url.IsValidUrl() &&
!configuration.TextModel.IsNullOrEmpty();
//
if (!result)
{
return result;
}
//
return result;
}
}
}
+58 -2
View File
@@ -1,28 +1,84 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel.ChatCompletion;
using xAiApi.AI.Configuration;
namespace xAiApi.AI.Interfaces
{
public interface IXAIService
{
/// <summary>
/// Provides Options for Chat ...
/// </summary>
/// <value></value>
ChatOptions ChatOptions { get; }
/// <summary>
/// Provides History for Chat ...
/// </summary>
/// <value></value>
ChatHistory ChatHistory { get; }
/// <summary>
/// a Client for Text Chat ...
/// </summary>
/// <value></value>
IChatClient TextGenreatorClient { get; }
/// <summary>
/// a Client for Code Chat ...
/// </summary>
/// <value></value>
IChatClient CodeGenreatorClient { get; }
/// <summary>
/// a Client for Image Chats ...
/// </summary>
/// <value></value>
IChatClient ImageGenreatorClient { get; }
/// <summary>
/// Configuration ...
/// </summary>
/// <value></value>
XAiApiConfiguration Configuration { get; }
//
#region Actions ...
/// <summary>
/// Generated Text ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<string> GetTextResponseAsync(string prompt);
Task<string> GetTextResponseAsync(
string prompt,
CancellationToken cancellationToken = default
);
/// <summary>
/// Generated Response ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
Task<ChatResponse> GetResponseAsync(string prompt);
Task<ChatResponse> GetResponseAsync(
string prompt,
CancellationToken cancellationToken = default
);
/// <summary>
/// Generate Text Response Stream ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
IAsyncEnumerable<ChatResponseUpdate> GetTextReponseStreamAsync(
string prompt,
CancellationToken cancellationToken = default
);
#endregion
}
}
+201 -12
View File
@@ -1,37 +1,140 @@
using System;
using OllamaSharp;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
using OllamaSharp;
using xAiApi.AI.Interfaces;
using xCommons.Extensions;
using xExceptions.Constants;
using xAiApi.AI.Configuration;
using System.Collections.Generic;
using Microsoft.SemanticKernel.ChatCompletion;
using System.Threading;
namespace xAiApi.AI.Services
{
public class XAIService : IXAIService
{
//
/// <summary>
/// Provides Options for Chat ...
/// </summary>
/// <value></value>
public ChatOptions ChatOptions { get; }
/// <summary>
/// Provides History for Chat ...
/// </summary>
/// <value></value>
public ChatHistory ChatHistory { get; }
/// <summary>
/// a Client for Text Chat ...
/// </summary>
/// <value></value>
public IChatClient TextGenreatorClient { get; }
/// <summary>
/// a Client for Code Chat ...
/// </summary>
/// <value></value>
public IChatClient CodeGenreatorClient { get; }
/// <summary>
/// a Client for Image Chats ...
/// </summary>
/// <value></value>
public IChatClient ImageGenreatorClient { get; }
public XAIService()
/// <summary>
/// Configuration ...
/// </summary>
/// <value></value>
public XAiApiConfiguration Configuration { get; }
/// <summary>
/// Constructing Service ...
/// </summary>
/// <param name="configuration">configuration ...</param>
public XAIService(
XAiApiConfiguration configuration
)
{
//
Configuration = configuration;
//
// here we are Initialize Text Generator Model ...
TextGenreatorClient = new OllamaApiClient(
new Uri("http://localhost:11434"),
"gemma3:1b"
);
TextGenreatorClient = new ChatClientBuilder(new OllamaApiClient(
new Uri(configuration.Url),
configuration.TextModel
))
// .UseFunctionInvocation()
.Build();
//
// Code Generator Client ...
if (!configuration.CodeModel.IsNullOrEmpty())
{
//
CodeGenreatorClient = new ChatClientBuilder(new OllamaApiClient(
new Uri(configuration.Url),
configuration.CodeModel
))
// .UseFunctionInvocation()
.Build();
}
//
// Image Generator Client ...
if (!configuration.ImageModel.IsNullOrEmpty())
{
//
ImageGenreatorClient = new ChatClientBuilder(new OllamaApiClient(
new Uri(configuration.Url),
configuration.ImageModel
))
// .UseFunctionInvocation()
.Build();
}
//
// Configuring Chant Options ...
ChatOptions = new ChatOptions()
{
//
// Preparing Tools ...
// Tools = [
// //
// // Tempreature Tool ...
// AIFunctionFactory.Create((string location, string unit) => {
// //
// var temp = Random.Shared.Next(5, 20);
// var cond = Random.Shared.Next(0, 1) == 0 ? "sunny" : "rainy";
// //
// var result = $"The weather is {temp} degrees C and {cond}.";
// //
// return result;
// },
// "get_current_weather",
// "Get the current weather in given location"
// )
// ],
};
}
//
#region Actions ...
#region Text Actions ...
/// <summary>
/// Generated Response ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<ChatResponse> GetResponseAsync(string prompt)
public async Task<ChatResponse> GetResponseAsync(
string prompt,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
@@ -41,10 +144,21 @@ namespace xAiApi.AI.Services
XException.InvalidArgs.Throw();
}
//
// Preparing Prompt ...
prompt = await PreparePrompt(
prompt: prompt,
cancellationToken: cancellationToken
);
//
// Generate Response ...
var result = await TextGenreatorClient
.GetResponseAsync(prompt);
.GetResponseAsync(
chatMessage: prompt,
options: ChatOptions,
cancellationToken: cancellationToken
);
//
return result;
@@ -54,13 +168,88 @@ namespace xAiApi.AI.Services
/// Generated Text ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<string> GetTextResponseAsync(string prompt)
public async Task<string> GetTextResponseAsync(
string prompt,
CancellationToken cancellationToken = default
)
{
//
var response = await GetResponseAsync(prompt);
var response = await GetResponseAsync(
prompt: prompt,
cancellationToken: cancellationToken
);
//
return response.Text;
}
/// <summary>
/// Generate Text Response Stream ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public IAsyncEnumerable<ChatResponseUpdate> GetTextReponseStreamAsync(
string prompt,
CancellationToken cancellationToken = default
)
{
//
// Validate ...
var isValid = !prompt.IsNullOrEmpty();
if (!isValid)
{
XException.InvalidArgs.Throw();
}
//
// Preparing Prompt ...
prompt = PreparePrompt(
prompt: prompt,
cancellationToken: cancellationToken
)
.RunTask();
//
// Generate Response ...
var result = TextGenreatorClient
.GetStreamingResponseAsync(
chatMessage: prompt,
options: ChatOptions,
cancellationToken: cancellationToken
);
//
return result;
}
#endregion
//
#region Code Actions ...
#endregion
//
#region Image Actions ...
#endregion
//
#region Private ...
/// <summary>
/// Preparing Prompt for AI ...
/// </summary>
/// <param name="prompt"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
private async Task<string> PreparePrompt(
string prompt,
CancellationToken cancellationToken = default
)
{
//
return await Task.FromResult(prompt);
}
#endregion
}
}
+32
View File
@@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
using xAiApi.AI.Interfaces;
using xAiApi.Base;
using xCommons.Configurations;
using xCommons.Extensions;
using xCommons.Providers;
using xIdentityService.Interfaces;
@@ -57,6 +58,37 @@ namespace xAiApi.Controllers.V1
return result;
}
}
[AllowAnonymous]
[HttpGet("AskAIStream")]
public async Task AskAIStream(
[FromQuery] string prompt
)
{
//
// Do ...
try
{
//
var stream = aiService
.GetTextReponseStreamAsync(prompt);
await foreach (var message in stream)
{
//
// Do What we Have to Do with Message ...
//
var msgBytes = message.Text.ToBytes();
await Response.Body.WriteAsync(msgBytes, 0, msgBytes.Length);
await Response.Body.FlushAsync();
}
//
await Response.Body.FlushAsync();
}
catch
{ }
}
#endregion
}
}
View File
-32
View File
@@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
namespace xAiApi.DI
{
public static class XPushDIExtensions
{
/// <summary>
/// Register XPushProvider Services
/// </summary>
/// <param name="services"></param>
public static void AddXPushHubProvider(
this IServiceCollection services,
ServiceLifetime lifeTime = ServiceLifetime.Transient
)
{
AddPushHubProvider(services, lifeTime);
}
//
#region Private ...
private static void AddPushHubProvider(
this IServiceCollection services,
ServiceLifetime lifeTime = ServiceLifetime.Transient
)
{ }
#endregion
}
}
+8 -2
View File
@@ -23,11 +23,11 @@ using xDataService.DI;
using xDataService.Interfaces;
using xPushService.Helpers;
using xAiApi.Extensions;
using xAiApi.DI;
using xAiApi.Data.Helpers;
using xAiApi.Data;
using xAiApi.Data.Seeder;
using xAiApi.AI.DI;
using xAiApi.AI.Extensions;
// using xApi.Extensions;
// using xDataHelper;
// using xDataHelper.DbSeeder;
@@ -122,7 +122,7 @@ namespace xAiApi
//
// Register XPushService ...
services.AddXPushService(Configuration);
services.AddXPushHubProvider(lifeTime);
// services.AddXPushHubProvider(lifeTime);
//
// Register XIdentityService ...
@@ -203,6 +203,12 @@ namespace xAiApi
});
#endregion
//
// Registering Configurations ...
var xAiApiConfiguration = Configuration
.GetXAiApiConfiguration();
services.AddXAiApiConfiguration(xAiApiConfiguration);
//
// Register AI Service ...
services.AddXAIServices();
+4
View File
@@ -7,6 +7,10 @@
"http://api.saherelmhub.ir",
"https://api.saherelmhub.ir"
],
"AiApiServiceConfiguration": {
"Url":"http://localhost:11434",
"TextModel": "gemma3:1b"
},
"IdentityServiceConfiguration": {
"Authority": "https://localhost:4001",
"ApiName": "xSaherElmAPI",