/* ELYSIA MARKDOWN STUDIO v1.0 - AI Tools Module Elysia's AI-powered features */ import Utils from "./utils.js"; import API from "./api.js"; import DB from "./db.js"; const AITools = { isProcessing: false, init() { document.getElementById("btn-ai-tools").addEventListener("click", () => { Utils.modal.open("modal-ai-tools"); }); document.querySelectorAll(".ai-tool-card").forEach(card => { card.addEventListener("click", () => { const tool = card.getAttribute("data-tool"); this.executeTool(tool); }); }); }, async executeTool(tool) { if (this.isProcessing) { Utils.toast.warning("Please wait - Elysia is already working on something!"); return; } Utils.modal.close("modal-ai-tools"); this.isProcessing = true; // Show loading indicator const loadingToast = this.showLoadingState(tool); try { switch (tool) { case "summarize": await this.summarize(); break; case "improve": await this.improveWriting(); break; case "merge": await this.mergeDocuments(); break; case "outline": await this.extractOutline(); break; case "duplicates": await this.findDuplicates(); break; case "organize": await this.smartOrganize(); break; } } catch (err) { console.error(`AI tool ${tool} failed:`, err); // User-friendly error messages let errorMsg = "AI tool failed"; if (err.message.includes("API key")) { errorMsg = "API key not configured. Please add it in Settings ⚙️"; } else if (err.message.includes("network") || err.message.includes("fetch")) { errorMsg = "Network error. Check your connection and try again."; } else if (err.message.includes("rate limit")) { errorMsg = "Rate limit reached. Please wait a moment and try again."; } else { errorMsg = err.message || "AI tool failed. Please try again."; } Utils.toast.error(errorMsg, 5000); } finally { this.isProcessing = false; // Remove loading toast if (loadingToast) loadingToast.remove(); } }, showLoadingState(tool) { const messages = { summarize: "🧠 Elysia is reading and summarizing...", improve: "✨ Elysia is polishing your writing...", merge: "📚 Elysia is merging documents...", outline: "🎯 Elysia is extracting outline...", duplicates: "🔍 Elysia is analyzing duplicates...", organize: "🏷️ Elysia is organizing content..." }; const toast = Utils.toast.show(messages[tool] || "🧠 Elysia is thinking...", "loading", 0); // 0 = no auto-close return toast; }, async summarize() { const content = window.app?.editor.getContent(); if (!content) { Utils.toast.warning("No content to summarize"); return; } if (content.length < 100) { Utils.toast.warning("Content too short. Add at least 100 characters for better summary."); return; } const summary = await API.summarize(content); // Create new document with summary const doc = await DB.createDocument({ title: `Summary of ${window.app?.currentDoc?.title || "Document"}`, content: summary }); Utils.toast.success("Summary created!"); window.app?.loadDocument(doc.id); }, async improveWriting() { const content = window.app?.editor.getContent(); if (!content) { Utils.toast.warning("No content to improve"); return; } if (content.length < 50) { Utils.toast.warning("Content too short. Add at least 50 characters for improvement."); return; } // 🎲 Show style selection modal (VS-inspired) this.showImproveStyleModal(content); }, // 🎲 VS-INSPIRED: Show style selection modal showImproveStyleModal(content) { // Add styles if not present if (!document.getElementById("improve-styles-css")) { const style = document.createElement("style"); style.id = "improve-styles-css"; style.textContent = ` .improve-style-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 20px 0; } .improve-style-card { padding: 16px; background: var(--bg-secondary); border: 2px solid transparent; border-radius: 12px; cursor: pointer; transition: all 0.2s ease; text-align: center; } .improve-style-card:hover { border-color: var(--accent); transform: translateY(-2px); } .improve-style-card.selected { border-color: var(--accent); background: rgba(167, 139, 250, 0.15); } .improve-style-icon { font-size: 28px; margin-bottom: 8px; } .improve-style-name { font-weight: 600; margin-bottom: 4px; } .improve-style-desc { font-size: 11px; color: var(--text-muted); } .improve-results { margin-top: 16px; max-height: 400px; overflow-y: auto; } .improve-result-card { padding: 16px; margin-bottom: 12px; background: var(--bg-secondary); border-radius: 10px; border-left: 4px solid var(--accent); } .improve-result-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .improve-result-preview { font-size: 13px; color: var(--text-secondary); line-height: 1.6; max-height: 150px; overflow-y: auto; padding: 10px; background: var(--bg-tertiary); border-radius: 6px; } `; document.head.appendChild(style); } const modal = document.createElement("div"); modal.className = "modal active"; modal.id = "modal-improve-styles"; modal.innerHTML = `
`; document.body.appendChild(modal); // Store content for later use this.pendingContent = content; // Add click handlers for style cards modal.querySelectorAll(".improve-style-card").forEach(card => { card.addEventListener("click", () => { modal.querySelectorAll(".improve-style-card").forEach(c => c.classList.remove("selected")); card.classList.add("selected"); }); }); }, // 🎲 Generate all 5 styles at once (VS approach) async generateAllStyles() { const content = this.pendingContent; if (!content) return; const loadingDiv = document.getElementById("improve-loading"); const resultsDiv = document.getElementById("improve-results"); const generateBtn = document.getElementById("btn-generate-all"); loadingDiv.style.display = "block"; generateBtn.disabled = true; generateBtn.textContent = "⏳ Génération en cours..."; const styles = [ { id: "concise", name: "📝 Concis", desc: "Version plus courte et directe, sans fioritures" }, { id: "creative", name: "🎨 Créatif", desc: "Version vivante avec métaphores et images" }, { id: "academic", name: "📚 Académique", desc: "Version formelle et bien structurée" }, { id: "professional", name: "💼 Professionnel", desc: "Version adaptée au monde des affaires" }, { id: "engaging", name: "🔥 Engageant", desc: "Version qui capte l'attention du lecteur" } ]; const results = []; const progressFill = loadingDiv.querySelector(".progress-fill"); for (let i = 0; i < styles.length; i++) { const style = styles[i]; try { const improved = await API.improveWritingWithStyle(content, style.id); results.push({ style: style, content: improved, success: true }); } catch (err) { results.push({ style: style, content: null, success: false, error: err.message }); } progressFill.style.width = `${((i + 1) / styles.length) * 100}%`; } // Display results loadingDiv.style.display = "none"; resultsDiv.style.display = "block"; generateBtn.style.display = "none"; let html = "Erreur: ${result.error}