feat: improve admin observability and translation-first summaries

This commit is contained in:
cesnimda
2026-03-22 21:37:30 +01:00
parent 8014c1e890
commit 4c49ffb0d6
8 changed files with 585 additions and 261 deletions
@@ -71,6 +71,20 @@ namespace JobTrackerApi.Controllers
return new string(value.Trim().ToLowerInvariant().Where(char.IsLetterOrDigit).ToArray());
}
private static string BuildSummarySource(JobApplication job)
{
// Prefer translated text for summaries and skill extraction so non-English
// postings become easier to understand while keeping the original text intact.
var parts = new[]
{
job.TranslatedDescription,
job.Description,
job.Notes
};
return string.Join("\n\n", parts.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x!.Trim()));
}
private static string? NormalizeTags(string? raw)
{
var normalized = SplitTags(raw)
@@ -363,8 +377,9 @@ namespace JobTrackerApi.Controllers
.MaxAsync(c => (DateTime?)c.Date, cancellationToken);
var d = RulesEngine.Evaluate(settings, job, now, lm);
// Return persisted short summary and compute a fuller summary on demand for the details view.
var full = await _summarizer.SummarizeAsync(job.Description ?? job.Notes ?? "", 250, 40);
// Prefer translated content for the detailed summary so Norwegian postings
// surface readable English analysis while the original text remains available.
var full = await _summarizer.SummarizeAsync(BuildSummarySource(job), 250, 40);
return Ok(new JobApplicationDto(
Id: job.Id,
@@ -596,7 +611,7 @@ namespace JobTrackerApi.Controllers
// Generate and persist a short summary at creation time to avoid repeated model calls.
try
{
var shortSum = await _summarizer.SummarizeAsync(job.Description ?? job.Notes ?? "", 160, 60);
var shortSum = await _summarizer.SummarizeAsync(BuildSummarySource(job), 160, 60);
job.ShortSummary = shortSum;
}
catch
@@ -752,11 +767,10 @@ namespace JobTrackerApi.Controllers
if (job is null) return NotFound();
var sourceText = string.Join("\n\n", new[] { job.Description, job.TranslatedDescription, job.Notes }
.Where(x => !string.IsNullOrWhiteSpace(x)));
var sourceText = BuildSummarySource(job);
if (string.IsNullOrWhiteSpace(sourceText))
{
return BadRequest("This job does not have enough description or notes to generate a summary and skills.");
return BadRequest("This job does not have enough translated text, description, or notes to generate a summary and skills.");
}
var tags = SkillTagger.Detect(sourceText)
@@ -1710,7 +1724,7 @@ Candidate master CV:
))
.ToList();
return Ok(new DuplicateCheckResult(matches.Count > 0, matches));
return Ok(new DuplicateCheckResult(matches.Any(), matches));
}
[HttpGet("{id:int}/followup-draft")]