feat(ai): refactor AI prompts and add bypass option to Job Positions

This commit is contained in:
jeremy bayse
2026-04-19 21:24:56 +02:00
parent 205c24182d
commit d924765b94
6 changed files with 111 additions and 30 deletions

View File

@@ -80,42 +80,42 @@ class AIAnalysisService
$provider = $provider ?: env('AI_DEFAULT_PROVIDER', 'ollama');
$job = $candidate->jobPosition;
$jobTitle = $job->title;
$jobDesc = $job->description;
$requirements = implode(", ", $job->requirements ?? []);
// Static Part: The job context and instructions (Cacheable)
$staticPrompt = "Tu es un expert en recrutement technique spécialisé dans l'infrastructure et la cybersécurité. Ton rôle est d'analyser le profil d'un candidat pour le poste de '{$jobTitle}'.";
if (!$job->ai_prompt) {
$staticPrompt .= " Attache une grande importance aux compétences techniques et à l'expérience, mais aussi à la capacité d'intégration et à la motivation.
DESCRIPTION DU POSTE:
{$jobDesc}
COMPÉTENCES REQUISES:
{$requirements}
Fournis une analyse structurée en JSON avec les clés suivantes:
- match_score: note de 0 à 100
- summary: résumé de 3-4 phrases sur le profil
- strengths: liste des points forts par rapport au poste
- gaps: liste des compétences manquantes ou points de vigilance
- verdict: une conclusion (Favorable, Très Favorable, Réservé, Défavorable)";
// --- BYPASS LOGIC ---
if ($job->ai_bypass_base_prompt && !empty($job->ai_prompt)) {
$staticPrompt = $job->ai_prompt;
// We still append the JSON requirement to ensure the frontend doesn't crash,
// unless the user specifically asked for "pure" takeover.
// Most users want to control the "logic" not the "serialization format".
if (!str_contains(strtolower($staticPrompt), 'json')) {
$staticPrompt .= "\n\nRéponds UNIQUEMENT en JSON pur. Format attendu:\n" . config('ai.defaults.json_format');
}
} else {
$staticPrompt .= "
// --- STANDARD LOGIC ---
// Base instructions from config
$baseInstruction = config('ai.defaults.base_instruction');
$jsonFormat = config('ai.defaults.json_format');
$staticPrompt = "{$baseInstruction} Ton rôle est d'analyser le profil d'un candidat pour le poste de '{$job->title}'.\n\n";
CONTEXTE DU POSTE:
{$jobDesc}
$staticPrompt .= "DESCRIPTION DU POSTE:\n{$job->description}\n\n";
COMPÉTENCES REQUISES:
{$requirements}
if (!empty($job->requirements)) {
$staticPrompt .= "COMPÉTENCES REQUISES:\n" . implode(", ", $job->requirements) . "\n\n";
}
if (!$job->ai_prompt) {
// Default generalist analysis instructions
$staticPrompt .= "CONSIGNES D'ANALYSE:\n" . config('ai.defaults.analysis_instructions') . "\n\n";
} else {
// Specific instructions from the job position
$staticPrompt .= "CONSIGNES D'ANALYSE SPÉCIFIQUES:\n" . $job->ai_prompt . "\n\n";
}
CONSIGNES D'ANALYSE SPÉCIFIQUES:
" . $job->ai_prompt;
$staticPrompt .= "FORMAT DE RÉPONSE ATTENDU:\n{$jsonFormat}\n";
}
$staticPrompt .= "\n\nRéponds UNIQUEMENT en JSON pur, sans texte avant ou après. Assure-toi que le JSON est valide.";
$staticPrompt .= "\nRéponds UNIQUEMENT en JSON pur, sans texte avant ou après. Assure-toi que le JSON est valide.";
// Dynamic Part: The candidate data (Not cached)
$dynamicPrompt = "CONTENU DU CV DU CANDIDAT:\n{$cvText}\n\nCONTENU DE LA LETTRE DE MOTIVATION:\n" . ($letterText ?? "Non fournie");