Files
myAi/cv-matcher-api/Services/RagApiClient.cs
T
claude fa1ef23c02
Build and Push Docker Images / build (push) Successful in 37s
Changes
2026-05-04 21:02:35 +03:00

81 lines
3.4 KiB
C#

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.");
}
}