using System.Net.Http; using System.Text; using System.Text.Json; namespace JobTrackerApi.Services; public sealed record CvBlockClassificationResult( string? Section, double? Confidence, string? Reason, string? Title, string? Company, string? Location, string? Start, string? End, List? Bullets, List? Summary, List? Skills); public interface ICvAiClassifier { Task ClassifyBlockAsync(string block, CancellationToken cancellationToken = default); } public sealed class CvAiClassifier : ICvAiClassifier { private readonly IHttpClientFactory _httpClientFactory; public CvAiClassifier(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task ClassifyBlockAsync(string block, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(block)) return null; try { var client = _httpClientFactory.CreateClient("ai-service"); var payload = JsonSerializer.Serialize(new { block }); using var content = new StringContent(payload, Encoding.UTF8, "application/json"); using var response = await client.PostAsync("/cv/classify-block", content, cancellationToken); if (!response.IsSuccessStatusCode) return null; await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken); var parsed = await JsonSerializer.DeserializeAsync(stream, new JsonSerializerOptions(JsonSerializerDefaults.Web) { PropertyNameCaseInsensitive = true }, cancellationToken); return parsed; } catch { return null; } } } public sealed class NoOpCvAiClassifier : ICvAiClassifier { public static NoOpCvAiClassifier Instance { get; } = new(); private NoOpCvAiClassifier() { } public Task ClassifyBlockAsync(string block, CancellationToken cancellationToken = default) => Task.FromResult(null); }