seo-generator-server/plan_implem_initialGen.md
StillHammer acb993cde4 docs: Add implementation plan for InitialGeneration reintegration
Plan détaillé pour réintégrer la logique de génération par couples
et contraintes de longueur du système legacy.

Analyse COT complète avec:
- Comparaison plan initial vs legacy code
- Identification erreurs de conception
- 2 options d'implémentation (Option A recommandée)
- Risques et mitigations
- Critères de succès
- Stratégie de rollback

Status: EN ATTENTE VALIDATION UTILISATEUR
Action requise: Analyser buildSmartHierarchy() output

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 08:23:33 +08:00

12 KiB

Plan d'Implémentation : Réintégration InitialGeneration

Date : 2025-10-12 Objectif : Réintégrer la logique de génération par couples et contraintes de longueur du système legacy Auteur : Claude Code (avec validation utilisateur requise)


🧠 Analyse Chain of Thought

Problèmes Identifiés

Dans le système actuel (generateSimple() dans SelectiveUtils.js) :

  1. Génération élément par élément → lent (33 appels), coûteux
  2. Prompt générique pour tous types → pas de contraintes adaptées
  3. Pas de contraintes de longueur → articles de 400 mots au lieu de 150
  4. Pas de gestion des couples → Q sans R cohérente, Titre sans Texte lié
  5. MaxTokens insuffisants pour certains modèles

Systèmes legacy existants et fonctionnels :

  • InitialGeneration.js : batch generation (chunks de 4) + détection de type + contraintes de longueur
  • buildSmartHierarchy() : associe automatiquement couples titre/texte et paires FAQ
  • parseFAQPairsResponse() : validation stricte de cohérence des paires

Erreurs dans le Plan Initial

1. Détection de type trop complexe

Legacy (InitialGeneration.js:132-146) :

detectElementType(tag) {
  if (tagLower.includes('titre') || tagLower.includes('h1') || tagLower.includes('h2')) {
    return 'titre';  // ← STRING simple
  }
}

Mon plan initial :

detectElementType(tag) {
  return { type: 'titre_h2', maxWords: 12, maxTokens: 30 }; // ← OBJET complexe
}

Problème : Sur-ingénierie. Le legacy est plus simple et fonctionne.


2. Chunking sur-complexifié

Legacy (InitialGeneration.js:52) :

const chunks = chunkArray(Object.entries(elementsToGenerate), 4); // Simple chunks de 4

Mon plan initial :

function groupIntoBatches(hierarchy) {
  // Logique complexe : calcul tokens, groupement intelligent des FAQ, etc.
  // ~60 lignes de code
}

Problème : Réinvente la roue. Le chunking simple par 4 marche déjà.


3. Hiérarchie ignorée

Point critique découvert :

Le pipeline utilise DÉJÀ buildSmartHierarchy() qui retourne cette structure :

{
  "H2_1": {
    title: { instructions: "..." },   // ← Titre H2_1
    text: { instructions: "..." },     // ← Texte P_1 associé
    questions: []                      // ← Vide si pas de FAQ
  },
  "q_1": {
    title: null,
    text: null,
    questions: [                       // ← q_1 et a_1 groupées ici
      { type: 'Faq', level: 'q', ... },
      { type: 'Faq', level: 'a', ... }
    ]
  }
}

Mon erreur majeure : Je traite H2_1, P_1, q_1, a_1 comme éléments séparés au lieu d'exploiter les couples déjà identifiés par buildSmartHierarchy().


Architecture Correcte

Principe de base

Réutiliser la logique d'InitialGeneration.js qui :

  1. Prépare les éléments avec type détecté
  2. Groupe en chunks de 4
  3. Génère par batch avec contraintes de longueur
  4. Parse les réponses avec fallback

MAIS : Adapter pour respecter la structure hiérarchique créée par buildSmartHierarchy().


📋 Plan Révisé

Option A : Réutiliser InitialGenerationLayer (RECOMMANDÉ)

Avantages :

  • Code déjà testé et fonctionnel
  • Gestion fallback robuste
  • Contraintes de longueur intégrées
  • Chunking optimisé

Modifications nécessaires :

1. Dans PipelineExecutor.js (ligne 214-247)

Avant :

const result = await generateSimple(hierarchy, csvData, { llmProvider });

