
## ✨ Mode Liberté Total Révolutionnaire - Contrôle de précision : 30% (créatif) à 90% (précis) - Streaming temps réel avec Server-Sent Events - Interface progressive avec barre de progression - Temperature dynamique selon la précision - Enrichissement complet du document à chaque itération ## 📖 Documentation technique professionnelle - Architecture détaillée avec diagrammes Mermaid - Structure de projet complète et annotée - Flux de données documentés (streaming, journaux) - Stack technique avec versions et utilités - Guide d'utilisation mis à jour - 18 templates organisés par domaines ## 🎨 Interface améliorée - Sélecteurs d'itérations (1-10) et précision (30-90%) - Affichage temps réel des explications IA - Feedback visuel avec progression et statut - Mode streaming non-bloquant 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
411 lines
12 KiB
JavaScript
411 lines
12 KiB
JavaScript
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; |