diff --git a/_bmad-output/implementation-artifacts/deferred-work.md b/_bmad-output/implementation-artifacts/deferred-work.md
index c88af4e..4639980 100644
--- a/_bmad-output/implementation-artifacts/deferred-work.md
+++ b/_bmad-output/implementation-artifacts/deferred-work.md
@@ -11,3 +11,7 @@
## Deferred from: code review of 4-1-gdpr-cookie-consent (2026-05-16)
- **AC5 anonymousAnalytics DB sync** — La synchronisation de `anonymousAnalytics` vers `UserAISettings` via `updateAISettings()` n'a pas été implémentée. Contrainte utilisateur : zéro écriture DB en 4.1, consentement 100 % client. À implémenter dans une story ultérieure si la cohérence DB devient requise.
+
+## Deferred from: chart suggestions feature (2026-05-23)
+
+- **Build error in note-graph-view.tsx** — Variable `plainText` définie plusieurs fois (ligne 238). Fichier préexistant modifié hors de cette tâche. À corriger indépendamment.
diff --git a/_bmad-output/implementation-artifacts/spec-tiptap-chart-extension.md b/_bmad-output/implementation-artifacts/spec-tiptap-chart-extension.md
new file mode 100644
index 0000000..00e6fe7
--- /dev/null
+++ b/_bmad-output/implementation-artifacts/spec-tiptap-chart-extension.md
@@ -0,0 +1,277 @@
+---
+title: 'AI Chart Suggestions in TipTap Editor'
+type: 'feature'
+created: '2026-05-23'
+status: 'done'
+baseline_commit: '4e8f45deae9845ad334dbfb8bd7a943e48cda7fc'
+context: []
+---
+
+
bar
+Ventes par Mois
+Jan: 5000
+Feb: 7500
+Mar: 6200
+```
+
+L'extension TipTap détecte ensuite ce pattern et le rend visuellement avec NoteChartFromCode.
+
+### Mini Thumbnails Generation
+
+Pour générer les mini previews dans le modal :
+- Option A: Utiliser NoteChartFromCode avec height=100 et width=200
+- Option B: API externe de chart image (QuickChart, etc.)
+- Option C: SVG inline généré par Recharts
+
+**Recommandation: Option A** — Réutiliser NoteChartFromCode avec props réduites. Plus simple et cohérent avec le rendu final.
+
+### Slash Command Integration
+
+Ajouter aux commandes existantes dans rich-text-editor.tsx :
+
+```typescript
+{
+ title: 'Suggest Charts',
+ description: 'AI suggère des graphiques basés sur votre contenu',
+ icon: BarChart3,
+ category: 'IA Note',
+ isAi: true,
+ command: (editor) => {
+ openChartSuggestions(editor)
+ }
+}
+```
+
+### Extension TipTap Structure (référence CustomImage)
+
+```typescript
+export const ChartExtension = Node.create({
+ name: 'chartBlock',
+ group: 'block',
+ code: true,
+
+ parseHTML() {
+ return [{
+ tag: 'pre',
+ getAttrs: node => {
+ const codeEl = (node as HTMLElement).querySelector('code')
+ return codeEl?.classList.contains('language-chart') ? {} : false
+ }
+ }]
+ },
+
+ renderHTML() {
+ return ['pre', {}, ['code', { class: 'language-chart' }, 0]]
+ },
+
+ addNodeView() {
+ return ReactNodeViewRenderer(ChartBlockView, {
+ contentEditable: false,
+ })
+ }
+})
+```
+
+## Verification
+
+**Commands:**
+- `npm run build` -- expected: Build成功 sans erreurs TypeScript
+- `npm run lint` -- expected: Pas d'erreurs de linting dans les nouveaux fichiers
+- `npm run test` -- expected: Tests passent (si applicable)
+
+**Manual checks:**
+- Créer une note avec des données numériques, taper `/suggest-charts` → 3 propositions s'affichent
+- Sélectionner une partie de la note, taper `/suggest-charts` → Propositions basées sur la sélection
+- Cliquer sur une proposition → Chart inséré et rendu visuellement
+- Double-cliquer sur le chart → Vue code pour édition
+- Recharger la page → Charts toujours rendus correctement
+- Note vide → Message informatif "aucune donnée détectée"
+
+## Suggested Review Order
+
+**Entry point: Slash command integration**
+
+- User triggers chart suggestions via `/suggest-charts` in menu
+ [`../../memento-note/components/rich-text-editor.tsx#L146`](../../memento-note/components/rich-text-editor.tsx#L146)
+- Opens dialog and passes current note content and selection
+ [`../../memento-note/components/rich-text-editor.tsx#L355`](../../memento-note/components/rich-text-editor.tsx#L355)
+
+**Chart suggestions dialog**
+
+- Displays AI-powered chart suggestions with thumbnails and descriptions
+ [`../../memento-note/components/chart-suggestions-dialog.tsx#L38`](../../memento-note/components/chart-suggestions-dialog.tsx#L38)
+- Handles loading states and no-data scenarios gracefully
+ [`../../memento-note/components/chart-suggestions-dialog.tsx#L157`](../../memento-note/components/chart-suggestions-dialog.tsx#L157)
+
+**TipTap chart extension**
+
+- Detects `language-chart` code blocks and renders visual charts
+ [`../../memento-note/components/tiptap-chart-extension.tsx#L66`](../../memento-note/components/tiptap-chart-extension.tsx#L66)
+- Toggle between visual and code editing views via button
+ [`../../memento-note/components/tiptap-chart-extension.tsx#L120`](../../memento-note/components/tiptap-chart-extension.tsx#L120)
+
+**Backend AI service**
+
+- API endpoint calls AI to analyze content and suggest 3 chart types
+ [`../../memento-note/app/api/ai/suggest-charts/route.ts#L24`](../../memento-note/app/api/ai/suggest-charts/route.ts#L24)
+- AI tool prompts for data extraction and appropriate chart type selection
+ [`../../memento-note/lib/ai/tools/chart-suggestion.tool.ts#L44`](../../memento-note/lib/ai/tools/chart-suggestion.tool.ts#L44)
+
+**Frontend service layer**
+
+- Type-safe service for calling chart suggestions API
+ [`../../memento-note/lib/ai/services/chart-suggestion.service.ts#L38`](../../memento-note/lib/ai/services/chart-suggestion.service.ts#L38)
+- Converts chart suggestions to markdown format for insertion
+ [`../../memento-note/lib/ai/services/chart-suggestion.service.ts#L58`](../../memento-note/lib/ai/services/chart-suggestion.service.ts#L58)
diff --git a/memento-note/app/api/ai/suggest-charts/route.ts b/memento-note/app/api/ai/suggest-charts/route.ts
index 25fc792..973c43d 100644
--- a/memento-note/app/api/ai/suggest-charts/route.ts
+++ b/memento-note/app/api/ai/suggest-charts/route.ts
@@ -90,11 +90,23 @@ export async function POST(req: Request) {
model: provider(model),
system: `You are a data visualization assistant. Analyze the provided text and suggest appropriate chart types.
-CRITICAL: Extract ONLY numerical data present in the text. Do NOT invent values.
+DATA EXTRACTION RULES:
+- Extract ANY numerical data present in the text
+- Look for patterns like: "X: 123", "X = 123", "X is 123", "X (123)", "123X", "X $123", "123%"
+- Accept partial data (e.g., if only 2 values exist, that's still valid for a simple chart)
- If fewer than 2 data points exist, return hasData=false with empty suggestions
- Each suggestion must use the SAME extracted data (only chart type differs)
- Return exactly 3 suggestions when data exists
-- Provide clear rationale for each chart type choice
+
+CHART TYPE SELECTION:
+- bar: Comparing values across categories (default choice)
+- horizontal-bar: Categories with long labels
+- line: Time series or sequential data
+- area: Time series where magnitude matters
+- pie: Parts of a whole (percentages or proportions)
+- radar: Comparing multiple dimensions
+- funnel: Stages or conversion steps
+- gauge: Single value vs target
Response format (JSON):
{
diff --git a/memento-note/app/api/chat/route.ts b/memento-note/app/api/chat/route.ts
index 9bb60d8..81681c3 100644
--- a/memento-note/app/api/chat/route.ts
+++ b/memento-note/app/api/chat/route.ts
@@ -225,7 +225,25 @@ Only use tools if you need more information. Never invent note IDs or URLs.
- document_search: Searches attached PDF documents for the current note/notebook. Use when the user asks about documents or files.
- task_extract: Extracts action items from notes and creates a synthesis note. Use when the user asks to extract tasks or TODOs.
- note_find_and_update: Finds a note by search query and appends/prepends/replaces content. Use when the user says "find the note about X and add Y to it".
-- insert_chart: Generates a chart (bar, line, area, pie, radar) and inserts it directly into the note. Use when the user asks "make a chart", "create a graph", "visualize this data", "show me a chart of X". Chart types: bar (comparisons), horizontal-bar (long labels), line/area (trends), pie (proportions), radar (comparisons).`,
+- insert_chart: Generates a chart and inserts it directly into the note. Use when the user asks "make a chart", "create a graph", "visualize this data", "show me a chart of X".
+IMPORTANT: Chart format MUST be exactly:
+\`\`\`chart
+{type}
+{title}
+{label}: {value}
+{label}: {value}
+\`\`\`
+
+Example for sales chart:
+\`\`\`chart
+bar
+Sales by Month
+Jan: 5000
+Feb: 7500
+Mar: 6200
+\`\`\`
+
+Available types: bar, horizontal-bar, line, area, pie, radar. NEVER use Mermaid or other formats.`,
},
fr: {
contextWithNotes: `## Notes et documents de l'utilisateur\n\n${contextNotes}\n\nQuand tu utilises une info venant des notes ci-dessus, cite le titre de la note source entre parenthèses, ex: "Le déploiement se fait via Docker (💻 Development Guide)". Pour les documents PDF, cite le nom du fichier et la page, ex: "Le chiffre d'affaires est de 5M$ (📄 rapport.pdf p.12)". Ne recopie pas mot pour mot — reformule.`,
@@ -260,7 +278,25 @@ Tu as accès à : note_search, note_read, note_find_and_update, document_search,
- document_search : Recherche dans les documents PDF attachés à la note/au carnet.
- task_extract : Extrait les tâches/action items des notes et crée une note de synthèse.
- note_find_and_update : Trouve une note par recherche textuelle et ajoute/prépose/remplace du contenu. Utilise quand l'utilisateur dit "trouve la note sur X et ajoute-y Y".
-- insert_chart : Génère un graphique (barres, ligne, aire, circulaire, radar) et l'insère directement dans la note. Utilise quand l'utilisateur demande "fais un graphique", "crée un chart", "visualise ces données", "montre-moi un chart de X". Types : bar (comparaisons), horizontal-bar (labels longs), line/area (tendances), pie (proportions), radar (comparaisons).`,
+- insert_chart : Génère un graphique et l'insère directement dans la note. Utilise quand l'utilisateur demande "fais un graphique", "crée un chart", "visualise ces données".
+IMPORTANT : Le format du graphique DOIT être exactement :
+\`\`\`chart
+{type}
+{titre}
+{label}: {valeur}
+{label}: {valeur}
+\`\`\`
+
+Exemple pour un graphique de ventes :
+\`\`\`chart
+bar
+Ventes par mois
+Jan: 5000
+Fév: 7500
+Mar: 6200
+\`\`\`
+
+Types disponibles : bar, horizontal-bar, line, area, pie, radar. JAMAIS utiliser Mermaid ou d'autres formats.`,
},
fa: {
contextWithNotes: `## یادداشتهای کاربر\n\n${contextNotes}\n\nهنگام استفاده از اطلاعات یادداشتهای بالا، عنوان یادداشت منبع را در پرانتز ذکر کنید.`,
@@ -352,8 +388,17 @@ Focus ONLY on this note unless asked otherwise.`
}
const chatTools = noteContext
- ? toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, notebookId: notebookId || undefined })
- : toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, notebookId: notebookId || undefined })
+ ? toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, notebookId: notebookId || undefined, noteId })
+ : toolRegistry.buildToolsForChat({ userId, config: sysConfig, webSearch, notebookId: notebookId || undefined, noteId })
+
+ // Detect if user is asking for a chart/visualization to force tool usage
+ const lastMessage = currentMessage.toLowerCase()
+ const chartKeywords = [
+ 'chart', 'graph', 'graphique', 'graphe', 'charte', 'visuali', 'diagramme',
+ 'plot', 'courbe', 'histogram', 'bar', 'pie', 'line', 'area', 'radar',
+ 'données', 'donnée', 'data', 'stat', 'mrr', 'arr', 'revenu', 'sales', 'vente'
+ ]
+ const wantsChart = chartKeywords.some(k => lastMessage.includes(k))
const { result, usedByok } = await runLaneWithBillingUser(
'chat',
@@ -365,6 +410,7 @@ Focus ONLY on this note unless asked otherwise.`
system: systemPrompt,
messages: incomingMessages,
tools: chatTools,
+ toolChoice: wantsChart && chatTools.insert_chart ? { type: 'tool', toolName: 'insert_chart' } : undefined,
stopWhen: stepCountIs(5),
onFinish: async (final) => {
const userContent = incomingMessages[incomingMessages.length - 1].content
diff --git a/memento-note/app/layout.tsx b/memento-note/app/layout.tsx
index 8458c10..46e78cc 100644
--- a/memento-note/app/layout.tsx
+++ b/memento-note/app/layout.tsx
@@ -110,10 +110,8 @@ export default async function RootLayout({
>
-