Après :

const { InitialGenerationLayer } = require('../generation/InitialGeneration');
const layer = new InitialGenerationLayer();

// Aplatir la hiérarchie pour InitialGeneration
const flatStructure = flattenHierarchy(hierarchy);

const result = await layer.apply(flatStructure, {
  llmProvider,
  temperature: 0.9,
  csvData
});

2. Créer fonction flattenHierarchy() dans PipelineExecutor.js

function flattenHierarchy(hierarchy) {
  const flat = {};

  Object.entries(hierarchy).forEach(([sectionKey, section]) => {
    // Ajouter titre si présent
    if (section.title && section.title.instructions) {
      const titleTag = sectionKey.includes('_') ? sectionKey : `${sectionKey}_title`;
      flat[titleTag] = section.title.instructions;
    }

    // Ajouter texte si présent
    if (section.text && section.text.instructions) {
      const textTag = sectionKey.includes('_') ? `${sectionKey}_text` : sectionKey;
      flat[textTag] = section.text.instructions;
    }

    // Ajouter questions FAQ
    if (section.questions && section.questions.length > 0) {
      section.questions.forEach((faq, index) => {
        if (faq.originalElement && faq.originalElement.resolvedContent) {
          const faqTag = faq.hierarchyPath || `faq_${index}`;
          flat[faqTag] = faq.originalElement.resolvedContent;
        }
      });
    }
  });

  return flat;
}

Impact : Minimal, réutilise code existant


Option B : Adapter generateSimple() pour respecter la hiérarchie

Avantages :

  • Pas de changement dans PipelineExecutor
  • Compatibilité maintenue

Inconvénients :

  • Réécriture partielle de generateSimple()
  • Plus de code à tester

Modifications dans SelectiveUtils.js

Ajouter détection de couples avant la boucle :

async function generateSimple(hierarchy, csvData, options = {}) {
  // ... début identique ...

  const batches = [];

  // Grouper éléments par couples et type
  for (const [sectionKey, section] of Object.entries(hierarchy)) {
    const batch = [];

    // Couple titre + texte
    if (section.title && section.text) {
      batch.push([`${sectionKey}_title`, section.title]);
      batch.push([`${sectionKey}_text`, section.text]);
    } else if (section.title) {
      batch.push([`${sectionKey}_title`, section.title]);
    } else if (section.text) {
      batch.push([`${sectionKey}_text`, section.text]);
    }

    // Paires FAQ
    if (section.questions && section.questions.length > 0) {
      for (let i = 0; i < section.questions.length; i += 2) {
        const question = section.questions[i];
        const answer = section.questions[i + 1];

        if (question && answer) {
          batch.push([question.hierarchyPath, question]);
          batch.push([answer.hierarchyPath, answer]);
        }
      }
    }

    if (batch.length > 0) {
      batches.push(batch);
    }
  }

  // Générer chaque batch avec prompt adapté
  // ... suite similaire au plan initial mais avec couples respectés ...
}

🎯 Décision Requise

Questions Critiques

1. Quelle option choisir ?

  • Option A : Réutiliser InitialGenerationLayer (moins de code, plus sûr)
  • Option B : Adapter generateSimple() (plus de flexibilité, plus de risque)

2. Structure réelle de buildSmartHierarchy() ?

Pour valider le plan, j'ai besoin de voir un exemple concret de ce que retourne buildSmartHierarchy() actuellement.

Action : Ajouter ce log temporaire dans PipelineExecutor.js:233 :

const hierarchy = await buildSmartHierarchy(elementsArray);
logSh(`DEBUG HIERARCHY: ${JSON.stringify(hierarchy, null, 2)}`, 'DEBUG');

Puis relancer une génération et me partager les logs.

3. Nombre d'éléments attendus ?

  • Si buildSmartHierarchy() retourne 23 sections au lieu de 33 éléments, c'est normal (couples fusionnés)
  • Si on veut 33 éléments générés, il faut aplatir la hiérarchie (Option A)

📊 Comparaison Options

Critère Option A (Réutiliser) Option B (Adapter)
Code à écrire ~30 lignes ~150 lignes
Risque Faible Moyen
Tests nécessaires Minimes Complets
Maintenance Simple Double système
Performance Identique Identique
Compatibilité Changement PipelineExecutor Transparent
Recommandation OUI ⚠️ Si besoin spécifique

