const express = require('express'); const router = express.Router(); require('dotenv').config({ path: './config/.env' }); // Configuration Mistral AI const MISTRAL_API_KEY = process.env.MISTRAL_API_KEY; const MISTRAL_BASE_URL = process.env.MISTRAL_BASE_URL || 'https://api.mistral.ai/v1'; const MISTRAL_MODEL = process.env.MISTRAL_MODEL || 'mistral-large-latest'; const AI_ENABLED = process.env.AI_ENABLED === 'true'; // Middleware de vérification function checkAIEnabled(req, res, next) { if (!AI_ENABLED) { return res.status(503).json({ success: false, error: 'Les fonctionnalités IA sont désactivées' }); } if (!MISTRAL_API_KEY) { return res.status(500).json({ success: false, error: 'Clé API Mistral non configurée' }); } next(); } // Fonction pour appeler l'API Mistral async function callMistralAPI(messages, temperature = null) { try { const response = await fetch(`${MISTRAL_BASE_URL}/chat/completions`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${MISTRAL_API_KEY}` }, body: JSON.stringify({ model: MISTRAL_MODEL, messages: messages, temperature: temperature !== null ? temperature : parseFloat(process.env.AI_TEMPERATURE) || 0.3, max_tokens: parseInt(process.env.AI_MAX_TOKENS) || 35000, top_p: parseFloat(process.env.AI_TOP_P) || 0.85 }) }); if (!response.ok) { const error = await response.text(); throw new Error(`Erreur API Mistral: ${response.status} - ${error}`); } const data = await response.json(); return data.choices[0].message.content; } catch (error) { console.error('Erreur Mistral API:', error); throw error; } } // POST /api/ai/rephrase - Reformuler du texte router.post('/rephrase', checkAIEnabled, async (req, res) => { try { const { text, context = '' } = req.body; if (!text || text.trim().length === 0) { return res.status(400).json({ success: false, error: 'Texte à reformuler requis' }); } const messages = [ { role: 'system', content: `Tu es un assistant spécialisé dans la reformulation de textes techniques et de conception. RÈGLES STRICTES : 1. Reformule le texte pour améliorer la clarté, le style et la fluidité 2. Conserve le niveau technique et tous les détails importants 3. Ne réponds QUE avec le texte reformulé final 4. Aucune introduction, conclusion, explication ou commentaire 5. Ne commence pas par "Voici", "Le texte reformulé" ou autre préambule 6. Commence directement par le contenu reformulé ${context ? `Contexte du document: ${context}` : ''}` }, { role: 'user', content: `Reformule ce texte: "${text}"` } ]; const result = await callMistralAPI(messages, 0.2); // Reformulation précise res.json({ success: true, data: { original: text, rephrased: result } }); } catch (error) { console.error('Erreur reformulation:', error); res.status(500).json({ success: false, error: 'Erreur lors de la reformulation: ' + error.message }); } }); // POST /api/ai/check-inconsistencies - Vérifier les incohérences router.post('/check-inconsistencies', checkAIEnabled, async (req, res) => { try { const { content } = req.body; if (!content || content.trim().length === 0) { return res.status(400).json({ success: false, error: 'Contenu à analyser requis' }); } const messages = [ { role: 'system', content: `Tu es un expert en analyse de documents de conception technique. Analyse le document suivant et identifie toutes les incohérences potentielles : - Contradictions dans les informations - Décisions qui se contredisent - Incohérences dans la terminologie - Problèmes logiques dans l'architecture ou les choix Réponds directement avec ton analyse détaillée des incohérences trouvées.` }, { role: 'user', content: `Analyse ce document pour détecter les incohérences:\n\n${content}` } ]; const result = await callMistralAPI(messages, 0.1); // Analyse précise et factuelle res.json({ success: true, data: { analysis: result } }); } catch (error) { console.error('Erreur analyse incohérences:', error); res.status(500).json({ success: false, error: 'Erreur lors de l\'analyse: ' + error.message }); } }); // POST /api/ai/check-duplications - Vérifier les doublons router.post('/check-duplications', checkAIEnabled, async (req, res) => { try { const { content } = req.body; if (!content || content.trim().length === 0) { return res.status(400).json({ success: false, error: 'Contenu à analyser requis' }); } const messages = [ { role: 'system', content: `Tu es un expert en analyse de contenu. Analyse le document suivant pour identifier : - Les informations répétées ou redondantes - Les sections qui traitent du même sujet - Les explications dupliquées - Les concepts présentés plusieurs fois Propose des suggestions pour éliminer ces duplications tout en préservant les informations importantes. Réponds directement avec ton analyse et tes suggestions.` }, { role: 'user', content: `Analyse ce document pour détecter les duplications:\n\n${content}` } ]; const result = await callMistralAPI(messages, 0.1); // Analyse précise et factuelle res.json({ success: true, data: { analysis: result } }); } catch (error) { console.error('Erreur analyse duplications:', error); res.status(500).json({ success: false, error: 'Erreur lors de l\'analyse: ' + error.message }); } }); // POST /api/ai/give-advice - Donner des conseils router.post('/give-advice', checkAIEnabled, async (req, res) => { try { const { content, domain = 'général' } = req.body; if (!content || content.trim().length === 0) { return res.status(400).json({ success: false, error: 'Contenu à analyser requis' }); } const messages = [ { role: 'system', content: `Tu es un consultant expert en conception et architecture technique dans le domaine: ${domain}. Analyse le document de conception fourni et donne des conseils constructifs pour l'améliorer. Concentre-toi sur : - La complétude de la documentation - La clarté des explications - L'organisation du contenu - Les bonnes pratiques du domaine - Les points manquants importants - Les suggestions d'amélioration concrètes Sois constructif et pratique dans tes recommandations. Réponds directement avec tes conseils et suggestions d'amélioration.` }, { role: 'user', content: `Analyse ce document de conception et donne des conseils pour l'améliorer:\n\n${content}` } ]; const result = await callMistralAPI(messages, 0.4); // Conseils équilibrés res.json({ success: true, data: { advice: result } }); } catch (error) { console.error('Erreur conseils:', error); res.status(500).json({ success: false, error: 'Erreur lors de l\'analyse: ' + error.message }); } }); // POST /api/ai/liberty-mode - Mode liberté total (génération itérative) router.post('/liberty-mode', checkAIEnabled, async (req, res) => { try { const { content, iterations = 1, precision = 70, focus = 'conception' } = req.body; if (!content || content.trim().length === 0) { return res.status(400).json({ success: false, error: 'Contenu de base requis' }); } const maxIterations = Math.min(parseInt(iterations), 10); // Limite à 10 itérations const precisionPercent = Math.min(Math.max(parseInt(precision), 10), 100); // Entre 10% et 100% // Configuration streaming pour réponses en temps réel res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*' }); let currentContent = content; for (let i = 0; i < maxIterations; i++) { try { const messages = [ { role: 'system', content: `Tu es un expert en conception technique avec mode "Liberté Total". MISSION: Améliore et enrichis le document en respectant EXACTEMENT ce niveau de précision: ${precisionPercent}% RÈGLES DE PRÉCISION: - À ${precisionPercent}%: Tu peux déduire et ajouter du contenu à hauteur de ${precisionPercent}% basé sur les informations existantes - À ${100 - precisionPercent}%: Tu peux créer du contenu logique et pertinent même sans info explicite dans le texte CONSIGNES: 1. Enrichis TOUT le document de manière cohérente 2. Ajoute sections, détails, explications, diagrammes conceptuels 3. Développe les idées existantes avec la créativité autorisée 4. Maintiens la structure logique RÉPONSE OBLIGATOIRE EN 2 PARTIES SÉPARÉES PAR "---SPLIT---": ## 📊 Explication (Itération ${i + 1}/${maxIterations}) [Explique les améliorations apportées, les sections ajoutées, le raisonnement] ---SPLIT--- [LE DOCUMENT MARKDOWN COMPLET ET AMÉLIORÉ - SANS TITRE "## Document" - DIRECTEMENT LE CONTENU] Focus: ${focus} Précision: ${precisionPercent}%` }, { role: 'user', content: `Document à améliorer (Itération ${i + 1}):\n\n${currentContent}` } ]; // Temperature basée sur la précision (plus créatif = température plus élevée) const temperature = (100 - precisionPercent) / 100 * 0.8 + 0.1; // Entre 0.1 et 0.9 const result = await callMistralAPI(messages, temperature); // Séparer l'explication du markdown const parts = result.split('---SPLIT---'); let explanation = ''; let newMarkdown = currentContent; // Par défaut, garder l'ancien contenu if (parts.length >= 2) { explanation = parts[0].trim(); newMarkdown = parts[1].trim(); // Mettre à jour pour la prochaine itération currentContent = newMarkdown; } else { // Fallback si pas de split trouvé explanation = result; } // Envoyer la réponse de cette itération const iterationData = { iteration: i + 1, explanation: explanation, markdown: newMarkdown, completed: false }; res.write(`data: ${JSON.stringify(iterationData)}\n\n`); // Petit délai pour permettre l'affichage côté client await new Promise(resolve => setTimeout(resolve, 500)); } catch (iterationError) { console.error(`Erreur itération ${i + 1}:`, iterationError); const errorData = { iteration: i + 1, error: `Erreur itération ${i + 1}: ${iterationError.message}`, completed: true }; res.write(`data: ${JSON.stringify(errorData)}\n\n`); break; } } // Signal de fin const finalData = { completed: true, totalIterations: maxIterations, finalMarkdown: currentContent }; res.write(`data: ${JSON.stringify(finalData)}\n\n`); res.end(); } catch (error) { console.error('Erreur mode liberté total:', error); const errorData = { error: 'Erreur lors de la génération: ' + error.message, completed: true }; res.write(`data: ${JSON.stringify(errorData)}\n\n`); res.end(); } }); // GET /api/ai/status - Statut de l'IA router.get('/status', (req, res) => { res.json({ success: true, data: { enabled: AI_ENABLED, model: MISTRAL_MODEL, configured: !!MISTRAL_API_KEY } }); }); module.exports = router;