From 8868afe656f3fb4df02c48f6c6f139c42aae5a99 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Fri, 17 Apr 2026 03:04:14 +0330 Subject: [PATCH] last ... --- AI/Extensions/AiModelsExtensions.cs | 25 ++++ AI/Interfaces/IXAIService.cs | 35 +++++- AI/Services/XAIService.cs | 176 +++++++++++++++++++++++++++- Controllers/V1/AIController.cs | 74 +++++++++++- xAiApi.csproj | 3 +- 5 files changed, 307 insertions(+), 6 deletions(-) create mode 100644 AI/Extensions/AiModelsExtensions.cs diff --git a/AI/Extensions/AiModelsExtensions.cs b/AI/Extensions/AiModelsExtensions.cs new file mode 100644 index 0000000..f5da4e0 --- /dev/null +++ b/AI/Extensions/AiModelsExtensions.cs @@ -0,0 +1,25 @@ +using xCommons.Extensions; +using System.Collections.Generic; +using Microsoft.Extensions.AI; +using System.Linq; + +namespace xAiApi.AI.Extensions +{ + public static class AiModelsExtensions + { + public static AIContent GetLast(IList source) + { + // + AIContent result = null; + + // + if (source.HasChild()) + { + result = source.ElementAt(source.Count - 1); + } + + // + return result; + } + } +} \ No newline at end of file diff --git a/AI/Interfaces/IXAIService.cs b/AI/Interfaces/IXAIService.cs index 0e37b82..716480a 100644 --- a/AI/Interfaces/IXAIService.cs +++ b/AI/Interfaces/IXAIService.cs @@ -69,13 +69,46 @@ namespace xAiApi.AI.Interfaces CancellationToken cancellationToken = default ); + /// + /// Generated Response ... + /// + /// ChatMessage instance + /// + /// + Task GetResponseByChatMessageAsync( + ChatMessage message, + CancellationToken cancellationToken = default + ); + + /// + /// Generated Response ... + /// + /// ChatMessage Enumerable instance + /// + /// + Task GetResponseByChatMessagesAsync( + IEnumerable messages, + CancellationToken cancellationToken = default + ); + /// /// Generate Text Response Stream ... /// /// /// /// - IAsyncEnumerable GetTextReponseStreamAsync( + IAsyncEnumerable GetReponseStreamAsync( + string prompt, + CancellationToken cancellationToken = default + ); + + /// + /// Generate Text Response Stream ... + /// + /// + /// + /// + IAsyncEnumerable GetTextReponseStreamAsync( string prompt, CancellationToken cancellationToken = default ); diff --git a/AI/Services/XAIService.cs b/AI/Services/XAIService.cs index 8559eb1..881b89c 100644 --- a/AI/Services/XAIService.cs +++ b/AI/Services/XAIService.cs @@ -9,6 +9,7 @@ using xAiApi.AI.Configuration; using System.Collections.Generic; using System.Threading; using Microsoft.SemanticKernel.ChatCompletion; +using System.Runtime.CompilerServices; namespace xAiApi.AI.Services { @@ -155,7 +156,85 @@ namespace xAiApi.AI.Services // Generate Response ... var result = await TextGenreatorClient .GetResponseAsync( - chatMessage: prompt, + chatMessage: prompt, + options: ChatOptions, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Generated Response ... + /// + /// ChatMessage instance + /// + /// + public async Task GetResponseByChatMessageAsync( + ChatMessage message, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = !message.IsNull() && !message.Contents.HasChild(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Preparing Prompt ... + var prompt = await PreparePrompt( + message: message, + cancellationToken: cancellationToken + ); + + // + // Generate Response ... + var result = await TextGenreatorClient + .GetResponseAsync( + chatMessage: prompt, + options: ChatOptions, + cancellationToken: cancellationToken + ); + + // + return result; + } + + /// + /// Generated Response ... + /// + /// ChatMessage Enumerable instance + /// + /// + public async Task GetResponseByChatMessagesAsync( + IEnumerable messages, + CancellationToken cancellationToken = default + ) + { + // + // Validate ... + var isValid = !messages.IsNull() && messages.HasChild(); + if (!isValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Preparing Prompt ... + var prompt = await PreparePrompt( + messages: messages, + cancellationToken: cancellationToken + ); + + // + // Generate Response ... + var result = await TextGenreatorClient + .GetResponseAsync( + messages: prompt, options: ChatOptions, cancellationToken: cancellationToken ); @@ -191,7 +270,59 @@ namespace xAiApi.AI.Services /// /// /// - public IAsyncEnumerable GetTextReponseStreamAsync( + public async IAsyncEnumerable GetTextReponseStreamAsync( + string prompt, + [EnumeratorCancellation] + 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 stream = TextGenreatorClient + .GetStreamingResponseAsync( + chatMessage: prompt, + options: ChatOptions, + cancellationToken: cancellationToken + ); + + // + await foreach (var response in stream) + { + // + if (response.IsNull()) + { + yield break; + } + + // + var model = response.Text; + yield return model; + } + } + + /// + /// Generate Text Response Stream ... + /// + /// + /// + /// + public IAsyncEnumerable GetReponseStreamAsync( string prompt, CancellationToken cancellationToken = default ) @@ -248,7 +379,46 @@ namespace xAiApi.AI.Services ) { // - return await Task.FromResult(prompt); + return await Task.Run(() => + { + return prompt; + }, cancellationToken); + } + + /// + /// Preparing Prompt for AI ... + /// + /// + /// + /// + private async Task PreparePrompt( + ChatMessage message, + CancellationToken cancellationToken = default + ) + { + // + return await Task.Run(() => + { + return message; + }, cancellationToken); + } + + /// + /// Preparing Prompt for AI ... + /// + /// + /// + /// + private async Task> PreparePrompt( + IEnumerable messages, + CancellationToken cancellationToken = default + ) + { + // + return await Task.Run(() => + { + return messages; + }, cancellationToken); } #endregion } diff --git a/Controllers/V1/AIController.cs b/Controllers/V1/AIController.cs index ce09c0e..8ac330f 100644 --- a/Controllers/V1/AIController.cs +++ b/Controllers/V1/AIController.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.AI; using Microsoft.Extensions.Logging; using xAiApi.AI.Interfaces; using xAiApi.Base; @@ -66,6 +67,35 @@ namespace xAiApi.Controllers.V1 } } + [HttpGet("AskAIAsChatMessage")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task> AskAIAsChatMessage( + [FromQuery] string prompt, + CancellationToken cancellationToken = default + ) + { + // + // Do ... + try + { + // + var result = await aiService + .GetResponseAsync( + prompt: prompt, + cancellationToken: cancellationToken + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + [HttpGet("AskAIStream")] [Authorize(Policy = XPolicies.EnabledUser)] public async Task AskAIStream( @@ -97,7 +127,7 @@ namespace xAiApi.Controllers.V1 // Do What we Have to Do with Message ... // - var msgBytes = message.Text.ToBytes(); + var msgBytes = message.ToBytes(); await Response.Body.WriteAsync( msgBytes, 0, @@ -113,6 +143,48 @@ namespace xAiApi.Controllers.V1 catch (Exception) { } } + + [HttpGet("AskAIStreamAsChatMessage")] + [Authorize(Policy = XPolicies.EnabledUser)] + public async Task AskAIStreamAsChatMessage( + [FromQuery] string prompt, + CancellationToken cancellationToken = default + ) + { + // + // Do ... + try + { + // + // Adding Content Type ... + Response.Headers + .Append("Content-Type", "text/event-stream"); + + // + // Retrieving Stream ... + var stream = aiService + .GetReponseStreamAsync( + prompt: prompt, + cancellationToken: cancellationToken + ); + + // + await foreach (var message in stream) + { + // + await Response.Body.WriteModelToStream( + model: message, + cancellationToken: cancellationToken + ); + } + + // + // Closing Connection ... + await Response.Body.FlushAsync(); + } + catch (Exception) + { } + } #endregion } } \ No newline at end of file diff --git a/xAiApi.csproj b/xAiApi.csproj index da9bf91..832f180 100644 --- a/xAiApi.csproj +++ b/xAiApi.csproj @@ -17,12 +17,13 @@ + - +