Changelog
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
[1.2.1] - 2026-09-06
Changé — le zip de release ne contient plus les sources Python (.pyc + Python portable embarqué)
- Décision produit — retour utilisateur : « je ne souhaite plus vraiment partager les sources de notre travail qui commence à représenter pas mal d'heures de travail », en gardant le même zip/
slydeforge.bat(pas de bascule vers un exe PyInstaller frozen).packaging/build_release.pycompile désormais chaque.pyd'INCLUDE_FILES/INCLUDE_DIRS en bytecode.pyc« sourceless » (packaging/compile_release_sources.py, niveau d'optimisation 2 — retire aussi les docstrings) puis retire le.py, et embarque souspython/un Python « embeddable » officiel figé (packaging/build_portable_python.py, réutiliseslydeforge_installer/worker/python_setup.py::install_portable) — impératif car un.pycest lié à la version mineure EXACTE de l'interpréteur qui l'a produit, ce que ne garantissait pas le Python système (potentiellement différent) de chaque poste utilisateur.slydeforge.batprivilégie désormais cepython\embarqué avant tout Python système, et lanceapp.pyc(ouapp.pyen repli, ex. lancement depuis les sources en développement).build()reste rétro-compatible : sansportable_python_dirfourni (défaut, utilisé par les tests pour rester rapides/hors-ligne), le zip reste en.pysource — c'est le CLI (python packaging/build_release.py) qui active systématiquement la compilation pour une vraie release. - Limite assumée, à ne pas présenter comme une protection forte : un
.pycreste décompilable (pyinstxtractor/decompyle3…) — dissuasion, pas un verrou. Les chaînes de caractères hors docstring (messages, libellés UI, valeurs codées en dur) restent lisibles dans le bytecode quel que soit le niveau d'optimisation, limite inhérente au format. - Bug réel découvert et corrigé en testant ce chemin bout en bout (jamais exercé avant) : le Python « embeddable » restreint
sys.pathEXCLUSIVEMENT au contenu de son fichierpython3XX._pth— niPYTHONPATH, ni le préfixage habituel du dossier du script lancé ne s'appliquent. Sans correctif, AUCUN module posé à côté depython\(app.py, tout le code applicatif) n'était importable,ModuleNotFoundErrorsilencieux — ce bug préexistait dansslydeforge_installer/worker/python_setup.py::install_portable(assistant d'installation, jamais testé bout en bout jusqu'ici) et affectait donc aussi ce chemin-là, pas seulement celui-ci._enable_site_packagesajoute désormais..au fichier._pth. services/package_installer.py::pip_commandn'ajoute plus--userquand SlydeForge tourne sous ce Python portable embarqué (déjà un environnement dédié à cette seule installation) — même distinction déjà faite parslydeforge_installer/worker/cli.pypour l'assistant d'installation, appliquée ici à l'installation à la volée des dépendances d'un composant marketplace (exqrcode,mediapipe).slydeforge.batcorrigé au passage : le fichier avait des fins de ligne LF (Unix) au lieu de CRLF, provoquant une corruption sporadique et silencieuse de l'exécution (fragments de commandes tronqués) découverte en testant réellement un lancement complet — reconverti en CRLF.- Vérifié bout en bout (pas seulement le contenu du zip) : build réel, extraction, installation des dépendances dans le Python portable, lancement de l'app compilée jusqu'à l'affichage de la fenêtre principale (
slydeforge.logde ce test conservé comme preuve).
Ajouté — composant marketplace « Application externe » (site web/fichier/appli incrusté dans une slide)
- Retour utilisateur — « j'ajoute le composant application interactive de type navigateur edge et je peux directement depuis mon slide utiliser l'application pour montrer aux spectateur un site internet [...] ou encore ajouter un fichier Excel et pouvoir l'utiliser directement depuis le composant inséré dans le slide [...] le plus simple serait d'avoir une liste d'application ou sélectionner un exe [...] mais si je veux ouvrir un fichier spécifique ou une page internet avec une URL directement c'est plus complexe à paramétrer » : nouveau composant marketplace (
slide_component_addons/external_app_addon.py, cf. son DEPLOY.md pour le détail) — UN SEUL composant générique plutôt qu'un par application, avec 3 modes de cible en préparation (Site web/URL, Fichier, Application .exe), zone éditable (même_ZonePicker/_ZoneEditorque poll_addon.py/webcam_addon.py). L'application n'a jamais besoin d'être déjà ouverte : lancée automatiquement (subprocess.Popen/os.startfile) dès l'affichage de sa slide. Incrustation par docking (repositionnement continu parSetWindowPos, bordure retirée) plutôt que par reparenting Win32 réel (SetParent, trop fragile avec les applications modernes) ; la fenêtre externe est cachée (jamais fermée) à chaque changement de slide pour garder son état (scroll Excel, page affichée) — et n'est plus jamais fermée non plus à la fin de la présentation, cf. le 4e bug corrigé ci-dessous. - Dépendance optionnelle
pywin32, auto-proposée à l'installation (même mécanisme queqrcodepour poll_addon.py) — 1er cas réel où le nom du paquet pip diverge du nom du module importable (pywin32n'expose jamais de modulepywin32lui-même) :services/package_installer.pygagne une table d'alias (_IMPORT_NAME_ALIASES) pour que la vérification « déjà installé ? » reste correcte, exactement la limite que ce fichier documentait déjà par anticipation. - Bugs réels corrigés après un vrai test (captures d'écran à l'appui) : (1) « je viens de tester avec un fichier Excel, il s'ouvre mais pas dans le slide de façon interactive » + « pour la page web [...] il ne faut pas que ce soit le premier slide qui s'affiche car sinon ça fait quelque chose de bizarre [...] on voit le mode présentateur dans la zone où devrait s'afficher la page web et une autre fenêtre est ouverte avec la page web à part » — root cause identifiée depuis la capture : sur la toute première slide d'une présentation, la console présentateur de SlydeForge s'ouvre EN MÊME TEMPS que l'application externe est lancée, et se faisait incruster À SA PLACE (elle-même "nouvelle" au moment du diff avant/après utilisé pour repérer la fenêtre cible, parfois plus grande que la fenêtre encore en cours de chargement de l'appli visée) — jamais reproduit en naviguant vers une slide plus tard, où plus aucune fenêtre SlydeForge ne se crée au même instant.
_is_real_app_windowexclut désormais INCONDITIONNELLEMENT toute fenêtre appartenant au PROCESSUS de SlydeForge lui-même (win32process.GetWindowThreadProcessId+ pid courant), quelle que soit sa taille. (2) Fichier Excel mono-instance (comme Word/PowerPoint) : ouvrir un fichier alors qu'une instance tourne déjà réutilise sa fenêtre EXISTANTE plutôt que d'en créer une nouvelle, invisible au diff avant/après seul — recherche additionnelle par titre de fenêtre (nom du fichier sans extension, ex "budget" trouve "budget.xlsx - Excel") parmi toutes les fenêtres visibles, pas seulement les nouvelles. Délai de recherche allongé de 12 à 20 secondes (Office peut être lent à ouvrir une 1ère fenêtre). (3)SetWindowPos(..., HWND_TOP, ...)seul peut être silencieusement ignoré par Windows quand la fenêtre cible appartient à un AUTRE processus (restriction anti-vol-de-premier-plan) — remplacé par un aller-retourHWND_TOPMOST->HWND_NOTOPMOST(astuce Win32 standard), qui force réellement le passage au premier plan sans y rester collé en permanence. - (v1.2) Bug réel corrigé — Excel réouvert 2 fois après un aller-retour de slide : retour utilisateur — « j'ouvre un fichier Excel, je vais sur une autre slide et je reviens, il considère que le fichier est déjà ouvert car il le réouvre une 2e fois » (capture : Excel se plaint d'un fichier verrouillé par l'utilisateur lui-même). Root cause : un aller-retour trop rapide détruisait le 1er overlay avant que sa fenêtre ait été trouvée (
_LIVE[key].hwndencoreNone) — l'ancien code ne savait alors QUE relancer un 2eos.startfile/Popenpar-dessus le 1er processus, lui toujours vivant en arrière-plan. Une entrée_LIVEexistante, même sans hwnd connu, signifie désormais « déjà en cours de lancement, ne jamais relancer » (ExternalAppOverlay._resume_search, nouveau) : reprend seulement la recherche de sa fenêtre — par titre en mode Fichier, par pid du processus déjà suivi (live.process) dans les deux autres modes. - (v1.3) Bug réel corrigé — le fichier restait verrouillé même après le correctif v1.2, capture d'écran à l'appui : la vraie root cause du verrouillage n'était pas (seulement) un double-lancement —
_terminate_keyenvoyaitWM_CLOSEà la fenêtre encore CACHÉE en fin de présentation ; Excel, avec des modifications non enregistrées, ouvre alors sa boîte « Voulez-vous enregistrer ? », restée INVISIBLE (propriétaire caché, dialogue coincé derrière la présentation en train de se fermer) — personne ne peut y répondre, Excel reste bloqué indéfiniment en attente, et le fichier reste verrouillé jusqu'à un « Fermer » manuel dans le Gestionnaire des tâches (3e dialogue de la capture : « Vous ne pouvez pas fermer Microsoft Excel, car une boîte de dialogue est ouverte »)._terminate_keyne ferme donc plus JAMAIS l'application (niWM_CLOSE, niprocess.terminate()) — elle est rendue visible normalement à la place (bordure/taille d'origine restaurées via_LiveTarget.original_style, jamais laissée microscopique à la taille de la zone), exactement comme si l'utilisateur l'avait lui-même ouverte : à lui de la fermer quand il le souhaite, avec sa propre boîte de dialogue bien VISIBLE si besoin. - (v1.4) Bug réel corrigé — le fichier restait verrouillé même après le correctif v1.3, capture d'écran à l'appui : root cause bien plus basique que les précédentes —
ExternalAppOverlay.__init__connectait le nettoyage réel (_terminate_key) àself.window().destroyed, mais appelé DANS__init__, AVANT queui/present_window.py::_sync_interactive_overlayn'appelleoverlay.setParent(self)— à ce stade, l'overlay est encore SANS PARENT, doncself.window()retourne l'overlay LUI-MÊME (une fenêtre sans parent est sa propre "top-level window" pour Qt), jamais la vraie fenêtre de présentation._terminate_keyse retrouvait donc connecté à la destruction de CET overlay — qui a lieu à CHAQUE changement de slide (cf._flush_interactive_overlays), pas seulement à la fin de la présentation : chaque aller-retour retirait prématurément l'entrée_LIVE, provoquant un 2eos.startfileau retour malgré les correctifs v1.2/v1.3. Même piège déjà rencontré et corrigé de la même façon danswebcam_addon.py(_destroyed_hook_connected) — la connexion se fait désormais dansshowEvent(une seule fois, une fois l'overlay réellement parenté parui/present_window.py), jamais dans__init__.
Ajouté — variante anglaise de l'usage réseau des composants marketplace (ADDON_NETWORK_USAGE_EN)
- Retour utilisateur — « gérer les informations de Usage réseau en direct — Français (obligatoire) + Usage réseau en direct — English (optionnel) dans le code source comme pour les autres afin que lorsque je sélectionne depuis la partie admin du site les information se renseignent automatiquement » : nouvelle constante optionnelle
ADDON_NETWORK_USAGE_EN, même principe queADDON_CATEGORY_EN/ADDON_DESCRIPTION_ENdéjà en place (repli sur le texte français si absente).packaging/build_slide_components_catalog.py::_build_entryexpose désormaisnetwork_usage_endanscatalog.json, aux côtés denetwork_usage, pour préremplir les DEUX champs du formulaire de publication admin slydeforge.com. Déclarée pour les 4 composants existants (poll_addon.py,postits_addon.py— vraies traductions du texte FR déjà en place ;webcam_addon.py,external_app_addon.py— chaîne vide dans les deux langues, 100% locaux) et documentée dans_template_component.py/DEPLOY.mdpour tout futur composant.
Ajouté — recherche d'images multi-fournisseurs + usage automatique par l'IA
- Retour utilisateur — « ce paramétrage devrait être séparé de la partie IA [...] un bouton direct qui envoie sur le site pour s'enregistrer et créer les tokens [...] mieux expliquer [...] proposer autre chose que unsplash [...] on pourra sélectionner le service ou dire tous » : l'onglet Paramètres > Images (déjà séparé de l'onglet IA) est réorganisé en 2 sections claires (Recherche / Génération), chaque fournisseur de recherche (
ai/settings.py::IMAGE_PROVIDER_INFO, désormais Unsplash et Pexels) avec sa propre aide et un bouton direct de création de clé (même pattern que les backends IA "essai gratuit").services/image_search.py::search()interroge tous les fournisseurs configurés et entrelace les résultats par rang (round-robin) plutôt qu'une simple concaténation, pour ne pas faire dominer un fournisseur juste parce qu'il est listé en premier — un sélecteur Tous/Unsplash/Pexels apparaît dans le dialogue d'insertion d'image dès que 2 fournisseurs sont configurés. - Retour utilisateur — « je souhaite retirer la case "Repartir de zéro", que je n'utilise jamais, et y mettre une case utiliser des images libres de droits [...] l'IA va chercher des images sur le thème du slide en cours de génération et va voir si une image peut être utilisée et réfléchir si ça peut apporter un plus » : la case (jamais utilisée) qui déclenchait une régénération complète du deck depuis le chat est retirée — cette capacité restait de toute façon disponible via "Nouveau depuis un brief". Remplacée par « Images libres de droits » (chat IA, portées deck ET slide, et dialogue "Nouveau depuis un brief") :
services/image_search.py::search_and_download_candidatescherche quelques photos pour le sujet en cours (requête en anglais générée par le planificateur viaimage_query, cf.generate/planner.py/generate/prompts.py::system_plan), présentées à l'IA dans un bloc de prompt dédié et FACULTATIF (generate/prompts.py::_stock_images_note, distinct des images de charte "à utiliser par défaut") — l'IA les référence par nom comme une image de charte (même mécanismeasset_ref, cf.core/assets.py), résolues via une copie ÉPHÉMÈRE du thème (services/stock_images.py::theme_with_candidates) qui ne pollue jamais le thème réel du projet. Une légende de crédit (photographe + service) est ajoutée automatiquement sous toute photo réellement utilisée (services/stock_images.py::apply_credit_captions), respectant les CGU Unsplash/Pexels sans action de l'utilisateur. - Mise en forme (
/suggest_design) : propose désormais explicitement d'ajouter une photo libre de droits même quand l'IA n'a proposé aucune zone "image" dans sa disposition (si une clé est configurée) — synthétise une zone image dans la disposition retenue, traitée ensuite exactement comme une zone proposée par l'IA (aucun changement du mécanisme de sélection/insertion existant).
[1.2.0] - 2026-08-24
Ajouté (2026-08-24 — 6e vague : emplacement et couleurs éditables pour le composant Sondage)
- Retour utilisateur — « pour un composant comme le sondage ça serait bien que l'utilisateur puisse définir une zone dans le slide où ça doit apparaitre et il pourrait même configurer les couleurs (utilisation de la charte ou avec une personnalisation manuelle) » :
PollPrepDialog(slide_component_addons/poll_addon.py, v1.2.0) ajoute un aperçu 16:9 glisser-déposer (_ZonePicker— déplacer/redimensionner la carte, coordonnées en pourcentage de la slide) et deux sélecteurs de couleur (ui/color_picker_combo.py::ColorPickerCombo, même contrôle que le reste de l'app) pour le fond et le texte, chacun acceptant un rôle de la charte du deck OU une couleur personnalisée. Un sondage posé avant cette évolution garde son apparence d'origine (fond sombre translucide, texte blanc, zone équivalente à l'ancien positionnement figé) — rien de cassé. Le contratInteractiveComponentSpec.make_overlay/make_prep_dialog(core/interactive/registry.py) gagne un paramètrethemeoptionnel pour permettre cette résolution de couleur — ignoré sans effet par tout composant qui n'en a pas besoin (Tableau blanc, Post-its, gabarit).
Corrigé (2026-08-24 — 5e vague : l'offre d'installation de dépendance ne se déclenchait pas après mise à jour d'un composant)
- Retour utilisateur — « j'ai mis à jour le composant d'interaction de sondage depuis le site, je l'ai supprimé sur mon application, réinstallé mais je ne vois toujours pas de QR code [...] apparemment le composant qr code de python ne s'est pas déployé automatiquement » : deux causes possibles, corrigées ensemble. (1)
ui/slide_component_marketplace_dialog.py::_install_from_local_file(installation depuis un fichier local, sans passer par le catalogue en ligne) n'appelait jamais_offer_missing_dependencies— seul le chemin d'installation depuis le catalogue le faisait ; les deux chemins déclenchent désormais la même offre. (2)entry.requires(déclaré par le CATALOGUE distant) peut être périmé par rapport au fichier.pyréellement déployé sur le poste (catalogue reconstruit après coup, ou jamais republié) —core/interactive/addons.py::load_addons()conserve désormaisADDON_REQUIRESdu MODULE fraîchement chargé dansADDON_COMPONENT_META, et_offer_missing_dependenciespréfère cette source àentry.requires, qui ne sert plus que de repli.
Ajouté (2026-08-24 — 4e vague : installation guidée des dépendances de composants marketplace)
- Retour utilisateur — « est-ce que l'installation d'un composant interactif peut déclencher l'installation automatique (avec acceptation de l'utilisateur) de dépendances (ex le cas du QR code) ? » : oui.
services/package_installer.py(nouveau, généralisé depuisservices/tts_installer.py— moteurs de voix Edge/Piper) +ui/package_install_dialog.pyproposent l'installation viapip(confirmation explicite, progression en direct) de tout paquet déclaré (ADDON_REQUIRES/CatalogEntry.requires) et manquant, juste après l'installation d'un composant interactif (ui/slide_component_marketplace_dialog.py::_offer_missing_dependencies).qrcode(composant Sondage/Notation) est le premier paquet concerné —slide_component_addons/poll_addon.pypasse en v1.1.0. Repli honnête (instruction manuelle) si SlydeForge tourne dans un mode oùpipn'est pas exploitable (cf.services/package_installer.py::is_frozen_without_pip) — sans effet dans le mode réellement distribué aujourd'hui (lanceur +slydeforge.bat+ Python système).
Ajouté (2026-08-23 — composants interactifs de présentation + marketplace dédiée)
- Menu Insérer > Interactif (
ui/main_window.py) : un slide peut désormais porter zéro, un ou plusieurs composants interactifs (deck.schema.json::interactive_component, nouveau champslide.interactive_components), détectés en mode présentation pour dériver un panneau d'outils entièrement CONTEXTUEL (pas de barre permanente) — cf.design/interactive-components-marketplace.mdpour l'architecture complète. Contenu du menu dynamique, reconstruit à chaque ouverture depuiscore/interactive/registry.py. - Composant intégré Tableau blanc (Dessin) (
ui/interactive/drawing_overlay.py) : crayon/surligneur/rectangle/ellipse/annotation texte en direct par-dessus la slide affichée, undo/redo (Ctrl+Z/Ctrl+Y, pile dédiée à la session de présentation — jamais mêlée à la timeline de versions du deck), réinitialisation, état persisté par slide (capté par l'autosave existant via un chemin d'écriture volontairement ÉTROIT,PresentWindow.component_state_changed, qui préserve la garantie « le mode présentation ne modifie rien par mégarde » pour tout le reste du deck). Seul composant livré par défaut — « assez standard dans ce type de solution ». - Marketplace de composants interactifs (
services/slide_component_marketplace.py,ui/slide_component_marketplace_dialog.py,core/interactive/addons.py) : les autres modes interactifs envisagés (Sondage/Notation, Post-its/Zones, Mur d'idées, cf.design/interactive-modes-reflexion.md) ne sont PAS intégrés au cœur de l'application — un composant interactif peut faire transiter des interactions du public par slydeforge.com pendant toute une présentation, un impact serveur récurrent qui doit rester optionnel et suivi composant par composant, jamais imposé à tous les utilisateurs. Miroir du marketplace de composants de workflow déjà existant (services/addon_marketplace.py), avec un ajout : chaque composant publié doit déclarer son usage réseau (ADDON_NETWORK_USAGE, obligatoire — cf.slide_component_addons/DEPLOY.md), affiché à l'utilisateur AVANT installation.
Ajouté (2026-08-24 — 2e vague : composants Sondage/Post-its, visibilité/édition sur la slide, navigation en présentation, guide utilisateur)
- Composants marketplace Sondage/Notation et Post-its/Zones développés et publiés (
slide_component_addons/poll_addon.py,postits_addon.py, catalogue régénéré dansdist/marketplace/slide-components/) : le Sondage relaie les votes du public via QR code et le relais générique décrit dansSlydeForge_www/SETUP_INTERACTIVE_COMPONENTS.md(agrégation locale, dédoublonnage parvoter_token— « un vote modifiable tant que le sondage reste ouvert »), les Post-its restent 100% locaux (glisser-déposer d'étiquettes dans des zones, aucun réseau). ContratInteractiveComponentSpec.make_overlayétendu (params, state, on_state_changed— les réglages de préparation, absents jusqu'ici, sont enfin transmis à l'overlay de présentation, corrigeant un gap qui rendait un composant comme le Sondage incapable de connaître sa propre question). - Retour utilisateur — « comment voir qu'un mode interactif est actif sur la slide ? et comment le supprimer ou le paramétrer ? » : nouvelle barre de « puces » au-dessus du canevas (
ui/main_window.py::_refresh_interactive_bar), une par composant posé sur la slide affichée — Paramétrer…/Activer-Désactiver/Retirer, toutes annulables (Ctrl+Z). Masquée par défaut, visible uniquement quand la slide en porte au moins un. - Retour utilisateur — « en mode normal on ne peut pas passer au slide suivant sauf avec Entrée ou les flèches [...] ajouter un élément pour aider l'utilisateur » : deux boutons ‹ › discrets sur les bords de l'écran en mode présentation (
ui/present_window.py), désactivés en début/fin de diaporama, toujours au-dessus d'un éventuel composant interactif actif. - Guide utilisateur enrichi (
docs/guide-utilisateur.md/docs/user-guide.md) : nouvelle section 15 documentant les composants interactifs de bout en bout (ajout, barre de gestion, présentation, marketplace, navigation). - Retour utilisateur — « il y a un problème dans les liens avec ancre qui ne fonctionnent pas » : root cause —
QTextBrowser.setMarkdown()ne place pas le document en mode navigation d'URL, et l'algorithme de slug généré automatiquement par Qt pour chaque titre ne correspondait pas à celui utilisé pour écrire les liens du Sommaire. Corrigé (ui/user_guide_dialog.py) par une résolution manuelle des ancres (slug maison appliqué aux titres du document lui-même, garanti cohérent avec la règle d'écriture du Sommaire), avec un test qui vérifie qu'aucun lien du Sommaire (FR et EN) n'est mort. - Retour utilisateur — « ajouter un mode de recherche [...] pour trouver plus facilement une rubrique » : champ de recherche dans le guide utilisateur (
ui/user_guide_dialog.py), occurrence suivante/précédente avec retour en boucle en bout de document. - Instructions de déploiement
SlydeForge_wwwcomplétées (SlydeForge_www/SETUP_INTERACTIVE_COMPONENTS.md) : rubrique admin + page publique pour le catalogueslide-components(même patron que Chartes/Composants/Workflows), page de vote/s/<session_id>(celle que le QR code du Sondage encode — configuration transportée dans l'URL, le relais restant volontairement aveugle), correction de la sémantique decomponent_id(le TYPE du composant pour l'agrégation du tableau de bord, pas l'id d'instance).
Corrigé (2026-08-24 — 3e vague : bugs réels remontés après un vrai test avec 2 composants sur la même slide)
- Bug réel corrigé — impossible de combiner deux composants interactifs sur la même slide (retour utilisateur : « je ne peux pas multiplier les interactions sur une même slide », confirmé) :
ui/present_window.py::_sync_interactive_overlayne construisait l'overlay que du PREMIER composant activé de la slide (self._interactive_overlayunique). Remplacé parself._interactive_overlays(dictcomponent_id -> QWidget) : tous les composants activés d'une slide obtiennent désormais un overlay simultanément, chacun responsable de son propre espace visuel pour ne pas se chevaucher. Ctrl+Z/Ctrl+Y ciblent le premier composant (ordre d'insertion) qui a réellement quelque chose à annuler/rétablir. - Menu Interactif remis dans Insérer (retour utilisateur : « je préfère le conserver dans Insérer comme si c'était un objet qui s'ajoute et ne pas complexifier le menu principal ») — un aller-retour en menu de premier niveau (fait puis annulé dans la même journée) laissait une entrée dupliquée dans
ui/main_window.py; il n'en reste qu'une, sous-menu d'Insérer. - Popup de lancement du diaporama — mémoire du dernier choix (retour utilisateur : « serait-il possible de se souvenir de ce que l'utilisateur a mis d'une fois sur l'autre ») : le mode d'affichage des flèches ‹ › et le choix du mode présentateur sont désormais enregistrés par utilisateur (
prefs) dès qu'on clique OK — jamais sur Annuler — et priment sur la présélection intelligente basée sur le contenu du deck aux ouvertures suivantes (ui/launch_presentation_dialog.py). - Boutons de navigation ‹ › conditionnels en présentation (retour utilisateur : « on ne devrait les faire apparaître que sur une slide avec un mode interactif [...] laisser le choix à l'utilisateur dans la popup ») : 3 modes désormais proposés au lancement du diaporama (
ui/launch_presentation_dialog.py) — seulement sur les slides avec un composant interactif activé (présélectionné si le deck en a au moins une), sur toutes les slides, ou jamais (présélectionné sinon) ; le dialogue ne s'affiche que s'il y a réellement quelque chose à décider (2+ écrans ou au moins une slide interactive), comme avant pour le mode présentateur seul. - Composant Sondage — mise en page et diagnostic réseau améliorés (retour utilisateur, capture d'un vrai test — carte étirée sur toute la hauteur, aucune indication que le service était injoignable) : carte de résultats désormais centrée verticalement (
slide_component_addons/poll_addon.py) plutôt qu'étirée sur toute la hauteur de la slide ; message d'avertissement affiché après plusieurs échecs réseau consécutifs (« Service de sondage injoignable ») au lieu de laisser un silencieux « 0 réponse(s) » se faire passer pour « personne n'a encore voté » ; lien de secours corrigé pour afficher l'URL exacte (l'ancien texte tronqué/mis en majuscules ne pointait vers aucune session réelle, unsession_idétant sensible à la casse).
[1.1.8] - 2026-08-22
Corrigé (2026-08-22 — mode présentateur : raccourcis et sélecteur de langue restaient en français)
- Retour utilisateur (captures, interface anglaise) — « les explications sur les touches (raccourcis) » et « les langues dans la liste de sélection » : la barre d'aide des raccourcis (rappel permanent sur la console présentateur, et écran « H » côté diaporama public) provient d'une constante
SHORTCUTS(ui/presenter_window.py) jamais passée parself.tr()— corrigé aux deux points d'affichage (ui/presenter_window.py,ui/present_window.py::toggle_help). Le sélecteur de langue de narration (mode présentateur ET bibliothèque de voix,ui/voice_library_dialog.py) affichait quant à lui les noms natifs du registrecore/languages.py("Français") sans jamais les retraduire — désormais traduit ("French") en interface anglaise.
Corrigé (2026-08-22 — contenu généré par IA et deck de démonstration restaient en français quelle que soit la langue)
- Retour utilisateur (bug réel, capture) — « si je suis avec une interface en langue anglaise et que je questionne en anglais les slides générés sont en français » :
generate/prompts.py::system_plan/system_generate_slide(pipeline « Nouveau depuis un brief ») forçaient jusqu'ici EXPLICITEMENT « en français » dans leurs instructions système, quelle que soit la langue du brief fourni par l'utilisateur — root cause directe, pas un simple biais du modèle. Un audit du reste des prompts système du projet a trouvé 2 autres occurrences EXACTEMENT du même bug, corrigées de la même façon : le nommage automatique de projet/version (services/naming_service.py) et la suggestion de notes de présentateur (services/notes_suggest_service.py). Les 4 prompts suivent désormais une consigne PARTAGÉE (ai/language.py::CONTENT_LANGUAGE_NOTE) qui suit la langue DU BRIEF/CONTENU lui-même (jamais une langue fixe, jamais nécessairement celle de l'interface — cohérent avec le principe déjà établi ailleurs dans ce projet : le contenu de présentation suit la demande de l'utilisateur, seul le texte "méta" de l'assistant suit l'interface). Aucune demande de confirmation de langue ajoutée : la consigne au modèle suffit à corriger le bug constaté, une clarification systématique aurait ajouté un clic à chaque génération pour un cas déjà couvert. - Retour utilisateur (capture) — « la présentation de base qui s'affiche à l'ouverture de l'application est toujours en français [...] idem lorsque l'on fait "New sample" » : le deck de démonstration (3 gabarits de la charte SlydeForge bundlée) était un texte 100% statique, jamais concerné par aucune traduction.
ui/main_window.py::_localize_startup_deckretraduit désormais ce texte viaself.tr()(même mécanisme que le reste de l'interface) à la fois à l'ouverture de l'application et via Fichier > Nouveau (exemple) — jamais appliqué à une charte personnelle importée par l'utilisateur, dont le contenu reste dans sa langue d'origine.
Corrigé (2026-08-22 — modèles gratuits Gemini/Groq par défaut dépréciés par les fournisseurs)
- Retour utilisateur (bug réel, capture) — « Tester la connexion » sur Groq renvoyait
HTTP 404 — The model 'llama-3.3-70b-versatile' does not exist or you do not have access to it; idem pour le modèle Gemini par défaut, qui ne fonctionnait plus non plus : les deux modèles gratuits recommandés par défaut ont été dépréciés côté fournisseur depuis l'écriture initiale deai/settings.py. Remplacés par les modèles gratuits actuellement disponibles (vérifiés auprès de la documentation à jour des fournisseurs) :gemini-3.6-flashpour Gemini (Google AI Studio, ~15 requêtes/minute, ~1500 requêtes/jour) etqwen/qwen3.6-27bpour Groq (~30 requêtes/minute, ~1000 requêtes/jour — Groq recommande ce modèle multimodal en remplacement deqwen3-32b/llama-3.3-70b-versatile, tous deux dépréciés). Une installation ayant DÉJÀ enregistré l'un des deux anciens modèles (ai/settings.py::get_config) bascule automatiquement vers le nouveau défaut au prochain appel IA, sans manipulation requise — jamais un modèle personnalisé par l'utilisateur, qui reste inchangé.