diff --git a/README.md b/README.md index e69de29..efbb9a9 100644 Binary files a/README.md and b/README.md differ diff --git a/assets/js/app.js b/assets/js/app.js index 14d5195..1996e68 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -6,6 +6,8 @@ class ConceptionAssistant { this.undoStack = []; this.redoStack = []; this.tocTimer = null; + this.isPreviewMode = false; + this.originalContent = ''; this.init(); } @@ -66,6 +68,7 @@ class ConceptionAssistant { // Boutons de contrôle des journaux document.getElementById('save-journal')?.addEventListener('click', () => this.saveJournal()); document.getElementById('load-journal')?.addEventListener('click', () => this.showJournalSelector()); + document.getElementById('preview-toggle')?.addEventListener('click', () => this.togglePreview()); // Table des matières document.getElementById('refresh-toc')?.addEventListener('click', () => this.generateTOC()); @@ -445,31 +448,47 @@ class ConceptionAssistant { for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith('#') && line.replace(/^#+\s*/, '') === title) { - // Créer un range temporaire pour scroller vers cette ligne - const range = document.createRange(); - const selection = window.getSelection(); - - // Calculer la position approximative du caractère - const beforeLines = lines.slice(0, i).join('\n'); - const charPosition = beforeLines.length; - try { - // Créer un range au début de la ligne trouvée - range.setStart(this.editor.childNodes[0] || this.editor, Math.min(charPosition, this.editor.textContent.length)); - range.collapse(true); + // Approche plus simple : utiliser un élément temporaire avec une position spécifique + const tempElement = document.createElement('div'); + tempElement.style.position = 'absolute'; + tempElement.style.visibility = 'hidden'; + tempElement.style.height = '1px'; - // Créer un élément temporaire pour le scroll - const tempElement = document.createElement('span'); - range.insertNode(tempElement); + // Calculer la position approximative en fonction de la ligne + const editorRect = this.editor.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(this.editor); + const lineHeight = parseInt(computedStyle.lineHeight) || 20; - tempElement.scrollIntoView({ - behavior: 'smooth', - block: 'start', - inline: 'nearest' + // Insérer l'élément temporaire dans l'éditeur + this.editor.appendChild(tempElement); + + // Calculer la position de scroll basée sur le numéro de ligne + const targetPosition = i * lineHeight; + + // Scroller vers la position calculée + this.editor.scrollTo({ + top: targetPosition, + behavior: 'smooth' }); + // Si l'éditeur n'a pas de scroll, utiliser le parent + if (this.editor.scrollHeight <= this.editor.clientHeight) { + const scrollContainer = this.editor.parentElement || document.documentElement; + const editorTop = this.editor.offsetTop; + + scrollContainer.scrollTo({ + top: editorTop + targetPosition - 100, // -100 pour un padding + behavior: 'smooth' + }); + } + // Nettoyer l'élément temporaire - setTimeout(() => tempElement.remove(), 100); + setTimeout(() => { + if (tempElement.parentNode) { + tempElement.parentNode.removeChild(tempElement); + } + }, 100); this.showNotification('Navigation vers la section', 'success'); return; @@ -618,23 +637,30 @@ class ConceptionAssistant { // Mode liberté utilise toujours le document complet result = await this.callAI('/api/ai/liberty-mode', { content: fullContent, iterations: count, focus: 'conception' }); - // Appliquer automatiquement chaque itération au document - let updatedContent = fullContent; - result.results.forEach(iteration => { - updatedContent += '\n\n' + iteration.content; - }); + // Utiliser le contenu final mis à jour par le backend + if (result.finalContent) { + this.editor.innerText = result.finalContent; + this.generateTOC(); + this.saveState(); + } - // Appliquer les changements directement - this.editor.innerText = updatedContent; - this.generateTOC(); - this.saveState(); + let libertyHTML = `🚀 Mode Liberté Intelligent (${result.iterations} itérations)

`; + + // Vérifier si l'IA s'est arrêtée prématurément + const lastIteration = result.results[result.results.length - 1]; + if (lastIteration && lastIteration.stopped) { + libertyHTML += `

🛑 Analyse terminée après ${result.iterations} itérations - Aucune amélioration évidente supplémentaire détectée.

`; + } else { + libertyHTML += `

✅ Les ${result.iterations} itérations d'amélioration ont été automatiquement appliquées au document.

`; + } - let libertyHTML = `🚀 Mode Liberté appliqué (${result.iterations} itérations)

`; - libertyHTML += `

✅ Les ${result.iterations} itérations ont été automatiquement ajoutées au document.

`; result.results.forEach(iteration => { + const borderColor = iteration.stopped ? 'var(--warning-color)' : 'var(--success-color)'; + const icon = iteration.stopped ? '🛑' : '🎯'; + libertyHTML += ` -
- Itération ${iteration.iteration} ajoutée :

+
+ ${icon} Itération ${iteration.iteration} ${iteration.stopped ? '(Arrêt)' : '(Appliquée)'} :

${this.formatAIResponse(iteration.content)}
`; @@ -673,20 +699,21 @@ class ConceptionAssistant { const sections = text.split('##'); let formattedHTML = ''; + const self = this; sections.forEach((section, index) => { if (index === 0 && section.trim()) { // Première section sans titre - formattedHTML += `
${this.parseMarkdown(section.trim())}
`; + formattedHTML += `
${self.parseMarkdown(section.trim())}
`; } else if (section.trim()) { const lines = section.split('\n'); const title = lines[0].trim(); const content = lines.slice(1).join('\n').trim(); - // Sections normales - pas de markdown + // Sections normales - avec markdown formattedHTML += `
- ${title}

- ${content} + ${title}

+
${self.parseMarkdown(content)}
`; } @@ -695,6 +722,47 @@ class ConceptionAssistant { return formattedHTML || text; } + parseMarkdown(text) { + if (!text) return ''; + + return text + // Titres H1-H6 (#, ##, ###, etc.) + .replace(/^(#{1,6})\s+(.+)$/gm, (match, hashes, title) => { + const level = hashes.length; + return `${title}`; + }) + // Listes à puces (- ou *) + .replace(/^[\s]*[-\*]\s+(.+)$/gm, '
  • $1
  • ') + // Listes numérotées + .replace(/^[\s]*\d+\.\s+(.+)$/gm, '
  • $1
  • ') + // Code blocks avec ``` + .replace(/```([\s\S]*?)```/g, '
    $1
    ') + // Citations avec > + .replace(/^>\s+(.+)$/gm, '
    $1
    ') + // Gras **texte** + .replace(/\*\*(.*?)\*\*/g, '$1') + // Italique *texte* + .replace(/\*(.*?)\*/g, '$1') + // Code inline `code` + .replace(/`([^`]+)`/g, '$1') + // Liens [texte](url) + .replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1') + // Séparer les listes en blocs `; + } + return match; + }) + // Sauts de ligne doubles pour paragraphes + .replace(/\n\n+/g, '\n\n') + .replace(/\n\n/g, '

    ') + // Sauts de ligne simples + .replace(/\n/g, '
    ') + // Encapsuler dans un paragraphe si pas déjà fait + .replace(/^(?!<[h1-6|ul|ol|pre|blockquote])/i, '

    ') + .replace(/$/i, '

    '); + } showAIFeedback(message) { const feedback = document.getElementById('ai-assistant-feedback'); @@ -894,4 +962,48 @@ function initializeTemplateForm() { }); } + togglePreview() { + const previewBtn = document.getElementById('preview-toggle'); + + if (!this.isPreviewMode) { + // Passer en mode prévisualisation + this.originalContent = this.editor.innerHTML; + const markdownContent = this.editor.innerText; + + // Convertir le Markdown en HTML joliment formaté + const previewHTML = this.parseMarkdown(markdownContent); + + // Désactiver l'édition et appliquer le style preview + this.editor.contentEditable = false; + this.editor.innerHTML = `
    ${previewHTML}
    `; + this.editor.style.background = 'var(--background-color)'; + this.editor.style.border = '1px solid var(--border-color)'; + this.editor.style.borderRadius = '8px'; + + // Changer le bouton + previewBtn.innerHTML = '✏️ Éditer'; + previewBtn.classList.remove('primary'); + previewBtn.classList.add('secondary'); + + this.isPreviewMode = true; + this.showNotification('Mode prévisualisation activé', 'success'); + + } else { + // Revenir en mode édition + this.editor.contentEditable = true; + this.editor.innerHTML = this.originalContent; + this.editor.style.background = ''; + this.editor.style.border = ''; + this.editor.style.borderRadius = ''; + + // Changer le bouton + previewBtn.innerHTML = '👁️ Visualiser'; + previewBtn.classList.remove('secondary'); + previewBtn.classList.add('primary'); + + this.isPreviewMode = false; + this.showNotification('Mode édition activé', 'success'); + } + } + } \ No newline at end of file diff --git a/config/.env.example b/config/.env.example index a94da1b..9b309f0 100644 --- a/config/.env.example +++ b/config/.env.example @@ -8,10 +8,6 @@ MISTRAL_BASE_URL=https://api.mistral.ai/v1 # AI Features Configuration AI_ENABLED=false -AI_MAX_TOKENS=4000 -AI_TEMPERATURE=0.7 -AI_TOP_P=0.95 - -# Rate Limiting for AI -AI_RATE_LIMIT_REQUESTS=10 -AI_RATE_LIMIT_WINDOW=60000 \ No newline at end of file +AI_MAX_TOKENS=35000 +AI_TEMPERATURE=0.3 +AI_TOP_P=0.85 \ No newline at end of file diff --git a/data/936a1104-7afa-438f-b352-aa1f9294132d.md b/data/936a1104-7afa-438f-b352-aa1f9294132d.md deleted file mode 100644 index 339e38b..0000000 --- a/data/936a1104-7afa-438f-b352-aa1f9294132d.md +++ /dev/null @@ -1 +0,0 @@ -#Fait moi un texte sur le fairy \ No newline at end of file diff --git a/data/cb853f57-e578-42b4-8d39-bd71319d4d47.md b/data/cb853f57-e578-42b4-8d39-bd71319d4d47.md deleted file mode 100644 index 005769e..0000000 --- a/data/cb853f57-e578-42b4-8d39-bd71319d4d47.md +++ /dev/null @@ -1,88 +0,0 @@ -**Spécifications Techniques – Projet Informatique** - -## 1. Cadre général du projet - -### 1.1 Contexte -[Résumé synthétique du projet, incluant son périmètre et sa finalité] - -### 1.2 Objectifs -**Objectif principal** : -- [Description concise et orientée résultats] - -**Fonctionnalités clés** : -- [Liste des éléments critiques, formulés sous forme de livrables ou de capacités] - -### Description du projet -[Résumé en quelques lignes] - -### Objectifs -- Objectif principal : -- Fonctionnalités clés : - -## 2. Spécifications techniques - -### Technologies utilisées -- **Frontend** : -- **Backend** : -- **Base de données** : -- **Outils** : - -### Architecture -[Description simple de l'architecture] - -## 3. Fonctionnalités - -### Fonctionnalités principales -- [ ] Feature 1 -- [ ] Feature 2 -- [ ] Feature 3 - -### Fonctionnalités secondaires -- [ ] Feature A -- [ ] Feature B - -## 4. Interface utilisateur - -### Pages principales -- Page d'accueil : -- Page utilisateur : -- Page admin : - -## 5. Base de données - -### Modèles principaux -- **Utilisateur** : id, nom, email -- **Contenu** : id, titre, description -- **Session** : id, token, user_id - -## 6. Planning de développement - -### Sprint 1 (2 semaines) -- [ ] Setup du projet -- [ ] Authentification -- [ ] Interface de base - -### Sprint 2 (2 semaines) -- [ ] CRUD principal -- [ ] Tests unitaires -- [ ] Déploiement - -### Sprint 3 (2 semaines) -- [ ] Fonctionnalités avancées -- [ ] Optimisation -- [ ] Documentation - -## 7. Tests et déploiement - -### Tests -- [ ] Tests unitaires -- [ ] Tests d'intégration -- [ ] Tests utilisateur - -### Déploiement -- **Environnement dev** : -- **Environnement prod** : - -## 8. Notes techniques - -[Espace pour notes de développement] \ No newline at end of file diff --git a/data/d8ec4a9b-4c0f-4ea8-b374-1c85c13fd954.md b/data/d8ec4a9b-4c0f-4ea8-b374-1c85c13fd954.md deleted file mode 100644 index a45de7a..0000000 --- a/data/d8ec4a9b-4c0f-4ea8-b374-1c85c13fd954.md +++ /dev/null @@ -1,94 +0,0 @@ -# Journal de Conception - Projet Informatique - -## 1. Introduction -Une calculatrice - -**Idée principale :** -une calculatrice que je peux accéder sur mon pc - -## 2. Objectifs du projet -**Objectifs principaux :** -- [ ] Objectif 1 -- [ ] Objectif 2 -- [ ] Objectif 3 - -**Fonctionnalités clés recherchées :** -- Fonctionnalité essentielle 1 -- Fonctionnalité essentielle 2 - -## 3. Présentation et spécifications -**Description détaillée :** -[Expliquer ce que fait le projet et ses enjeux] - -**Cahier des charges :** -- **Besoin général** : [Problème à résoudre] -- **Besoins spécifiques** : [Liste des exigences] - -## 4. Fonctionnalités attendues -- [ ] **Module utilisateur** : Inscription, connexion, profil -- [ ] **Module principal** : [Fonctionnalité cœur du projet] -- [ ] **Module administration** : Gestion des données -- [ ] **Module sécurité** : Authentification, autorisation - -## 5. Conception globale -**Vue utilisateur :** -``` -Interface Web → Authentification → Dashboard → Modules fonctionnels -``` - -**Architecture technique :** -``` -[Client] ↔ [API REST] ↔ [Logique métier] ↔ [Base de données] -``` - -**Architecture logicielle :** -- **Frontend** : React/Vue.js + CSS Framework -- **Backend** : Node.js/Python + Framework web -- **Base de données** : PostgreSQL/MongoDB -- **API** : REST ou GraphQL - -## 6. Problématiques et solutions -| Problématique | Solution technique | -|---------------|-------------------| -| Performance | Cache Redis + optimisation requêtes | -| Sécurité | HTTPS + JWT + validation inputs | -| Scalabilité | Architecture microservices | - -## 7. Environnement et outils -**Outils de développement :** -- IDE : VS Code / IntelliJ -- Versioning : Git + GitHub/GitLab -- Gestion projet : Jira / Trello - -**Stack technique :** -- Runtime : Node.js / Python -- Framework : Express / Django -- Tests : Jest / Pytest - -## 8. Phases du projet -**Phase 1 - Conception (2 semaines) :** -- [ ] Finaliser l'architecture -- [ ] Mockups des interfaces -- [ ] Setup environnement dev - -**Phase 2 - Développement (6 semaines) :** -- [ ] Backend et API -- [ ] Frontend et interfaces -- [ ] Intégration continue - -**Phase 3 - Tests et déploiement (2 semaines) :** -- [ ] Tests automatisés -- [ ] Déploiement production -- [ ] Documentation utilisateur - -## 9. Conclusion -**État d'avancement :** -[À compléter au fur et à mesure] - -**Prochaines étapes :** -- [ ] Étape prioritaire 1 -- [ ] Étape prioritaire 2 - ---- -*Journal créé le : [DATE]* -*Dernière mise à jour : [DATE]* \ No newline at end of file diff --git a/data/uuid_map.json b/data/uuid_map.json deleted file mode 100644 index 4fa925f..0000000 --- a/data/uuid_map.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "0": "936a1104-7afa-438f-b352-aa1f9294132d", - "1": "cb853f57-e578-42b4-8d39-bd71319d4d47", - "2": "d8ec4a9b-4c0f-4ea8-b374-1c85c13fd954" -} \ No newline at end of file diff --git a/routes/ai.js b/routes/ai.js index c6643dd..e51e8ba 100644 --- a/routes/ai.js +++ b/routes/ai.js @@ -28,7 +28,7 @@ function checkAIEnabled(req, res, next) { } // Fonction pour appeler l'API Mistral -async function callMistralAPI(messages, temperature = 0.7) { +async function callMistralAPI(messages, temperature = null) { try { const response = await fetch(`${MISTRAL_BASE_URL}/chat/completions`, { method: 'POST', @@ -39,9 +39,9 @@ async function callMistralAPI(messages, temperature = 0.7) { body: JSON.stringify({ model: MISTRAL_MODEL, messages: messages, - temperature: temperature, - max_tokens: parseInt(process.env.AI_MAX_TOKENS) || 4000, - top_p: parseFloat(process.env.AI_TOP_P) || 0.95 + 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 }) }); @@ -91,7 +91,7 @@ router.post('/rephrase', checkAIEnabled, async (req, res) => { } ]; - const result = await callMistralAPI(messages, 0.7); + const result = await callMistralAPI(messages, 0.2); // Reformulation précise res.json({ success: true, @@ -141,7 +141,7 @@ router.post('/check-inconsistencies', checkAIEnabled, async (req, res) => { } ]; - const result = await callMistralAPI(messages, 0.3); + const result = await callMistralAPI(messages, 0.1); // Analyse précise et factuelle res.json({ success: true, @@ -191,7 +191,7 @@ router.post('/check-duplications', checkAIEnabled, async (req, res) => { } ]; - const result = await callMistralAPI(messages, 0.3); + const result = await callMistralAPI(messages, 0.1); // Analyse précise et factuelle res.json({ success: true, @@ -245,7 +245,7 @@ router.post('/give-advice', checkAIEnabled, async (req, res) => { } ]; - const result = await callMistralAPI(messages, 0.6); + const result = await callMistralAPI(messages, 0.4); // Conseils équilibrés res.json({ success: true, @@ -275,54 +275,82 @@ router.post('/liberty-mode', checkAIEnabled, async (req, res) => { }); } - const maxIterations = Math.min(parseInt(iterations), 5); // Limite à 5 itérations + const maxIterations = Math.min(parseInt(iterations), 15); // Limite à 15 itérations const results = []; + let currentContent = content; for (let i = 0; i < maxIterations; i++) { const messages = [ { role: 'system', - content: `Tu es un assistant créatif spécialisé en conception technique. + content: `Tu es un assistant créatif spécialisé en conception technique avec une approche itérative intelligente. - IMPORTANT: Montre ton raisonnement en suivant cette structure: + MISSION: Analyse le document et identifie LE PREMIER point que tu peux compléter, créer ou modifier avec plus de 90% de confiance basé sur les informations existantes dans le texte. - ## 🧠 Raisonnement (Itération ${i + 1}/${maxIterations}) - [Explique ton processus de création et ta logique] + RÈGLES STRICTES: + 1. Ne traite qu'UN SEUL point par itération + 2. Choisis le point le plus évident et logique à améliorer + 3. Utilise uniquement les informations déjà présentes dans le document + 4. Si rien ne peut être amélioré avec 90%+ de confiance, indique "STOP" - ## 🚀 Contenu généré - [Ton contenu créatif complémentaire] + STRUCTURE OBLIGATOIRE: - Basé sur le contenu existant, génère de nouvelles idées et sections qui complètent naturellement le document. + ## 🧠 Analyse (Itération ${i + 1}/${maxIterations}) + [Identifie et explique le point le plus évident à améliorer] - Focus: ${focus} + ## 🎯 Point identifié + [Le point spécifique que tu vas traiter] - Propose des extensions créatives mais pertinentes : - - Nouvelles sections logiques - - Détails techniques manquants - - Alternatives à considérer - - Implications et conséquences - - Améliorations possibles + ## ✅ Amélioration + [Le contenu précis à ajouter/modifier, avec 90%+ de confiance] - Reste cohérent avec le style et le niveau technique du document existant.` + OU si rien ne peut être amélioré avec assez de confiance: + + ## 🛑 STOP + [Explication pourquoi aucune amélioration évidente n'est possible] + + Focus: ${focus}` }, { role: 'user', - content: `Génère du contenu complémentaire pour ce document:\n\n${content}` + content: `Document à analyser (Itération ${i + 1}):\n\n${currentContent}` } ]; - const result = await callMistralAPI(messages, 0.8); + const result = await callMistralAPI(messages, 0.2); // Mode itératif intelligent et précis + + // Vérifier si l'IA indique qu'il faut s'arrêter + if (result.toLowerCase().includes('🛑 stop') || result.toLowerCase().includes('## 🛑 stop')) { + results.push({ + iteration: i + 1, + content: result, + stopped: true + }); + break; + } + + // Extraire l'amélioration de la réponse de l'IA + let improvement = ''; + const improvementMatch = result.match(/## ✅ Amélioration\s*([\s\S]*?)(?=##|$)/i); + if (improvementMatch) { + improvement = improvementMatch[1].trim(); + // Mettre à jour le contenu pour la prochaine itération + currentContent += '\n\n' + improvement; + } + results.push({ iteration: i + 1, - content: result + content: result, + improvement: improvement }); } res.json({ success: true, data: { - iterations: maxIterations, - results: results + iterations: results.length, + results: results, + finalContent: currentContent } }); diff --git a/views/main.js b/views/main.js index df62e8e..44f74d7 100644 --- a/views/main.js +++ b/views/main.js @@ -16,6 +16,7 @@ function getMain() {
    +
    @@ -62,6 +63,16 @@ function getMain() { + + + + + + + + + +