feat(keywords): Add hierarchical context to missing keywords prompt and fix LLM response format
This commit improves keyword generation by providing hierarchical context for each element and fixing the LLM response format parsing. Changes: 1. lib/MissingKeywords.js: - Add buildHierarchicalContext() to generate compact contextual info for each element - Display hierarchy in prompt (e.g., "H2 existants: 'Titre1', 'Titre2'") - For Txt elements: show associated MC keyword + parent title - For FAQ elements: count existing FAQs - Fix LLM response format by providing 3 concrete examples from actual list - Add explicit warning to use exact tag names [Titre_H2_3], [Txt_H2_6] - Improve getElementContext() to better retrieve hierarchical elements 2. lib/selective-enhancement/SelectiveUtils.js: - Fix createTypedPrompt() to use specific keyword from resolvedContent - Remove fallback to csvData.mc0 (log error if no specific keyword) 3. lib/pipeline/PipelineExecutor.js: - Integrate generateMissingSheetVariables() as "Étape 0" before extraction Prompt format now: 1. [Titre_H2_3] (titre) — H2 existants: "Titre1", "Titre2" 2. [Txt_H2_6] (texte) — MC: "Plaque dibond" | Parent: "Guide dibond" 3. [Faq_q_1] (question) — 3 FAQ existantes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
957df21e18
commit
3751ab047b
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,9 @@ const { tracer } = require('../trace');
|
||||
const { PipelineDefinition } = require('./PipelineDefinition');
|
||||
const { getPersonalities, readInstructionsData, selectPersonalityWithAI } = require('../BrainConfig');
|
||||
const { extractElements, buildSmartHierarchy } = require('../ElementExtraction');
|
||||
const { generateMissingKeywords } = require('../MissingKeywords');
|
||||
const { generateMissingKeywords, generateMissingSheetVariables } = require('../MissingKeywords');
|
||||
const { injectGeneratedContent } = require('../ContentAssembly');
|
||||
const { saveGeneratedArticleOrganic } = require('../ArticleStorage');
|
||||
|
||||
// Modules d'exécution
|
||||
const { generateSimple } = require('../selective-enhancement/SelectiveUtils');
|
||||
@ -31,6 +33,10 @@ class PipelineExecutor {
|
||||
this.currentContent = null;
|
||||
this.executionLog = [];
|
||||
this.checkpoints = [];
|
||||
this.versionHistory = []; // ✅ Historique des versions sauvegardées
|
||||
this.parentArticleId = null; // ✅ ID parent pour versioning
|
||||
this.csvData = null; // ✅ Données CSV pour sauvegarde
|
||||
this.finalElements = null; // ✅ Éléments extraits pour assemblage
|
||||
this.metadata = {
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
@ -55,9 +61,12 @@ class PipelineExecutor {
|
||||
this.metadata.startTime = Date.now();
|
||||
this.executionLog = [];
|
||||
this.checkpoints = [];
|
||||
this.versionHistory = []; // ✅ Reset version history
|
||||
this.parentArticleId = null; // ✅ Reset parent ID
|
||||
|
||||
// Charger les données
|
||||
const csvData = await this.loadData(rowNumber);
|
||||
this.csvData = csvData; // ✅ Stocker pour sauvegarde
|
||||
|
||||
// Exécuter les étapes
|
||||
const enabledSteps = pipelineConfig.pipeline.filter(s => s.enabled !== false);
|
||||
@ -99,6 +108,11 @@ class PipelineExecutor {
|
||||
logSh(`💾 Checkpoint sauvegardé (étape ${step.step})`, 'DEBUG');
|
||||
}
|
||||
|
||||
// ✅ Sauvegarde Google Sheets si activée
|
||||
if (options.saveIntermediateSteps && this.currentContent) {
|
||||
await this.saveStepVersion(step, result.modifications || 0, pipelineConfig.name);
|
||||
}
|
||||
|
||||
logSh(`✔ Étape ${step.step} terminée (${stepDuration}ms, ${result.modifications || 0} modifs)`, 'INFO');
|
||||
|
||||
} catch (error) {
|
||||
@ -130,6 +144,7 @@ class PipelineExecutor {
|
||||
finalContent: this.currentContent,
|
||||
executionLog: this.executionLog,
|
||||
checkpoints: this.checkpoints,
|
||||
versionHistory: this.versionHistory, // ✅ Inclure version history
|
||||
metadata: {
|
||||
...this.metadata,
|
||||
pipelineName: pipelineConfig.name,
|
||||
@ -204,12 +219,19 @@ class PipelineExecutor {
|
||||
return { content: this.currentContent, modifications: 0 };
|
||||
}
|
||||
|
||||
// Étape 1: Extraire les éléments depuis le template XML
|
||||
// 🆕 Étape 0: Générer les variables Google Sheets manquantes (MC+1_5, T+1_6, etc.)
|
||||
logSh('🔄 Vérification variables Google Sheets...', 'DEBUG');
|
||||
const updatedCsvData = await generateMissingSheetVariables(csvData.xmlTemplate, csvData);
|
||||
// Mettre à jour csvData pour les étapes suivantes
|
||||
Object.assign(csvData, updatedCsvData);
|
||||
|
||||
// Étape 1: Extraire les éléments depuis le template XML (avec csvData complet)
|
||||
const elements = await extractElements(csvData.xmlTemplate, csvData);
|
||||
logSh(`✓ Extraction: ${elements.length} éléments extraits`, 'DEBUG');
|
||||
|
||||
// Étape 2: Générer les mots-clés manquants
|
||||
// Étape 2: Générer les mots-clés manquants (titres, textes, FAQ)
|
||||
const finalElements = await generateMissingKeywords(elements, csvData);
|
||||
this.finalElements = finalElements; // ✅ Stocker pour sauvegarde
|
||||
|
||||
// Étape 3: Construire la hiérarchie
|
||||
const elementsArray = Array.isArray(finalElements) ? finalElements :
|
||||
@ -218,7 +240,7 @@ class PipelineExecutor {
|
||||
logSh(`✓ Hiérarchie: ${Object.keys(hierarchy).length} sections`, 'DEBUG');
|
||||
|
||||
// Étape 4: Génération simple avec LLM configurable
|
||||
const llmProvider = step.parameters?.llmProvider || 'claude';
|
||||
const llmProvider = step.parameters?.llmProvider || 'claude-sonnet-4-5';
|
||||
const result = await generateSimple(hierarchy, csvData, { llmProvider });
|
||||
|
||||
logSh(`✓ Génération: ${Object.keys(result.content || {}).length} éléments créés avec ${llmProvider}`, 'DEBUG');
|
||||
@ -242,7 +264,7 @@ class PipelineExecutor {
|
||||
}
|
||||
|
||||
// Configuration de la couche
|
||||
const llmProvider = step.parameters?.llmProvider || 'openai';
|
||||
const llmProvider = step.parameters?.llmProvider || 'gpt-4o-mini';
|
||||
const config = {
|
||||
csvData,
|
||||
personality: csvData.personality,
|
||||
@ -267,7 +289,7 @@ class PipelineExecutor {
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
modifications: result.modificationsCount || 0
|
||||
modifications: result.modifications || 0 // ✅ CORRIGÉ: modifications au lieu de modificationsCount
|
||||
};
|
||||
|
||||
}, { mode: step.mode, intensity: step.intensity });
|
||||
@ -288,7 +310,7 @@ class PipelineExecutor {
|
||||
return { content: this.currentContent, modifications: 0 };
|
||||
}
|
||||
|
||||
const llmProvider = step.parameters?.llmProvider || 'gemini';
|
||||
const llmProvider = step.parameters?.llmProvider || 'gemini-pro';
|
||||
const config = {
|
||||
csvData,
|
||||
detectorTarget: step.parameters?.detector || 'general',
|
||||
@ -326,7 +348,7 @@ class PipelineExecutor {
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
modifications: result.modificationsCount || 0
|
||||
modifications: result.modifications || 0 // ✅ CORRIGÉ: modifications au lieu de modificationsCount
|
||||
};
|
||||
|
||||
}, { mode: step.mode, detector: step.parameters?.detector });
|
||||
@ -347,7 +369,7 @@ class PipelineExecutor {
|
||||
return { content: this.currentContent, modifications: 0 };
|
||||
}
|
||||
|
||||
const llmProvider = step.parameters?.llmProvider || 'mistral';
|
||||
const llmProvider = step.parameters?.llmProvider || 'mistral-small';
|
||||
const config = {
|
||||
csvData,
|
||||
personality: csvData.personality,
|
||||
@ -373,7 +395,7 @@ class PipelineExecutor {
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
modifications: result.modificationsCount || 0
|
||||
modifications: result.modifications || 0 // ✅ CORRIGÉ: modifications au lieu de modificationsCount
|
||||
};
|
||||
|
||||
}, { mode: step.mode, intensity: step.intensity });
|
||||
@ -394,7 +416,7 @@ class PipelineExecutor {
|
||||
return { content: this.currentContent, modifications: 0 };
|
||||
}
|
||||
|
||||
const llmProvider = step.parameters?.llmProvider || 'deepseek';
|
||||
const llmProvider = step.parameters?.llmProvider || 'deepseek-chat';
|
||||
const config = {
|
||||
csvData,
|
||||
personality: csvData.personality,
|
||||
@ -419,7 +441,7 @@ class PipelineExecutor {
|
||||
|
||||
return {
|
||||
content: result.content || result,
|
||||
modifications: result.modificationsCount || 0
|
||||
modifications: result.modifications || 0 // ✅ CORRIGÉ: modifications au lieu de modificationsCount
|
||||
};
|
||||
|
||||
}, { mode: step.mode, intensity: step.intensity });
|
||||
@ -460,6 +482,10 @@ class PipelineExecutor {
|
||||
this.currentContent = null;
|
||||
this.executionLog = [];
|
||||
this.checkpoints = [];
|
||||
this.versionHistory = [];
|
||||
this.parentArticleId = null;
|
||||
this.csvData = null;
|
||||
this.finalElements = null;
|
||||
this.metadata = {
|
||||
startTime: null,
|
||||
endTime: null,
|
||||
@ -467,6 +493,67 @@ class PipelineExecutor {
|
||||
personality: null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ✅ Sauvegarde une version intermédiaire dans Google Sheets
|
||||
*/
|
||||
async saveStepVersion(step, modifications, pipelineName) {
|
||||
try {
|
||||
if (!this.csvData || !this.finalElements) {
|
||||
logSh('⚠️ Données manquantes pour sauvegarde, ignorée', 'WARN');
|
||||
return;
|
||||
}
|
||||
|
||||
// Déterminer la version basée sur le module et le nombre d'étapes
|
||||
const versionNumber = `v1.${step.step}`;
|
||||
const stageName = `${step.module}_${step.mode}`;
|
||||
|
||||
logSh(`💾 Sauvegarde ${versionNumber}: ${stageName}`, 'INFO');
|
||||
|
||||
// Assemblage du contenu
|
||||
const xmlString = this.csvData.xmlTemplate.startsWith('<?xml')
|
||||
? this.csvData.xmlTemplate
|
||||
: Buffer.from(this.csvData.xmlTemplate, 'base64').toString('utf8');
|
||||
|
||||
await injectGeneratedContent(xmlString, this.currentContent, this.finalElements);
|
||||
|
||||
// Sauvegarde dans Google Sheets
|
||||
const storage = await saveGeneratedArticleOrganic(
|
||||
{ generatedTexts: this.currentContent },
|
||||
this.csvData,
|
||||
{
|
||||
version: versionNumber,
|
||||
stage: stageName,
|
||||
source: `pipeline_${pipelineName}`,
|
||||
adversarialMode: step.mode === 'adversarial' ? step.mode : 'none',
|
||||
stageDescription: `${step.module} (${step.mode}) - ${modifications} modifications`,
|
||||
parentArticleId: this.parentArticleId,
|
||||
useVersionedSheet: true // ✅ Sauvegarder dans Generated_Articles_Versioned
|
||||
}
|
||||
);
|
||||
|
||||
// Stocker l'ID parent si c'est la première version
|
||||
if (!this.parentArticleId) {
|
||||
this.parentArticleId = storage.articleId;
|
||||
}
|
||||
|
||||
// Ajouter à l'historique
|
||||
this.versionHistory.push({
|
||||
version: versionNumber,
|
||||
stage: stageName,
|
||||
articleId: storage.articleId,
|
||||
length: storage.textLength,
|
||||
wordCount: storage.wordCount,
|
||||
modifications: modifications
|
||||
});
|
||||
|
||||
logSh(` ✅ Sauvé ${versionNumber} - ID: ${storage.articleId}`, 'INFO');
|
||||
|
||||
} catch (error) {
|
||||
logSh(`❌ Erreur sauvegarde version: ${error.message}`, 'ERROR');
|
||||
// Ne pas propager l'erreur pour ne pas bloquer l'exécution
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { PipelineExecutor };
|
||||
|
||||
Loading…
Reference in New Issue
Block a user