What changed, straight from the code
This isn't a marketing page: it's the actual CHANGELOG.md shipped inside the downloadable zip, read automatically on every visit — never retyped by hand, so it never drifts out of sync.
Current version : v1.4.0 Download this version
Changelog
Toutes les évolutions notables de SlydeForge. Format inspiré de Keep a Changelog,
versionnement SemVer.
[Non publié]
[1.4.0] - 2026-09-25
Ajouté — images générées par IA (bouton « Image IA », /generate_image, case dans « Nouveau depuis un brief »)
- Retour utilisateur : « je souhaite également utiliser des images générées par IA si option active ».
- Slide courante (
refine.propose_ai_images) : bouton Image IA à côté de « Photo » (visible seulement si un service de génération d'images est configuré, Paramètres > IA) et commande/generate_image [souhait]. 1 appel IA court propose des concepts d'image nettement différents (2 par défaut, 4 au plus) ; la mise en page est vérifiée avec une image fictive AVANT de payer la génération, puis les images sont générées en parallèle et montrées déjà intégrées à la slide, dans la même fenêtre que « Photo » (✨ Affiner = nouvelle génération, Agrandir, Créer une nouvelle slide). Avertissement de coût préalable (nombre d'images mémorisé, « Ne plus afficher »). Aucun faux texte dans les images (consigne ajoutée à chaque prompt). - Depuis un brief : case « Générer des images par IA, au plus N » (jamais cochée par défaut, plafond 10, désactivée si aucun service n'est configuré) : le plan choisit les slides qui gagnent le plus à être illustrées (couverture d'abord) avec un style visuel commun, sans appel supplémentaire ; les images sont générées PENDANT la rédaction (mesuré, 5 slides : 18,8 s → 29,5 s). Une slide issue d'un modèle de charte (qui n'affiche pas d'image) est passée sur une mise en page qui en accueille une.
- Couverture et « visuel + texte » avec image : l'image s'arrête avant le logo de la charte — elle était auparavant refusée (« empiète sur le logo ») et « Photo »/« Image IA » ne proposaient rien.
Amélioré — images et liens du brief réellement intégrés
- Retour utilisateur : « si je mets des images/icônes dans un prompt, c'est que j'attends qu'elles soient intégrées ».
- Images jointes (
ingest.attached_images) : chaque image jointe au brief est nommée (« Image jointe N ») et le plan DOIT la placer sur une slide ; les portraits vont sur une slide « équipe » (photos rondes, initiales à défaut). Elles restent attachées à leur slide lors des retouches (Mise en forme, Challenger). Le bilan signale une image non placée. - Pages web citées dans le brief (
ingest.fetch_urls, 5 au plus, en parallèle) : elles sont désormais réellement lues et placées en tête des sources — auparavant, l'IA écrivait de mémoire sans jamais les ouvrir. Le bilan liste les pages lues et celles qui n'ont pas pu l'être (page dynamique, protégée…). - Étapes renumérotées dans l'ordre de lecture quand l'utilisateur a déplacé des blocs (« Étape 3 » ne se retrouve plus avant « Étape 2 »).
Ajouté — recherche dans toutes les slides et les notes (Ctrl+F)
- Retour utilisateur : « rechercher dans l'ensemble des slides et des notes quelque chose et pouvoir le retrouver facilement [...] visible pour que je puisse identifier facilement où il se trouve [...] naviguer dans toutes les occurrences ».
- Barre de recherche au-dessus du canevas (Édition > Rechercher…, bouton Rechercher de la barre d'outils, Ctrl+F) : compteur « 2 / 7 », occurrence suivante/précédente (Entrée / Maj+Entrée, F3 / Maj+F3, flèches), fermeture par Échap. Options : respecter la casse, mot entier, ignorer les accents (activé par défaut : « resume » trouve « résumé »). Aucun résultat : champ teinté en rouge.
- Où chercher (
core/deck_search.py) : zones de texte et formes, cellules de tableau, catégories et séries de graphique, jalons de frise, entrées d'agenda, texte alternatif des images, et notes de l'orateur ; parcours slide par slide, en partant de la slide affichée. - Repérage : la slide de l'occurrence s'affiche, le mot est surligné dans le texte (jaune, orange pour l'occurrence courante), l'élément est encadré (seul repère pour un tableau, un graphique ou une frise) et la vue défile jusqu'à lui ; dans les notes, dépliées au besoin, même surlignage. Pastille loupe + nombre d'occurrences sur les vignettes concernées. Liste : toutes les occurrences avec slide, emplacement et contexte, un clic pour s'y rendre. Les résultats se mettent à jour quand le deck est modifié.
Corrigé — slide « équipe » vide (photos jointes jamais affichées) et rond vide dans un sommaire de charte
- Retour utilisateur (deck ORCOM, facturation électronique) : « il me dit qu'il a inséré les images fournies mais je ne les vois pas », slide 7 vide ; « sur la slide 2, un rond vide comme si ce n'était pas complet après les points 1, 2, 3, 4 ».
- Slide vide : dans un lot de rédaction mêlant modèles de charte (contenu sous
"slots") et archétype « team », l'IA a rangé l'équipe sous"slots"aussi ; la mise en page ne trouvait ni titre ni membres → slide vide, sans alerte, et le bilan comptait quand même les photos comme intégrées. Correction : un archétype générique rédigé sous"slots"est remis à plat (compose.unwrap_slots) — les 2 portraits s'affichent ; garde-fou final : une slide sans aucun texte ni visuel reçoit une mise en forme de repli signalée dans le bilan, jamais une slide vide silencieuse. - Rond vide : les blocs inutilisés d'un modèle n'étaient retirés que s'ils avaient une forme conteneur (carte) ; un sommaire en lignes (pastille + numéro + intitulé + filet) gardait la pastille et le filet de la ligne vide. Les lignes répétées sans conteneur sont désormais reconnues (même structure qu'une ligne remplie) et retirées en entier ; un titre ou sur-titre vide n'est jamais concerné.
Corrigé — génération figée avec un modèle local « à raisonnement » (Ollama, gemma4…) + diagnostic du modèle
- Retour utilisateur : génération lancée sur un serveur Ollama local (gemma4:26b) bloquée 13 min sur « Conception du plan de la présentation… », sans rien afficher.
- Cause : les modèles « à raisonnement » (gemma4, qwen3, deepseek-r1…) réfléchissent avant de répondre ; Ollama renvoie cette réflexion dans un champ à part et la compte dans
max_tokens. Sur un gros brief (pages web + photos), le plan (3 000 tokens) était entièrement consommé par la réflexion → réponse vide → « Format de réponse inattendu », classé transitoire → repli non streamé + nouvelles tentatives : jusqu'à 12 générations complètes pour rien, sans que le bouton Stop puisse couper l'appel en cours. Mesuré sur le serveur : 25 s de réflexion, 0 caractère de réponse. - Corrections (
ai/reasoning.py,ai/streaming.py) : dès qu'un modèle réfléchit, SlydeForge coupe le flux et relance sans réflexion (reasoning_effort: "none"), puis s'en souvient pour ce modèle — le plan qui échouait passe en 3,7 s, une présentation de 8 slides en 19,8 s au lieu de 53,9 s. Si le serveur refuse ou ignore ce réglage, budget de tokens élargi ; réponse faite de réflexion seule → erreur claire, non retentée, qui dit quoi faire. Plus de repli non streamé qui refaisait le même travail. Réflexion encore active : le chat l'indique (« Le modèle réfléchit… ») au lieu d'un écran figé. Aucun changement pour les modèles classiques ni pour les autres connecteurs (Copilot, Gemini, Groq…). - Paramètres > IA > API compatible OpenAI : case « Autoriser le mode réflexion » (décochée par défaut) pour qui veut la garder.
- « Tester la connexion » devient un diagnostic du modèle (
ai/model_check.py,ui/model_check_dialog.py) : vitesse mesurée traduite en durée d'une présentation, mode réflexion (et s'il peut être coupé), respect du format JSON, et pour Ollama : vision, longueur de contexte, part du modèle dans la carte graphique, modèles déjà installés. Chaque point est expliqué avec « Que faire », suivi de critères simples pour choisir un modèle, de la marche à suivre pour en installer un, et d'un bouton « Copier une question à poser à une IA » (mesures incluses, matériel à compléter) — le test restant juge de paix. Ouvert d'office seulement s'il y a un point à corriger.
Amélioré — zoom avant de choisir, photo demandée depuis l'affinage de la mise en forme
- Retours utilisateur : « pouvoir faire un zoom avant de sélectionner pour voir mieux le résultat » (mise en forme et photo) ; « je n'arrive pas à ajouter des images depuis la mise en forme IA en le demandant depuis le texte libre de l'étape 2 » — l'IA répondait que l'ajout d'une image n'était pas réalisable pour des cartes.
- 🔍 Agrandir (ou Espace) dans les fenêtres Mise en forme et Photo : la proposition sélectionnée en grand, à côté de la version actuelle, zoom à la molette et déplacement synchronisés, bascule en vue unique (
ZoomCompareDialog: mode image seule et libellés personnalisés). - Photo dans la barre ✨ Affiner : une demande de photo/image est détectée (
refine.wants_photo) ; l'IA donne une requête (sinon un appel très courtrefine.photo_query), la mise en page est transposée si elle ne peut pas afficher de photo (refine.photo_layout, textes/icônes/tons conservés) et chaque direction reçoit une vraie photo libre de droits avec son crédit ; un nouvel affinage d'une proposition avec photo la garde. Sans banque d'images : explication (Paramètres > Images). « Tel quel » reste la slide d'origine.
Ajouté — photo libre de droits pour la slide courante (bouton « Photo », /suggest_image)
- Retour utilisateur : « proposer d'intégrer automatiquement une image libre de droits si l'utilisateur a paramétré cette fonctionnalité [...] plusieurs propositions [...] adaptée au thème de la présentation mais surtout de la slide courante [...] dispo depuis les fonctions "/" ».
- Moteur (
refine.propose_photos) : 1 appel IA court (≈ 2 000 tokens, ~6 s) donne 3 requêtes photographiables en anglais (message de la slide + thème du deck + souhait éventuel) et, si la mise en page ne peut pas afficher de photo, une transposition qui garde textes, icônes et code couleur ; recherche dans les banques configurées (Pexels/Unsplash) ; jusqu'à 6 photos, chacune composée et contrôlée par le moteur (style actuel, puis style de la charte, puis typographie compacte si la photo prend trop de place), crédit compris. - Cartes + photo : l'archétype
cardsaccepte une photo (colonne à droite en paysage, bandeau en bas en portrait/carré ; grille adaptée, liste pleine largeur si besoin). - Interface : bouton Photo à côté de Challenger, commande
/suggest_image [souhait]; fenêtre unique avec vrais aperçus, barre ✨ Affiner = nouvelle recherche, case « Créer une nouvelle slide », version actuelle en comparaison, coût en tokens. Sans banque d'images configurée : message immédiat (Paramètres > Images), aucun appel IA.
Corrigé — Challenger « plus moche après qu'avant » sur une demande de photo libre de droits
- Retour utilisateur (capture, slide « Un potentiel inexploité », 9:16, modèle de charte « Trio de fonctionnalités ») : réponses « refonte ambitieuse » + remarque « Ajouter une image libre de droits » → une liste de puces sans icônes ni photo, plus pauvre que l'original.
- Causes : (1) les pictos du modèle de charte (petites images éclair/bouclier/coche) étaient pris pour « la photo de la slide » et proposés comme image ; (2) aucune recherche de photo libre de droits n'était lancée par le Challenger — l'IA ne pouvait donc pas honorer la demande et retombait sur des puces ; (3) rien ne détectait qu'une réécriture appauvrissait la slide.
- Corrections :
refine.is_photoécarte icônes, logos, pastilles et petites images ; le Challenger peut demander une photo (photo_query) cherchée dans les banques configurées et placée avec son crédit (sinon il explique comment activer une banque) ; un archétype « image + texte » sans photo redevient une liste plutôt qu'un cadre vide ; garde-fou de richesse visuelle (refine.visual_richness/poorer) : si la nouvelle version perd photo, icônes ou cartes sans demande de sobriété, l'IA est relancée une fois, sinon l'assistant le signale. - Crédit photo lisible : toujours en blanc sur un voile noir semi-opaque (
stock_images.credit_elements) — il était en texte foncé, illisible sur une photo sombre. - Rejoué sur la slide du retour utilisateur : cartes en relief avec leurs icônes + vraie photo Pexels en bandeau + crédit.
Corrigé — une seule direction artistique (« Tel quel ») sur une slide issue d'un modèle de la charte
- Retour utilisateur : « il ne m'a proposé qu'une seule direction artistique. Comment est-ce possible ? » (slide « Un potentiel inexploité », modèle « Trio de fonctionnalités », format 9:16).
- Cause : le visuel d'un modèle de charte est celui du concepteur — aucun levier (couleurs, bandeau, relief…) n'y a d'effet ; toutes les directions ressortaient identiques à la version actuelle et étaient écartées comme doublons, sans explication.
- Correction : la slide est d'abord transposée fidèlement (1 appel court) dans l'archétype générique le plus proche, icônes comprises, puis les directions s'appliquent normalement ; « Tel quel » reste le modèle d'origine. Une galerie réduite à « Tel quel » affiche désormais toujours une explication.
- Cartes en portrait (disposition en liste) : icônes de la charte affichées (elles étaient ignorées), posées sur une pastille claire sur fond sombre ; disposition empilée (titre au-dessus du texte) quand le côte à côte ne tient pas — un mot long ne déborde plus.
Corrigé — correction orthographique fiable et clic libre dans le texte
- Retours utilisateur : choisir la proposition « conservait des lettres d'avant » (texte encore plus faux) ; dès qu'une faute était détectée, on ne pouvait plus cliquer dans le texte pour se placer à la souris (obligé de passer par les flèches).
- Causes : les fautes étaient mémorisées par positions figées au moment de l'analyse — tout texte tapé avant le mot (ou une correction précédente, ou des espaces en début de texte) décalait la plage remplacée ; le passage fautif pouvait aussi être trouvé au milieu d'un autre mot. Un menu modal s'ouvrait à chaque clic sur un mot souligné et avalait le clic.
- Correction (
ui/spellcheck_text_edit.py, commun à tous les champs vérifiés : assistant, retours, génération, agents, analyse de thème, modèles de slide) : chaque faute suit sa position en direct ; la correction remplace exactement le mot signalé ou ne fait rien s'il a été retouché (son soulignage disparaît dès qu'on le modifie) ; recherche en mot entier, toutes occurrences ; un seul Ctrl+Z annule une correction. - Interaction : le clic place toujours le curseur normalement ; sur un mot souligné, une petite carte non bloquante propose « ✓ correction » et « Ignorer » (continuer à taper, cliquer ailleurs ou Échap la ferme). Le clic droit propose aussi la correction en tête du menu habituel. « Ignorer » n'est plus reproposé pendant la saisie.
Amélioré — demandes visuelles enfin suivies (couleurs, icônes, relief), nouvelle slide plutôt qu'écraser
- Retours utilisateur : « mettre plus de couleurs, icônes et de relief » (affinage de la mise en forme, remarque libre du Challenger) semblait ignoré ; l'option « appliquer à tout le deck » risquait des effets étranges ; pouvoir « créer une nouvelle slide plutôt que d'écraser la version actuelle » ; coût en tokens non visible dans la mise en forme.
- Cause : le moteur n'avait aucun levier pour ces demandes et l'IA ne le disait pas ; sur un modèle de charte (visuel fixe du concepteur), seuls les textes pouvaient changer.
- Nouveaux leviers du moteur (
style.OPTION_KEYS) :depth: raised(relief — ombres portées des cartes et blocs),tone_style: fill(code couleur en FOND teinté — rôles « tint_* » de la charte),status_icons(pastille d'icône de statut ✓ / ⚠ / ✗ de la charte sur les cartes, chiffres clés, jalons et étapes), icônes par carte ; toujours contrôlés (débordement, contraste, mots coupés) et assagis si besoin. - L'IA dit ce qui reste impossible : champ « note » des directions (affiché sous la recommandation) et « not_done » du Challenger (affiché dans l'assistant).
- Challenger : peut appliquer ces leviers (champ « design ») ; un modèle de charte au visuel fixe peut être remplacé par l'archétype générique équivalent, qui garde alors un bandeau d'en-tête pour rester cohérent avec le deck.
- Mise en forme : option « appliquer à tout le deck » retirée ; case « Créer une nouvelle slide » (la mise en forme est insérée juste après l'originale, conservée) ; coût en tokens affiché en direct dans la fenêtre (et dans celle du Challenger).
Amélioré — Challenger plus économe et plus sûr, zoom dans l'aperçu, modèles de charte réparés
- Retours utilisateur : pas de trace des réponses données au Challenger ; « pouvoir zoomer sur les modifications lors de l'aperçu » ; « laisser un commentaire ou remarques complémentaires » ; afficher le coût en tokens ; « analyser si la génération de la modif ne peut pas être encore plus performante (moins de tokens, plus rapide, parfaite) » avec une frise mal alignée.
- Trace et coût : les réponses et remarques données au Challenger sont journalisées dans l'assistant ; le coût (≈ tokens, prompt + réponse) de chaque calcul s'affiche, avec un total pour le Challenger (diagnostic + réécriture) et pour la mise en forme.
- Remarques libres toujours visibles (champ multi-ligne sous les questions), prises en compte même avec « Proposer sans répondre ».
- Zoom dans l'aperçu avant/après : un clic sur une image ouvre une comparaison en grand, zoom (molette) et déplacement synchronisés, et une vue unique qui bascule avant ⇄ après (Espace).
- ~70 % de tokens en moins par Challenger (mesuré sur une charte de 23 modèles : ~7 500 tokens au lieu de ~20 000, ~11 s) : le détail des champs n'est plus envoyé que pour les modèles de charte utiles (même famille de représentation), le diagnostic se contente des noms. Relance automatique sur réponse malformée du fournisseur.
- Modèles de charte : blocs répétés (cartes, jalons) non utilisés supprimés en entier (fond, pastille, connecteur, repère) au lieu de laisser des cartes vides — l'IA n'a plus à dupliquer « Analyse 07/10 » cinq fois pour remplir un modèle à 8 cartes ; texte recouvert par une pastille décorative décalé automatiquement (défaut du modèle importé « Frise chronologique (cartes) ») ; jamais de mot coupé en plein milieu dans un emplacement de modèle.
- Garde-fou chiffres et dates : après une réécriture (Challenger, mise en forme), les chiffres/dates disparus ou apparus sont signalés dans l'assistant avant l'aperçu (cas réel : « Semaine du 28/09 » perdue).
Amélioré — affiner / combiner les directions artistiques, Challenger qui pose des questions
- Retours utilisateur : « fusionner le résultat de 2 propositions afin de garder le meilleur des 2 [...] ou avoir une zone où l'utilisateur détaille comment il voit les choses », « toujours naturel et simple » ; Challenger : « poser des questions à l'utilisateur pour être encore plus performant [...] il a seulement ajouté une phrase ».
- Mise en forme — barre ✨ Affiner sous la galerie de directions : demande libre et/ou sélection de plusieurs propositions (Ctrl+clic → « Combiner ces 2 propositions »). Nouveau tour de propositions dans la même fenêtre : la fusion directe (calculée, sans IA : leviers réunis, code couleur et mise en avant repris) en tête, puis des variantes de l'IA qui partent de la sélection et de la demande (
refine.propose_directions(picked=, feedback=),refine.merge_directions). « Étape précédente » annule le dernier affinage. - Challenger en deux temps (
ui/challenge_dialog.py, fenêtre persistante avec indicateur) : diagnostic + au plus 3 questions ciblées avec réponses en un clic, réponse libre et précision libre (refine.diagnose_slide, ~5 s) ; réécriture guidée par les réponses (refine.challenge_slide(answers=, note=)) — une « refonte ambitieuse » doit changer au moins trois éléments (titre, représentation, hiérarchie, message…). Mesuré : même slide KPI, sans questions → titre et ordre des chiffres retouchés ; avec « refonte ambitieuse » → passage en message fort centré sur l'échéance. « Proposer sans répondre » reste possible. - Mise en avant franche d'un chiffre clé : carte pleine dans la couleur forte (au lieu d'un fin contour), textes recolorés pour rester lisibles ; avec un code couleur, le ton devient un cadre épais. Visible aussi à la génération.
Amélioré — « Mise en forme » : structure puis direction artistique, code couleur par valeur
- Retours utilisateur : un 2e niveau pour challenger tailles de police et couleurs ; puis, sur un premier assistant en 4 étapes : « ça fait beaucoup d'étapes », propositions « assez similaires », « pourquoi ne pas mettre des codes couleurs en fonction des valeurs », « que l'utilisateur se dise à chaque étape : excellent, je n'y aurais pas pensé », et « la fenêtre se ferme entre chaque étape au lieu de montrer qu'un travail est en cours » ; miniatures trop petites.
- 2 étapes dans une seule fenêtre qui reste ouverte, avec indicateur animé pendant les calculs, retour arrière (les directions déjà calculées sont gardées), un seul Ctrl+Z à la fin.
- Direction artistique (
generate/engine/refine.py::propose_directions, 1 appel texte ~8 s) : l'IA imagine 4 partis pris complets et contrastés, en combinant de nouveaux leviers du moteur — code couleur par valeur (generate/engine/tones.py: ton positif / vigilance / négatif par chiffre clé, carte, étape, jalon ou ligne de tableau ; couleurs de la charte reconnues par leur nom, sinon vert/orange/rouge, toujours ajustés au contraste), bandeau d'en-tête dans la couleur de marque, fond teinté/fort, blocs en contour, échelles typographiques, mise en avant, retrait de l'« À retenir »/surtitre/introduction. Recommandation ★ présélectionnée avec son idée. - Garanties : chaque direction est composée par le moteur ; une direction qui déborde, coupe un mot ou produit un défaut est assagie (échelles, puis leviers de couleur) ou écartée ; préréglages (Éditoriale, Bandeau de marque, Immersive, Douce) si l'IA échoue.
- Style retenu mémorisé sur la slide (
slide.engine.style) et conservé par les retouches ultérieures. Miniatures agrandies (340 px au lieu de 220). Tests mis à jour et ajoutés (tests/test_suggest_design_feature.py,tests/test_engine_v2_refine.py).
Amélioré — boutons IA branchés sur le moteur v2, finitions dès la première génération
- Demande utilisateur : revoir les boutons IA (Mise en forme, Challenger, Animation, Suggérer/Retaguer les notes…) avec le nouveau moteur, retirer le réglage de l'ancien moteur, et proposer notes/transitions/animations dès la création pour un résultat complet du premier coup.
- Principe : comme pour la génération, l'IA ne retravaille plus que le CONTENU d'une slide ; le moteur recalcule la mise en page dans la charte (plus aucun patch JSON de rendu demandé au LLM par ces boutons). Chaque slide générée garde sa source (
slide.engine) ; une slide importée ou retouchée est relue depuis ses textes. - Mise en forme : 3 représentations alternatives (cartes, étapes, chiffres clés, modèle de charte…) montrées en vrais aperçus dans la charte, version actuelle comprise — 1 appel texte au lieu d'un assistant en 3 étapes + patch.
- Challenger / /review_deck / challenge de fin de génération : critique de fond (message, densité, représentation, fil du deck) + version réécrite et recomposée ; appels texte, en parallèle pour le deck ; relance en un clic en cas d'erreur.
- Animation et transitions : calculées par le moteur (un clic par carte / chiffre clé / étape / jalon, titre fixe ; rythme de transitions cohérent) — instantané, sans appel IA ; repli IA pour une slide qui ne vient pas du moteur.
- Notes : rédigées par lots en appels texte, synchronisées avec les clics d'animation décrits précisément ; nombre de tags
[[anim]]garanti ; « Retaguer » ne modifie jamais le texte. - Finitions à la génération : cases « Ajouter transitions et animations » (gratuit) et « Rédiger les notes du présentateur » dans « Nouveau depuis un brief ». Mesuré (8 slides) : +2 appels, ≈ +50 % de tokens (~10 200 au lieu de ~6 800), durée inchangée.
- Ancien moteur : réglage retiré de Paramètres > IA ; code conservé comme référence (
tools/engine_bench.py --engine legacy, variableSLYDEFORGE_GENERATION_ENGINE=legacy). Les anciens services (design_suggest_service,slide_review_service,challenge_service,notes_suggest_service) restent en place, marqués historiques. - Détails :
design/moteur-generation-v2.md(« Retouches et finitions ») ; +25 tests (tests/test_engine_v2_refine.pyet tests d'interface mis à jour).
Amélioré — photos libres de droits réellement utilisées par le moteur v2
- Retour utilisateur : deck « 7 minutes de terreur : poser un robot sur Mars », 15 slides, Pexels activé : « l'IA n'en a retenu aucune ». Cause : le plan ne demandait des photos que pour 1 à 3 slides, souvent sur un archétype incapable d'en afficher (message fort), et seuls 3 archétypes sur 16 savaient afficher une photo.
- Photo plein écran (voile sombre garantissant la lisibilité) pour les slides message fort, intercalaire, citation et conclusion ; crédit en blanc sur la photo.
- Plan : requêtes photo sur environ une slide sur deux, uniquement là où une photo peut s'afficher ; mots-clés « photographiables » (pas de noms propres ni d'abstractions, métaphores visuelles concrètes) ; « visuel + texte » autorisé quand des photos sont demandées.
- Recherche : jusqu'à 10 slides illustrées, recherche élargie si une requête ne donne rien, jamais la même photo proposée à deux slides ; consigne moins restrictive (une photo d'ambiance cohérente suffit).
- Mesuré (même brief) : 9 photos insérées sur 27 proposées (au lieu de 0/3), 0 défaut de mise en page. +13 tests (
tests/test_engine_v2.py).
Ajouté — nouveau moteur de génération de deck (v2), activé par défaut
- Demande utilisateur : un résultat bien meilleur dès la première demande (mise en page, couleurs, tailles, placement), à coût limité et en environ une minute.
- Principe : le LLM ne rédige plus que le CONTENU (textes courts aux longueurs bornées, par archétype) ; la mise en page est CALCULÉE par le code à partir de la charte (
generate/engine/) — grille sur les marges, échelle typographique, contraste WCAG calculé, mesure réelle du texte avec le moteur de l'aperçu, tailles homogènes entre éléments frères, en-tête identique sur toutes les slides. 16 archétypes (couverture, intercalaire, sommaire, puces, 2 colonnes, chiffres clés, cartes, démarche, frise, comparaison, tableau, graphique, visuel + texte, message fort, citation, conclusion), adaptés aux formats paysage/carré/portrait. - Modèles de la charte : les types de slides de la charte sont « compilés » en emplacements (textes, tableaux, frises) ; le modèle est recopié à l'identique, seuls les textes/données sont injectés — y compris les modèles importés d'un PPTX (ex. « COBO - Suivi mensuel projet »), dont les libellés fixes restent intacts.
- Pipeline : 1 appel de plan + lots de contenu en parallèle + au plus 1 appel de raccourcissement ; aperçu progressif ; jamais d'échec global pour un lot en erreur ; contrôles automatiques (débordement, chevauchement, marges, contraste, taille, logo) et signalement des chiffres absents du brief/des sources.
- Mesuré (même brief, charte Socomec, 8 slides) : 13,6 s au lieu de 152,7 s, 3 appels au lieu de 21, ~4 800 tokens au lieu de ~84 600, 0 défaut détecté au lieu de 24. Rendu natif PowerPoint vérifié conforme à l'aperçu.
- Réversible : Paramètres > IA > « Génération d'un deck » permet de revenir au moteur historique (inchangé). Détails :
design/moteur-generation-v2.md; banc d'évaluation :tools/engine_bench.py; +29 tests (tests/test_engine_v2.py,tests/test_engine_v2_main_window.py). Nouvelles tentatives automatiques sur erreur passagère du fournisseur (503/429/délai).
Amélioré — les modèles de la charte guident le rendu dans TOUS les formats (moteur v2)
- Retour utilisateur : deck 9:16 avec la charte « Aurora — Keynote Premium » : « on n'a plus le lien avec les layouts de la charte […] l'idée c'était que l'utilisateur puisse donner des orientations graphiques ». Root cause : les modèles de charte (conçus en 16:9) étaient écartés dès que le format du deck différait.
- Modèles réagencés pour le format du deck (
generate/engine/charter_adapt.py, sans appel IA) : décor (halos, fonds, grands numéros en filigrane) adapté parcore/decoration_adapt.py; contenu empilé dans l'ordre de lecture (colonnes du modèle empilées colonne par colonne), hauteurs de texte mesurées avec un palier commun (hiérarchie typographique du modèle préservée) ; puces dessinées, filets et guillemets décoratifs suivent leur texte ; panneaux redimensionnés autour de leur contenu ; séparateurs verticaux retirés quand les colonnes sont empilées. Vérifié sur les 15 modèles Aurora en 16:9, 1:1 et 9:16 (0 défaut détecté). - Priorité aux modèles de la charte dans le plan : un modèle qui correspond au rôle d'une slide est utilisé plutôt que l'archétype générique équivalent (brief « Mars », Aurora : 8 à 10 slides sur 15 issues des modèles, contre 0 en 9:16 auparavant).
- Les slides génériques adoptent les choix typographiques de la charte : couleur des titres, des surtitres et du texte courant déduite des modèles (ex. titres blancs et surtitres gris pour Aurora), dès que le contraste le permet.
- Corrigé : un grand numéro décoratif (« 01 » en filigrane) pouvait être pris pour le titre à remplir ; capacités des emplacements trop serrées (titre de couverture limité à 11 caractères) ; lignes stylées d'un titre renvoyées « a / b » ; chiffres clés coupés sur 2 lignes ; mots coupés en plein milieu dans les colonnes étroites. Frise de 6 jalons et plus : textes alternés au-dessus/au-dessous de la ligne ; démarche de 5-6 étapes : 2 rangées.
Ajouté — progression visible pendant la génération (moteur v2), sans surcoût
- Retour utilisateur : « c'est surprenant car tout arrive d'un coup […] donner une idée de la progression sans dégrader les perfs/qualité ».
- Les réponses de l'IA sont désormais reçues EN FLUX (même nombre d'appels, mêmes tokens) : les titres du plan s'affichent un à un dans la ligne de statut (« Plan : slide 3 — … »), puis le bandeau montre immédiatement le squelette du deck (toutes les slides avec leur titre), et chaque slide est mise en page et affichée dès que son contenu est reçu (« Rédaction : 4/9 slides prêtes »). Mesuré : 1er titre du plan à ~5 s, squelette à ~14 s, deck complet à ~21 s (9 slides), durée totale inchangée. Backends sans flux (API SlydeForge, Gemini) : progression par lot, repli automatique.
- Les photos libres de droits proposées sont désormais davantage retenues (consigne explicite : l'utilisateur a demandé des photos) ; le bilan de fin s'intitule « Bilan » (et non plus « Contrôle visuel ») avec le nouveau moteur.
Corrigé — numéros mal centrés dans les pastilles (sommaire, démarche)
- Retour utilisateur (capture) : le numéro était décalé vers le haut dans son rond. Le texte des pastilles est désormais centré verticalement (
vertical_align: middle), vérifié à l'écran et dans PowerPoint.
Corrigé — aperçu et export plus fidèles (tous moteurs)
- Cellules de tableau : retour à la ligne dans l'aperçu écran, comme à l'export PPTX (le texte était coupé à l'écran).
- Graphiques : valeurs et catégories affichées à la taille « légende » de la charte dans l'aperçu (au lieu de 75 %, ~8 pt, illisible).
- Export PPTX des puces : retrait suspendu (la puce n'est plus collée au texte, « •Texte »).
[1.3.4] - 2026-09-14
Corrigé — double-clic sur un élément ouvrait parfois EN PLUS les propriétés du fond
- Retour utilisateur : « de temps en temps, quand je double-clique sur la frise pour éditer les paramètres, il ouvre en dessous les propriétés du fond ».
- Root cause :
ui/canvas_view.py::mouseDoubleClickEventdéterminait l'élément touché APRÈSsuper()— or un double-clic sur un élément (table/graphique/frise/agenda) ouvre un dialogue modal dont l'annulation, après un aperçu en direct, déclenche_reload_canvas(): la scène est reconstruite EN PLEIN MILIEU du dispatch de l'événement. L'iteminitialement cliqué, comparé après coup à la scène reconstruite, n'y était alors plus retrouvé — déclenchant à tort le signalbackground_double_clicked. - Correctif : le verdict « élément touché ? » est désormais figé AVANT
super(), jamais recalculé après une éventuelle reconstruction de scène.super().mouseDoubleClickEvent(event)est en plus protégé par untry/except RuntimeError(crash shiboken « Internal C++ object already deleted » constaté en usage réel). +1 test (tests/test_canvas_background_selection.py::test_double_click_on_element_survives_scene_rebuild_during_dispatch).
Corrigé — le sélecteur de couleur personnalisée se rouvrait parfois tout seul juste après validation
- Root cause (cause réelle du symptôme, au-delà d'un 1er correctif déjà publié via
QTimer.singleShot) :ui/color_picker_combo.py::_pick_custom_colorpeut insérer un nouvel item HEX juste AVANT l'item « Personnalisée… » actuellement sélectionné — Qt réagit à cette insertion en décalant automatiquementcurrentIndex, ce qui redéclenchait_on_index_changedet donc une 2e ouverture du sélecteur. - Correctif :
blockSignals(True)enveloppe désormais toute la séquence lecture-insertion-sélection, pas seulement lesetCurrentIndexfinal.
Corrigé — un graphique à plusieurs séries devenait monochrome, texte illisible sur fond sombre (aperçu ET export PPTX)
- Retour utilisateur (fichier réel importé) : un graphique à plusieurs séries devenait entièrement monochrome, alors que le pptx source distinguait chaque série/catégorie par une teinte propre ; sur un camembert importé, le texte d'une part devenait illisible sur une couleur de fond sombre.
- Correctif :
core/theme.py::resolve_series_color()fait désormais cycler les séries sans couleur explicite à travers les rôles « vifs » de la charte (primaire/accent/secondaire), puis les éclaircit progressivement au-delà de la 3e série ;core/theme.py::contrasting_text_hex()choisit blanc/noir selon la luminance perçue du fond. Les deux sont partagées par l'aperçu (render/items.py, graphiques barres/lignes/camemberts + badges de frise/agenda) ET par l'export PPTX natif (render/pptx_renderer.py) — celui-ci ignorait jusqu'ici totalement les couleurs de série choisies, retombant sur le jeu de couleurs PAR DÉFAUT de PowerPoint, contrairement à l'aperçu déjà correct. +5 tests (tests/test_theme.py).
Changé — le dialogue « composant payant » n'ouvre plus qu'un lien vers slydeforge.com, sans collecter d'e-mail
- Retour utilisateur : « il ne doit pas pouvoir s'abonner depuis l'application » — l'achat/abonnement d'un composant marketplace payant se fait désormais EXCLUSIVEMENT sur slydeforge.com.
- Correctif :
ui/marketplace_payment_dialog.pyne collecte plus d'e-mail et n'appelle pluslicense_service.start_purchase()(choix Stripe/PayPal in-app) — il se contente d'informer (nom du composant, prix) puis d'ouvrir la page des tarifs (license_service.pricing_url()) dans le navigateur système. +tests dédiés (tests/test_marketplace_payment_dialog.py) vérifiant l'absence de champ e-mail/flux d'achat et l'ouverture de la page tarifs.
Ajouté — export PPTX des liens hypertexte (complète l'import déjà existant)
- Retour utilisateur : rendre un lien cliquable — un VRAI hyperlien PowerPoint (fonctionne au clic pendant la présentation), pas seulement un style visuel.
- Correctif :
render/pptx_renderer.pypose désormaisrun.hyperlink.addressà partir du nouveau champrun.link(deck.schema.json) sur chaque fragment de texte concerné. L'import (render/pptx_importer.py) lisait déjà ce champ depuis un .pptx importé ; seul l'export était manquant — le round-trip est maintenant complet. Export uniquement pour l'instant, pas encore de rendu visuel du lien dans l'aperçu à l'écran.
Ajouté — bordures de tableau indépendantes par axe + largeurs de colonnes/hauteurs de lignes personnalisables
- Retour utilisateur : « il y a systématiquement des séparateurs de colonne ou de ligne [...] il faut offrir cette option manuellement » + « je veux pouvoir redimensionner plusieurs lignes et colonnes en une seule fois ».
- Correctif :
deck.schema.jsongagne 4 champs sur un tableau —row_lines/col_lines(booléens,truepar défaut, réglables indépendamment : un tableau « designer » réel n'a souvent QUE des lignes horizontales) etcol_widths/row_heights(poids relatifs, pas des % absolus ; absents/vides = répartition uniforme, comportement historique inchangé). Nouveaurender/geometry.py::distribute_weights()partagé par l'aperçu (render/items.py::_paint_table) et l'export PPTX natif (render/pptx_renderer.py::_apply_table_cell_borders) pour convertir ces poids en tailles de cellules réelles, avec le même tracé de grille indépendant par axe dans les deux rendus.ui/table_edit_dialog.pyajoute 2 cases (Lignes/Colonnes) et 2 boutons (« Largeur des colonnes sélectionnées… » / « Hauteur des lignes sélectionnées… ») pour régler plusieurs en-têtes à la fois d'un coup.
Ajouté — identité stable de charte (origin_id) pour reconnaître la même charte entre projets/installations
- Contexte produit : infrastructure invisible pour l'utilisateur aujourd'hui, posée en vue de la future reconnaissance d'une même charte à travers plusieurs projets/installations (
design/roadmap-chartes-apprenantes.md). - Correctif :
core/theme.py::ensure_origin_id()assigne unuuid4stable et idempotent à une charte qui n'en a pas encore (jamais régénéré si déjà présent) ;core/presets.py::PRESET_ORIGIN_IDSfixe unuuid5déterministe par preset (Neutre/Prisme/SlydeForge) partagé par toutes les installations.storage/themes_store.py::update_theme()conserve toujours l'origin_idexistant en base, quelle que soit la valeur passée par l'appelant.services/theme_transfer.pytolère en plus, à l'import, la coquille historique"slideforge_theme"(sans le « y ») présente dans les 4 premières chartes publiées sur slydeforge.com — n'écrit que l'orthographe correcte. Nouveau champtheme.origin_id(deck.schema.json). +tests (tests/test_theme.py,tests/test_themes_store.py,tests/test_theme_transfer.py).
[1.3.3] - 2026-09-14
Corrigé — la finalisation d'une mise à jour (finish_update.ps1) ne s'exécutait en réalité JAMAIS
- Root cause : launch_finish_update lançait PowerShell avec le flag Windows
DETACHED_PROCESS — celui-ci ne fournit aucune console au process enfant.
Sur ce poste (vérifié avec un script .ps1 trivial, une seule ligne écrivant un
fichier) : PowerShell ressort alors IMMÉDIATEMENT avec le code de sortie 0 (succès,
au sens de Python — subprocess.Popen/.poll() ne voient aucune erreur) sans
exécuter la moindre ligne du script. Conséquence concrète : une mise à jour
restait indéfiniment « stagée » (préparée dans %APPDATA%\SlydeForge\pending_update)
sans jamais être appliquée, aucun message d'erreur nulle part — ni côté application
(le lancement « réussit »), ni côté finish_update.ps1 (jamais exécuté, donc jamais
la moindre ligne dans son propre journal). Découvert en observant une mise à jour
réelle rester bloquée après un clic sur « Redémarrer maintenant ».
- Correctif : CREATE_NO_WINDOW à la place — alloue une console (nécessaire ici :
le script invoque robocopy, un exécutable console) mais ne l'affiche jamais à
l'écran, contrairement à DETACHED_PROCESS qui n'en fournit aucune. -WindowStyle (déjà présent) masque en plus la fenêtre PowerShell elle-même. Vérifié de
Hidden
bout en bout : la mise à jour se finalise désormais réellement.