refactor, security updates, cv extraction upgrades
This commit is contained in:
@@ -111,6 +111,35 @@ namespace JobTrackerApi.Services
|
||||
return $"summ:{hash}";
|
||||
}
|
||||
|
||||
|
||||
private static async Task<string> ReadErrorBodyAsync(HttpResponseMessage response, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
if (string.IsNullOrWhiteSpace(body))
|
||||
{
|
||||
return $"HTTP {(int)response.StatusCode}";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
if (doc.RootElement.TryGetProperty("detail", out var detailEl) && detailEl.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return $"HTTP {(int)response.StatusCode}: {detailEl.GetString()}";
|
||||
}
|
||||
if (doc.RootElement.TryGetProperty("message", out var messageEl) && messageEl.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
return $"HTTP {(int)response.StatusCode}: {messageEl.GetString()}";
|
||||
}
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
}
|
||||
|
||||
body = body.Length <= 400 ? body : body[..400];
|
||||
return $"HTTP {(int)response.StatusCode}: {body}";
|
||||
}
|
||||
|
||||
public async Task<string?> SummarizeAsync(string text, int maxLength = 150, int minLength = 30)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(text)) return null;
|
||||
@@ -171,12 +200,12 @@ namespace JobTrackerApi.Services
|
||||
Interlocked.Add(ref _totalLatencyTicks, sw.ElapsedTicks);
|
||||
if (!res.IsSuccessStatusCode)
|
||||
{
|
||||
var errorBody = await res.Content.ReadAsStringAsync();
|
||||
var errorBody = await ReadErrorBodyAsync(res);
|
||||
Interlocked.Increment(ref _failures);
|
||||
lock (_metricsLock)
|
||||
{
|
||||
_lastFailureAt = DateTimeOffset.UtcNow;
|
||||
_lastError = $"AI summarize returned {(int)res.StatusCode}: {errorBody}";
|
||||
_lastError = $"AI summarize failed: {errorBody}";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -235,11 +264,12 @@ namespace JobTrackerApi.Services
|
||||
Interlocked.Add(ref _totalOcrLatencyTicks, sw.ElapsedTicks);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var errorBody = await ReadErrorBodyAsync(response, cancellationToken);
|
||||
Interlocked.Increment(ref _ocrFailures);
|
||||
lock (_metricsLock)
|
||||
{
|
||||
_lastOcrFailureAt = DateTimeOffset.UtcNow;
|
||||
_lastError = $"AI extraction returned {(int)response.StatusCode}.";
|
||||
_lastError = $"AI extraction failed: {errorBody}";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -296,11 +326,12 @@ namespace JobTrackerApi.Services
|
||||
|
||||
if (!res.IsSuccessStatusCode)
|
||||
{
|
||||
var errorBody = await ReadErrorBodyAsync(res, cancellationToken);
|
||||
Interlocked.Increment(ref _probeFailures);
|
||||
lock (_metricsLock)
|
||||
{
|
||||
_lastProbeFailureAt = DateTimeOffset.UtcNow;
|
||||
_lastError = $"Probe returned {(int)res.StatusCode}.";
|
||||
_lastError = $"AI probe failed: {errorBody}";
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -358,6 +389,8 @@ namespace JobTrackerApi.Services
|
||||
double? healthLatencyMs = null;
|
||||
var healthy = false;
|
||||
string? healthError = null;
|
||||
bool? summarizeAvailable = null;
|
||||
string? modelLoadError = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -377,6 +410,8 @@ namespace JobTrackerApi.Services
|
||||
if (doc.RootElement.TryGetProperty("gpu_name", out var gpuNameEl)) gpuName = gpuNameEl.GetString();
|
||||
if (doc.RootElement.TryGetProperty("ocr_available", out var ocrAvailableEl) && ocrAvailableEl.ValueKind is JsonValueKind.True or JsonValueKind.False) ocrAvailable = ocrAvailableEl.GetBoolean();
|
||||
if (doc.RootElement.TryGetProperty("ocr_languages", out var ocrLanguagesEl)) ocrLanguages = ocrLanguagesEl.GetString();
|
||||
if (doc.RootElement.TryGetProperty("summarize_available", out var summarizeAvailableEl) && summarizeAvailableEl.ValueKind is JsonValueKind.True or JsonValueKind.False) summarizeAvailable = summarizeAvailableEl.GetBoolean();
|
||||
if (doc.RootElement.TryGetProperty("model_load_error", out var modelLoadErrorEl) && modelLoadErrorEl.ValueKind == JsonValueKind.String) modelLoadError = modelLoadErrorEl.GetString();
|
||||
if (doc.RootElement.TryGetProperty("ollama_configured", out var ollamaConfiguredEl) && ollamaConfiguredEl.ValueKind is JsonValueKind.True or JsonValueKind.False) ollamaConfigured = ollamaConfiguredEl.GetBoolean();
|
||||
if (doc.RootElement.TryGetProperty("ollama_reachable", out var ollamaReachableEl) && ollamaReachableEl.ValueKind is JsonValueKind.True or JsonValueKind.False) ollamaReachable = ollamaReachableEl.GetBoolean();
|
||||
if (doc.RootElement.TryGetProperty("ollama_model", out var ollamaModelEl)) ollamaModel = ollamaModelEl.GetString();
|
||||
@@ -391,6 +426,13 @@ namespace JobTrackerApi.Services
|
||||
ollamaLoadedModels = ollamaLoadedModelsEl.EnumerateArray().Where(x => x.ValueKind == JsonValueKind.String).Select(x => x.GetString()).Where(x => !string.IsNullOrWhiteSpace(x)).Cast<string>().ToList();
|
||||
}
|
||||
if (doc.RootElement.TryGetProperty("ollama_loaded_count", out var ollamaLoadedCountEl) && ollamaLoadedCountEl.ValueKind == JsonValueKind.Number) ollamaLoadedCount = ollamaLoadedCountEl.GetInt32();
|
||||
if (summarizeAvailable == false)
|
||||
{
|
||||
healthy = false;
|
||||
healthError = string.IsNullOrWhiteSpace(modelLoadError)
|
||||
? "AI summarize capability is unavailable."
|
||||
: modelLoadError;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user