718 lines
28 KiB
JavaScript
718 lines
28 KiB
JavaScript
// ========================================
|
|
// FICHIER: PatternBreakingCore.js
|
|
// RESPONSABILITÉ: Orchestrateur principal Pattern Breaking
|
|
// Niveau 2: Casser les patterns syntaxiques typiques des LLMs
|
|
// ========================================
|
|
|
|
const { logSh } = require('../ErrorReporting');
|
|
const { tracer } = require('../trace');
|
|
const { varyStructures, splitLongSentences, mergeShorter } = require('./SyntaxVariations');
|
|
const { replaceLLMFingerprints, detectLLMPatterns } = require('./LLMFingerprints');
|
|
const { humanizeTransitions, replaceConnectors } = require('./NaturalConnectors');
|
|
|
|
/**
|
|
* CONFIGURATION MODULAIRE AGRESSIVE PATTERN BREAKING
|
|
* Chaque feature peut être activée/désactivée individuellement
|
|
*/
|
|
const DEFAULT_CONFIG = {
|
|
// ========================================
|
|
// CONTRÔLES GLOBAUX
|
|
// ========================================
|
|
intensityLevel: 0.8, // Intensité globale (0-1) - PLUS AGRESSIVE
|
|
preserveReadability: true, // Maintenir lisibilité
|
|
maxModificationsPerElement: 8, // Limite modifications par élément - DOUBLÉE
|
|
qualityThreshold: 0.5, // Seuil qualité minimum - ABAISSÉ
|
|
|
|
// ========================================
|
|
// FEATURES SYNTAXE & STRUCTURE
|
|
// ========================================
|
|
syntaxVariationEnabled: true, // Variations syntaxiques de base
|
|
aggressiveSentenceSplitting: true, // Découpage phrases plus agressif (<80 chars)
|
|
aggressiveSentenceMerging: true, // Fusion phrases courtes (<60 chars)
|
|
microSyntaxVariations: true, // Micro-variations subtiles
|
|
questionInjection: true, // Injection questions rhétoriques
|
|
|
|
// ========================================
|
|
// FEATURES LLM FINGERPRINTS
|
|
// ========================================
|
|
llmFingerprintReplacement: true, // Remplacement fingerprints de base
|
|
frenchLLMPatterns: true, // Patterns spécifiques français
|
|
overlyFormalVocabulary: true, // Vocabulaire trop formel → casual
|
|
repetitiveStarters: true, // Débuts de phrases répétitifs
|
|
perfectTransitions: true, // Transitions trop parfaites
|
|
|
|
// ========================================
|
|
// FEATURES CONNECTEURS & TRANSITIONS
|
|
// ========================================
|
|
naturalConnectorsEnabled: true, // Connecteurs naturels de base
|
|
casualConnectors: true, // Connecteurs très casual (genre, enfin, bref)
|
|
hesitationMarkers: true, // Marqueurs d'hésitation (..., euh)
|
|
colloquialTransitions: true, // Transitions colloquiales
|
|
|
|
// ========================================
|
|
// FEATURES IMPERFECTIONS HUMAINES
|
|
// ========================================
|
|
humanImperfections: true, // Système d'imperfections humaines
|
|
vocabularyRepetitions: true, // Répétitions vocabulaire naturelles
|
|
casualizationIntensive: true, // Casualisation intensive
|
|
naturalHesitations: true, // Hésitations naturelles en fin de phrase
|
|
informalExpressions: true, // Expressions informelles ("pas mal", "sympa")
|
|
|
|
// ========================================
|
|
// FEATURES RESTRUCTURATION
|
|
// ========================================
|
|
intelligentRestructuring: true, // Restructuration intelligente
|
|
paragraphBreaking: true, // Cassage paragraphes longs
|
|
listToTextConversion: true, // Listes → texte naturel
|
|
redundancyInjection: true, // Injection redondances naturelles
|
|
|
|
// ========================================
|
|
// FEATURES SPÉCIALISÉES
|
|
// ========================================
|
|
personalityAdaptation: true, // Adaptation selon personnalité
|
|
temporalConsistency: true, // Cohérence temporelle (maintenant/aujourd'hui)
|
|
contextualVocabulary: true, // Vocabulaire contextuel
|
|
registerVariation: true // Variation registre langue
|
|
};
|
|
|
|
/**
|
|
* ORCHESTRATEUR PRINCIPAL - Pattern Breaking Layer
|
|
* @param {object} content - Contenu généré à traiter
|
|
* @param {object} options - Options de pattern breaking
|
|
* @returns {object} - { content, stats, fallback }
|
|
*/
|
|
async function applyPatternBreakingLayer(content, options = {}) {
|
|
return await tracer.run('PatternBreakingCore.applyPatternBreakingLayer()', async () => {
|
|
const startTime = Date.now();
|
|
|
|
await tracer.annotate({
|
|
contentKeys: Object.keys(content).length,
|
|
intensityLevel: options.intensityLevel,
|
|
personality: options.csvData?.personality?.nom
|
|
});
|
|
|
|
logSh(`🔧 PATTERN BREAKING - Début traitement`, 'INFO');
|
|
logSh(` 📊 ${Object.keys(content).length} éléments | Intensité: ${options.intensityLevel || DEFAULT_CONFIG.intensityLevel}`, 'DEBUG');
|
|
|
|
try {
|
|
// Configuration fusionnée
|
|
const config = { ...DEFAULT_CONFIG, ...options };
|
|
|
|
// Stats de pattern breaking
|
|
const patternStats = {
|
|
elementsProcessed: 0,
|
|
syntaxModifications: 0,
|
|
llmFingerprintReplacements: 0,
|
|
connectorReplacements: 0,
|
|
totalModifications: 0,
|
|
fallbackUsed: false,
|
|
patternsDetected: 0
|
|
};
|
|
|
|
// Contenu traité
|
|
let processedContent = { ...content };
|
|
|
|
// ========================================
|
|
// TRAITEMENT PAR ÉLÉMENT
|
|
// ========================================
|
|
for (const [elementKey, elementContent] of Object.entries(content)) {
|
|
await tracer.run(`PatternBreaking.processElement(${elementKey})`, async () => {
|
|
|
|
logSh(` 🎯 Traitement élément: ${elementKey}`, 'DEBUG');
|
|
|
|
let currentContent = elementContent;
|
|
let elementModifications = 0;
|
|
|
|
try {
|
|
// 1. Détection patterns LLM
|
|
const detectedPatterns = detectLLMPatterns(currentContent);
|
|
patternStats.patternsDetected += detectedPatterns.count;
|
|
|
|
if (detectedPatterns.count > 0) {
|
|
logSh(` 🔍 ${detectedPatterns.count} patterns LLM détectés: ${detectedPatterns.patterns.slice(0, 3).join(', ')}`, 'DEBUG');
|
|
}
|
|
|
|
// 2. SYNTAXE & STRUCTURE - Couche de base
|
|
if (config.syntaxVariationEnabled) {
|
|
const syntaxResult = await applySyntaxVariation(currentContent, config);
|
|
currentContent = syntaxResult.content;
|
|
elementModifications += syntaxResult.modifications;
|
|
patternStats.syntaxModifications += syntaxResult.modifications;
|
|
logSh(` 📝 Syntaxe: ${syntaxResult.modifications} variations appliquées`, 'DEBUG');
|
|
}
|
|
|
|
// 3. SYNTAXE AGRESSIVE - Couche intensive
|
|
if (config.aggressiveSentenceSplitting || config.aggressiveSentenceMerging) {
|
|
const aggressiveResult = await applyAggressiveSyntax(currentContent, config);
|
|
currentContent = aggressiveResult.content;
|
|
elementModifications += aggressiveResult.modifications;
|
|
patternStats.syntaxModifications += aggressiveResult.modifications;
|
|
logSh(` ✂️ Syntaxe agressive: ${aggressiveResult.modifications} modifications`, 'DEBUG');
|
|
}
|
|
|
|
// 4. MICRO-VARIATIONS - Subtiles mais importantes
|
|
if (config.microSyntaxVariations) {
|
|
const microResult = await applyMicroVariations(currentContent, config);
|
|
currentContent = microResult.content;
|
|
elementModifications += microResult.modifications;
|
|
patternStats.syntaxModifications += microResult.modifications;
|
|
logSh(` 🔧 Micro-variations: ${microResult.modifications} ajustements`, 'DEBUG');
|
|
}
|
|
|
|
// 5. LLM FINGERPRINTS - Détection de base
|
|
if (config.llmFingerprintReplacement && detectedPatterns.count > 0) {
|
|
const fingerprintResult = await applyLLMFingerprints(currentContent, config);
|
|
currentContent = fingerprintResult.content;
|
|
elementModifications += fingerprintResult.modifications;
|
|
patternStats.llmFingerprintReplacements += fingerprintResult.modifications;
|
|
logSh(` 🤖 LLM Fingerprints: ${fingerprintResult.modifications} remplacements`, 'DEBUG');
|
|
}
|
|
|
|
// 6. PATTERNS FRANÇAIS - Spécifique langue française
|
|
if (config.frenchLLMPatterns) {
|
|
const frenchResult = await applyFrenchPatterns(currentContent, config);
|
|
currentContent = frenchResult.content;
|
|
elementModifications += frenchResult.modifications;
|
|
patternStats.llmFingerprintReplacements += frenchResult.modifications;
|
|
logSh(` 🇫🇷 Patterns français: ${frenchResult.modifications} corrections`, 'DEBUG');
|
|
}
|
|
|
|
// 7. VOCABULAIRE FORMEL - Casualisation
|
|
if (config.overlyFormalVocabulary) {
|
|
const casualResult = await applyCasualization(currentContent, config);
|
|
currentContent = casualResult.content;
|
|
elementModifications += casualResult.modifications;
|
|
patternStats.llmFingerprintReplacements += casualResult.modifications;
|
|
logSh(` 😎 Casualisation: ${casualResult.modifications} simplifications`, 'DEBUG');
|
|
}
|
|
|
|
// 8. CONNECTEURS NATURELS - Base
|
|
if (config.naturalConnectorsEnabled) {
|
|
const connectorResult = await applyNaturalConnectors(currentContent, config);
|
|
currentContent = connectorResult.content;
|
|
elementModifications += connectorResult.modifications;
|
|
patternStats.connectorReplacements += connectorResult.modifications;
|
|
logSh(` 🔗 Connecteurs naturels: ${connectorResult.modifications} humanisés`, 'DEBUG');
|
|
}
|
|
|
|
// 9. CONNECTEURS CASUAL - Très familier
|
|
if (config.casualConnectors) {
|
|
const casualConnResult = await applyCasualConnectors(currentContent, config);
|
|
currentContent = casualConnResult.content;
|
|
elementModifications += casualConnResult.modifications;
|
|
patternStats.connectorReplacements += casualConnResult.modifications;
|
|
logSh(` 🗣️ Connecteurs casual: ${casualConnResult.modifications} familiarisés`, 'DEBUG');
|
|
}
|
|
|
|
// 10. IMPERFECTIONS HUMAINES - Système principal
|
|
if (config.humanImperfections) {
|
|
const imperfResult = await applyHumanImperfections(currentContent, config);
|
|
currentContent = imperfResult.content;
|
|
elementModifications += imperfResult.modifications;
|
|
patternStats.totalModifications += imperfResult.modifications;
|
|
logSh(` 👤 Imperfections: ${imperfResult.modifications} humanisations`, 'DEBUG');
|
|
}
|
|
|
|
// 11. QUESTIONS RHÉTORIQUES - Engagement
|
|
if (config.questionInjection) {
|
|
const questionResult = await applyQuestionInjection(currentContent, config);
|
|
currentContent = questionResult.content;
|
|
elementModifications += questionResult.modifications;
|
|
patternStats.totalModifications += questionResult.modifications;
|
|
logSh(` ❓ Questions: ${questionResult.modifications} injections`, 'DEBUG');
|
|
}
|
|
|
|
// 12. RESTRUCTURATION INTELLIGENTE - Dernière couche
|
|
if (config.intelligentRestructuring) {
|
|
const restructResult = await applyIntelligentRestructuring(currentContent, config);
|
|
currentContent = restructResult.content;
|
|
elementModifications += restructResult.modifications;
|
|
patternStats.totalModifications += restructResult.modifications;
|
|
logSh(` 🧠 Restructuration: ${restructResult.modifications} réorganisations`, 'DEBUG');
|
|
}
|
|
|
|
// 5. Validation qualité
|
|
const qualityCheck = validatePatternBreakingQuality(elementContent, currentContent, config.qualityThreshold);
|
|
|
|
if (qualityCheck.acceptable) {
|
|
processedContent[elementKey] = currentContent;
|
|
patternStats.elementsProcessed++;
|
|
patternStats.totalModifications += elementModifications;
|
|
|
|
logSh(` ✅ Élément traité: ${elementModifications} modifications totales`, 'DEBUG');
|
|
} else {
|
|
// Fallback: garder contenu original
|
|
processedContent[elementKey] = elementContent;
|
|
patternStats.fallbackUsed = true;
|
|
|
|
logSh(` ⚠️ Qualité insuffisante, fallback vers contenu original`, 'WARNING');
|
|
}
|
|
|
|
} catch (elementError) {
|
|
logSh(` ❌ Erreur pattern breaking élément ${elementKey}: ${elementError.message}`, 'WARNING');
|
|
processedContent[elementKey] = elementContent; // Fallback
|
|
patternStats.fallbackUsed = true;
|
|
}
|
|
|
|
}, { elementKey, originalLength: elementContent?.length });
|
|
}
|
|
|
|
// ========================================
|
|
// RÉSULTATS FINAUX
|
|
// ========================================
|
|
const duration = Date.now() - startTime;
|
|
const success = patternStats.elementsProcessed > 0 && !patternStats.fallbackUsed;
|
|
|
|
logSh(`🔧 PATTERN BREAKING - Terminé (${duration}ms)`, 'INFO');
|
|
logSh(` ✅ ${patternStats.elementsProcessed}/${Object.keys(content).length} éléments traités`, 'INFO');
|
|
logSh(` 📊 ${patternStats.syntaxModifications} syntaxe | ${patternStats.llmFingerprintReplacements} fingerprints | ${patternStats.connectorReplacements} connecteurs`, 'INFO');
|
|
logSh(` 🎯 Patterns détectés: ${patternStats.patternsDetected} | Fallback: ${patternStats.fallbackUsed ? 'OUI' : 'NON'}`, 'INFO');
|
|
|
|
await tracer.event('Pattern Breaking terminé', {
|
|
success,
|
|
duration,
|
|
stats: patternStats
|
|
});
|
|
|
|
return {
|
|
content: processedContent,
|
|
stats: patternStats,
|
|
fallback: patternStats.fallbackUsed,
|
|
duration
|
|
};
|
|
|
|
} catch (error) {
|
|
const duration = Date.now() - startTime;
|
|
logSh(`❌ PATTERN BREAKING ÉCHOUÉ (${duration}ms): ${error.message}`, 'ERROR');
|
|
|
|
await tracer.event('Pattern Breaking échoué', {
|
|
error: error.message,
|
|
duration,
|
|
contentKeys: Object.keys(content).length
|
|
});
|
|
|
|
// Fallback complet
|
|
return {
|
|
content,
|
|
stats: { fallbackUsed: true, error: error.message },
|
|
fallback: true,
|
|
duration
|
|
};
|
|
}
|
|
|
|
}, {
|
|
contentElements: Object.keys(content).length,
|
|
intensityLevel: options.intensityLevel
|
|
});
|
|
}
|
|
|
|
/**
|
|
* APPLICATION VARIATION SYNTAXIQUE
|
|
*/
|
|
async function applySyntaxVariation(content, config) {
|
|
const syntaxResult = varyStructures(content, config.intensityLevel, {
|
|
preserveReadability: config.preserveReadability,
|
|
maxModifications: Math.floor(config.maxModificationsPerElement / 2)
|
|
});
|
|
|
|
return {
|
|
content: syntaxResult.content,
|
|
modifications: syntaxResult.modifications || 0
|
|
};
|
|
}
|
|
|
|
/**
|
|
* APPLICATION REMPLACEMENT LLM FINGERPRINTS
|
|
*/
|
|
async function applyLLMFingerprints(content, config) {
|
|
const fingerprintResult = replaceLLMFingerprints(content, {
|
|
intensity: config.intensityLevel,
|
|
preserveContext: true,
|
|
maxReplacements: Math.floor(config.maxModificationsPerElement / 2)
|
|
});
|
|
|
|
return {
|
|
content: fingerprintResult.content,
|
|
modifications: fingerprintResult.replacements || 0
|
|
};
|
|
}
|
|
|
|
/**
|
|
* APPLICATION CONNECTEURS NATURELS
|
|
*/
|
|
async function applyNaturalConnectors(content, config) {
|
|
const connectorResult = humanizeTransitions(content, {
|
|
intensity: config.intensityLevel,
|
|
preserveMeaning: true,
|
|
maxReplacements: Math.floor(config.maxModificationsPerElement / 2)
|
|
});
|
|
|
|
return {
|
|
content: connectorResult.content,
|
|
modifications: connectorResult.replacements || 0
|
|
};
|
|
}
|
|
|
|
/**
|
|
* VALIDATION QUALITÉ PATTERN BREAKING
|
|
*/
|
|
function validatePatternBreakingQuality(originalContent, processedContent, qualityThreshold) {
|
|
if (!originalContent || !processedContent) {
|
|
return { acceptable: false, reason: 'Contenu manquant' };
|
|
}
|
|
|
|
// Métriques de base
|
|
const lengthDiff = Math.abs(processedContent.length - originalContent.length) / originalContent.length;
|
|
const wordCountOriginal = originalContent.split(/\s+/).length;
|
|
const wordCountProcessed = processedContent.split(/\s+/).length;
|
|
const wordCountDiff = Math.abs(wordCountProcessed - wordCountOriginal) / wordCountOriginal;
|
|
|
|
// Vérifications qualité
|
|
const checks = {
|
|
lengthPreserved: lengthDiff < 0.3, // Pas plus de 30% de différence
|
|
wordCountPreserved: wordCountDiff < 0.2, // Pas plus de 20% de différence
|
|
noEmpty: processedContent.trim().length > 0, // Pas de contenu vide
|
|
readableStructure: processedContent.includes('.') // Structure lisible
|
|
};
|
|
|
|
const passedChecks = Object.values(checks).filter(Boolean).length;
|
|
const score = passedChecks / Object.keys(checks).length;
|
|
|
|
const acceptable = score >= qualityThreshold;
|
|
|
|
logSh(` 🎯 Validation Pattern Breaking: ${acceptable ? 'ACCEPTÉ' : 'REJETÉ'} (score: ${score.toFixed(2)})`, acceptable ? 'DEBUG' : 'WARNING');
|
|
|
|
return {
|
|
acceptable,
|
|
score,
|
|
checks,
|
|
reason: acceptable ? 'Qualité acceptable' : 'Score qualité insuffisant'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* APPLICATION SYNTAXE AGRESSIVE
|
|
* Seuils plus bas pour plus de transformations
|
|
*/
|
|
async function applyAggressiveSyntax(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
// Découpage agressif phrases longues (>80 chars au lieu de >120)
|
|
if (config.aggressiveSentenceSplitting) {
|
|
const sentences = modified.split('. ');
|
|
const processedSentences = sentences.map(sentence => {
|
|
if (sentence.length > 80 && Math.random() < (config.intensityLevel * 0.7)) {
|
|
const cutPoints = [
|
|
{ pattern: /, qui (.+)/, replacement: '. Celui-ci $1' },
|
|
{ pattern: /, que (.+)/, replacement: '. Cette solution $1' },
|
|
{ pattern: /, car (.+)/, replacement: '. En fait, $1' },
|
|
{ pattern: /, donc (.+)/, replacement: '. Du coup, $1' },
|
|
{ pattern: / et (.{20,})/, replacement: '. Aussi, $1' },
|
|
{ pattern: /, mais (.+)/, replacement: '. Par contre, $1' }
|
|
];
|
|
|
|
for (const cutPoint of cutPoints) {
|
|
if (sentence.match(cutPoint.pattern)) {
|
|
modifications++;
|
|
return sentence.replace(cutPoint.pattern, cutPoint.replacement);
|
|
}
|
|
}
|
|
}
|
|
return sentence;
|
|
});
|
|
modified = processedSentences.join('. ');
|
|
}
|
|
|
|
// Fusion agressive phrases courtes (<60 chars au lieu de <40)
|
|
if (config.aggressiveSentenceMerging) {
|
|
const sentences = modified.split('. ');
|
|
const processedSentences = [];
|
|
|
|
for (let i = 0; i < sentences.length; i++) {
|
|
const current = sentences[i];
|
|
const next = sentences[i + 1];
|
|
|
|
if (current && current.length < 60 && next && next.length < 80 && Math.random() < (config.intensityLevel * 0.5)) {
|
|
const connectors = [', du coup,', ', genre,', ', enfin,', ' et puis'];
|
|
const connector = connectors[Math.floor(Math.random() * connectors.length)];
|
|
processedSentences.push(current + connector + ' ' + next.toLowerCase());
|
|
modifications++;
|
|
i++; // Skip next sentence
|
|
} else {
|
|
processedSentences.push(current);
|
|
}
|
|
}
|
|
modified = processedSentences.join('. ');
|
|
}
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION MICRO-VARIATIONS
|
|
* Changements subtiles mais nombreux
|
|
*/
|
|
async function applyMicroVariations(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
const microPatterns = [
|
|
// Intensificateurs
|
|
{ from: /\btrès (.+?)\b/g, to: 'super $1', probability: 0.4 },
|
|
{ from: /\bassez (.+?)\b/g, to: 'plutôt $1', probability: 0.5 },
|
|
{ from: /\bextrêmement\b/g, to: 'vraiment', probability: 0.6 },
|
|
|
|
// Connecteurs basiques
|
|
{ from: /\bainsi\b/g, to: 'du coup', probability: 0.4 },
|
|
{ from: /\bpar conséquent\b/g, to: 'donc', probability: 0.7 },
|
|
{ from: /\bcependant\b/g, to: 'mais', probability: 0.3 },
|
|
|
|
// Formulations casual
|
|
{ from: /\bde cette manière\b/g, to: 'comme ça', probability: 0.5 },
|
|
{ from: /\bafin de\b/g, to: 'pour', probability: 0.4 },
|
|
{ from: /\ben vue de\b/g, to: 'pour', probability: 0.6 }
|
|
];
|
|
|
|
microPatterns.forEach(pattern => {
|
|
if (Math.random() < (config.intensityLevel * pattern.probability)) {
|
|
const before = modified;
|
|
modified = modified.replace(pattern.from, pattern.to);
|
|
if (modified !== before) modifications++;
|
|
}
|
|
});
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION PATTERNS FRANÇAIS SPÉCIFIQUES
|
|
* Détection patterns français typiques LLM
|
|
*/
|
|
async function applyFrenchPatterns(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
// Patterns français typiques LLM
|
|
const frenchPatterns = [
|
|
// Expressions trop soutenues
|
|
{ from: /\bil convient de noter que\b/gi, to: 'on peut dire que', probability: 0.8 },
|
|
{ from: /\bil est important de souligner que\b/gi, to: 'c\'est important de voir que', probability: 0.8 },
|
|
{ from: /\bdans ce contexte\b/gi, to: 'là-dessus', probability: 0.6 },
|
|
{ from: /\bpar ailleurs\b/gi, to: 'sinon', probability: 0.5 },
|
|
{ from: /\ben outre\b/gi, to: 'aussi', probability: 0.7 },
|
|
|
|
// Formulations administratives
|
|
{ from: /\bil s'avère que\b/gi, to: 'en fait', probability: 0.6 },
|
|
{ from: /\btoutefois\b/gi, to: 'par contre', probability: 0.5 },
|
|
{ from: /\bnéanmoins\b/gi, to: 'quand même', probability: 0.7 }
|
|
];
|
|
|
|
frenchPatterns.forEach(pattern => {
|
|
if (Math.random() < (config.intensityLevel * pattern.probability)) {
|
|
const before = modified;
|
|
modified = modified.replace(pattern.from, pattern.to);
|
|
if (modified !== before) modifications++;
|
|
}
|
|
});
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION CASUALISATION INTENSIVE
|
|
* Rendre le vocabulaire plus décontracté
|
|
*/
|
|
async function applyCasualization(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
const casualizations = [
|
|
// Verbes formels → casual
|
|
{ from: /\boptimiser\b/gi, to: 'améliorer', probability: 0.7 },
|
|
{ from: /\beffectuer\b/gi, to: 'faire', probability: 0.8 },
|
|
{ from: /\bréaliser\b/gi, to: 'faire', probability: 0.6 },
|
|
{ from: /\bmettre en œuvre\b/gi, to: 'faire', probability: 0.7 },
|
|
|
|
// Adjectifs formels → casual
|
|
{ from: /\bexceptionnel\b/gi, to: 'super', probability: 0.4 },
|
|
{ from: /\bremarquable\b/gi, to: 'pas mal', probability: 0.5 },
|
|
{ from: /\bconsidérable\b/gi, to: 'important', probability: 0.6 },
|
|
{ from: /\bsubstantiel\b/gi, to: 'important', probability: 0.8 },
|
|
|
|
// Expressions formelles → casual
|
|
{ from: /\bde manière significative\b/gi, to: 'pas mal', probability: 0.6 },
|
|
{ from: /\ben définitive\b/gi, to: 'au final', probability: 0.7 },
|
|
{ from: /\bdans l'ensemble\b/gi, to: 'globalement', probability: 0.5 }
|
|
];
|
|
|
|
casualizations.forEach(casual => {
|
|
if (Math.random() < (config.intensityLevel * casual.probability)) {
|
|
const before = modified;
|
|
modified = modified.replace(casual.from, casual.to);
|
|
if (modified !== before) modifications++;
|
|
}
|
|
});
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION CONNECTEURS CASUAL
|
|
* Connecteurs très familiers
|
|
*/
|
|
async function applyCasualConnectors(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
const casualConnectors = [
|
|
{ from: /\. De plus,/g, to: '. Genre,', probability: 0.3 },
|
|
{ from: /\. En outre,/g, to: '. Puis,', probability: 0.4 },
|
|
{ from: /\. Par ailleurs,/g, to: '. Sinon,', probability: 0.3 },
|
|
{ from: /\. Cependant,/g, to: '. Mais bon,', probability: 0.4 },
|
|
{ from: /\. Néanmoins,/g, to: '. Ceci dit,', probability: 0.5 },
|
|
{ from: /\. Ainsi,/g, to: '. Du coup,', probability: 0.6 }
|
|
];
|
|
|
|
casualConnectors.forEach(connector => {
|
|
if (Math.random() < (config.intensityLevel * connector.probability)) {
|
|
const before = modified;
|
|
modified = modified.replace(connector.from, connector.to);
|
|
if (modified !== before) modifications++;
|
|
}
|
|
});
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION IMPERFECTIONS HUMAINES
|
|
* Injection d'imperfections réalistes
|
|
*/
|
|
async function applyHumanImperfections(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
// Répétitions vocabulaire
|
|
if (config.vocabularyRepetitions && Math.random() < (config.intensityLevel * 0.4)) {
|
|
const repetitionWords = ['vraiment', 'bien', 'assez', 'plutôt', 'super'];
|
|
const word = repetitionWords[Math.floor(Math.random() * repetitionWords.length)];
|
|
const sentences = modified.split('. ');
|
|
if (sentences.length > 2) {
|
|
sentences[1] = word + ' ' + sentences[1];
|
|
modified = sentences.join('. ');
|
|
modifications++;
|
|
}
|
|
}
|
|
|
|
// Hésitations naturelles
|
|
if (config.naturalHesitations && Math.random() < (config.intensityLevel * 0.2)) {
|
|
const hesitations = ['... enfin', '... disons', '... bon'];
|
|
const hesitation = hesitations[Math.floor(Math.random() * hesitations.length)];
|
|
const words = modified.split(' ');
|
|
const insertPos = Math.floor(words.length * 0.6);
|
|
words.splice(insertPos, 0, hesitation);
|
|
modified = words.join(' ');
|
|
modifications++;
|
|
}
|
|
|
|
// Expressions informelles
|
|
if (config.informalExpressions && Math.random() < (config.intensityLevel * 0.3)) {
|
|
const informalReplacements = [
|
|
{ from: /\bc'est bien\b/gi, to: 'c\'est sympa', probability: 0.4 },
|
|
{ from: /\bc'est intéressant\b/gi, to: 'c\'est pas mal', probability: 0.5 },
|
|
{ from: /\bc'est efficace\b/gi, to: 'ça marche bien', probability: 0.4 }
|
|
];
|
|
|
|
informalReplacements.forEach(replacement => {
|
|
if (Math.random() < replacement.probability) {
|
|
const before = modified;
|
|
modified = modified.replace(replacement.from, replacement.to);
|
|
if (modified !== before) modifications++;
|
|
}
|
|
});
|
|
}
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION QUESTIONS RHÉTORIQUES
|
|
* Injection questions pour engagement
|
|
*/
|
|
async function applyQuestionInjection(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
if (Math.random() < (config.intensityLevel * 0.3)) {
|
|
const sentences = modified.split('. ');
|
|
if (sentences.length > 3) {
|
|
const questionTemplates = [
|
|
'Mais pourquoi est-ce important ?',
|
|
'Comment faire alors ?',
|
|
'Que faut-il retenir ?',
|
|
'Est-ce vraiment efficace ?'
|
|
];
|
|
|
|
const question = questionTemplates[Math.floor(Math.random() * questionTemplates.length)];
|
|
const insertPos = Math.floor(sentences.length / 2);
|
|
sentences.splice(insertPos, 0, question);
|
|
modified = sentences.join('. ');
|
|
modifications++;
|
|
}
|
|
}
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
/**
|
|
* APPLICATION RESTRUCTURATION INTELLIGENTE
|
|
* Réorganisation structure générale
|
|
*/
|
|
async function applyIntelligentRestructuring(content, config) {
|
|
let modified = content;
|
|
let modifications = 0;
|
|
|
|
// Cassage paragraphes longs
|
|
if (config.paragraphBreaking && modified.length > 400) {
|
|
const sentences = modified.split('. ');
|
|
if (sentences.length > 6) {
|
|
const breakPoint = Math.floor(sentences.length / 2);
|
|
sentences[breakPoint] = sentences[breakPoint] + '\n\n';
|
|
modified = sentences.join('. ');
|
|
modifications++;
|
|
}
|
|
}
|
|
|
|
// Injection redondances naturelles
|
|
if (config.redundancyInjection && Math.random() < (config.intensityLevel * 0.2)) {
|
|
const redundancies = ['comme je le disais', 'encore une fois', 'je le répète'];
|
|
const redundancy = redundancies[Math.floor(Math.random() * redundancies.length)];
|
|
const sentences = modified.split('. ');
|
|
if (sentences.length > 2) {
|
|
sentences[sentences.length - 2] = redundancy + ', ' + sentences[sentences.length - 2];
|
|
modified = sentences.join('. ');
|
|
modifications++;
|
|
}
|
|
}
|
|
|
|
return { content: modified, modifications };
|
|
}
|
|
|
|
// ============= EXPORTS =============
|
|
module.exports = {
|
|
applyPatternBreakingLayer,
|
|
applySyntaxVariation,
|
|
applyLLMFingerprints,
|
|
applyNaturalConnectors,
|
|
validatePatternBreakingQuality,
|
|
applyAggressiveSyntax,
|
|
applyMicroVariations,
|
|
applyFrenchPatterns,
|
|
applyCasualization,
|
|
applyCasualConnectors,
|
|
applyHumanImperfections,
|
|
applyQuestionInjection,
|
|
applyIntelligentRestructuring,
|
|
DEFAULT_CONFIG
|
|
}; |