## SelectiveSmartTouch (NEW) - Architecture révolutionnaire: Analyse intelligente → Améliorations ciblées précises - 5 modules: SmartAnalysisLayer, SmartTechnicalLayer, SmartStyleLayer, SmartReadabilityLayer, SmartTouchCore - Système 10% segments: amélioration uniquement des segments les plus faibles (intensity-based) - Détection contexte globale pour prompts adaptatifs multi-secteurs - Intégration complète dans PipelineExecutor et PipelineDefinition ## Pipeline Validator Spec (NEW) - Spécification complète système validation qualité par LLM - 5 critères universels: Qualité, Verbosité, SEO, Répétitions, Naturalité - Échantillonnage intelligent par filtrage balises (pas XML) - Évaluation multi-versions avec justifications détaillées - Coût estimé: ~$1/validation (260 appels LLM) ## Optimizations - Réduction intensités fullEnhancement (technical 1.0→0.7, style 0.8→0.5) - Ajout gardes-fous anti-familiarité excessive dans StyleLayer - Sauvegarde étapes intermédiaires activée par défaut (pipeline-runner) ## Fixes - Fix typo critique SmartTouchCore.js:110 (determineLayers ToApply → determineLayersToApply) - Prompts généralisés multi-secteurs (e-commerce, SaaS, services, informatif) 🚀 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
216 lines
7.3 KiB
JavaScript
216 lines
7.3 KiB
JavaScript
// ========================================
|
|
// SMART STYLE LAYER - Améliorations style CIBLÉES
|
|
// Responsabilité: Appliquer UNIQUEMENT les améliorations style identifiées par analyse
|
|
// LLM: Mistral (excellence style et personnalité)
|
|
// Architecture: Phase 2 de SelectiveSmartTouch (post-analyse)
|
|
// ========================================
|
|
|
|
const { callLLM } = require('../LLMManager');
|
|
const { logSh } = require('../ErrorReporting');
|
|
const { tracer } = require('../trace');
|
|
|
|
/**
|
|
* SMART STYLE LAYER
|
|
* Applique améliorations style précises identifiées par SmartAnalysisLayer
|
|
*/
|
|
class SmartStyleLayer {
|
|
constructor() {
|
|
this.name = 'SmartStyle';
|
|
this.defaultLLM = 'mistral-small';
|
|
}
|
|
|
|
/**
|
|
* APPLIQUER AMÉLIORATIONS STYLE CIBLÉES
|
|
*/
|
|
async applyTargeted(content, analysis, context = {}) {
|
|
return await tracer.run('SmartStyle.applyTargeted()', async () => {
|
|
const { mc0, personality, intensity = 1.0 } = context;
|
|
|
|
// Si aucune amélioration style nécessaire, skip
|
|
if (!analysis.style.needed) {
|
|
logSh(`⏭️ SMART STYLE: Aucune amélioration nécessaire (score: ${analysis.style.score.toFixed(2)})`, 'DEBUG');
|
|
return {
|
|
content,
|
|
modifications: 0,
|
|
skipped: true,
|
|
reason: 'No style improvements needed'
|
|
};
|
|
}
|
|
|
|
await tracer.annotate({
|
|
smartStyle: true,
|
|
contentLength: content.length,
|
|
hasPersonality: !!personality,
|
|
intensity
|
|
});
|
|
|
|
// ✅ Utiliser LLM fourni dans context, sinon fallback sur defaultLLM
|
|
const llmToUse = context.llmProvider || this.defaultLLM;
|
|
|
|
const startTime = Date.now();
|
|
logSh(`🎨 SMART STYLE: Application améliorations style ciblées avec ${llmToUse}`, 'DEBUG');
|
|
|
|
try {
|
|
const prompt = this.createTargetedPrompt(content, analysis, context);
|
|
|
|
const response = await callLLM(llmToUse, prompt, {
|
|
temperature: 0.7, // Créativité modérée pour style
|
|
maxTokens: 2500
|
|
}, personality);
|
|
|
|
const improvedContent = this.cleanResponse(response);
|
|
const modifications = this.countModifications(content, improvedContent);
|
|
|
|
const duration = Date.now() - startTime;
|
|
logSh(`✅ SMART STYLE terminé: ${modifications} modifications appliquées (${duration}ms)`, 'DEBUG');
|
|
|
|
await tracer.event('Smart Style appliqué', {
|
|
duration,
|
|
modifications,
|
|
personalityApplied: personality?.nom || 'generic'
|
|
});
|
|
|
|
return {
|
|
content: improvedContent,
|
|
modifications,
|
|
duration,
|
|
personalityApplied: personality?.nom
|
|
};
|
|
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
logSh(`❌ SMART STYLE ÉCHOUÉ (${duration}ms): ${error.message}`, 'ERROR');
|
|
|
|
return {
|
|
content,
|
|
modifications: 0,
|
|
error: error.message,
|
|
fallback: true
|
|
};
|
|
}
|
|
}, { contentLength: content.length, analysis });
|
|
}
|
|
|
|
/**
|
|
* CRÉER PROMPT CIBLÉ
|
|
*/
|
|
createTargetedPrompt(content, analysis, context) {
|
|
const { mc0, personality, intensity = 1.0 } = context;
|
|
|
|
// Extraire améliorations style
|
|
const styleImprovements = analysis.improvements.filter(imp =>
|
|
imp.toLowerCase().includes('style') ||
|
|
imp.toLowerCase().includes('ton') ||
|
|
imp.toLowerCase().includes('personnalis') ||
|
|
imp.toLowerCase().includes('expression') ||
|
|
imp.toLowerCase().includes('vocabulaire')
|
|
);
|
|
|
|
return `MISSION: Améliore UNIQUEMENT les aspects STYLE listés ci-dessous.
|
|
|
|
CONTENU ORIGINAL:
|
|
"${content}"
|
|
|
|
${mc0 ? `CONTEXTE SUJET: ${mc0}` : ''}
|
|
${personality ? `PERSONNALITÉ CIBLE: ${personality.nom} (${personality.style})
|
|
VOCABULAIRE PRÉFÉRÉ: ${personality.vocabulairePref || 'professionnel'}` : 'STYLE: Professionnel standard'}
|
|
INTENSITÉ: ${intensity.toFixed(1)}
|
|
|
|
AMÉLIORATIONS STYLE À APPLIQUER:
|
|
${styleImprovements.map((imp, i) => `${i + 1}. ${imp}`).join('\n')}
|
|
|
|
${analysis.style.genericPhrases && analysis.style.genericPhrases.length > 0 ? `
|
|
EXPRESSIONS GÉNÉRIQUES À PERSONNALISER:
|
|
${analysis.style.genericPhrases.map(phrase => `- "${phrase}"`).join('\n')}
|
|
` : ''}
|
|
|
|
${analysis.style.toneIssues && analysis.style.toneIssues.length > 0 ? `
|
|
PROBLÈMES DE TON IDENTIFIÉS:
|
|
${analysis.style.toneIssues.map(issue => `- ${issue}`).join('\n')}
|
|
` : ''}
|
|
|
|
CONSIGNES STRICTES:
|
|
- Applique UNIQUEMENT les améliorations style listées ci-dessus
|
|
- NE CHANGE PAS le fond du message ni les informations factuelles
|
|
- GARDE la même structure et longueur (±15%)
|
|
${personality ? `- Applique style "${personality.style}" de façon MESURÉE (pas d'exagération)` : '- Style professionnel web standard'}
|
|
- ⚠️ MAINTIENS un TON PROFESSIONNEL (limite connecteurs oraux à 1-2 MAX)
|
|
- ⚠️ ÉVITE bombardement de marqueurs de personnalité
|
|
|
|
EXEMPLES AMÉLIORATION STYLE (génériques multi-secteurs):
|
|
|
|
**E-commerce mode:**
|
|
- ✅ BON: "Cette robe allie élégance et confort" → style commercial mesuré
|
|
- ❌ MAUVAIS: "Écoutez, du coup cette robe, voilà, elle est vraiment top" → trop oral
|
|
|
|
**Services professionnels:**
|
|
- ✅ BON: "Notre expertise comptable garantit votre conformité" → professionnel et spécifique
|
|
- ❌ MAUVAIS: "Nos solutions de qualité" → générique et vague
|
|
|
|
**SaaS/Tech:**
|
|
- ✅ BON: "Automatisez vos workflows en 3 clics" → action concrète
|
|
- ❌ MAUVAIS: "Notre plateforme innovante optimise vos processus" → buzzwords creux
|
|
|
|
**Contenu informatif:**
|
|
- ✅ BON: "Le réchauffement climatique atteint +1.2°C depuis 1850" → factuel et précis
|
|
- ❌ MAUVAIS: "Le réchauffement climatique est un problème important" → vague
|
|
|
|
RÈGLES VOCABULAIRE & TON:
|
|
- Remplace expressions génériques par spécificités
|
|
- 1-2 touches de personnalité par paragraphe MAXIMUM
|
|
- Pas de saturation de connecteurs familiers ("du coup", "voilà", "écoutez")
|
|
- Privilégie authenticité sur artifice
|
|
|
|
FORMAT RÉPONSE:
|
|
Retourne UNIQUEMENT le contenu stylisé, SANS balises, SANS métadonnées, SANS explications.`;
|
|
}
|
|
|
|
/**
|
|
* NETTOYER RÉPONSE
|
|
*/
|
|
cleanResponse(response) {
|
|
if (!response) return response;
|
|
|
|
let cleaned = response.trim();
|
|
|
|
// Supprimer balises
|
|
cleaned = cleaned.replace(/^TAG:\s*[^\s]+\s+/gi, '');
|
|
cleaned = cleaned.replace(/\bTAG:\s*[^\s]+\s+/gi, '');
|
|
cleaned = cleaned.replace(/^CONTENU:\s*/gi, '');
|
|
cleaned = cleaned.replace(/^CONTENU STYLISÉ:\s*/gi, '');
|
|
cleaned = cleaned.replace(/^(voici\s+)?le\s+contenu\s+(stylisé|avec\s+style)\s*[:.]?\s*/gi, '');
|
|
cleaned = cleaned.replace(/^(dans\s+le\s+style\s+de\s+)[^:]*[:.]?\s*/gi, '');
|
|
|
|
// Nettoyer formatage
|
|
cleaned = cleaned.replace(/\*\*([^*]+)\*\*/g, '$1');
|
|
cleaned = cleaned.replace(/\s{2,}/g, ' ');
|
|
cleaned = cleaned.trim();
|
|
|
|
return cleaned;
|
|
}
|
|
|
|
/**
|
|
* COMPTER MODIFICATIONS
|
|
*/
|
|
countModifications(original, improved) {
|
|
if (original === improved) return 0;
|
|
|
|
const originalWords = original.toLowerCase().split(/\s+/);
|
|
const improvedWords = improved.toLowerCase().split(/\s+/);
|
|
|
|
let differences = 0;
|
|
differences += Math.abs(originalWords.length - improvedWords.length);
|
|
|
|
const minLength = Math.min(originalWords.length, improvedWords.length);
|
|
for (let i = 0; i < minLength; i++) {
|
|
if (originalWords[i] !== improvedWords[i]) {
|
|
differences++;
|
|
}
|
|
}
|
|
|
|
return differences;
|
|
}
|
|
}
|
|
|
|
module.exports = { SmartStyleLayer };
|