Staging to Production #51

Merged
claude merged 165 commits from main into production 2026-06-08 18:28:46 +00:00
2 changed files with 13 additions and 19 deletions
Showing only changes of commit 64e003a639 - Show all commits
@@ -123,11 +123,11 @@ public sealed class CvMatcherService : ICvMatcherService
var cvText = Limit(cv.Text, 18000); var cvText = Limit(cv.Text, 18000);
var jobText = Limit(job.Text, 14000); var jobText = Limit(job.Text, 14000);
var evidence = evidenceChunks.Count > 0 ? string.Join("\n\n", evidenceChunks.Take(4)) : Limit(job.Text, 4000); var evidence = evidenceChunks.Count > 0 ? string.Join("\n\n", evidenceChunks.Take(4)) : Limit(job.Text, 4000);
var languageName = LanguageName(language);
var promptTemplate = await _aiPrompts.GetAsync("ai.cv-match.system-prompt", "*", ct) var systemPrompt = await _aiPrompts.GetAsync("ai.cv-match.system-prompt", language, ct)
?? "You are a strict CV-to-job matching engine. Return JSON only."; ?? (language == "ro"
var systemPrompt = promptTemplate.Replace("{{languageName}}", languageName, StringComparison.OrdinalIgnoreCase); ? "Ești un motor strict de potrivire CV-job. Returnează doar JSON. Punctează realist între 0 și 100."
: "You are a strict CV-to-job matching engine. Return JSON only. Score realistically from 0 to 100.");
var userPrompt = $""" var userPrompt = $"""
CV: CV:
@@ -195,14 +195,6 @@ public sealed class CvMatcherService : ICvMatcherService
private static string NormalizeLanguage(string? language) => private static string NormalizeLanguage(string? language) =>
string.IsNullOrWhiteSpace(language) ? "en" : language.ToLowerInvariant().Split('-')[0].Trim(); string.IsNullOrWhiteSpace(language) ? "en" : language.ToLowerInvariant().Split('-')[0].Trim();
/// <summary>Maps a language code to its full English name for use in the LLM system prompt.</summary>
private static string LanguageName(string language) => language switch
{
"ro" => "Romanian",
"en" => "English",
_ => "English"
};
/// <summary>Truncates <paramref name="value"/> to at most <paramref name="max"/> characters.</summary> /// <summary>Truncates <paramref name="value"/> to at most <paramref name="max"/> characters.</summary>
private static string Limit(string value, int max) => value.Length <= max ? value : value[..max]; private static string Limit(string value, int max) => value.Length <= max ? value : value[..max];
} }
@@ -71,16 +71,18 @@ namespace CvMatcher.Data.Migrations
columns: new[] { "CvDocumentId", "JobDocumentId", "Language" }, columns: new[] { "CvDocumentId", "JobDocumentId", "Language" },
unique: true); unique: true);
// Seed AI prompts for CV matching // Seed AI prompts for CV matching (language-specific)
migrationBuilder.Sql($$""" migrationBuilder.Sql($$"""
INSERT INTO [cvMatcher].AiPrompts ([Key], [Language], [Value], [Description]) INSERT INTO [cvMatcher].AiPrompts ([Key], [Language], [Value], [Description])
VALUES VALUES
('ai.cv-match.system-prompt', '*', ('ai.cv-match.system-prompt', 'en',
'You are a strict CV-to-job matching engine. Return JSON only. Score realistically from 0 to 100. 'You are a strict CV-to-job matching engine. Return JSON only. Score realistically from 0 to 100. Penalize missing required skills. Do not invent experience. Use concise business language. All text fields in the JSON response must be in English.
Penalize missing required skills. Do not invent experience. Use concise business language. JSON shape: {""score"":number,""summary"":""one-line summary in English"",""strengths"":[""strength 1 in English"",""strength 2 in English""],""gaps"":[""gap 1 in English""],""recommendations"":[""recommendation 1 in English""],""evidence"":[""evidence 1 in English""]}',
Respond entirely in {{languageName}} — all text fields in the JSON must be in {{languageName}}. 'System prompt for CV-to-job matching in English. Instructs LLM to return JSON with CV strengths, gaps, and recommendations relative to the job.'),
JSON shape: {""score"":number,""summary"":""..."",""strengths"":[""...""],""gaps"":[""...""],""recommendations"":[""...""],""evidence"":[""...""]}', ('ai.cv-match.system-prompt', 'ro',
'System prompt template for the CV-to-job LLM matching call. {{languageName}} is substituted at runtime.'); 'Ești un motor strict de potrivire CV-job. Returnează doar JSON. Punctează realist între 0 și 100. Penalizează abilitățile lipsă necesare. Nu inventa experiență. Folosește limbaj profesional concis. Toate câmpurile text din răspunsul JSON trebuie să fie în limba română.
JSON shape: {""score"":number,""summary"":""rezumat pe o linie în română"",""strengths"":[""punct forte 1 în română"",""punct forte 2 în română""],""gaps"":[""lipsă 1 în română""],""recommendations"":[""recomandare 1 în română""],""evidence"":[""dovadă 1 în română""]}',
'System prompt pentru potrivire CV-job în limba română. Instruiește LLM-ul să returneze JSON cu punctele forte ale CV-ului, lacunele și recomandări relative la job.');
"""); """);
} }