@@ -0,0 +1,80 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Api.Requests;
|
||||
using Api.Responses;
|
||||
using Api.Services.Contracts;
|
||||
using Api.Settings;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Api.Services;
|
||||
|
||||
public sealed class RagApiClient : IRagApiClient
|
||||
{
|
||||
private readonly HttpClient _http;
|
||||
private readonly RagApiSettings _settings;
|
||||
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
||||
|
||||
public RagApiClient(HttpClient http, IOptions<RagApiSettings> options)
|
||||
{
|
||||
_http = http;
|
||||
_settings = options.Value;
|
||||
_http.BaseAddress = new Uri(_settings.BaseUrl.TrimEnd('/') + "/");
|
||||
if (!string.IsNullOrWhiteSpace(_settings.InternalApiKey))
|
||||
{
|
||||
_http.DefaultRequestHeaders.Add("X-Internal-Api-Key", _settings.InternalApiKey);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<RagIndexResponse> IndexCvPdfAsync(IFormFile file, CancellationToken ct)
|
||||
{
|
||||
using var content = new MultipartFormDataContent();
|
||||
await using var stream = file.OpenReadStream();
|
||||
using var fileContent = new StreamContent(stream);
|
||||
fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
|
||||
content.Add(fileContent, "file", file.FileName);
|
||||
content.Add(new StringContent("cv"), "documentType");
|
||||
content.Add(new StringContent(file.FileName), "title");
|
||||
using var response = await _http.PostAsync("api/rag/documents", content, ct);
|
||||
return await ReadJsonAsync<RagIndexResponse>(response, ct);
|
||||
}
|
||||
|
||||
public async Task<RagIndexResponse> IndexJobTextAsync(string text, string? url, string? title, CancellationToken ct)
|
||||
{
|
||||
using var content = new MultipartFormDataContent
|
||||
{
|
||||
{ new StringContent(text), "text" },
|
||||
{ new StringContent("job"), "documentType" },
|
||||
{ new StringContent(title ?? "Job description"), "title" }
|
||||
};
|
||||
if (!string.IsNullOrWhiteSpace(url)) content.Add(new StringContent(url), "sourceUrl");
|
||||
using var response = await _http.PostAsync("api/rag/documents", content, ct);
|
||||
return await ReadJsonAsync<RagIndexResponse>(response, ct);
|
||||
}
|
||||
|
||||
public async Task<RagDocumentDetails?> GetDocumentAsync(string documentId, CancellationToken ct)
|
||||
{
|
||||
using var response = await _http.GetAsync($"api/rag/documents/{Uri.EscapeDataString(documentId)}", ct);
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.NotFound) return null;
|
||||
return await ReadJsonAsync<RagDocumentDetails>(response, ct);
|
||||
}
|
||||
|
||||
public async Task<RagSearchResponse> SearchAsync(RagSearchRequest request, CancellationToken ct)
|
||||
{
|
||||
using var response = await _http.PostAsync(
|
||||
"api/rag/search",
|
||||
new StringContent(JsonSerializer.Serialize(request, JsonOptions), Encoding.UTF8, "application/json"),
|
||||
ct);
|
||||
return await ReadJsonAsync<RagSearchResponse>(response, ct);
|
||||
}
|
||||
|
||||
private static async Task<T> ReadJsonAsync<T>(HttpResponseMessage response, CancellationToken ct)
|
||||
{
|
||||
var json = await response.Content.ReadAsStringAsync(ct);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
throw new InvalidOperationException($"RAG API failed: {(int)response.StatusCode} {json}");
|
||||
}
|
||||
return JsonSerializer.Deserialize<T>(json, JsonOptions) ?? throw new InvalidOperationException("RAG API returned invalid JSON.");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user