🚀 Étapes d'Implémentation (Option A - Recommandée)

Phase 1 : Validation de la structure (30 min)

  1. Ajouter logs debug pour comprendre buildSmartHierarchy()
  2. Analyser la sortie réelle
  3. Valider que les couples sont bien formés

Phase 2 : Fonction flattenHierarchy (45 min)

  1. Créer la fonction dans PipelineExecutor.js
  2. Tests unitaires avec fixtures
  3. Validation que tous les éléments sont extraits

Phase 3 : Intégration InitialGenerationLayer (60 min)

  1. Importer InitialGenerationLayer dans PipelineExecutor
  2. Remplacer appel à generateSimple()
  3. Adapter le retour pour compatibilité

Phase 4 : Augmentation maxTokens (15 min)

Mettre à jour LLMManager.js :

'claude-sonnet-4-5': { maxTokens: 8000 },
'gpt-4o-mini': { maxTokens: 6000 },
'gpt-5-mini': { maxTokens: 10000 },
// etc.

Phase 5 : Tests et validation (60 min)

  1. Test génération ligne 2 production
  2. Vérifier 33 éléments générés
  3. Vérifier longueurs respectées
  4. Vérifier cohérence FAQ
  5. Mesurer temps (~40-50s attendu)

Temps total : 3h30


📝 Modifications de Code

Fichiers impactés

  1. lib/pipeline/PipelineExecutor.js (ligne 214-247)

    • Import InitialGenerationLayer
    • Fonction flattenHierarchy()
    • Remplacement generateSimple()
  2. lib/LLMManager.js (ligne 18-67)

    • Augmentation maxTokens
  3. lib/selective-enhancement/SelectiveUtils.js (optionnel)

    • Marquer generateSimple() comme DEPRECATED
    • Ajouter commentaire pointant vers InitialGeneration

⚠️ Risques et Mitigations

Risque 1 : Structure hiérarchie différente de l'attendu

Impact : High Probabilité : Medium Mitigation : Logs debug + validation avant implémentation

Risque 2 : Parsing échoue sur certains éléments

Impact : Medium Probabilité : Low (code legacy testé) Mitigation : Fallback déjà présent dans InitialGenerationLayer

Risque 3 : Régression performance

Impact : Medium Probabilité : Very Low Mitigation : Tests avant/après avec métriques

Risque 4 : Incompatibilité avec pipeline actuel

Impact : High Probabilité : Low Mitigation : Tests complets sur environnement dev


Critères de Succès

  1. Fonctionnel :

    • 33/33 éléments générés (pas de skip)
    • Longueurs respectées (H2: 8-15 mots, P: 80-200 mots)
    • Paires FAQ cohérentes (Q pertinente pour R)
    • Aucune erreur FATAL
  2. Performance :

    • Temps < 60s (vs ~150s actuellement)
    • Coût -30% minimum
  3. Qualité :

    • Contenu non générique
    • Pas de troncature
    • Style personnalité respecté

🔄 Rollback Strategy

En cas de problème :

  1. Phase 1-3 : git revert simple
  2. Phase 4 : Restaurer anciennes valeurs maxTokens
  3. Phase 5 : Si échec tests, rollback complet

Fallback automatique : InitialGenerationLayer a déjà un fallback intégré par chunk.


📌 TODO Immédiat

  • DÉCISION : Choisir Option A ou Option B
  • ACTION : Ajouter logs debug buildSmartHierarchy()
  • PARTAGE : Envoyer exemple output buildSmartHierarchy()
  • Valider avec utilisateur avant implémentation

📚 Références Code Legacy

  • lib/generation/InitialGeneration.js (ligne 1-284)
  • lib/ElementExtraction.js - buildSmartHierarchy() (ligne 276-313)
  • lib/ElementExtraction.js - parseFAQPairsResponse() (ligne 402-451)
  • lib/pipeline/PipelineExecutor.js - runGeneration() (ligne 214-247)

Status : ⏸️ EN ATTENTE VALIDATION UTILISATEUR

Avant de commencer l'implémentation, il faut :

  1. Décider de l'option (A recommandée)
  2. Analyser la structure réelle de buildSmartHierarchy()
  3. Valider que le plan correspond aux besoins