Images IA vocales et dictaphone inline dans TAMSIV
La v1.3.2 est la release la plus ambitieuse que j'ai publiée sur TAMSIV. Deux features majeures, une migration technique délicate, et un changement de philosophie sur le rapport entre la voix et les contenus visuels.
En surface, c'est simple : tu parles, l'IA génère une image, elle s'attache à ta tâche. En dessous, c'est un pipeline qui enchaîne speech-to-text, analyse contextuelle par LLM, génération d'image, upload Supabase Storage, et affichage avec URL signée. Plus un dictaphone qui passe d'un overlay plein écran à un composant inline intégré en bas de l'écran. Et en bonus, une migration gesture handler qui m'a fait parcourir chaque fichier du projet à la recherche d'imports vicieux.
Points clés
- Les images IA sont générées directement depuis la voix : le LLM analyse le contexte de la tâche pour crafter un prompt optimisé, sans intervention de l'utilisateur.
- Le dictaphone inline remplace l'overlay plein écran, avec transcription affichée avant la fin du TTS pour un sentiment de réactivité immédiat.
- La migration gesture handler a corrigé un bug invisible sur iOS mais bloquant sur Android en mode release.
- L'option "skip TTS" permet un double gain : temps de réponse divisé et coûts d'API réduits pour les utilisateurs qui n'ont pas besoin de la réponse vocale.
Comment fonctionne la génération d'images IA directement depuis la voix ?
L'idée est née d'un constat simple : une tâche avec une image est immédiatement plus engageante qu'une tâche avec juste du texte. Les recherches en psychologie cognitive le confirment : selon une étude de John Medina (Brain Rules), le cerveau traite les images 60 000 fois plus vite que le texte. Si tu peux associer un visuel pertinent à chaque tâche, tu augmentes la rétention et la motivation.
Le problème, c'est que personne ne va chercher une image manuellement pour chaque tâche. Il fallait que ce soit automatique, contextuel, et déclenché par la voix. Voici le pipeline complet :
- L'utilisateur parle : "Crée une tâche pour préparer la présentation client avec une image".
- STT natif transcrit la voix en texte, comme décrit dans mon article sur STT natif vs Deepgram.
- Le LLM analyse le contexte : titre de la tâche, description, tags existants.
- Le LLM génère un prompt optimisé pour le modèle d'image, en anglais, avec des détails de style et de composition.
- Le provider d'image (Runware ou Gemini) génère le visuel.
- Upload vers Supabase Storage, création d'un enregistrement dans
privat.task_attachmentsavec le typeai_generated. - Affichage immédiat via URL signée.
J'avais détaillé le choix entre les providers d'image dans l'article dédié à la génération d'images IA. La v1.3.2 a intégré ce pipeline directement dans le flux vocal, ce qui le rend accessible sans aucune friction.
Pourquoi le LLM rédige-t-il le prompt à la place de l'utilisateur ?
Demander à un utilisateur d'écrire un bon prompt d'image, c'est comme demander à quelqu'un de parler couramment une langue qu'il n'a jamais apprise. Les modèles de génération d'image sont sensibles à la formulation : l'ordre des mots, les modificateurs de style, les termes techniques comme "cinematic lighting" ou "shallow depth of field" font une différence massive sur le résultat.
La solution est élégante : le LLM conversationnel, qui comprend déjà le contexte de la discussion, devient un traducteur entre l'intention humaine et le langage technique du modèle d'image. L'utilisateur dit "une image de présentation pro", le LLM traduit en "professional business presentation slides on a modern desk, clean corporate environment, soft directional lighting, photorealistic, 4K detail".
C'est le même principe que j'applique dans toute l'architecture de TAMSIV : l'IA doit faire le travail cognitif que l'utilisateur ne devrait pas avoir à faire. J'en parlais dans l'article sur la personnalisation vocale : l'intelligence, ce n'est pas juste comprendre les mots. C'est comprendre l'intention derrière les mots.
Comment le dictaphone inline change-t-il l'expérience utilisateur ?
Avant la v1.3.2, le dictaphone ouvrait un overlay plein écran. Tu appuyais sur le micro, tout disparaissait au profit d'une interface dédiée à la conversation. C'était fonctionnel, mais ça coupait le contexte. Tu ne voyais plus ta liste de tâches, tu ne voyais plus où tu en étais.
Le dictaphone inline change la donne. Il s'intègre directement en bas de l'écran, comme un clavier. Tu vois toujours ton contenu au-dessus. La transcription du texte apparaît en temps réel pendant que tu parles. Et surtout, le texte transcrit s'affiche avant la fin de la génération TTS.
Pourquoi c'est important ? Selon les études de Nielsen Norman Group sur les temps de réponse, 1 seconde est la limite pour maintenir le flux de pensée de l'utilisateur. Au-delà, il commence à sentir un délai. En affichant la transcription immédiatement pendant que l'audio se génère en parallèle, on triche avec la perception : l'utilisateur voit que l'IA a compris, même si la réponse audio n'est pas encore prête.
C'est une technique bien connue en UX : le modèle RAIL de Google recommande exactement ça. Répondre visuellement en moins de 100ms pour que l'interaction semble instantanée, même si le traitement complet prend plus longtemps.
Qu'apporte l'option "skip TTS" en pratique ?
Tous les utilisateurs n'ont pas besoin d'entendre la réponse de l'IA. Certains sont dans un environnement bruyant. D'autres veulent juste lire la transcription. D'autres encore utilisent TAMSIV en mode silencieux par habitude.
L'option "skip TTS" permet de désactiver la synthèse vocale de la réponse. Le gain est double :
- Temps de réponse : sans attendre la génération et le téléchargement de l'audio TTS, la réponse s'affiche quasi instantanément.
- Coûts d'API : chaque appel TTS a un coût (OpenAI facture au caractère). Sur des milliers d'interactions quotidiennes, ça s'additionne vite.
C'est aussi une question d'accessibilité. Certaines personnes préfèrent lire plutôt qu'écouter. D'autres ont des contraintes auditives. En offrant le choix, on respecte les préférences de chacun. C'est le même esprit que le design du dictaphone original : la voix est un canal, pas une obligation.
Pourquoi la migration gesture handler était-elle si critique ?
C'est le genre de bug qui te fait douter de ta santé mentale. Tout fonctionne en debug. Tout fonctionne sur iOS. Tu passes en mode release sur Android : le composant ne répond plus au toucher. Aucune erreur dans les logs. Aucun crash. Ça ne marche juste... pas.
Le coupable : des imports de TouchableOpacity, FlatList et ScrollView provenant de react-native au lieu de react-native-gesture-handler, utilisés à l'intérieur de GestureDetector. La documentation de React Native Gesture Handler est claire : dans un GestureDetector, tous les composants tactiles doivent venir de la bibliothèque gesture handler, pas de React Native standard.
Le bug était vicieux pour trois raisons :
- Invisible en debug : le bridge JavaScript de React Native en mode debug gère les événements tactiles différemment du mode release avec Hermes.
- Invisible sur iOS : UIKit et le système de responder chain d'iOS sont plus tolérants que le système de gestion des événements d'Android.
- Pas d'erreur explicite : aucun warning, aucun crash. Le composant s'affiche, il a le bon style, mais le toucher ne déclenche rien.
La correction a nécessité de parcourir chaque fichier du projet. Pas un grep rapide, parce que certains imports étaient mélangés : le TouchableOpacity venait de gesture handler, mais le ScrollView dans le même fichier venait de React Native. J'ai fini par établir une règle stricte pour la suite du développement, que j'applique encore aujourd'hui.
Comment garantir les performances avec ces nouvelles features ?
Ajouter des features, c'est facile. Ajouter des features sans dégrader les performances, c'est un métier. La v1.3.2 introduit un pipeline d'image et un dictaphone inline, deux composants potentiellement lourds. Voici les optimisations mises en place.
D'abord, zéro re-render inutile. Le dictaphone inline utilise React.memo et des callbacks stables pour éviter de déclencher des re-renders dans la liste de tâches au-dessus. Chaque animation passe par useNativeDriver: true pour tourner sur le thread natif, pas sur le thread JavaScript.
Ensuite, le cleanup agressif. L'AudioPlayerService implémente un timeout de sécurité de 30 secondes. Si un audio ne termine pas dans ce délai (problème réseau, fichier corrompu), le service force le nettoyage. Sans ça, les ressources audio s'accumulent en mémoire. J'avais déjà détaillé l'architecture de ce service dans l'article sur le pipeline vocal.
Enfin, les images générées sont chargées en lazy loading avec un placeholder blur. L'image ne se télécharge que quand la carte de tâche est visible à l'écran. Sur un feed de 50 tâches, ça fait potentiellement 50 images qu'on ne charge pas inutilement. C'est le genre d'optimisation qui impacte directement l'egress Supabase que j'avais travaillé à réduire.
Quel est l'impact de la v1.3.2 sur l'usage quotidien ?
Le changement le plus notable, c'est la fluidité. Avant la v1.3.2, utiliser TAMSIV était fonctionnel mais un peu rigide. Après, c'est devenu naturel. Tu parles, tu vois ta tâche se créer avec une image, tu continues ta journée. Le dictaphone inline ne te sort plus de ton contexte.
Les retours des testeurs alpha ont confirmé l'intuition. Le dictaphone inline a été unanimement préféré à l'overlay. L'image IA est devenue la feature la plus utilisée après la création de tâches basique. Et surtout, la correction gesture handler a résolu une douzaine de signalements de "boutons qui ne marchent pas" qu'on n'arrivait pas à reproduire en debug.
C'est la release qui a fait passer TAMSIV de "ça marche" à "c'est agréable". Et en build in public, c'est un jalon aussi important que le premier commit. J'en parlais dans le bilan à 650 commits : la qualité perçue fait la différence entre une app qu'on essaye et une app qu'on garde.
Questions fréquentes
Peut-on générer des images IA pour les mémos aussi ?
Actuellement, la génération d'images IA est disponible pour les tâches. Le mécanisme utilise la table privat.task_attachments avec le type ai_generated. L'extension aux mémos est prévue et techniquement simple puisque la table privat.memo_attachments existe déjà avec la même structure.
Le dictaphone inline fonctionne-t-il en arrière-plan ?
Non. Le dictaphone nécessite que l'app soit au premier plan pour la capture audio et l'affichage de la transcription en temps réel. C'est un choix délibéré : la reconnaissance vocale native du device est optimisée pour le foreground, et l'affichage immédiat de la transcription est la clé de l'expérience.
L'option skip TTS est-elle permanente ou par conversation ?
C'est un réglage permanent stocké dans le profil utilisateur. Une fois activé, toutes les conversations futures seront en mode texte uniquement. Tu peux le réactiver à tout moment depuis les paramètres.
Le bug gesture handler affecte-t-il encore l'app ?
Non. La migration a été complète et une règle de développement stricte a été mise en place : tout composant tactile à l'intérieur d'un GestureDetector doit obligatoirement utiliser les imports de react-native-gesture-handler. C'est vérifié à chaque code review.
Combien coûte la génération d'une image IA ?
Avec le provider Runware (HiDream-I1-Fast), environ 0,003 euros par image. Avec Gemini 2.5 Flash Image, légèrement plus. Les coûts sont maîtrisés par des quotas par plan d'abonnement : le plan Free n'a pas accès, Pro a un quota quotidien, Team un quota plus élevé.