316 lines
11 KiB
JavaScript
316 lines
11 KiB
JavaScript
// ========================================
|
|
// ÉTAPE 2: ENHANCEMENT TECHNIQUE ADVERSARIAL
|
|
// Responsabilité: Améliorer la précision technique avec GPT-4 + anti-détection
|
|
// LLM: GPT-4o-mini (température 0.4) + Prompts adversariaux
|
|
// ========================================
|
|
|
|
const { callLLM } = require('../LLMManager');
|
|
const { logSh } = require('../ErrorReporting');
|
|
const { tracer } = require('../trace');
|
|
const { createAdversarialPrompt } = require('./AdversarialPromptEngine');
|
|
const { DetectorStrategyManager } = require('./DetectorStrategies');
|
|
|
|
/**
|
|
* MAIN ENTRY POINT - ENHANCEMENT TECHNIQUE ADVERSARIAL
|
|
* Input: { content: {}, csvData: {}, context: {}, adversarialConfig: {} }
|
|
* Output: { content: {}, stats: {}, debug: {} }
|
|
*/
|
|
async function enhanceTechnicalTermsAdversarial(input) {
|
|
return await tracer.run('AdversarialTechnicalEnhancement.enhanceTechnicalTermsAdversarial()', async () => {
|
|
const { content, csvData, context = {}, adversarialConfig = {} } = input;
|
|
|
|
// Configuration adversariale par défaut
|
|
const config = {
|
|
detectorTarget: adversarialConfig.detectorTarget || 'general',
|
|
intensity: adversarialConfig.intensity || 1.0,
|
|
enableAdaptiveStrategy: adversarialConfig.enableAdaptiveStrategy || true,
|
|
contextualMode: adversarialConfig.contextualMode !== false,
|
|
...adversarialConfig
|
|
};
|
|
|
|
// Initialiser manager détecteur
|
|
const detectorManager = new DetectorStrategyManager(config.detectorTarget);
|
|
|
|
await tracer.annotate({
|
|
step: '2/4',
|
|
llmProvider: 'gpt4',
|
|
elementsCount: Object.keys(content).length,
|
|
mc0: csvData.mc0
|
|
});
|
|
|
|
const startTime = Date.now();
|
|
logSh(`🎯 ÉTAPE 2/4 ADVERSARIAL: Enhancement technique (GPT-4 + ${config.detectorTarget})`, 'INFO');
|
|
logSh(` 📊 ${Object.keys(content).length} éléments à analyser`, 'INFO');
|
|
|
|
try {
|
|
// 1. Analyser tous les éléments pour détecter termes techniques (adversarial)
|
|
const technicalAnalysis = await analyzeTechnicalTermsAdversarial(content, csvData, config, detectorManager);
|
|
|
|
// 2. Filter les éléments qui ont besoin d'enhancement
|
|
const elementsNeedingEnhancement = technicalAnalysis.filter(item => item.needsEnhancement);
|
|
|
|
logSh(` 📋 Analyse: ${elementsNeedingEnhancement.length}/${Object.keys(content).length} éléments nécessitent enhancement`, 'INFO');
|
|
|
|
if (elementsNeedingEnhancement.length === 0) {
|
|
logSh(`✅ ÉTAPE 2/4: Aucun enhancement nécessaire`, 'INFO');
|
|
return {
|
|
content,
|
|
stats: { processed: Object.keys(content).length, enhanced: 0, duration: Date.now() - startTime },
|
|
debug: { llmProvider: 'gpt4', step: 2, enhancementsApplied: [] }
|
|
};
|
|
}
|
|
|
|
// 3. Améliorer les éléments sélectionnés avec prompts adversariaux
|
|
const enhancedResults = await enhanceSelectedElementsAdversarial(elementsNeedingEnhancement, csvData, config, detectorManager);
|
|
|
|
// 4. Merger avec contenu original
|
|
const finalContent = { ...content };
|
|
let actuallyEnhanced = 0;
|
|
|
|
Object.keys(enhancedResults).forEach(tag => {
|
|
if (enhancedResults[tag] !== content[tag]) {
|
|
finalContent[tag] = enhancedResults[tag];
|
|
actuallyEnhanced++;
|
|
}
|
|
});
|
|
|
|
const duration = Date.now() - startTime;
|
|
const stats = {
|
|
processed: Object.keys(content).length,
|
|
enhanced: actuallyEnhanced,
|
|
candidate: elementsNeedingEnhancement.length,
|
|
duration
|
|
};
|
|
|
|
logSh(`✅ ÉTAPE 2/4 TERMINÉE: ${stats.enhanced} éléments améliorés (${duration}ms)`, 'INFO');
|
|
|
|
await tracer.event(`Enhancement technique terminé`, stats);
|
|
|
|
return {
|
|
content: finalContent,
|
|
stats,
|
|
debug: {
|
|
llmProvider: 'gpt4',
|
|
step: 2,
|
|
enhancementsApplied: Object.keys(enhancedResults),
|
|
technicalTermsFound: elementsNeedingEnhancement.map(e => e.technicalTerms),
|
|
adversarialConfig: config,
|
|
detectorTarget: config.detectorTarget,
|
|
intensity: config.intensity
|
|
}
|
|
};
|
|
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
logSh(`❌ ÉTAPE 2/4 ÉCHOUÉE après ${duration}ms: ${error.message}`, 'ERROR');
|
|
throw new Error(`TechnicalEnhancement failed: ${error.message}`);
|
|
}
|
|
}, input);
|
|
}
|
|
|
|
/**
|
|
* Analyser tous les éléments pour détecter termes techniques (adversarial)
|
|
*/
|
|
async function analyzeTechnicalTermsAdversarial(content, csvData, adversarialConfig, detectorManager) {
|
|
logSh(`🎯 Analyse termes techniques adversarial batch`, 'DEBUG');
|
|
|
|
const contentEntries = Object.keys(content);
|
|
|
|
const analysisPrompt = `MISSION: Analyser ces ${contentEntries.length} contenus et identifier leurs termes techniques.
|
|
|
|
CONTEXTE: ${csvData.mc0} - Secteur: signalétique/impression
|
|
|
|
CONTENUS À ANALYSER:
|
|
|
|
${contentEntries.map((tag, i) => `[${i + 1}] TAG: ${tag}
|
|
CONTENU: "${content[tag]}"`).join('\n\n')}
|
|
|
|
CONSIGNES:
|
|
- Identifie UNIQUEMENT les vrais termes techniques métier/industrie
|
|
- Évite mots génériques (qualité, service, pratique, personnalisé)
|
|
- Focus: matériaux, procédés, normes, dimensions, technologies
|
|
- Si aucun terme technique → "AUCUN"
|
|
|
|
EXEMPLES VALIDES: dibond, impression UV, fraisage CNC, épaisseur 3mm
|
|
EXEMPLES INVALIDES: durable, pratique, personnalisé, moderne
|
|
|
|
FORMAT RÉPONSE:
|
|
[1] dibond, impression UV OU AUCUN
|
|
[2] AUCUN
|
|
[3] aluminium, fraisage CNC OU AUCUN
|
|
etc...`;
|
|
|
|
try {
|
|
// Générer prompt adversarial pour analyse
|
|
const adversarialAnalysisPrompt = createAdversarialPrompt(analysisPrompt, {
|
|
detectorTarget: adversarialConfig.detectorTarget,
|
|
intensity: adversarialConfig.intensity * 0.8, // Intensité modérée pour analyse
|
|
elementType: 'technical_analysis',
|
|
personality: csvData.personality,
|
|
contextualMode: adversarialConfig.contextualMode,
|
|
csvData: csvData,
|
|
debugMode: false
|
|
});
|
|
|
|
const analysisResponse = await callLLM('gpt4', adversarialAnalysisPrompt, {
|
|
temperature: 0.3,
|
|
maxTokens: 2000
|
|
}, csvData.personality);
|
|
|
|
return parseAnalysisResponse(analysisResponse, content, contentEntries);
|
|
|
|
} catch (error) {
|
|
logSh(`❌ Analyse termes techniques échouée: ${error.message}`, 'ERROR');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Améliorer les éléments sélectionnés avec prompts adversariaux
|
|
*/
|
|
async function enhanceSelectedElementsAdversarial(elementsNeedingEnhancement, csvData, adversarialConfig, detectorManager) {
|
|
logSh(`🎯 Enhancement adversarial ${elementsNeedingEnhancement.length} éléments`, 'DEBUG');
|
|
|
|
const enhancementPrompt = `MISSION: Améliore UNIQUEMENT la précision technique de ces contenus.
|
|
|
|
CONTEXTE: ${csvData.mc0} - Secteur signalétique/impression
|
|
PERSONNALITÉ: ${csvData.personality?.nom} (${csvData.personality?.style})
|
|
|
|
CONTENUS À AMÉLIORER:
|
|
|
|
${elementsNeedingEnhancement.map((item, i) => `[${i + 1}] TAG: ${item.tag}
|
|
CONTENU: "${item.content}"
|
|
TERMES TECHNIQUES: ${item.technicalTerms.join(', ')}`).join('\n\n')}
|
|
|
|
CONSIGNES:
|
|
- GARDE même longueur, structure et ton ${csvData.personality?.style}
|
|
- Intègre naturellement les termes techniques listés
|
|
- NE CHANGE PAS le fond du message
|
|
- Vocabulaire expert mais accessible
|
|
- Termes secteur: dibond, aluminium, impression UV, fraisage, PMMA
|
|
|
|
FORMAT RÉPONSE:
|
|
[1] Contenu avec amélioration technique
|
|
[2] Contenu avec amélioration technique
|
|
etc...`;
|
|
|
|
try {
|
|
// Générer prompt adversarial pour enhancement
|
|
const adversarialEnhancementPrompt = createAdversarialPrompt(enhancementPrompt, {
|
|
detectorTarget: adversarialConfig.detectorTarget,
|
|
intensity: adversarialConfig.intensity,
|
|
elementType: 'technical_enhancement',
|
|
personality: csvData.personality,
|
|
contextualMode: adversarialConfig.contextualMode,
|
|
csvData: csvData,
|
|
debugMode: false
|
|
});
|
|
|
|
const enhancedResponse = await callLLM('gpt4', adversarialEnhancementPrompt, {
|
|
temperature: 0.4,
|
|
maxTokens: 5000
|
|
}, csvData.personality);
|
|
|
|
return parseEnhancementResponse(enhancedResponse, elementsNeedingEnhancement);
|
|
|
|
} catch (error) {
|
|
logSh(`❌ Enhancement éléments échoué: ${error.message}`, 'ERROR');
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parser réponse analyse
|
|
*/
|
|
function parseAnalysisResponse(response, content, contentEntries) {
|
|
const results = [];
|
|
const regex = /\[(\d+)\]\s*([^[]*?)(?=\[\d+\]|$)/gs;
|
|
let match;
|
|
const parsedItems = {};
|
|
|
|
while ((match = regex.exec(response)) !== null) {
|
|
const index = parseInt(match[1]) - 1;
|
|
const termsText = match[2].trim();
|
|
parsedItems[index] = termsText;
|
|
}
|
|
|
|
contentEntries.forEach((tag, index) => {
|
|
const termsText = parsedItems[index] || 'AUCUN';
|
|
const hasTerms = !termsText.toUpperCase().includes('AUCUN');
|
|
|
|
const technicalTerms = hasTerms ?
|
|
termsText.split(',').map(t => t.trim()).filter(t => t.length > 0) :
|
|
[];
|
|
|
|
results.push({
|
|
tag,
|
|
content: content[tag],
|
|
technicalTerms,
|
|
needsEnhancement: hasTerms && technicalTerms.length > 0
|
|
});
|
|
|
|
logSh(`🔍 [${tag}]: ${hasTerms ? technicalTerms.join(', ') : 'aucun terme technique'}`, 'DEBUG');
|
|
});
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Parser réponse enhancement
|
|
*/
|
|
function parseEnhancementResponse(response, elementsNeedingEnhancement) {
|
|
const results = {};
|
|
const regex = /\[(\d+)\]\s*([^[]*?)(?=\[\d+\]|$)/gs;
|
|
let match;
|
|
let index = 0;
|
|
|
|
while ((match = regex.exec(response)) && index < elementsNeedingEnhancement.length) {
|
|
let enhancedContent = match[2].trim();
|
|
const element = elementsNeedingEnhancement[index];
|
|
|
|
// Nettoyer le contenu généré
|
|
enhancedContent = cleanEnhancedContent(enhancedContent);
|
|
|
|
if (enhancedContent && enhancedContent.length > 10) {
|
|
results[element.tag] = enhancedContent;
|
|
logSh(`✅ Enhanced [${element.tag}]: "${enhancedContent.substring(0, 100)}..."`, 'DEBUG');
|
|
} else {
|
|
results[element.tag] = element.content;
|
|
logSh(`⚠️ Fallback [${element.tag}]: contenu invalide`, 'WARNING');
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
// Compléter les manquants
|
|
while (index < elementsNeedingEnhancement.length) {
|
|
const element = elementsNeedingEnhancement[index];
|
|
results[element.tag] = element.content;
|
|
index++;
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* Nettoyer contenu amélioré
|
|
*/
|
|
function cleanEnhancedContent(content) {
|
|
if (!content) return content;
|
|
|
|
// Supprimer préfixes indésirables
|
|
content = content.replace(/^(Bon,?\s*)?(alors,?\s*)?pour\s+/gi, '');
|
|
content = content.replace(/\*\*[^*]+\*\*/g, '');
|
|
content = content.replace(/\s{2,}/g, ' ');
|
|
content = content.trim();
|
|
|
|
return content;
|
|
}
|
|
|
|
module.exports = {
|
|
enhanceTechnicalTermsAdversarial, // ← MAIN ENTRY POINT ADVERSARIAL
|
|
analyzeTechnicalTermsAdversarial,
|
|
enhanceSelectedElementsAdversarial,
|
|
parseAnalysisResponse,
|
|
parseEnhancementResponse
|
|
}; |