Ce qui a changé, en direct du code
Le contenu ci-dessous n'est pas une page marketing : c'est le fichier CHANGELOG.md réellement livré dans le zip téléchargeable, lu automatiquement à chaque affichage — jamais ressaisi à la main, donc jamais désynchronisé.
Version actuelle : v1.4.0 Télécharger cette version
[0.1.1] - 2026-07-23
Ajouté (2026-07-23, bordures et ombres configurables)
- Bordure et relief (ombre portée) configurables sur tout type d'élément
(forme, zone de texte, image, tableau) : nouvelles propriétés line_color/
line_width_pt (déjà existantes pour les formes, étendues aux autres
types) et shadow (booléen). Rendu à l'écran (render/items.py) ET à
l'export PPTX (render/pptx_renderer.py), avec un panneau de propriétés
dédié ("Bordure et relief") disponible pour tout élément sélectionné.
L'IA (génération, édition, et propositions de types de slides personnalisés
via l'analyse de charte) peut désormais choisir d'utiliser ce type de mise
en forme pour mettre en valeur un élément clé.
- Versionning des releases : packaging/build_release.py incrémente
désormais automatiquement le numéro de version (composant PATCH) et
capitalise le contenu de "[Non publié]" du CHANGELOG sous un nouvel en-tête
versionné à chaque build réel (build(bump=True)) — un nouveau build
produit donc toujours un NOUVEAU fichier zip, jamais un écrasement
silencieux du précédent. L'outil de mise à jour (services/update_service.py) affiche désormais TOUTES les notes accumulées entre la
::changelog_since
version installée et celle du zip en cours d'installation, pas seulement le
dernier lot de changements.
Corrigé (2026-07-23, bugs remontés par l'utilisateur)
- Bordures/ombres parasites en export PPTX : python-pptx référence par
défaut le style du thème PowerPoint (<p:style>, avec une bordure ET une
ombre) sur toute forme créée via add_shape() — un cadre et un relief
apparaissaient donc à l'export sur des formes n'en ayant AUCUN dans SlydeForge
(l'aperçu ne dessine ni bord ni ombre par défaut). Supprimé systématiquement
pour que seules les propriétés explicites déterminent le rendu, comme à
l'écran.
- Aperçu vide (rectangle blanc) d'un type de slide généré par l'IA :
un unique élément structurellement incomplet (typiquement une image sans
data_uri réel, ajoutée naturellement par l'IA pour un type nommé "Contenu
visuel") faisait échouer la validation du template ENTIER, alors que le
reste (titre, formes décoratives) était parfaitement valide. Confirmé en
base sur un vrai projet (plusieurs types "Section"/"Contenu visuel"/
"Conclusion" sans template alors que "Ouverture" en avait un). Ces éléments
incomplets sont désormais filtrés individuellement plutôt que de faire
échouer tout le template (charter/analyze_ai.py::_sanitized_template).
- Message d'erreur HTTP tronqué ("Erreur HTTP 400" sans détail) : le
message d'erreur du service IA n'était extrait que pour certaines formes de
corps de réponse (message/error au premier niveau) ; retombe maintenant
sur plusieurs formes usuelles (error.message imbriqué, detail) puis, en
dernier recours, sur le texte brut de la réponse plutôt que de ne rien
afficher (ai/client.py::extract_error_detail).
- Contexte de conversation pouvant dépasser la limite de tokens du modèle
(cas réel : 1 765 673 tokens envoyés pour une limite de 936 000) : le
compteur déclenchant la compression automatique du contexte
(ai/conversation.py::Conversation._char_len) ne mesurait QUE le texte,
ignorant totalement le poids des images (capture de slide à chaque tour
d'une édition portée "slide", pièces jointes) — une data URI base64 pèse
facilement plusieurs centaines de milliers de caractères. La compression ne
se déclenchait donc jamais malgré une conversation réellement énorme.
Corrigé (2026-07-22, fidélité export PPTX + nom de fichier + portée slide visible)
- Bug réel corrigé — export PPTX ne respectait pas la mise en forme prévue
(render/pptx_renderer.py), révélé en comparant le .pptx exporté au deck
JSON d'origine d'un vrai projet : (1) le fit d'une image (contain/
cover) était totalement ignoré — l'export étirait TOUJOURS l'image
exactement au rect (comportement stretch), déformant visiblement toute
image dont l'aspect ratio différait de sa boîte (photo 16:9 dans une boîte
portrait, logo large dans une boîte carrée) ; corrigé pour reproduire
render/items.py::ElementItem._paint_image — contain centre l'image à
taille réduite (letterbox), cover rogne via picture.crop_left/right/top/ plutôt que d'étirer. (2) Les rectangles arrondis utilisaient le
bottom
rayon d'angle par défaut de python-pptx (0.16667), le DOUBLE de celui
dessiné à l'écran (0.08) — synchronisé via shape.adjustments[0].
(3) Les tableaux exportés recevaient le style intégré PowerPoint (bandes
alternées + habillage d'en-tête), très différent de la grille sobre de
l'aperçu — désactivé (first_row/horz_banding = False) et l'en-tête
teinté par défaut (comme à l'écran) reproduit explicitement. (4) Les
graphiques natifs ignoraient la couleur de série (thème ou couleur
explicite), utilisant le jeu de couleurs par défaut de PowerPoint — les
séries sont maintenant coloriées explicitement via series.format.fill.
- Nom de fichier PPTX générique : le nom par défaut proposé à l'export
reprenait deck["deck"]["title"] (souvent le titre littéral d'origine,
jamais mis à jour après un renommage automatique IA ou manuel du projet) —
utilise maintenant le nom ACTUEL du projet (storage/projects.py::) suivi de la date de génération, ex.
get_title
« Bilan qualité des données SIM 3 (2026-07-22).pptx ».
- Portée "Cette slide" invisible dans le fil du chat : impossible de
savoir/se souvenir après coup quelle slide avait été ciblée par un prompt,
surtout en enchaînant plusieurs prompts en changeant de slide entre deux —
MainWindow._on_prompt journalise maintenant (affichage + persistance)
« Portée : slide N — « Titre » » à chaque prompt en portée "slide", lu
depuis self.current_index AU MOMENT de ce prompt précis (jamais une
valeur mémorisée d'un tour antérieur).
- Double-clic sur un type de slide personnalisé (ui/theme_editor.py)
ouvre maintenant directement l'aperçu/édition de sa mise en forme
(SlideTemplateEditorDialog), au lieu de simplement sélectionner la ligne
et devoir chercher le bouton dédié.
Corrigé (2026-07-22, portée "Cette slide" qui modifiait une autre slide)
- Bug réel corrigé : une édition portée « Cette slide » (ex. slide 8
sélectionnée) pouvait finir par modifier une AUTRE slide (ex. slide 1) sans
prévenir. Root cause dans services/edit_service.py::_rebase_ops — quand
le LLM avait déjà vu, plus tôt dans la MÊME conversation persistante, des
chemins de patch absolus /slides/N/... (typiquement après un tour portant
sur tout le deck), il pouvait réémettre par contamination un chemin
/slides/0/... au lieu du chemin relatif attendu pour la slide en cours
d'édition ; l'ancien code « tolérait » tout chemin déjà préfixé par
/slides/ SANS vérifier que l'index correspondait à la slide réellement
autorisée, laissant passer la modification hors périmètre — y compris
pendant la passe d'auto-critique (le patch de correction pouvait dériver
vers une autre slide). Un chemin /slides/N/... dont l'index ne correspond
pas à la slide ciblée est maintenant rejeté (patch.PatchError), capté par
la boucle de relance existante au 1er patch, et silencieusement ignoré (au
profit du candidat déjà bien scopé) pendant l'auto-critique.
Ajouté (2026-07-22, bouton Stop + refonte de l'analyse IA de charte)
- Bouton Stop pendant un traitement IA (ui/chat_panel.py, barre de
statut) : retour utilisateur — pouvoir couper à tout moment un prompt lancé
par erreur, sans attendre la fin. Interruption COOPÉRATIVE via un
threading.Event partagé (cancel_token), pas un arrêt forcé du thread :
ai/streaming.py::stream_chat vérifie le token à CHAQUE fragment SSE reçu
(interruption quasi immédiate pour l'édition par prompt, le cas le plus
courant, qui passe toujours par le flux streamé) ; complete_chat et les
boucles multi-appels (génération slide par slide, contrôle visuel) le
vérifient entre deux appels (interruption bornée à la prochaine étape).
Nouvelle exception dédiée ai.client.AIClientCancelled (jamais avalée par
les mécanismes de retry/repli existants — vérifié explicitement à chaque
endroit qui attrapait Exception largement) et nouveau signal Worker. (pas
cancellederr : ce n'est pas un échec, l'UI affiche un message
neutre plutôt qu'un bandeau rouge).
- Refonte de l'analyse IA de charte (ui/theme_analyze_dialog.py,
ui/theme_analysis_progress_dialog.py) : (1) le sélecteur de fichiers
permet maintenant de piocher dans PLUSIEURS dossiers différents (bouton
« Ajouter… » cliquable plusieurs fois, accumulation sans doublon — même
mécanisme déjà en place dans ui/generate_dialog.py) ; (2) un champ
d'indications libres complémentaires est transmis à l'IA en plus des
indices extraits automatiquement (charter/analyze_ai.py::propose_theme,
services/theme_service.py::analyze) ; (3) la progression n'utilise plus
la barre d'état de la fenêtre principale (facilement manquée) mais une
fenêtre DÉDIÉE montrant les étapes de réflexion, le temps écoulé, une icône
animée (réutilise SpinnerWidget) et un bouton Stop.
Corrigé (2026-07-22, export PPTX WEBP)
- Bug réel corrigé (capture d'écran) : l'export PPTX échouait avec
"unsupported image format... got 'WEBP'" dès qu'une image WEBP (recherche
libre de droits, import utilisateur) était présente dans le deck —
render/pptx_renderer.py appelait add_picture() directement sur les
octets bruts sans vérifier le format ; python-pptx n'accepte que BMP/GIF/
JPEG/PNG/TIFF/WMF. Reconversion automatique en PNG (Pillow) avant insertion
si le format détecté n'est pas supporté — appliqué aux 3 points d'insertion
(logo, image de fond, image d'élément).
Corrigé (2026-07-22, aperçu vide d'un type de slide créé par l'IA)
- Bug réel corrigé : ouvrir l'aperçu/édition d'un type de slide (ui/) créé par l'analyse IA de charte affichait
slide_template_editor_dialog.py
un carré vide. Root cause : charter/analyze_ai.py::propose_theme ne
proposait jamais qu'un nom/une description pour chaque slide_type, jamais
de template (fond+éléments) — rien à afficher, ce n'était pas un bug du
dialogue lui-même. L'IA génère désormais un VRAI template concret par type
(bandes/filets/rôles explicites, textes placeholders génériques), réparé
par le même filet de sécurité que les slides générées/éditées (nouveau
core/deck.py::sanitize_template, ids/rôles/couleurs invalides corrigés)
et validé contre le schéma avant d'être conservé — un template qui reste
invalide après réparation est silencieusement abandonné (le type garde son
nom/sa description) plutôt que de faire échouer toute la proposition de
charte. Le pipeline de génération de slides tenait déjà compte de ces
templates quand ils existent (generate/slide_gen.py::_template_for,
fonctionnalité antérieure) — il n'y avait simplement jamais rien à
utiliser pour un type créé par l'IA avant ce correctif.
Ajouté (2026-07-22, charte par défaut + prompt redimensionnable + repartir de zéro + exemple pro)
- Charte par défaut configurable (storage/themes_store.py::set_default_theme/
get_default_theme_record, nouvelle colonne themes.is_default) : bouton
« Définir par défaut » dans l'éditeur de charte. list_themes() place
désormais la charte par défaut en tête (corrige automatiquement tous les
endroits qui présélectionnaient naïvement "le 1er élément", ex le dialogue
"Nouveau depuis un brief") ; MainWindow._new_sample() (projet vierge)
utilise aussi cette charte par défaut au lieu du seul préréglage Neutre.
- Zone de prompt redimensionnable (ui/chat_panel.py) : la saisie
principale (hauteur fixe 70px) partage désormais un splitter vertical avec
la ligne de boutons (glisser pour l'agrandir), même mécanisme déjà en place
pour le journal/les pièces jointes.
- « Repartir de zéro » (case à cocher à côté de la portée, ui/chat_panel.py) :
sur un projet vierge/exemple, l'édition incrémentale en portée "tout le
deck" restait bridée par le design/contenu EXISTANT — cocher la case route
le prompt vers le MÊME pipeline de génération complète que "Nouveau depuis
un brief" (planner.make_plan + slide_gen.generate_slide +
visual_review.review_and_fix), en conservant la charte et le titre actuels.
- Exemple de démarrage plus moderne/pro (core/presets.py::sample_deck) :
3 slides (au lieu de 2) suivant la MÊME anatomie premium exigée de l'IA en
génération (generate/layouts.py) — couverture fond plein sombre + filet
d'accent, slide de chiffres clés (fond plein + grille de 3 KPI), slide de
contenu avec bande d'en-tête + accent latéral — pour montrer d'emblée le
niveau de qualité visuelle attendu plutôt qu'un simple titre+puces.
- Outil de build de release vérifié de bout en bout (packaging/ →
build_release.pyservices/update_service.py::inspect_zip/
apply_update_from_zip) : build réel exécuté (94 fichiers, ~242 Ko
compressé, aucune fuite __pycache__/config utilisateur/tests/packaging),
puis appliqué dans un dossier scratch pour confirmer la compatibilité
réelle bout-en-bout (pas seulement la documentation). Le dossier dist/
n'existait pas simplement parce que l'outil n'avait encore jamais été
exécuté (pas de build automatique) — corrigé en le lançant.
Ajouté (2026-07-22, spinner éclair + gestion de projets en colonnes + détection d'erreurs d'écriture)
- Indicateur de traitement repensé (ui/spinner_widget.py::SpinnerWidget) :
remplace l'ancien spinner à points (assets/spinner.gif via QMovie,
supprimé) par un éclair peint nous-mêmes (même tracé/dégradé que
assets/icon.svg, cohérence graphique directe avec l'app), pulsation +
lueur fluides en vraie transparence Qt — élimine au passage toute la classe
de bug QMovie.stop()/start() (frame figée) déjà rencontrée.
- Gestion des projets en tableau (ui/project_manager_dialog.py) :
colonnes Nom/Créé le/Modifié le/Versions/Créé par (nouvelle colonne
projects.created_by, prefs.current_user()), filtrée par défaut sur les
projets créés par l'utilisateur Windows courant (case à cocher pour voir
aussi ceux des autres) — pertinent sur une installation partagée disque réseau.
- Détection d'erreurs d'écriture avec correction en un clic
(ui/spellcheck_text_edit.py::SpellcheckTextEdit) : pensé pour les
utilisateurs dyslexiques — un appel IA débounce (jamais à chaque frappe)
souligne en rouge ondulé les fautes d'orthographe/grammaire ; cliquer dessus
propose la correction, l'appliquer d'un clic. Câblé sur les 3 zones de
rédaction libre existantes : prompt principal et commentaire de retour
(ui/chat_panel.py), brief de génération (ui/generate_dialog.py).
L'assistant de création de charte est aujourd'hui purement basé sur des
fichiers (pas de champ de texte libre) : rien à câbler là pour l'instant.
- Titres de projet auto-générés plus synthétiques : le flux "Nouveau
depuis un brief" utilisait jusqu'ici la 1re ligne LITTÉRALE du brief comme
titre (jamais passée par le synthétiseur IA), contrairement au flux "prompt
sans projet ouvert" qui en bénéficiait déjà — _on_generation_done déclenche
maintenant le même renommage en tâche de fond (_auto_name_project).
Prompt de services/naming_service.py::generate_project_title durci contre
les titres verbeux/mal synthétisés (jamais un verbe d'action, jamais une
reformulation mot à mot).
Corrigé (2026-07-22, contrôle visuel qui ne corrigeait pas vraiment)
- Bug réel corrigé, remonté avec captures : le contrôle visuel
post-génération (services/visual_review.py) annonçait "corrigé" sans
jamais RE-VÉRIFIER visuellement que le problème signalé avait réellement
disparu — et la consigne de correction se limitait explicitement aux
COULEURS ("Ne change QUE les couleurs..."), incapable de résoudre un texte
tronqué/qui chevauche (dimensions de zone) ou une police trop petite
(taille). Chaque correction est maintenant re-vérifiée par un appel vision
dédié, avec une 2e tentative plus insistante si la 1re échoue, et le message
final distingue honnêtement "corrigé" de "corrigé partiellement, à vérifier
manuellement" plutôt que de toujours prétendre un succès.
Ajouté (2026-07-22, extraction dynamique de charte depuis un PPTX source)
- charter/extract_pptx.py étendu : extract_images() (images embarquées
d'un PPTX — slides puis mises en page puis masters, dédupliquées par
contenu, bornées) et extract_layout_names() (noms des mises en page
réellement définies). Root cause corrigée : un PPTX d'entreprise existant
(design system riche en logos/pictogrammes/mises en page nommées, ex un
fichier réel testé avec 64 images uniques et 52 mises en page nommées sur 20
slides) ne contribuait jusqu'ici QUE des couleurs/polices de thème — tout le
reste était laissé de côté. services/theme_service.py/charter/analyze_ai.py
exploitent maintenant ces images (classées image/icône comme les autres) et
ces noms de mise en page (pour ancrer les suggestions de slide_types sur
ce que la charte source distingue réellement) — outil dynamique, fonctionne
pour n'importe quel PPTX source, pas un gabarit particulier.
Ajouté (2026-07-22, dialogue de démarrage + bibliothèque d'icônes + charte IA multi-fichiers)
- Dialogue de démarrage obligatoire (ui/startup_dialog.py,
MainWindow.run_startup_chooser()) : l'application ne démarre plus JAMAIS
sur le deck-témoin non enregistré — root cause du rendu "bridé" en mode
démarrage (les prompts routaient alors vers l'édition incrémentale plutôt
que la génération complète, et la charte choisie n'était jamais vraiment
persistée). Force le choix « Nouveau projet depuis un brief (IA) » /
« Nouveau projet vierge » / « Ouvrir un projet existant » ; reboucle sur le
choix si un sous-dialogue est annulé, quitte l'application si le sélecteur
lui-même est fermé sans choix.
- Bibliothèque d'icônes de charte (theme.icons, séparée de
theme.images) : pictogrammes destinés à ACCENTUER/METTRE EN VALEUR un
élément (KPI, action, point clé), à la différence des images (illustratif).
Même mécanisme de stockage fichier (storage/theme_assets.py, paramètre
kind), même convention asset_ref côté IA (espace de noms unifié avec les
images dans core/assets.py/generate/slide_gen.py), catalogue et
consignes d'usage dédiés dans les prompts de génération/édition
(generate/prompts.py::_icon_catalog/_ICON_NOTE), nouveau groupe « Icônes
de charte » dans l'éditeur de charte, et insertion manuelle possible depuis
le dialogue d'insertion d'image (ui/image_insert_dialog.py, préfixe 🔹).
- Refonte de l'analyse IA de charte depuis plusieurs fichiers
(charter/analyze_ai.py::propose_theme) : la proposition couvre désormais
aussi les TAILLES de police (font_scale), classe chaque visuel fourni en
IMAGE ou ICÔNE de charte (par index, jamais de pixels recopiés) pour peupler
directement theme.images/theme.icons, et suggère des TYPES DE SLIDES
éditoriaux (Intro, variantes claire/sombre/neutre, Outro...) — jusqu'ici
seules la palette et les polices étaient proposées, et les visuels fournis
étaient perdus après l'analyse vision.
Corrigé (2026-07-22, charte : doublons de nom + choix de la cible d'un modèle de slide)
- Deux chartes pouvaient porter le même nom : suffixage automatique
(2), (3)... à l'enregistrement/renommage (storage/themes_store.py::), même logique que pour les projets/versions.
_unique_name
- Impossible d'associer un modèle de slide à une AUTRE charte que celle du
deck ouvert : _save_slide_as_type_template demande maintenant
explicitement la charte cible avant le type, et peut enregistrer dans une
charte de la bibliothèque sans toucher au deck ouvert.
Ajouté (2026-07-22, éditeur de modèles de slide + confort chat)
- Éditeur visuel complet pour les modèles de type de slide
(ui/slide_template_editor_dialog.py) : aperçu ET édition directe (sélection,
déplacement/redimensionnement, ajout/suppression d'éléments, image de fond,
tableau/graphique) — jusqu'ici un modèle ne pouvait être créé qu'en capturant
la slide courante depuis le menu principal. Accessible depuis l'éditeur de
charte.
- Liste de fichiers joints redimensionnable dans le chat (splitter avec le
journal), hauteur par défaut confortable pour 2 fichiers.
Corrigé (2026-07-22, spinner statique + images de charte ignorées)
- Icône de traitement figée dès le 2e échange : QMovie.stop() puis un
simple start() ne relance pas toujours l'avancement des frames sous Qt —
jumpToFrame(0) avant start() corrige le figement.
- Images de charte quasi jamais utilisées en génération : pas un bug
mécanique (le pipeline asset_ref fonctionnait déjà), mais un prompt trop
timide qui ne faisait que suggérer une image sans jamais pousser l'IA à en
choisir une. Renforcé pour un usage par défaut sur les layouts éditoriaux
(title/section/quote/conclusion/Intro-Outro), toujours prudent sur les
layouts denses en données.
Ajouté (2026-07-22, nommage automatique des versions)
- Chaque version créée après un échange d'édition IA est désormais nommée
automatiquement d'après ce qui a été demandé (intitulé court, appel LLM
borné en tâche de fond, jamais bloquant — services/naming_service.py::), au lieu du label générique « Modification IA ».
generate_version_label
Suffixe automatique (2), (3)... en cas de collision avec un autre label
du même projet (storage/versions.py::rename_version(..., unique=True)).
Corrigé (2026-07-22, 3e récidive — fill/color en objet)
- 3e occurrence de la même classe de bug (après id, puis role) : fill/
line_color/run.color/table cell.fill/chart series.color/
background.color donnés en objet façon PowerPoint
({"type":"solid","color":"accent"}) au lieu d'une simple chaîne. Réparé
silencieusement dans core/deck.py (extraction de la chaîne exploitable, ou
retrait du champ si rien de récupérable) ; _COLOR_NOTE renforcé en amont.
Ajouté (2026-07-22, contrôle qualité + historique + versions + modèles + mise à jour)
- Contrôle visuel automatique post-génération (services/visual_review.py) :
un appel vision repère les problèmes de lisibilité/contraste sur l'ensemble
des slides générées, puis une correction ciblée bornée (max 4) est appliquée
automatiquement avant de redonner la main.
- Historique de chat persistant par projet (storage/chat_history.py) :
chaque échange significatif est désormais sauvegardé et rechargé à l'ouverture
d'un projet — plus de contexte perdu à la fermeture de l'application. Le
brief et les fichiers d'une génération restent visibles dans le chat.
- Compteur explicite de fichiers joints dans le chat.
- Refonte de la gestion des versions (ui/timeline_dialog.py) : vignettes,
point de sauvegarde manuel nommé, renommer/supprimer une version.
- Modèles de mise en forme pour les types de slides personnalisés :
theme.slide_types[].template capture fond+éléments d'une slide existante,
réutilisable manuellement (Insérer > Slide depuis un modèle) et injecté comme
exemple concret dans le prompt de génération IA.
- Mise à jour depuis un fichier .zip local (services/update_service.py,
menu Paramètres) : extraction sécurisée (garde anti zip-slip) par-dessus le
dossier d'installation, jamais %APPDATA%. packaging/build_release.py
construit le zip depuis un manifeste explicite (code applicatif uniquement).
L'ancien module updater/apply_update.py (mort, jamais câblé) est supprimé.
Corrigé (2026-07-22, récidive — role hors énumération)
- 2e occurrence de la même classe de bug que la vague précédente : cette
fois role hors énumération ('accent_bar', 'kpi1'..'kpi6') faisait échouer
un patch d'édition deck-entier. core/deck.py::sanitize_element_ids répare
désormais aussi role (mapping par sous-chaîne puis repli par type
d'élément), toujours avant validation, jamais un rôle déjà valide touché.
_ROLE_NOTE ajouté aux prompts système en défense en profondeur.
Ajouté (2026-07-22, projets auto-enregistrés + nommés par l'IA)
- Un prompt de chat sans projet ouvert enregistre désormais IMMÉDIATEMENT
un nouveau projet (titre provisoire), au lieu de dépendre d'une action
manuelle — root cause du travail parfois perdu. services/naming_service.py
le renomme ensuite automatiquement (appel LLM unique et borné, jamais
bloquant) une fois la modification acceptée.
- Noms de projet uniques : suffixe automatique ' (2)', ' (3)'... sur
collision (création et renommage), jamais de rejet bloquant.
- Charte visible et changeable depuis le chat : nouveau sélecteur à côté
de la portée deck/slide, présélectionnant la charte du projet courant.
Ajouté (2026-07-22, pièces jointes et image de fond)
- Suppression unitaire des fichiers joints dans le chat (liste avec
sélection, au lieu de tout-ou-rien).
- Édition de l'image de fond de slide (remplacer/retirer/position/zoom) :
nouveau champ background.image_rect (absent = plein-cadre, rétrocompatible)
et dialogue dédié avec aperçu live. La slide elle-même ne change jamais de
taille — seule l'image, à l'intérieur, est repositionnable/redimensionnable.
Ajouté (2026-07-22, lancement silencieux + types de slides personnalisés)
- .bat sans console persistante : lance l'appli via pyw/pythonw, seule
la fenêtre SlydeForge reste visible.
- Types de slides personnalisés dans la charte (ex Intro/Outro, avec
description d'usage) : gérables dans l'éditeur de charte, exposés à l'IA
(planification/génération/édition) pour qu'elle sache quand les utiliser.
Corrigé (2026-07-22, retour d'usage réel — ids/shape_kind invalides)
- Bug réel reproduit par l'utilisateur (génération COSYNC/TANIT SIM3) :
patch rejeté après 2 tentatives — 'shape_kind' is a required property et
une dizaine d'ids à 5 caractères ('ekf1n') ne respectant pas le motif
^[a-z0-9]{6,}$ du schéma. Le LLM invente parfois des ids courts hors
convention et oublie shape_kind sur une forme, sans toujours se corriger
malgré l'erreur détaillée en relance. Fix en profondeur :
core/deck.py::sanitize_element_ids/sanitize_deck_ids répare
silencieusement ces défauts avant la validation (jamais les ids déjà
valides), câblé à la fois dans l'édition (core/patch.py) et la génération
initiale (generate/slide_gen.py).
- Boutons zoom −/+ visuellement vides (capture utilisateur) : le padding
QSS générique rongeait le glyphe sur ces boutons trop étroits. Style dédié
ZoomButton avec padding nul.
Retiré (2026-07-22, charte générique)
- Charte Socomec retirée des préréglages : SlydeForge n'embarque plus
qu'un préréglage neutre, l'outil n'est dédié à aucune société. Migration
automatique pour les installations existantes (purge de la ligne + de ses
images).
Ajouté (2026-07-22, projet chargé visible)
- Titre de fenêtre affichant le projet actuellement ouvert
(NomDuProjet — SlydeForge X.Y), mis à jour à l'ouverture/la création/le
renommage.
Ajouté (2026-07-22, bibliothèque de chartes)
- Sélecteur de charte dans l'éditeur (ui/theme_editor.py) : combo listant
toutes les chartes enregistrées, présélectionnant automatiquement celle du
projet courant (nouvelle colonne projects.theme_id).
- Renommer/supprimer une charte depuis l'éditeur (désactivé sur les
préréglages Neutre/Socomec).
- Bug racine corrigé — images de charte « disparaissant » : trou de
workflow, pas bug isolé — « Enregistrer sous... » créait toujours une
nouvelle ligne, jamais de mise à jour en place, et rouvrir l'éditeur
rechargeait le thème du deck (pas un enregistrement précis de la
bibliothèque). Un vrai bouton « Enregistrer » met désormais à jour EN PLACE
la charte identifiée par un id stable suivi tout du long ; « Enregistrer
sous... » reste un fork explicite.
- Suivi des modifications non enregistrées : changer de charte ou fermer
l'éditeur avec des modifs en attente déclenche une confirmation
Enregistrer/Ignorer/Annuler.
- Images de charte en fichiers locaux (storage/theme_assets.py), un
dossier par charte keyé par ID STABLE (jamais le nom — un renommage ne
déplace rien). Elles ne sont plus embarquées dans le blob JSON de la
bibliothèque (storage/themes_store.py), avec migration automatique des
bases existantes.
Corrigé (2026-07-22, retour d'usage réel — patch tronqué)
- Bug réel reproduit par l'utilisateur : une édition deck-entier ajoutant
plusieurs slides complètes en une seule réponse LLM dépassait max_tokens et
produisait un JSON tronqué. Le fallback de parsing (core/jsonutil.py)
isolait alors par erreur le PREMIER élément (complet) du tableau inachevé,
provoquant l'erreur trompeuse « Le patch doit être une liste d'opérations
JSON Patch (RFC 6902) » au lieu d'un message clair. Corrigé : parse_json ne
tente d'isoler {...}/[...] que si le texte commence par ce crochet, et
détecte explicitement une troncature. À la relance, le LLM reçoit une
consigne corrective : limiter le patch à UNE seule nouvelle slide plutôt que
de tout regénérer d'un coup. DEFAULT_MAX_TOKENS 8000→16000,
DEFAULT_TIMEOUT_SEC 120→180 (ai/settings.py).
Ajouté (2026-07-22, renommage + cohérence UI + traçabilité du feedback)
- Renommer une slide : double-clic ou clic droit sur sa vignette
(ui/slide_strip.py). L'IA garde aussi le titre synchronisé avec le contenu
quand elle modifie une slide existante (consigne ajoutée aux prompts d'édition).
- Cohérence UI : le panneau « Détails » repliable se referme désormais
automatiquement avec le bandeau d'avancement en fin de traitement.
- Transcript de feedback + purge automatique : chaque retour 👍/👎 capture
désormais l'instruction complète et l'échange brut avec l'IA (colonne
feedback.transcript), affiché dans le dialogue de feedback et injecté (en
extrait) dans le prompt de synthèse pour aider à comprendre la cause réelle
d'un problème signalé. Purge automatique au démarrage : seul le transcript
(pas la note ni le commentaire) des retours déjà synthétisés et vieux de plus
de 30 jours est vidé, pour ne pas charger le disque inutilement.
Corrigé (2026-07-22, retour d'usage réel)
- Bug réel découvert via les captures de l'utilisateur : une demande d'ajout
de slides via l'ÉDITION (pas la génération initiale) n'aboutissait qu'à
enrichir les slides existantes — system_edit_patch_deck ne disait jamais
explicitement au LLM qu'il pouvait ajouter des slides ENTIÈRES via une
opération {"op":"add","path":"/slides/-","value":{...}}. Corrigé : le prompt
explique maintenant l'ajout de slides complètes (avec convention d'id inventé
unique) et reçoit les mêmes principes de design/catalogue d'images que la
génération initiale.
- Résolution asset_ref étendue au pipeline d'édition (elle n'existait que
pour la génération initiale) : core/patch.py gagne un hook resolve_fn
appelé entre l'application mécanique du patch et sa validation, utilisé par
services/edit_service.py via core/assets.py (nouveau module partagé).
Ajouté (2026-07-22, boucle de feedback)
- Historique des synthèses (storage/synthesis_store.py) : chaque exécution
de « Synthétiser » est conservée intégralement (contenu + ids de retours
inclus), consultable dans un nouvel onglet du dialogue de feedback même après
fusion dans IMPROVEMENT_NOTES.md. Confirmé : chaque synthèse ne considère
que les retours pas encore analysés et repart de zéro sur ce sous-ensemble.
- Copier le texte brut d'un retour : panneau de détail + bouton dans le
dialogue de feedback (retours individuels et synthèses de l'historique).
- Zone de commentaire agrandie (ui/chat_panel.py) : la barre de feedback
passe d'un champ mono-ligne à une zone multi-lignes redimensionnable.
Ajouté (2026-07-22, sourcing d'images)
- Images de charte privilégiées (theme.images) : logos/photos officiels
gérables depuis l'éditeur de charte, prioritaires dans le sélecteur d'insertion.
- Bibliothèque d'images par projet (storage/image_library.py) : images déjà
importées/utilisées réutilisables sans réimporter le fichier.
- Dialogue unifié d'insertion d'image (ui/image_insert_dialog.py, 3 onglets) :
Bibliothèque (charte épinglée + projet), Recherche libre de droits, Génération IA.
- Recherche Unsplash (services/image_search.py) : clé d'accès dans
Paramètres > IA, recherche + aperçu + crédit photographe affiché (attribution
requise par les conditions Unsplash).
- Génération d'images par IA (ai/image_gen.py) : endpoint OpenAI-compatible
/images/generations (DALL-E, Azure OpenAI…), réutilise par défaut les
identifiants du backend OpenAI-compatible existant, URL/clé dédiée en option.
- Résolution asset_ref à la génération (generate/slide_gen.py) : le LLM
référence une image de charte par son NOM exact (jamais de data_uri inventée —
techniquement impossible pour un modèle de texte) ; résolue en pixels réels
avant validation du schéma, avec relance automatique si le nom est inconnu.
Limite assumée : l'insertion d'images issues d'une recherche/génération
reste une étape confirmée par l'utilisateur via le dialogue, jamais silencieuse
dans le pipeline de patch — seules les images de charte peuvent être
auto-référencées par le LLM lors de la génération initiale.
Corrigé (2026-07-22, édition manuelle)
- Perte de focus lors de l'édition de propriétés : chaque modification (couleur,
gras, texte…) reconstruisait toute la scène du canevas, ce qui recréait le panneau
de propriétés en cascade et cassait le curseur/focus du champ en cours de frappe.
CanvasView.update_element() met désormais l'élément à jour EN PLACE
(ElementItem.refresh(), déjà présent mais jamais appelé), sans reconstruction ni
re-sélection. Les pushes undo consécutifs sur le même élément sont coalescés
(coalesce_key). Le rafraîchissement des vignettes (coûteux : rendu de toutes les
slides) est debouncé au lieu de se déclencher à chaque frappe.
- Fond des zones de texte jamais dessiné à l'écran : le champ fill d'un textbox
était bien exporté en PPTX mais jamais peint dans render/items.py. Corrigé, et
contrôle « Fond de la zone » ajouté au panneau de propriétés.
- Forme « Flèche » invisible à l'écran mais visible en export PPTX : _paint_shape
traitait « arrow » comme une simple ligne diagonale ; dessine désormais un vrai
polygone de flèche (idem pour « chevron », auparavant un simple rectangle).
- Image de fond de slide jamais exportée en PPTX (visible à l'écran seulement) :
pptx_renderer._apply_background ne gérait que la couleur, jamais
background.image_data_uri. Corrigé.
- Les guides d'alignement (snap) pouvaient apparaître à tort lors d'un simple
rafraîchissement programmatique (non déclenché par un glisser souris réel) —
bornés à _user_dragging uniquement.
Ajouté (2026-07-22, édition manuelle)
- Édition de texte inline : double-clic sur une zone de texte/forme → éditeur
flottant superposé directement sur l'élément (Échap annule, clic ailleurs valide),
au lieu du seul détour par le panneau latéral.
- Panneau de propriétés type-aware : contrôles dédiés par type — forme (type,
remplissage, contour, épaisseur), image (ajustement, remplacer le fichier),
tableau et graphique (bouton « Modifier… » ouvrant un éditeur dédié), verrouillage.
- Éditeur de tableau (ui/table_edit_dialog.py) : ajout/suppression de lignes et
colonnes, édition du texte des cellules, couleurs de fond (en-tête/corps) et de
texte, taille — impossible à faire après création jusqu'ici.
- Éditeur de graphique (ui/chart_edit_dialog.py) : type, catégories, séries
(nom/valeurs/couleur) ajoutables/supprimables.
- Barre contextuelle au-dessus du canevas : libellé de l'élément sélectionné +
action rapide adaptée au type (modifier le tableau/graphique, remplacer l'image,
éditer le texte).
- Image de fond de slide (menu Insérer) distincte d'un élément image classique
(slide.background.image_data_uri), plein cadre, sous tous les éléments.
- Gestion des projets (ui/project_manager_dialog.py) : renommer et supprimer un
projet (avec confirmation) — fonctions de stockage déjà présentes mais jamais
reliées à une interface.
Ajouté (2026-07-22, suite retours utilisateur)
- Portée par défaut = tout le deck, sélecteur repositionné juste au-dessus de la
zone de saisie (visible à chaque nouvelle itération, plutôt qu'en haut du panneau).
- Indicateur de traitement (ui/chat_panel.py) : spinner GIF animé
(assets/spinner.gif, généré via packaging/make_spinner.py), phase en cours,
chronomètre, estimation de tokens. Le flux brut du modèle (JSON de patch) est
relégué dans un panneau Détails repliable (fermé par défaut) — le journal
principal ne montre que des messages conviviaux. Canal on_phase threadé à
travers Worker/edit_service/planner/theme_service.
- Boucle de retour utilisateur structurée par l'IA : barre 👍/👎 + commentaire
après chaque génération/modification (storage/feedback_store.py), synthèse IA
en axes d'amélioration priorisés dans IMPROVEMENT_NOTES.md
(services/feedback_service.py), consultable/régénérable via Aide > Retours
utilisateurs & axes d'amélioration… (ui/feedback_dialog.py).
- Feuille de route de l'auto-réflexion IA (design/roadmap-reflexion-ia.md) :
plan phasé (auto-critique visuelle, critiques spécialisées, planification avant
action, préférences apprises, budget borné explicite) — jamais de boucle
illimitée, toujours un budget visible.
- Modernisation visuelle (ui/style.py) : palette plate moderne, panneaux en
cartes blanches arrondies avec espacement, boutons/champs/scrollbars/menus
restylés, bouton d'action principal (accent bleu) cohérent dans tous les
dialogues. Limite documentée : QTextDocument (journal de chat) ne supporte pas
border-radius — seuls les widgets (cadres, boutons, champs) en bénéficient
pleinement.
Ajouté
- Analyse de fichiers sources pour la génération (generate/ingest.py) : extraction
de .xlsx/.xlsm, .csv/.tsv, .pptx, .docx, .pdf, .txt/.md et images. Les
données (KPI, statuts, items) alimentent le plan et chaque slide, avec chiffres exacts
et mise en évidence des actions. Nouveau dialogue « Nouveau depuis un brief » avec pièces
jointes (ui/generate_dialog.py), et pièces jointes également disponibles directement
dans la zone de chat (📎) pour enrichir une modification en cours.
- Icône applicative (assets/icon.svg/.png/.ico) : éclair bleu/jaune, lisible dès
16-32px, utilisée dans l'en-tête de fenêtre et la barre des tâches Windows
(AppUserModelID dédié) ; embarquée au packaging PyInstaller.
- Éditeur de charte (ui/theme_editor.py) : color pickers par rôle, choix de polices,
tailles, puces, aperçu live sur une slide d'exemple, enregistrement sous un nom,
application au deck courant. Analyse IA de charte câblée dans l'UI (menu
Charte) : à partir d'un logo/PPTX, combine extraction programmatique (couleurs
dominantes Pillow, couleurs/polices des masters python-pptx) et proposition LLM
vision, ouverte directement dans l'éditeur pour ajustement.
- Préréglage Socomec authentique : vraies couleurs du Design System fourni
(#004F9F / #4CAFE4 / #FFCC00), police Archivo, logo officiel embarqué.
- Logo de charte posé automatiquement sur chaque slide (render/branding.py) :
jusqu'ici le token theme.logo n'était jamais dessiné ; il apparaît maintenant au
même endroit à l'écran et à l'export PPTX. Le LLM reçoit l'instruction explicite de
ne jamais le dupliquer comme élément.
- Édition par prompt à l'échelle du deck entier : sélecteur de portée dans le chat
(« Cette slide » / « Tout le deck »), nouvelle fonction
edit_service.edit_deck_by_prompt capable de patcher plusieurs slides en une
demande (ex. harmoniser tous les titres). Aperçu avant/après étendu à plusieurs
slides (ui/diff_preview.py).
- Contexte persistant + questions de clarification + auto-critique bornée : la
conversation d'édition n'est plus recréée à chaque prompt (bouton « Nouvelle
conversation » pour repartir à zéro). Le LLM peut répondre par une question
(EditQuestion) plutôt qu'un patch s'il juge la demande ambiguë. Après un patch
valide, une passe d'auto-évaluation bornée (1 relance max, jamais bloquante)
vérifie que la demande est bien satisfaite et corrige si besoin.
- Zoom explicite du canevas (boutons +/−/Ajuster, pourcentage affiché, raccourcis
Ctrl+molette/Ctrl+0) qui conserve le niveau de zoom d'une slide à l'autre.
- Guides d'alignement (snap) en édition manuelle : accroche automatique sur les
bords/centres des autres éléments et de la slide pendant le déplacement, avec
lignes de guidage visuelles (comme PowerPoint/Figma).
- Barre d'outils Insertion : zone de texte, formes (rectangle, rectangle arrondi,
ellipse, ligne, flèche, chevron), image (fichier local), tableau (dialogue
lignes/colonnes), graphique simple (catégories/valeurs) — chaque insertion passe
par la pile de commandes (undo/redo).
- Layouts enrichis (generate/layouts.py) : anatomie concrète par layout (bandes
d'en-tête, filets d'accent, grilles de KPI, cartes, diviseurs de section) inspirée
du Design System Socomec fourni, injectée dans le prompt système de génération pour
un rendu moins générique qu'un simple titre + puces.
- Lanceur .bat : contrôle et installation automatiques des dépendances au premier
lancement (marqueur par version), en plus de la compatibilité UNC.
- Dépendance openpyxl (lecture Excel).
Corrigé
- Mojibake UTF-8 sur le streaming SSE (ai/streaming.py) : requests décodait
text/event-stream en ISO-8859-1 par défaut (pas de charset dans l'en-tête), ce qui
corrompait tout caractère accentué (« é » → « é »). Le flux est désormais décodé en
UTF-8 explicitement, quel que soit le backend.
Modifié
- DEFAULT_MAX_TOKENS relevé de 4000 à 8000 (les slides riches (fonds, grilles,
tableaux) étaient parfois tronquées). Ajout d'une compression automatique du
contexte (ai/conversation.py) : au-delà d'un volume de conversation donné, les
tours anciens sont résumés par un appel LLM dédié, les derniers tours restant
verbatim — évite de dépasser la fenêtre de contexte sur une longue session d'édition.