Génération d'images IA dans une app de productivité
Permettre aux utilisateurs de générer des images pour leurs tâches, directement depuis l'app, par la voix. "Crée une image pour ma tâche" et hop, une illustration pertinente apparaît. Derrière cette simplicité se cache un pipeline technique avec deux providers d'images IA, un système de prompt engineering automatisé, quatre styles visuels, un fallback automatique et une gestion des coûts par plan d'abonnement.
La génération d'images IA dans une app de productivité, ce n'est pas un gadget. C'est une réponse à un constat : les tâches avec un visuel sont plus mémorables, plus engageantes et plus faciles à retrouver dans un feed. Et si l'utilisateur peut obtenir ce visuel en une phrase, sans quitter son workflow vocal, l'adoption est naturelle.
Points clés
- Deux providers d'images IA intégrés : Gemini 2.5 Flash Image pour la qualité et Runware HiDream-I1-Fast pour l'économie (~0,003 euros/image).
- Le LLM conversationnel génère automatiquement un prompt optimisé en analysant le titre, la description et les tags de la tâche.
- Quatre styles prédéfinis (flat, minimaliste, réaliste, aquarelle) modifient le prompt envoyé au modèle.
- Fallback automatique Gemini vers Runware avec retry et backoff exponentiel, piloté par l'admin depuis le dashboard.
Pourquoi intégrer deux providers d'images IA ?
Un seul provider, c'est un single point of failure. Si l'API tombe, si les quotas sont dépassés, si la qualité se dégrade : l'utilisateur n'a plus d'images. Deux providers, c'est de la résilience et de la flexibilité.
Gemini 2.5 Flash Image (via OpenRouter) est le provider par défaut. La qualité est excellente, la vitesse correcte (2-4 secondes par image). C'est le meilleur rapport qualité/vitesse que j'ai testé. Le modèle comprend bien les prompts complexes avec plusieurs sujets, des styles artistiques spécifiques et des compositions détaillées.
Runware HiDream-I1-Fast est l'alternative économique. À environ 0,003 euros par image, c'est 5 à 10 fois moins cher que Gemini selon le prompt. La qualité est légèrement inférieure sur les prompts complexes, mais parfaitement suffisante pour des illustrations de tâches. Et la vitesse est comparable.
L'admin bascule entre les deux depuis le dashboard d'administration. C'est un toggle dans la table app_config de Supabase. Pourquoi un toggle admin et pas un choix utilisateur ? Parce que le coût est porté par le service, pas par l'utilisateur. C'est à moi de décider quel provider optimise le ratio qualité/coût en fonction du volume d'utilisation.
Comment le LLM génère-t-il le prompt parfait ?
Demander à un utilisateur d'écrire un bon prompt d'image, c'est irréaliste. Les modèles de génération d'image sont sensibles à la formulation. "Un chat" donne un résultat générique. "A domestic shorthair cat sitting on a windowsill, golden hour sunlight, shallow depth of field, photorealistic, warm tones" donne une image professionnelle.
La différence entre les deux ? Du prompt engineering. Et c'est exactement le job du LLM conversationnel de TAMSIV.
Quand l'utilisateur demande une image, le LLM analyse trois sources de contexte :
- Le titre de la tâche : "Préparer la présentation client Q2" → le LLM comprend qu'il faut un visuel professionnel.
- La description : "Inclure les chiffres de vente et le graphique de croissance" → le LLM ajoute des éléments de data visualization au prompt.
- Les tags/dossier : si la tâche est dans le dossier "Marketing", le LLM oriente le style vers du branding.
Le prompt est toujours généré en anglais, même si l'utilisateur parle en français. Pourquoi ? Parce que les modèles d'images sont entraînés majoritairement sur des données anglophones. Un prompt en anglais donne systématiquement de meilleurs résultats. C'est le même constat que j'avais fait pour le système i18n en 6 langues : la langue de travail interne n'est pas forcément la langue de l'utilisateur.
Le LLM ajoute aussi des modificateurs techniques automatiquement : résolution, éclairage, composition. Ces modificateurs sont calibrés pour le provider actif. Gemini et Runware n'interprètent pas les prompts de la même façon, donc le LLM adapte sa formulation. Selon les bonnes pratiques d'OpenAI sur le prompting d'images, les modificateurs de style et de composition sont les facteurs qui influencent le plus la qualité du résultat.
Quels sont les quatre styles visuels disponibles ?
Chaque style modifie le prompt envoyé au modèle en ajoutant des suffixes et modificateurs spécifiques :
Style Flat (illustrations vectorielles)
Ajoute : "flat vector illustration, clean lines, solid colors, minimal shading, modern graphic design style". Idéal pour les tâches professionnelles et les présentations. Le rendu est propre et imprimable.
Style Minimaliste
Ajoute : "minimalist, simple composition, lots of white space, single focal point, clean aesthetic". Parfait pour les tâches personnelles. Le rendu est épuré et apaisant.
Style Réaliste
Ajoute : "photorealistic, high detail, natural lighting, shallow depth of field, 4K quality". Le rendu le plus proche d'une photo. Idéal quand tu veux un visuel concret de ce que tu imagines.
Style Aquarelle
Ajoute : "watercolor painting, soft edges, flowing colors, artistic, hand-painted look". Le rendu le plus créatif. Idéal pour les projets artistiques ou les tâches créatives.
Le choix du style est optionnel. Si l'utilisateur ne précise pas, le LLM choisit le style le plus adapté au contexte de la tâche. Une tâche "Préparer les courses" sera en style minimaliste. Une tâche "Designer le logo du nouveau produit" sera en style flat. C'est une décision contextuelle, pas aléatoire. La même philosophie que pour la personnalisation vocale : l'IA s'adapte sans qu'on le lui demande.
Comment fonctionne le pipeline technique de bout en bout ?
Le pipeline complet, de la demande utilisateur à l'affichage de l'image, enchaîne 6 étapes avec des points de failure potentiels à chaque transition :
- Demande utilisateur → transcription STT → texte envoyé au backend via WebSocket.
- Analyse LLM → le LLM conversationnel détecte l'intention de générer une image et appelle le function tool
create_taskavec un flaggenerate_image: true. - Prompt engineering → le backend passe le contexte de la tâche au LLM qui génère un prompt optimisé.
- Appel provider → le backend envoie le prompt au provider configuré (Gemini ou Runware).
- Upload Storage → l'image reçue (base64 ou URL) est uploadée vers Supabase Storage dans le bucket dédié. Un enregistrement est créé dans
privat.task_attachmentsavectype: 'ai_generated',storage_pathet les métadonnées. - Affichage → le frontend reçoit la confirmation via WebSocket, génère une URL signée et affiche l'image dans la carte de tâche.
Chaque étape peut échouer. Le STT peut mal transcrire. Le LLM peut ne pas détecter l'intention. Le provider peut timeout. L'upload peut échouer. La stratégie : retry avec backoff exponentiel à chaque étape, et fallback automatique entre providers si le provider principal échoue 3 fois consécutives.
Le fallback Gemini vers Runware (ou inversement) est automatique et transparent pour l'utilisateur. Il ne voit pas que le provider a changé. Il voit juste son image apparaître, peut-être avec 2 secondes de plus. C'est la même philosophie de résilience que dans le système STT natif vs Deepgram : toujours avoir un plan B.
Comment les coûts sont-ils maîtrisés par plan d'abonnement ?
La génération d'images IA a un coût direct par image. Même à 0,003 euros par image avec Runware, si 10 000 utilisateurs génèrent 3 images par jour, ça fait 900 euros par mois. Il faut des garde-fous.
Le système de limites par plan utilise RevenueCat et les plans d'abonnement :
- Plan Free : pas d'accès à la génération d'images. C'est une feature premium qui justifie l'upgrade.
- Plan Pro : quota quotidien de N images par jour (configurable côté admin).
- Plan Team : quota quotidien plus élevé, partagé entre les membres du groupe.
Le compteur est géré côté backend, pas côté frontend (pour éviter la triche). Chaque génération incrémente un compteur dans la DB avec un reset quotidien via un cron job. Si le quota est atteint, le backend renvoie une erreur explicite et le frontend affiche un message clair : "Quota d'images atteint pour aujourd'hui. Réessaye demain ou passe au plan Team."
Le dashboard admin affiche les statistiques de consommation en temps réel : nombre d'images générées par jour, coût moyen par image, ratio Gemini/Runware, taux d'échec par provider. Ces métriques sont cruciales pour ajuster les quotas et choisir le provider optimal. J'avais déjà mis en place ce type de monitoring dans le dashboard admin analytics.
Pourquoi les utilisateurs adorent-ils cette feature ?
Le retour le plus fréquent des testeurs : "J'ai pas l'impression d'utiliser de l'IA, c'est juste naturel." C'est le meilleur compliment possible. L'IA est invisible. L'utilisateur dit "crée une tâche pour le barbecue de samedi avec une image" et il obtient une tâche avec une illustration de barbecue. Pas de sélection de modèle. Pas de réglage de paramètres. Pas de prompt à écrire.
Une tâche avec une image est immédiatement plus engageante qu'une tâche texte-only. Dans le feed avec gamification, les tâches illustrées attirent le regard. C'est un principe de design bien documenté : les contenus avec images génèrent selon Social Media Examiner 2 à 3 fois plus d'engagement que les contenus texte seuls.
Et c'est aussi un facteur de différenciation. Aucune app de gestion de tâches ne propose de génération d'images IA intégrée dans le flux vocal. C'est un avantage compétitif concret par rapport aux alternatives comme Todoist ou TickTick, que j'avais comparées dans l'article comparatif.
Quel est l'avenir de la génération d'images dans TAMSIV ?
Le système actuel est une base solide. Mais plusieurs évolutions sont prévues. L'extension aux mémos, d'abord : la table privat.memo_attachments existe déjà avec la même structure que privat.task_attachments, comme détaillé dans l'article sur les pièces jointes.
L'édition d'images ensuite : pouvoir dire "change le fond en bleu" ou "ajoute du texte" sur une image existante. Les APIs de Gemini et Runware supportent déjà l'image-to-image. Et la génération collaborative : dans un groupe, un membre génère une image et les autres la voient en temps réel via le canal Realtime.
L'objectif reste le même : rendre l'IA invisible. Plus la technologie est puissante, plus elle doit être simple à utiliser.
Questions fréquentes
Quels formats d'image sont générés ?
Les images sont générées en JPEG avec une qualité de 95%. La résolution standard est de 1024x1024 pixels. Les images sont optimisées pour l'affichage mobile mais restent de qualité suffisante pour un usage desktop via le dashboard web.
Peut-on régénérer une image si le résultat ne convient pas ?
Oui. L'utilisateur peut demander une nouvelle génération à tout moment. L'ancienne image est conservée dans le storage et la nouvelle la remplace dans l'affichage. Le quota quotidien est décrémenté à chaque génération.
L'image générée est-elle stockée de manière permanente ?
Oui. L'image est uploadée dans Supabase Storage et liée à la tâche via privat.task_attachments. Elle reste disponible tant que la tâche existe. La suppression de la tâche entraîne la suppression en cascade de l'image.
Le prompt généré par le LLM est-il visible pour l'utilisateur ?
Non, par défaut. Le prompt est technique et en anglais, ce qui ne serait pas utile pour la majorité des utilisateurs. Cependant, le prompt est loggé côté backend pour le debugging et l'amélioration continue du système.
La génération d'images fonctionne-t-elle hors ligne ?
Non. La génération nécessite un appel API vers le provider d'images (Gemini ou Runware) et un upload vers Supabase Storage. Une connexion internet est indispensable. L'app affiche un message d'erreur clair si la connexion est absente.