Sign in Home
Features
The AI FAQ
Library
Overview Themes Interactive components Workflows Workflow components
Download
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.py compile désormais chaque .py d'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 sous python/ un Python « embeddable » officiel figé (packaging/build_portable_python.py, réutilise slydeforge_installer/worker/python_setup.py::install_portable) — impératif car un .pyc est 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.bat privilégie désormais ce python\ embarqué avant tout Python système, et lance app.pyc (ou app.py en repli, ex. lancement depuis les sources en développement). build() reste rétro-compatible : sans portable_python_dir fourni (défaut, utilisé par les tests pour rester rapides/hors-ligne), le zip reste en .py source — 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 .pyc reste 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.path EXCLUSIVEMENT au contenu de son fichier python3XX._pth — ni PYTHONPATH, ni le préfixage habituel du dossier du script lancé ne s'appliquent. Sans correctif, AUCUN module posé à côté de python\ (app.py, tout le code applicatif) n'était importable, ModuleNotFoundError silencieux — ce bug préexistait dans slydeforge_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_packages ajoute désormais .. au fichier ._pth.
  • services/package_installer.py::pip_command n'ajoute plus --user quand SlydeForge tourne sous ce Python portable embarqué (déjà un environnement dédié à cette seule installation) — même distinction déjà faite par slydeforge_installer/worker/cli.py pour l'assistant d'installation, appliquée ici à l'installation à la volée des dépendances d'un composant marketplace (ex qrcode, mediapipe).
  • slydeforge.bat corrigé 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.log de 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/_ZoneEditor que 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 par SetWindowPos, 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 que qrcode pour poll_addon.py) — 1er cas réel où le nom du paquet pip diverge du nom du module importable (pywin32 n'expose jamais de module pywin32 lui-même) : services/package_installer.py gagne 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_window exclut 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-retour HWND_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].hwnd encore None) — l'ancien code ne savait alors QUE relancer un 2e os.startfile/Popen par-dessus le 1er processus, lui toujours vivant en arrière-plan. Une entrée _LIVE existante, 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_key envoyait WM_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_key ne ferme donc plus JAMAIS l'application (ni WM_CLOSE, ni process.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 que ui/present_window.py::_sync_interactive_overlay n'appelle overlay.setParent(self) — à ce stade, l'overlay est encore SANS PARENT, donc self.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_key se 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 2e os.startfile au retour malgré les correctifs v1.2/v1.3. Même piège déjà rencontré et corrigé de la même façon dans webcam_addon.py (_destroyed_hook_connected) — la connexion se fait désormais dans showEvent (une seule fois, une fois l'overlay réellement parenté par ui/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 que ADDON_CATEGORY_EN/ADDON_DESCRIPTION_EN déjà en place (repli sur le texte français si absente). packaging/build_slide_components_catalog.py::_build_entry expose désormais network_usage_en dans catalog.json, aux côtés de network_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.md pour 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_candidates cherche quelques photos pour le sujet en cours (requête en anglais générée par le planificateur via image_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écanisme asset_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 contrat InteractiveComponentSpec.make_overlay/make_prep_dialog (core/interactive/registry.py) gagne un paramètre theme optionnel 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 .py réellement déployé sur le poste (catalogue reconstruit après coup, ou jamais republié) — core/interactive/addons.py::load_addons() conserve désormais ADDON_REQUIRES du MODULE fraîchement chargé dans ADDON_COMPONENT_META, et _offer_missing_dependencies pré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é depuis services/tts_installer.py — moteurs de voix Edge/Piper) + ui/package_install_dialog.py proposent l'installation via pip (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.py passe en v1.1.0. Repli honnête (instruction manuelle) si SlydeForge tourne dans un mode où pip n'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 champ slide.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.md pour l'architecture complète. Contenu du menu dynamique, reconstruit à chaque ouverture depuis core/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é dans dist/marketplace/slide-components/) : le Sondage relaie les votes du public via QR code et le relais générique décrit dans SlydeForge_www/SETUP_INTERACTIVE_COMPONENTS.md (agrégation locale, dédoublonnage par voter_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). Contrat InteractiveComponentSpec.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_www complétées (SlydeForge_www/SETUP_INTERACTIVE_COMPONENTS.md) : rubrique admin + page publique pour le catalogue slide-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 de component_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_overlay ne construisait l'overlay que du PREMIER composant activé de la slide (self._interactive_overlay unique). Remplacé par self._interactive_overlays (dict component_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, un session_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 par self.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 registre core/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_deck retraduit désormais ce texte via self.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 de ai/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-flash pour Gemini (Google AI Studio, ~15 requêtes/minute, ~1500 requêtes/jour) et qwen/qwen3.6-27b pour Groq (~30 requêtes/minute, ~1000 requêtes/jour — Groq recommande ce modèle multimodal en remplacement de qwen3-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é.