Compare commits
1
Commits
9afa413c6f
...
ed8a66f432
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed8a66f432 |
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xAiApi.Interfaces;
|
||||
@@ -12,7 +14,7 @@ using xCommons.Providers;
|
||||
namespace xAiApi.Controllers
|
||||
{
|
||||
[Authorize]
|
||||
[Route ("[controller]")]
|
||||
[Route("[controller]")]
|
||||
public abstract class XAiServiceControllerBase<TAiService> : XBaseController, IXAiServiceControllerBase
|
||||
where TAiService : IXAiServiceBase
|
||||
{
|
||||
@@ -39,8 +41,8 @@ namespace xAiApi.Controllers
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpGet("Ask")]
|
||||
public virtual async Task<ActionResult<string>> Ask(
|
||||
[HttpGet("AskText")]
|
||||
public virtual async Task<ActionResult<string>> AskText(
|
||||
[FromQuery] string question,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
@@ -53,7 +55,7 @@ namespace xAiApi.Controllers
|
||||
ValidationProvider.NotEmpty(question);
|
||||
|
||||
//
|
||||
var result = await aiService.AskAsync(
|
||||
var result = await aiService.AskTextAsync(
|
||||
prompt: question,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
@@ -68,5 +70,85 @@ namespace xAiApi.Controllers
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask Question and Get Response Stream ...
|
||||
/// </summary>
|
||||
/// <param name="question"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[AllowAnonymous]
|
||||
[HttpGet("AskTextStream")]
|
||||
public virtual async Task AskTextStream(
|
||||
[FromQuery] string question,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
//
|
||||
try
|
||||
{
|
||||
//
|
||||
// Validate ...
|
||||
ValidationProvider.NotEmpty(question);
|
||||
|
||||
//
|
||||
// Configure SSE Response Headers ...
|
||||
Response.Headers["X-Accel-Buffering"] = "no";
|
||||
Response.Headers["Connection"] = "keep-alive";
|
||||
Response.Headers["Content-Type"] = "text/event-stream";
|
||||
Response.Headers["Cache-Control"] = "no-cache, no-store";
|
||||
|
||||
//
|
||||
// Disable response buffering ...
|
||||
var responseBodyFeature = HttpContext.Features
|
||||
.Get<Microsoft.AspNetCore.Http.Features.IHttpResponseBodyFeature>();
|
||||
responseBodyFeature?.DisableBuffering();
|
||||
|
||||
//
|
||||
// Stream Response ...
|
||||
var jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||
};
|
||||
|
||||
//
|
||||
var enumerable = aiService.AskTextAsEnumerable(
|
||||
prompt: question,
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
await foreach (var chunk in enumerable)
|
||||
{
|
||||
//
|
||||
// Skip empty chunks ...
|
||||
if (string.IsNullOrEmpty(chunk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//
|
||||
// Build SSE message ...
|
||||
// Format: data: <json>\n\n
|
||||
// var payload = JsonSerializer.Serialize(
|
||||
// new { text = chunk },
|
||||
// jsonOptions
|
||||
// );
|
||||
var payload = chunk;
|
||||
|
||||
//
|
||||
// Write SSE Event ...
|
||||
await Response.WriteAsync($"{payload}\n\n", cancellationToken);
|
||||
await Response.Body.FlushAsync(cancellationToken);
|
||||
}
|
||||
|
||||
//
|
||||
await Response.Body.FlushAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await Response.Body.FlushAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,11 +34,9 @@ namespace xAiApi.Interfaces
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Access Embedding Client ...
|
||||
/// Embedding Generator ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
OllamaApiClient GetEmbeddingClient();
|
||||
|
||||
IEmbeddingGenerator<string, Embedding<float>> GetEmbeddingGenerator();
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace xAiApi.Interfaces
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> AskAsync(
|
||||
Task<string> AskTextAsync(
|
||||
string prompt,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
@@ -29,7 +29,7 @@ namespace xAiApi.Interfaces
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
IAsyncEnumerable<string> AskAsEnumerable(
|
||||
IAsyncEnumerable<string> AskTextAsEnumerable(
|
||||
string prompt,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
@@ -12,8 +12,20 @@ namespace xAiApi.Interfaces
|
||||
/// <param name="question"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("Ask")]
|
||||
Task<ActionResult<string>> Ask(
|
||||
[HttpGet("AskText")]
|
||||
Task<ActionResult<string>> AskText(
|
||||
[FromQuery] string question,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Ask Question and Get Response Stream ...
|
||||
/// </summary>
|
||||
/// <param name="question"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("AskTextStream")]
|
||||
Task AskTextStream(
|
||||
[FromQuery] string question,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
|
||||
+10
-41
@@ -47,7 +47,7 @@ namespace xAiApi.Providers
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async Task<string> AskAsync(
|
||||
public virtual async Task<string> AskTextAsync(
|
||||
string prompt,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
@@ -81,10 +81,6 @@ namespace xAiApi.Providers
|
||||
// Retrieve Response Text ...
|
||||
var result = response.Text;
|
||||
|
||||
//
|
||||
// Dispose Client ...
|
||||
client.Dispose();
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
@@ -95,7 +91,7 @@ namespace xAiApi.Providers
|
||||
/// <param name="prompt"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public virtual async IAsyncEnumerable<string> AskAsEnumerable(
|
||||
public virtual async IAsyncEnumerable<string> AskTextAsEnumerable(
|
||||
string prompt,
|
||||
[EnumeratorCancellation]
|
||||
CancellationToken cancellationToken = default
|
||||
@@ -117,7 +113,6 @@ namespace xAiApi.Providers
|
||||
);
|
||||
|
||||
//
|
||||
var result = "";
|
||||
await foreach (var res in enumerable)
|
||||
{
|
||||
//
|
||||
@@ -128,15 +123,8 @@ namespace xAiApi.Providers
|
||||
}
|
||||
|
||||
//
|
||||
result += res.Text;
|
||||
yield return res.Text;
|
||||
}
|
||||
|
||||
//
|
||||
// Dispose Client ...
|
||||
client.Dispose();
|
||||
|
||||
//
|
||||
yield return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -172,6 +160,7 @@ namespace xAiApi.Providers
|
||||
var ollamaClient = new OllamaApiClient(httpClient, model);
|
||||
result =
|
||||
new ChatClientBuilder(ollamaClient)
|
||||
.UseFunctionInvocation()
|
||||
.Build();
|
||||
break;
|
||||
|
||||
@@ -188,9 +177,12 @@ namespace xAiApi.Providers
|
||||
}
|
||||
);
|
||||
result =
|
||||
new ChatClientBuilder(
|
||||
openAiClient
|
||||
.GetChatClient(model)
|
||||
.AsIChatClient();
|
||||
.AsIChatClient())
|
||||
.UseFunctionInvocation()
|
||||
.Build();
|
||||
break;
|
||||
|
||||
//
|
||||
@@ -206,29 +198,6 @@ namespace xAiApi.Providers
|
||||
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())
|
||||
{
|
||||
@@ -330,7 +299,7 @@ namespace xAiApi.Providers
|
||||
// Preparing Introduction Prompt ...
|
||||
var introductionPrompt = new ChatMessage(
|
||||
ChatRole.System,
|
||||
configuration.GetPrompt()
|
||||
configuration.GetPrompt(XAiApiConstants.XAiApiIntroductionPromptName)
|
||||
);
|
||||
|
||||
//
|
||||
@@ -339,7 +308,7 @@ namespace xAiApi.Providers
|
||||
introductionPrompt,
|
||||
];
|
||||
if (forceMessage &&
|
||||
message is not null)
|
||||
!message.IsNullOrDefault())
|
||||
{
|
||||
result.Add(message);
|
||||
}
|
||||
|
||||
@@ -37,11 +37,7 @@ namespace xAiApi.Providers
|
||||
XAiApiConfiguration configuration,
|
||||
ILogger<XAiEmbeddingServiceBase> logger,
|
||||
string embeddingModelName = XAiApiConstants.XAiEmbeddingModelName
|
||||
) : base(
|
||||
dataProvider,
|
||||
logger,
|
||||
configuration
|
||||
)
|
||||
) : base(dataProvider, logger, configuration)
|
||||
{
|
||||
//
|
||||
// Prepare Embedding Model Descriptor ...
|
||||
@@ -75,15 +71,13 @@ namespace xAiApi.Providers
|
||||
|
||||
//
|
||||
using var generator = GetEmbeddingGenerator();
|
||||
|
||||
//
|
||||
GeneratedEmbeddings<Embedding<float>> response = null;
|
||||
try
|
||||
{
|
||||
response = await generator.GenerateAsync([content]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex.Message);
|
||||
}
|
||||
response = await generator.GenerateAsync(
|
||||
values: [content],
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
if (response.IsNullOrDefault())
|
||||
@@ -103,40 +97,6 @@ namespace xAiApi.Providers
|
||||
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);
|
||||
@@ -166,41 +126,25 @@ namespace xAiApi.Providers
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve Ollama Client ...
|
||||
using var client = GetEmbeddingClient();
|
||||
using var generator = GetEmbeddingGenerator();
|
||||
|
||||
//
|
||||
// Create Embedding Request ....
|
||||
var request = new EmbedRequest
|
||||
{
|
||||
Input = [.. batch],
|
||||
Model = descriptor.LLM,
|
||||
};
|
||||
|
||||
//
|
||||
// Make Request and Recieve Response ...
|
||||
var response = await client.EmbedAsync(
|
||||
request: request,
|
||||
GeneratedEmbeddings<Embedding<float>> response = null;
|
||||
response = await generator.GenerateAsync(
|
||||
values: [.. batch],
|
||||
cancellationToken: cancellationToken
|
||||
);
|
||||
|
||||
//
|
||||
if (response.IsNullOrDefault())
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
|
||||
//
|
||||
// Generae Result ...
|
||||
var result = response?
|
||||
.Embeddings
|
||||
.ToArray()
|
||||
?? [];
|
||||
|
||||
//
|
||||
// Validate Result ...
|
||||
if (result.Length == 0)
|
||||
{
|
||||
XException.ActionFailed.Throw();
|
||||
}
|
||||
var result = response
|
||||
.Select(e => e.Vector.ToArray())
|
||||
.ToList();
|
||||
|
||||
//
|
||||
// Normalize ...
|
||||
@@ -214,18 +158,9 @@ namespace xAiApi.Providers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access Embedding Client ...
|
||||
/// Embedding Generator ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public OllamaApiClient GetEmbeddingClient()
|
||||
{
|
||||
//
|
||||
var result = new OllamaApiClient(new Uri(descriptor.Url));
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
public IEmbeddingGenerator<string, Embedding<float>> GetEmbeddingGenerator()
|
||||
{
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user