IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Générer un script Python avec des outils d'IA

-Tutoriel-


précédentsommaire

3. Introduction

On se propose ici de reprendre un problème exposé en 2020 dans le cours [python3-flask-2020]. Ce cours prenait comme base un calcul d’impôt simplifié pour l’année 2019. Un script Python était développé pour résoudre le problème puis décliné en de multiples versions (18) jusqu’à porter le calcul de l’impôt dans une application web MVC.

On se propose ici de montrer que le script initial du calcul de l’impôt peut être désormais généré par des outils d’IA (Intelligence Artificielle). On a utilisé six outils : ChatGPT, Grok, Gemini, MistralAI, DeepSeek et ClaudeAI. Il en existe d’autres.

Le document ne nécessite pas forcément de connaître le langage Python. Les six outils vont générer un script Python comportant 11 tests unitaires. Il suffit de charger ce code dans un environnement de travail Python, de l’exécuter et de vérifier que les 11 tests sont réussis. Ensuite ce code généré peut être considéré comme « probablement correct ». L’utilisateur Python lui s’intéressera davantage au code. Il s’apercevra alors que les scripts Python générés sont en général très bien écrits.

Par ailleurs, ce document montre que les outils d’IA utilisés sont d’un usage plutôt facile et que le dialogue entre l’utilisateur (vous) et l’outil d’IA n’est pas différent de celui qu’aurait un enseignant avec son élève / étudiant.

Ce document a été écrit en septembre 2025. L’IA évolue vite et il est possible que les copies d’écran qui suivent deviennent rapidement obsolètes. Si vous posez les mêmes questions que le document, il est très plausible que vous obteniez des réponses différentes que celles obtenues ici. Suivez simplement le processus d’affinage de vos instructions, montré ici, pour aider l’IA.

Vous pouvez télécharger les codes et fichiers de ce tutoriel à l’adresse : [Générer un script Python avec des outils d'IA] (cloud OneDrive):

Image non disponible

Image non disponible

4. Les trois problèmes étudiés et les résultats

On va demander aux IA d’étudier trois problèmes du plus simple au plus compliqué. Regardons une copie d’écran de Google Gemini :

Image non disponible

 
  • En [1], l’URL de Gemini ;
  • En [2], la version de Gemini utilisée ;
  • En [3-5], les trois problèmes posés à Gemini ;

4-1. Problème 1

Le problème 1 est une simple question :

Image non disponible

 

Toutes les IA répondront correctement à cette question.

4-2. Problème 2

Le problème 2 est le suivant (copie d’écran de Gemini) :

Image non disponible

 
  • En [1], le principe du calcul de l’impôt 2019 sur les revenus 2018 est expliqué dans un PDF. Nous y reviendrons ;
  • En [2], on donne des instructions précises à Gemini sur ce qu’on veut, un script Python propre qui résout le problème posé et qui valide la solution proposée avec 11 tests unitaires ;
  • En [3], pour lancer Gemini on doit écrire quelque chose ;

On est là exactement dans le même cas que celui d’un TD donné à l’université.

Là encore, toutes les IA testées vont résoudre le problème mais plus ou moins rapidement. Gemini donne un code correct et rapidement.

4-3. Problème 3

Toujours avec une copie d’écran de Google Gemini, le problème 3 est le suivant :

Image non disponible

 
  • En [1] on donne nos instructions, les mêmes que précédemment. Mais comme on ne donne pas le PDF qui donnait les règles exactes de calcul, l’IA va devoir chercher ces règles sur internet ;
  • En [3], on lance l’exécution de l’IA ;

Seules trois IA ont passé ce test, dans l’ordre d’excellence (avis strictement personnel, cela va de soi) :

  1. ChatGPT d’OpenAI ;
  2. Grok de xAI ;
  3. Google Gemini ;

L’IA ClaudeAI a échoué sur le problème 3. L’IA MistralAI a échoué sur les problèmes 2 et 3. L’IA DeepSeek a échoué sur le problème 3.

5. Installation d'un environnement de travail

Nous montrons ici l’environnement de travail utilisé pour tester les scripts Python générés par l’IA. Ce paragraphe est pour les débutants en Python. Si vous avez déjà un environnement de travail Python, passez la totalité de ce paragraphe et allez au paragraphe suivant.

5-1. Python 3.13.7

Les exemples de ce document ont été testés avec l'interpréteur Python 3.13.7 disponible à l'URL |https://www.python.org/downloads/| (août 2025) sur une machine Windows 10 :

Une image contenant texte, capture d’écran, logiciel, Page web

Le contenu généré par l’IA peut être incorrect.

En [1-2] téléchargez l’exécutable de l’installateur de Python puis exécutez-le.

L'installation de Python donne naissance à l'arborescence de fichiers [1] suivante :

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

Pour exécuter Python en mode interactif, double-cliquez sur [2]. Voici un exemple de code Python à exécuter :

Une image contenant texte, capture d’écran, Police

Le contenu généré par l’IA peut être incorrect.

Le prompt >>> permet d'émettre une instruction Python qui est immédiatement exécutée. Le code tapé ci-dessus a la signification suivante :

 
Sélectionnez
>>> nom="tintin"
>>> print("nom=%s" % nom)
nom=tintin
>>> print("type=%s" % type(nom))
type=<class 'str'>
>>>

Lignes :

  • 1 : initialisation d'une variable. En Python, on ne déclare pas le type des variables. Celles-ci ont automatiquement le type de la valeur qu'on leur affecte. Ce type peut changer au cours du temps ;
  • 2 : affichage du nom. 'nom=%s' est un format d'affichage où %s est un paramètre formel désignant une chaîne de caractères. nom est le paramètre effectif qui sera affiché à la place de %s ;
  • 3 : le résultat de l'affichage ;
  • 4 : l'affichage du type de la variable nom ;
  • 5 : la variable nom est ici de type class. Avec Python 2.7 elle aurait la valeur <type 'str'> ;

Maintenant, ouvrons une console Windows :

Une image contenant texte, capture d’écran, Police

Le contenu généré par l’IA peut être incorrect.

Le fait qu'on ait pu taper [python] en [1] et que l'exécutable [python.exe] ait été trouvé montre que celui-ci est dans le PATH de la machine Windows. C'est important car cela signifie que les outils de développement Python sauront trouver l'interpréteur Python. On peut le vérifier ainsi :

Une image contenant texte, capture d’écran, logiciel, Site web

Le contenu généré par l’IA peut être incorrect.

  • En [1], on quitte l'interpréteur Python ;
  • En [2], la commande qui affiche le PATH des exécutables de la machine Windows ;
  • En [3], on voit que le dossier de l'interpréteur Python 3.13 fait partie du PATH ;

5-2. L'IDE PyCharm Community

Pour construire et exécuter les scripts de ce document, nous avons utilisé l'éditeur [PyCharm] Edition Community disponible (août 2025) à l'URL |https://www.jetbrains.com/fr-fr/pycharm/download/#section=windows| :

Une image contenant texte, capture d’écran, logiciel, Page web

Une image contenant texte, capture d’écran, Police, logo

Le contenu généré par l’IA peut être incorrect.

Téléchargez l'IDE PyCharm Community (ici pour Windows) [1-4] et installez-le.

Lançons l'IDE PyCharm. Un panneau de configuration apparaît :

Une image contenant texte, capture d’écran, logiciel, Police

Le contenu généré par l’IA peut être incorrect.

  • En [1] pour créer l’icône PyCharm sur le bureau ;
  • En [2] pour ouvrir n’importe quel dossier du système de fichiers comme un projet Python ;
  • En [3], les fichiers Python auront le suffixe .py ;
  • En [4], passer à l’étape suivante ;

La fenêtre suivante propose de nouveau de la configuration [1] :

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

  • En [2], on prend le thème [Light]. Le lecteur prendra le thème de son choix ;
  • En [3], on laisse l’IDE en anglais ;
  • En [4], on garde les raccourcis de Windows ;

Créons un premier projet Python [1-2] :

Une image contenant texte, capture d’écran, Police, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

Cela ouvre la fenêtre suivante :

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

  • En [2], indiquer le nom du dossier à créer pour le projet ;
  • En [3], indiquer que les différentes versions du code qui seront sauvegardées seront gérées par le gestionnaire de versions Git. PyCharm permet d’en utiliser d’autres ;
  • En [4-6], indiquer que votre projet va utiliser un environnement virtuel. L’environnement virtuel va créer un dossier [.venv] à la racine du projet. Tous les plugins (packages) utilisés par votre projet iront dans ce dossier. Cela assure une étanchéité entre projets lorsqu’il y a recherche de plugins. Le projet ne cherche ses plugins que dans son propre environnement virtuel [.venv] et pas ailleurs où il pourrait trouver des plugins de mêmes noms mais de versions peut-être différentes qui sont parfois partiellement incompatibles entre elles ;

L'IDE PyCharm présente le projet créé sous la forme suivante :

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

  • En [1-2], l’arborescence du projet ;
  • En [3], le dossier du projet ;
  • En [4], le dossier de l’environnement virtuel du projet. C’est dans ce dossier que s’installeront les plugins que nous utiliserons pour le projet ;

Avant de commencer à coder, allons plus loin dans la configuration de l’IDE :

Une image contenant texte, capture d’écran, Police, logo

Le contenu généré par l’IA peut être incorrect.

  • Cliquer sur [1] pour faire apparaître le menu principal ;

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

  • En [1-2], configurez l’IDE ;

    Une image contenant texte, capture d’écran, logiciel, Police

Le contenu généré par l’IA peut être incorrect.

  • En [1-4], indiquez que vous voulez voir le menu principal au-dessus de la barre d’outils principale. Rien ne vous y oblige. On le fait ici pour éclairer les copies d’écran qui sont produites dans ce document. Validez votre changement ;

    Désormais, le menu principal est toujours affiché [1] :

    Continuons la configuration de l’IDE :

    Une image contenant texte, capture d’écran, horloge, Police

Le contenu généré par l’IA peut être incorrect.

    En haut à droite de la fenêtre de PyCharm, on propose d’essayer la version pro de PyCharm. Selon la façon dont vous avez installé PyCharm, il se peut même que la version pro ait été installée d’office (2025). Cela amène des options de menu supplémentaires.

    Une image contenant capture d’écran, texte, Police, nombre

Le contenu généré par l’IA peut être incorrect.

    Si vous avez installé la version pro d’évaluation pour un essai d’un mois, vous avez le message [2] en haut à droite.

    Toujours pour la cohérence des copies d’écran qui vont suivre, je montre comment annuler la version d’essai pro de l’IDE (vous pouvez y revenir quand vous voulez) :

    Une image contenant texte, capture d’écran, logiciel, Page web

Le contenu généré par l’IA peut être incorrect.

  • En [1-2], gérez les souscriptions de votre IDE ;

    Une image contenant texte, Police, ligne, logiciel

Le contenu généré par l’IA peut être incorrect.

  • En [1], désactivez la version pro. L’IDE va se relancer ;

    Maintenant configurons l’interpréteur Python qui va exécuter notre projet. Nous nous souvenons d’en avoir téléchargé un lors d’une étape précédente :

    Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

    Une image contenant texte, capture d’écran, Police, ligne

Le contenu généré par l’IA peut être incorrect.

  • En [1-3], nous configurons l’interpréteur Python du projet ;

  • En [4], le chemin de l’interpréteur ;

  • En [5], les packages (plugins) associés à cet interpréteur ;

En [4], découvrons le chemin complet de l’interpréteur utilisé :

Une image contenant texte, Police, ligne, nombre

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, ligne, capture d’écran

Le contenu généré par l’IA peut être incorrect.

  • En [3], on découvre que l’interpréteur Python utilisé se trouve dans le dossier de l’environnement virtuel du projet [.venv] ;

    Il est possible de changer d’interpréteur Python, ce qui peut changer les plugins disponibles au projet :

    Une image contenant texte, ligne, Police, capture d’écran

Le contenu généré par l’IA peut être incorrect.

  • En [4], ajoutez un interpréteur Python ;

    Une image contenant texte, capture d’écran, Police, logo

Le contenu généré par l’IA peut être incorrect.

  • En [5], ajoutez un interpréteur local. PyCharm va alors explorer le PATH de la machine à la recherche d’un binaire [python.exe] ;

    Une image contenant texte, Police, ligne, nombre

Le contenu généré par l’IA peut être incorrect.

  • En [1], indiquez que le nouvel interpréteur doit utiliser l’environnement virtuel [.venv] existant du projet ;

  • En [2], l’IDE propose comme interpréteur l’application Python installée dans une étape précédente ;

  • Validez ce choix ;

Une image contenant texte, capture d’écran, logiciel, nombre

Le contenu généré par l’IA peut être incorrect.

  • En [4], le nouvel interpréteur ;
  • En [5], les packages auxquels aura accès le projet. C’est la principale différence amenée par le changement d’interpréteur. Si vous gérez plusieurs projets qui utilisent différents packages il est préférable d’utiliser les packages de l’environnement virtuel de chaque projet. Ainsi vous avez le contrôle des versions des plugins que vous utilisez. Pour cette raison, nous garderons l’interpréteur de l’environnement virtuel :

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, ligne, nombre

Le contenu généré par l’IA peut être incorrect.

Allons un peu plus loin dans la configuration :

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, nombre, ligne

Le contenu généré par l’IA peut être incorrect.

  • En [1-2], entrez dans le mode configuration de l’IDE ;
  • En [3-4], configurez des options du système ;
  • En [5], pas de confirmation avant de quitter l’IDE ;
  • En [6], lorsqu’on quitte l’IDE et qu’il y a un processus en cours d’exécution lancé par le code exécuté, on arrête celui-ci ;
  • En [7], lorsque l’IDE est lancée, on ne rouvre pas automatiquement le dernier projet utilisé. On laisse l’utilisateur choisir son projet ;
  • En [8], lorsque l’utilisateur gère plusieurs projets en même temps, chaque projet a sa fenêtre personnelle ;
  • En [9], on a désigné le dossier par défaut de notre projet ;

Maintenant nous pouvons commencer à coder. Commençons par créer un dossier dans lequel nous mettrons notre premier script Python :

Une image contenant texte, logiciel, Icône d’ordinateur, Police

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, carte de visite

Le contenu généré par l’IA peut être incorrect.

  • Cliquer droit sur le projet, puis [1-3] pour créer un dossier ;
  • En [4], tapez le nom du dossier : il sera créé dans le dossier du projet ;

Une image contenant texte, capture d’écran, logiciel, Police

Le contenu généré par l’IA peut être incorrect.

Puis créons un script Python :

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police

Le contenu généré par l’IA peut être incorrect.

Cliquer droit sur le dossier [bases], puis [1-4] :

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, logiciel, Page web

Le contenu généré par l’IA peut être incorrect.

  • Rappelons-nous ici que nous avons inclus le gestionnaire de versions Git à notre projet. Cela s’est fait lors de la création du projet où nous avons coché l’option Git. Git peut prendre des photos du projet à différentes étapes de celui-ci. Ici en [1-3], l’IDE nous demande si nous voulons inclure le fichier [bases.py] que nous sommes en train de créer dans la photo. Nous répondons oui [3]. Par ailleurs nous cochons [2] pour que cela soit fait systématiquement à la création d’un fichier. Nous reviendrons brièvement sur Git un peu plus loin ;
  • En [4-5], le script [bases_01] a été créé et est prêt à être édité ;

Écrivons notre premier script :

Une image contenant texte, Police, ligne, nombre

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, logiciel, Page web

Le contenu généré par l’IA peut être incorrect.

  • Lignes 1, 3 : les commentaires commencent avec le signe # ;
  • Ligne 2 : initialisation d'une variable. Python ne déclare pas le type de ses variables ;
  • Ligne 4 : affichage écran. La syntaxe utilisée ici est [format % données] avec :

    • format : nom=%s où %s désigne l'emplacement d'une chaîne de caractères. Celle-ci sera trouvée dans la partie [données] de l'expression ;
    • données : la valeur de la variable [nom] viendra remplacer le format %s dans la chaîne de format ;
  • Avec [1-2], on reformate le code selon les recommandations de l'organisme gérant Python. On peut aussi taper au clavier la séquence Ctrl-Alt-L ;

Sur la copie d’écran on voit que certains textes sont soulignés. PyCharm signale des erreurs d’orthographe dans les commentaires et chaînes de caractères. Il les appelle des typos. Il est par défaut configuré pour des textes en anglais. Pour éviter le signalement des typos en français, procédons comme suit :

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, logiciel, nombre

Le contenu généré par l’IA peut être incorrect.

  • En [1-2], configurons l’IDE ;
  • En [3-6], désactivons l’option [Proofreading] de l’éditeur ;

Une image contenant texte, Police, capture d’écran, ligne

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, capture d’écran

Le contenu généré par l’IA peut être incorrect.

En [7], le signalement des typos a disparu. Le script est exécuté avec un clic sur l’icône [8] de la barre d’outils principale. Le résultat est le suivant :

Une image contenant texte, ligne, Police, capture d’écran

Le contenu généré par l’IA peut être incorrect.

  • En [1-2], une fenêtre de résultats s’est ouverte ;
  • En [3], on voit que le code de [bases_01.py] a été exécuté par l’interpréteur Python de l’environnement virtuel du projet ;
  • En [4], le résultat de l’exécution ;

Pour exécuter les scripts de ce document, téléchargez le code à l'URL |Générer un script Python avec des outils d'IA| (cloud OneDrive) puis dans PyCharm procédez comme suit :

Une image contenant texte, capture d’écran, Police, Téléphone mobile

Le contenu généré par l’IA peut être incorrect.

   
  • En [1-2], fermez le projet sur lequel vous êtes en train de travailler ;

    Une image contenant texte, capture d’écran, Police, ligne

Le contenu généré par l’IA peut être incorrect.

  • En [1], on choisit l’option [Projects] ;

  • Dans la fenêtre [2], on a la liste des derniers projets sur lesquels on a travaillé ;

  • En [3], on indique qu’on veut ouvrir un projet existant ;

Image non disponible

 
  • En [1], on ouvre le dossier qu’on a téléchargé ;

    Image non disponible

     
  • En [1-2], le projet PyCharm ;

    Configurons ce projet pour qu’il ait un environnement virtuel d’exécution :

    Image non disponible

     
  • En [1-2], on configure le nouveau projet ;

    Image non disponible

     
  • En [3-4], on configure un interpréteur pour le projet ;

    Image non disponible

     
  • En [5-6], on choisit un environnement virtuel d’exécution ;

    Image non disponible

     
  • En [7], le nouvel interpréteur Python utilisé pour le projet ;

Ceci fait, vous pouvez exécuter les scripts du projet :

Image non disponible

 

6. Résolution des trois problèmes avec Google Gemini

Nous allons donner les copies d’écran des trois sessions Gemini qui ont permis de résoudre les trois problèmes posés. Nous irons assez dans les détails. Ceci fait, nous ne répéterons pas le processus pour les cinq autres IA testées. Elles fonctionnent de manière analogue. Nous ne donnerons que les détails frappants.

6-1. Introduction

Nous rappelons la première copie d’écran de Gemini donnée précédemment :

Une image contenant texte, capture d’écran, logiciel, Icône d’ordinateur

Description générée automatiquement

 
  • En [1], l’URL de Gemini ;
  • En [2], la version de Gemini utilisée ;
  • En [3-5], les trois problèmes posés à Gemini ;

Gemini est un produit de Google disponible à l’URL [https://gemini.google.com/]. Pour avoir un historique de vos sessions de questions / réponses comme ci-dessus, il vous faut créer un compte. Par ailleurs, comme toutes les autres IA testées, Gemini limite le nombre de vos questions et le nombre de fichiers téléchargés. Quand cette limite est atteinte, la session est terminée et on vous propose de la continuer plus tard dans le temps. Comme il est assez frustrant de s’arrêter en plein milieu d’une session, j’ai pris un abonnement. Le premier mois de l’abonnement Gemini est par chance gratuit. J’ai fait de même avec les autres IA qui avaient ces limites, à savoir ChatGPT, MistralAI, ClaudeAI. J’ai pris un abonnement d’un mois, mais là le premier mois était payant. Je n’ai pas rencontré de limites avec Grok. DeepSeek n’annonce pas de limites mais répond parfois [Server busy] et interrompt la session. Ça revient à mettre des limites sans le dire.

Dans la suite, je parlerai de session de questions / réponses, raccourcie à session simplement. Les IA utilisent le plus souvent le terme anglais chat (discussion) ou conversation.

L’interface de Gemini pour poser une question est la suivante :

Image non disponible

Image non disponible

  • En [1], votre question ;
  • En [2], l’icône qui lance l’IA pour le calcul de la réponse ;
  • En [3-4], vous pouvez joindre des fichiers ;

6-2. Le problème 1

La session pour le problème 1 est la suivante :

Image non disponible

 
  • En [1], la question ;
  • En [2], le début de la réponse de Gemini ;

La suite de la réponse est la suivante :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

La réponse est correcte. Les cinq autres IA donneront également la bonne réponse sous une forme analogue.

6-3. Le problème 2

6-3-1. Introduction

On rappelle ici le problème initial du cours [python3-flask-2020]. C’est un texte donné en TD à des étudiants.

   

Le tableau ci-dessus permet de calculer l’impôt dans le cas simplifié d'un contribuable n'ayant que son seul salaire à déclarer. Comme l’indique la note (1), l’impôt ainsi calculé est l’impôt avant trois mécanismes :

  • Le plafonnement du quotient familial qui intervient pour les hauts revenus ;
  • La décote et la réduction d’impôts qui interviennent pour les faibles revenus ;

Ainsi le calcul de l’impôt comprend les étapes suivantes [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php] :

   

On se propose d'écrire un programme permettant de calculer l'impôt d'un contribuable en 2019 dans le cas simplifié d'un contribuable n'ayant que son seul salaire à déclarer.

6-3-1-1. Calcul de l’impôt brut

L’impôt brut peut être calculé de la façon suivante :

On calcule d’abord le nombre de parts du contribuable :

  • Chaque parent amène 1 part ;
  • Les deux premiers enfants amènent chacun 1/2 part ;
  • Les enfants suivants amènent une part chacun :

    Le nombre de parts est donc :

  • nbParts=1+nbEnfants*0,5+(nbEnfants-2)*0,5 si le salarié n’est pas marié ;

  • nbParts=2+nbEnfants*0,5+(nbEnfants-2)*0,5 s'il est marié ;

  • nbEnfants est son nombre d'enfants ;

  • On calcule le revenu imposable R=0.9*SS est le salaire annuel ;

  • On calcule le quotient familial QF=R/nbParts ;

  • On calcule l’impôt brut I d'après les données suivantes (2019) :

9964

0

0

27519

0.14

1394.96

73779

0.3

5798

156244

0.4

13913.69

0

0.45

20163.45

Chaque ligne a 3 champs : champ1, champ2, champ3. Pour calculer l'impôt I, on recherche la première ligne où QF<=champ1 et on prend les valeurs de cette ligne. Par exemple, pour un salarié marié avec deux enfants et un salaire annuel S de 50000 euros :

Revenu imposable : R=0,9*S=45000

Nombre de parts : nbParts=2+2*0,5=3

Quotient familial : QF=45000/3=15000

La 1re ligne où QF<=champ1 est la suivante :

 
Sélectionnez
27519    0.14    1394.96

L'impôt I est alors égal à 0.14*R – 1394,96*nbParts=[0,14*45000-1394,96*3]=2115. L’impôt est arrondi à l’euro inférieur.

Si la relation QF<=champ1 dès la 1re ligne, alors l’impôt est nul.

Si QF est tel que la relation QF<=champ1 n'est jamais vérifiée, alors ce sont les coefficients de la dernière ligne qui sont utilisés. Ici :

 
Sélectionnez
0    0.45    20163.45

ce qui donne l'impôt brut I=0.45*R – 20163,45*nbParts.

6-3-1-2. Plafonnement du quotient familial
   

Pour savoir si le plafonnement du quotient familial QF s’applique, on refait le calcul de l’impôt brut sans les enfants. Toujours pour le salarié marié avec deux enfants et un salaire annuel S de 50000 euros :

Revenu imposable : R=0,9*S=45000

Nombre de parts : nbParts=2 (on ne compte plus les enfants)

Quotient familial : QF=45000/2=22500

La 1re ligne où QF<=champ1 est la suivante :

 
Sélectionnez
27519    0.14    1394.96

L'impôt I est alors égal à 0.14*R – 1394,96*nbParts=[0,14*45000-1394,96*2]=3510.

Gain maximal lié aux enfants : 1551 * 2 = 3102 euros

Impôt minimal : 3510-3102 = 408 euros

L’impôt brut avec 2 parts déjà calculé au paragraphe précédent 2115 euros est supérieur à l’impôt minimal 408 euros, donc le plafonnement familial ne s’applique pas ici.

De façon générale, l’impôt brut est sup(impôt1, impôt2) où :

  • [impôt1] : est l’impôt brut calculé avec les enfants ;
  • [impôt2] : est l’impôt brut calculé sans les enfants et diminué du gain maximal (ici 1551 euros par demi-part) lié aux enfants ;
6-3-1-3. Calcul de la décote
   

Toujours pour le salarié marié avec deux enfants et un salaire annuel S de 50000 euros :

L’impôt brut (2115 euros) issu de l’étape précédente est inférieur à 2627 euros pour un couple (1595 euros pour un célibataire) : la décote s’applique donc. Elle est obtenue avec le calcul suivant :

décote= seuil (couple=1970/célibataire=1196)-0,75* Impôt brut

décote=1970-0,75*2115=383,75 arrondi à 384 euros.

Nouvel Impôt brut= 2115-384= 1731 euros

Il faut observer deux règles dans le calcul de la décote (certains outils d’IA ont buté sur cette question) :

  • La décote ne peut être négative ;
  • La décote ne peut être supérieure à l’impôt déjà calculé ;
6-3-1-4. Calcul de la réduction d’impôts
   

Au-dessous d’un certain seuil, une réduction de 20 % est faite sur l’impôt brut issu des calculs précédents. En 2019, les seuils sont les suivants :

  • célibataire : 21037 euros ;
  • couple : 42074 euros ; (le chiffre 37968 utilisé dans l’exemple ci-dessus semble erroné) ;

    Ce seuil est augmenté de la valeur : 3797 * (nombre de demi-parts amenées par les enfants).

    Toujours pour le salarié marié avec deux enfants et un salaire annuel S de 50000 euros :

  • Son revenu imposable (45000 euros) est inférieur au seuil (42074+2*3797)=49668 euros ;

  • Il a donc droit à une réduction de 20 % de son impôt : 1731 * 0,2= 346,2 euros arrondi à 347 euros ;

  • L’impôt brut du contribuable devient : 1731-347= 1384 euros ;
6-3-1-5. Calcul de l’impôt net

Notre calcul s’arrêtera là : l’impôt net à payer sera de 1384 euros. Dans la réalité, le contribuable peut bénéficier d’autres réductions notamment pour des dons à des organismes d’intérêt public ou général.

6-3-1-6. Cas des hauts revenus

Notre exemple précédent correspond à la majorité des cas de salariés. Cependant le calcul de l’impôt est différent dans le cas des hauts revenus.

Plafonnement de la réduction de 10 % sur les revenus annuels

Dans la plupart des cas, le revenu imposable est obtenu par la formule : R=0,9*S où S est le salaire annuel. On appelle cela la réduction des 10 %. Cette réduction est plafonnée. En 2019 :

  • Elle ne peut être supérieure à 12502 euros ;
  • Elle ne peut être inférieure à 437 euros ;

    Prenons le cas d’un salarié non marié sans enfants et un salaire annuel de 200000 euros :

  • La réduction de 10 % est de 20000 euros > 12502 euros. Elle est donc ramenée à 12502 euros ;

    Plafonnement du quotient familial

    Prenons un cas où le plafonnement familial présenté au paragraphe |Plafonnement du quotient familial|, intervient. Prenons le cas d’un couple avec trois enfants et des revenus annuels de 100000 euros. Reprenons les étapes du calcul :

  • L’abattement de 10 % est de 100000 euros < 12502 euros. Le revenu imposable R est donc 100000-10000=90000 euros ;

  • Le couple a nbParts=2+0,5*2+1=4 parts ;

  • Son quotient familial est donc QF= R/nbParts=90000/4=22500 euros ;

  • Son impôt brut I1 avec enfants est I1=0,14*90000-1394,96*4= 7020 euros ;

  • Son impôt brut I2 sans enfants :

  • QF=90000/2=45000 euros ;

  • I2=0,3*90000-5798*2=15404 euros ;

  • La règle du plafonnement du quotient familial dit que le gain amené par les enfants ne peut dépasser (1551*4 demi-parts)=6204 euros. Or ici, il est I2-I1=15404-7020= 8384 euros, donc supérieur à 6204 euros ;

  • L’impôt brut est donc recalculé comme I3=I2-6204=15404-6204= 9200 euros ;

  • Comme I3>I1, ce sera l’impôt I3 qui sera conservé ;

Ce couple n’aura ni décote, ni réduction et son impôt final sera de 9200 euros.

6-3-1-7. Chiffres officiels

Le calcul de l’impôt est complexe. Tout au long du document, les tests seront faits avec les exemples suivants. Les résultats sont ceux du simulateur de l’administration fiscale |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm| :

Contribuable

Résultats officiels

Résultats de l’algorithme du document

Couple avec 2 enfants et des revenus annuels de 55555 euros

Impôt=2815 euros
Taux d’imposition=14 %

Impôt=2814 euros
Taux d’imposition=14 %

Couple avec 2 enfants et des revenus annuels de 50000 euros

Impôt=1385 euros
Décote=384 euros
Réduction=346 euros
Taux d’imposition=14 %

Impôt=1384 euros
Décote=384 euros
Réduction=347 euros
Taux d’imposition=14 %

Couple avec 3 enfants et des revenus annuels de 50000 euros

Impôt=0 euro
décote=720 euros
Réduction=0 euro
Taux d’imposition=14 %

Impôt=0 euro
décote=720 euros
Réduction=0 euro
Taux d’imposition=14 %

Célibataire avec 2 enfants et des revenus annuels de 100000 euros

Impôt=19884 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Impôt=19884 euros
Surcote=4480 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Célibataire avec 3 enfants et des revenus annuels de 100000 euros

Impôt=16782 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Impôt=16782 euros
Surcote=7176 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Couple avec 3 enfants et des revenus annuels de 100000 euros

Impôt=9200 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=30 %

Impôt=9200 euros
Surcote=2180 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=30 %

Couple avec 5 enfants et des revenus annuels de 100000 euros

Impôt=4230 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=14 %

Impôt=4230 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=14 %

Célibataire sans enfants et des revenus annuels de 100000 euros

Impôt=22986 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Impôt= 22986 euros
Surcote=0 euro
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Couple avec 2 enfants et des revenus annuels de 30000 euros

Impôt=0 euro
décote=0 euro
Réduction=0 euro
Taux d’imposition=0 %

Impôt=0 euro
décote=0 euro
Réduction=0 euro
Taux d’imposition=0 %

Célibataire sans enfants et des revenus annuels de 200000 euros

Impôt=64211 euro
décote=0 euro
Réduction=0 euro
Taux d’imposition=45 %

Impôt= 64210 euros
Surcote=7498 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=45 %

Couple avec 3 enfants et des revenus annuels de 200000 euros

Impôt=42843 euro
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Impôt=42842 euros
Surcote=17283 euros
décote=0 euro
Réduction=0 euro
Taux d’imposition=41 %

Ci-dessus, on appelle surcote, ce que paient en plus les hauts revenus à cause de deux phénomènes :

  • Le plafonnement de l’abattement de 10 % sur les revenus annuels ;
  • Le plafonnement du quotient familial ;

    Cet indicateur n’a pu être vérifié car le simulateur de l’administration fiscale ne le donne pas.

    On voit que l’algorithme du document donne un impôt juste à chaque fois, avec cependant une marge d’erreur de 1 euro. Cette marge d’erreur provient des arrondis. Toutes les sommes d’argent sont arrondies parfois à l’euro supérieur, parfois à l’euro inférieur. Comme je ne connaissais pas les règles officielles, les sommes d’argent de l’algorithme du document ont été arrondies :

  • À l’euro supérieur pour les décotes et réductions ;

  • À l’euro inférieur pour les surcotes et l’impôt final ;

Nous allons demander à l’IA de faire ce calcul d’impôt.

6-3-2. Configuration de la session Gemini

La question posée à Gemini s’accompagne de deux fichiers :

Image non disponible

 
  • En [1], le calcul qui vient d’être détaillé a été mis dans un PDF qui est donné à Gemini. Gemini va y trouver les règles exactes de calcul simplifié de l’impôt 2019 sur les revenus 2018 ;
  • En [2], nos instructions ;
  • En [3] pour lancer l’IA ;

Nos instructions dans le fichier texte [instructionsAvecPDF.txt] sont les suivantes :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
1 - Exprime-toi en français.

2 - Peux-tu générer un script Python permettant de calculer l'impôt payé par les familles en 2019 sur leurs revenus de 2018.

3 - Tu t'aideras du document PDF que j'ai joint et qui explique les calculs à faire.

4 - Tu dois faire attention aux points suivants :

- plafonnement du quotient familial. Il y a des seuils à vérifier.
- calcul de la décote dans certains cas. Il y a des seuils à vérifier.
- calcul de la réduction de 20% dans certains cas. Il y a des seuils à vérifier.
- plafonnement de l'abattement de 10% sur les revenus annuels dans certains cas.
- tu considèreras que tous les revenus sont à déclarer pour le déclarant 1 même si le couple est marié.

5 - Tu ajouteras au script généré des tests unitaires pour les cas suivants.

Dans ces tests on appelle :

adultes :nombre d'adultes du foyer fiscal
enfants : nombre d'enfants du foyer fiscal
revenus : revenus nets annuels avant impôt, ç-à-d avant le 1er calcul de l'abattement.
impot : l'impôt à payer
decote :la décote éventuelle du foyer fiscal
reduction : la réduction de 20% pour les faibles revenus

Voici les 11 tests à vérifier. Ils ont tous été vérifiés manuellement sur le simulateur officiel
du calcul de l'impôt 2019 [https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.html].
Si tu utilises ce simulateur les revenus doivent être associés au seul déclarant 1 dans le cas d'un couple, le déclarant 2 étant alors ignoré. Lorsqu'on répartit les revenus
sur deux déclarants, on n'obtient pas le même résultat.

On utilise la syntaxe (adultes, enfants, revenus) -> (impot, decote, reduction) pour dire que le script reçoit les entrées
(adultes, enfants, revenus) et produit les résultats (impot, decote, reduction)

test1 : (2,2,55555) -> (2815, 0, 0)
test2 : (2, 2, 50000) -> (1385, 384, 346)
test3 : (2,3,50000) -> (0, 720, 0)
test4: (1,2,100000) -> (19884, 0, 0)
test5: (1,3,100000) -> (16782, 0, 0)
test6 : (2, 3, 100000) -> (9200, 0, 0)
test7 : (2, 5, 100000) -> (4230, 0, 0)
test8 : (1, 0, 100000) -> (22986, 0, 0)
test9 : (2, 2, 30000) -> (0, 0, 0)
test10 : (1,0,200000) -> (64211, 0, 0)
test11  : (2, 3, 200000) -> (42843, 0, 0)

6 - Il peut y avoir des problèmes d'arrondis. Tu procèderas comme suit
- l'impôt à payer sera arrondi à l'euro inférieur,
- la décote sera arrondie à l'euro supérieur,
- la réduction de 20 % sera arrondie à l'euro supérieur.
- l'abattement de 10% sera arrondi à l'euro supérieur

Fais tous les tests unitaires à l'euro près à cause de ces éventuelles erreurs d'arrondi.
Ne cherche pas à avoir les valeurs exactes ci-dessus mais ces valeurs à 1 euro près.

7 - Evite de chercher sur internet. Le PDF que je te donne est correct.
Ne donne ton résultat que lorsque tu as passé les 11 tests unitaires avec succès.

8 - si l'un des tests échoue et que tu es bloqué, affiche ton raisonnement pour ce test
afin que je puisse t'aider.

9- Mets des commentaires détaillés dans le script que tu génères.
Mets le barème progressif dans une liste ou dictionnaire puis utilise cette liste ou dictionnaire
Mets les nombres en dur (nombres magiques) que tu utilises dans des constantes
Utilise des fonctions pour séparer les étapes du calcul.
Ecris le tout en français

9 - n'affiche pas le code généré à l'écran. Donne-moi simplement un lien pour le récupérer.
Si les tests unitaires échouent, je te donnerai les logs de l'exécution du script pour que
tu voies tes erreurs.

10 - si c'est possible, indique le temps en minutes et secondes que tu as mis pour produire
le script demandé.

Ces instructions sont le résultat de très nombreuses questions posées à Gemini. Assez rapidement, on se rend compte que l’IA doit être très cadrée si on veut obtenir ce qu’on veut. C’est à cause de tous ces tâtonnements que la session Gemini était finalement stoppée pour dépassement de limites. Examinons la suite de ces instructions :

  • Ligne 1 : on demande que la conversation soit en français. Cette indication est pour DeepSeek qui avait tendance à parler anglais ;
  • Ligne 3 : ce qu’on veut ;
  • Ligne 5 : on dit à l’IA d’utiliser le PDF qu’on lui a donné ;
  • Lignes 7-14 : un certain nombre de conseils utiles surtout pour le problème 3 sans PDF. Plusieurs IA se sont perdues dans le calcul de l’impôt ;
  • Lignes 15-44 : les 11 tests unitaires que l’on veut voir inclus dans le script généré. Lorsque le script sera généré, on l’exécutera dans PyCharm et on verra bien si les 11 tests passent ;
  • Lignes 46-53 : sans ces instructions, les IA généraient des tests unitaires cherchant des résultats exacts qui échouaient ;
  • Lignes 55-56 : je dis à l’IA de ne pas aller sur internet. La solution la plus simple est d’utiliser le PDF ;
  • Lignes 58-59 : cette instruction n’a pas été suivie par les IA. J’ai été obligé de l’écrire explicitement dans une question, lorsque je constatais qu’un test avait échoué ;
  • Lignes 61-65 : j’indique quel type de script Python je souhaite ;
  • Lignes 67-69 : j’aurais préféré un lien pour récupérer le script généré car l’affichage du code à l’écran prend du temps. Il s’est avéré que la plupart des IA ne savent pas faire cela. Les liens donnés ne marchaient pas ;
  • Lignes 71-72 : j’aurais aimé avoir le temps passé par l’IA pour répondre à la question. Seule Gemini a pu me donner ce renseignement. Les autres IA soit ne répondaient pas à cette instruction, soit donnaient des chiffres fantaisistes montrant qu’elles ne comprenaient pas cette instruction ;

6-3-3. La réponse de Gemini

La première réponse de Gemini est la suivante :

Image non disponible

 
  • En [1-4], Gemini fournit des liens sur la partie du PDF ou du fichier texte des instructions qu’il utilise à un moment donné ;

    La suite est la suivante :

    Image non disponible

     
  • En [1], Gemini affirme qu’il a exécuté les 11 tests unitaires avec succès. La plupart des IA ont affirmé cela aussi bien sur le problème 2 que le problème 3 et souvent lorsqu’on chargeait le script généré ça ne marchait pas. Il faut donc se méfier de cette affirmation. Pour Gemini cela va s’avérer vrai ;

  • En [2], un lien qui s’avérera ne pas marcher ;

  • En [3] seule Gemini a donné un temps d’exécution réaliste ;

Donc le lien [2] ne marche pas. On le dit à Gemini :

Image non disponible

 

La réponse de Gemini :

Image non disponible

 
  • En [1], le script Python généré par Gemini ;

    On charge ce script dans PyCharm et on l’exécute :

    Image non disponible

     
  • En [1], [gemini1] est le script généré par Gemini ;

    A l’exécution du script apparaissent des erreurs de compilation :

     
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    14.
    15.
    16.
    17.
    18.
    19.
    20.
    21.
    22.
    23.
    24.
    25.
    26.
    27.
    28.
    29.
    30.
    31.
    32.
    33.
    34.
    "C:\Program Files\Python313\python.exe" "C:/Program Files/JetBrains/PyCharm 2025.2.0.1/plugins/python-ce/helpers/pycharm/_jb_unittest_runner.py" --path "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\chatGPT\chatGPT1.py" 
    Testing started at 17:12 ...
    Launching unittests with arguments python -m unittest C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\chatGPT\chatGPT1.py in C:\Data\st-2025\dev\python\code\python-flask-2025-cours
    
    Traceback (most recent call last):
    File "C:\Program Files\JetBrains\PyCharm 2025.2.0.1\plugins\python-ce\helpers\pycharm\_jb_unittest_runner.py", line 38, in <module>
    sys.exit(main(argv=args, module=None, testRunner=unittestpy.TeamcityTestRunner,
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    buffer=not JB_DISABLE_BUFFERING))
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File "C:\Program Files\Python313\Lib\unittest\main.py", line 103, in __init__
    self.parseArgs(argv)
    ~~~~~~~~~~~~~~^^^^^^
    File "C:\Program Files\Python313\Lib\unittest\main.py", line 142, in parseArgs
    self.createTests()
    ~~~~~~~~~~~~~~~~^^
    File "C:\Program Files\Python313\Lib\unittest\main.py", line 153, in createTests
    self.test = self.testLoader.loadTestsFromNames(self.testNames,
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
    self.module)
    ^^^^^^^^^^^^
    File "C:\Program Files\Python313\Lib\unittest\loader.py", line 207, in loadTestsFromNames
    suites = [self.loadTestsFromName(name, module) for name in names]
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
    File "C:\Program Files\Python313\Lib\unittest\loader.py", line 137, in loadTestsFromName
    module = __import__(module_name)
    File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\chatGPT\chatGPT1.py", line 28, in <module>
    [cite_start]
    ^^^^^^^^^^
    NameError: name 'cite_start' is not defined
    
    Process finished with exit code 1
    
    Empty suite
    
  • Ligne 30, l’erreur de compilation. [cite_start] est un marqueur pour générer une certaine forme de texte ;

On met les logs ci-dessus dans un fichier [logs gemini1.txt] et on donne celui-ci à Gemini :

Image non disponible

 

La réponse de Gemini est alors la suivante :

Image non disponible

 

Chargé dans PyCharm, l’exécution du nouveau script génère exactement la même erreur. On le dit à Gemini en lui fournissant de nouveau les logs de l’exécution :

Image non disponible

 

La réponse de Gemini est la suivante :

Image non disponible

 

Cette fois c’est bon. Les 11 tests unitaires sont réussis. On le dit à Gemini :

Image non disponible

 

Qui répond :

Image non disponible

 

Le script généré par Gemini a suivi les instructions données dans le fichier texte [instructionsAvecPDF.txt] :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
# -*- coding: utf-8 -*-
"""
Script pour le calcul de l'impôt 2019 sur les revenus de 2018 en France,
basé sur les règles simplifiées fournies dans le document PDF.
"""

import math
import unittest

# --- CONSTANTES DE CALCUL POUR L'IMPÔT 2019 ---
# Toutes les valeurs sont extraites du document PDF fourni.

# Plafonds pour l'abattement de 10% sur les revenus annuels
PLAFOND_ABATTEMENT_10_POURCENT = 12502.0
MINIMUM_ABATTEMENT_10_POURCENT = 437.0

# Barème de l'impôt sur le revenu 2019
# Structure: (Seuil maximum de la tranche, Taux d'imposition, Montant à déduire par part)
BAREME_IMPOT_2019 = [
    {"seuil": 9964, "taux": 0.0, "deduction_par_part": 0},
    {"seuil": 27519, "taux": 0.14, "deduction_par_part": 1394.96},
    {"seuil": 73779, "taux": 0.30, "deduction_par_part": 5798},
    {"seuil": 156244, "taux": 0.41, "deduction_par_part": 13913.69},
    {"seuil": float('inf'), "taux": 0.45, "deduction_par_part": 20163.45}
]

# Plafonnement du quotient familial
GAIN_MAX_DEMI_PART = 1551.0  # Gain maximal par demi-part supplémentaire

# Seuils et montants pour la décote
SEUIL_APPLICATION_DECOTE = {"celibataire": 1595.0, "couple": 2627.0}
SEUIL_CALCUL_DECOTE = {"celibataire": 1196.0, "couple": 1970.0}

# Seuils pour la réduction d'impôt de 20%
SEUIL_BASE_REDUCTION_20 = {"celibataire": 21037.0, "couple": 42074.0}
MAJORATION_SEUIL_REDUCTION_PAR_DEMI_PART = 3797.0


def calculer_nombre_parts(adultes: int, enfants: int) -> float:
    """
    Calcule le nombre de parts fiscales du foyer.
    - Chaque parent amène 1 part.
    - Les deux premiers enfants amènent chacun 1/2 part.
    - Les enfants suivants amènent une part chacun.
    """
    if adultes not in [1, 2]:
        raise ValueError("Le nombre d'adultes doit être 1 ou 2.")

    parts = float(adultes)
    if enfants > 0:
        parts += 0.5 * min(enfants, 2)
    if enfants > 2:
        parts += 1.0 * (enfants - 2)

    return parts


def calculer_revenu_imposable(revenus: float) -> float:
    """
    Calcule le revenu net imposable après l'abattement de 10%.
    Cet abattement est plafonné.
    L'abattement est arrondi à l'euro supérieur.
    """
    abattement_calcule = revenus * 0.1
    # L'abattement est plafonné entre un minimum et un maximum
    abattement = min(PLAFOND_ABATTEMENT_10_POURCENT, max(MINIMUM_ABATTEMENT_10_POURCENT, abattement_calcule))

    # L'énoncé demande d'arrondir l'abattement à l'euro supérieur
    abattement_arrondi = math.ceil(abattement)

    return revenus - abattement_arrondi


def calculer_impot_brut_base(revenu_imposable: float, nombre_parts: float) -> float:
    """
    Calcule l'impôt brut selon le barème progressif.
    """
    if nombre_parts <= 0:
        return 0.0

    quotient_familial = revenu_imposable / nombre_parts

    tranche_applicable = None
    for tranche in BAREME_IMPOT_2019:
        if quotient_familial <= tranche["seuil"]:
            tranche_applicable = tranche
            break

    # Si le QF est supérieur à tous les seuils, on utilise la dernière tranche
    if tranche_applicable is None:
        tranche_applicable = BAREME_IMPOT_2019[-1]

    # Formule de calcul de l'impôt brut
    impot_brut = (revenu_imposable * tranche_applicable["taux"]) - (
            tranche_applicable["deduction_par_part"] * nombre_parts)

    return max(0.0, impot_brut)


def appliquer_plafonnement_qf(impot_brut_avec_enfants: float, revenu_imposable: float, adultes: int,
                              enfants: int) -> float:
    """
    Applique le plafonnement du quotient familial si nécessaire.
    L'impôt final ne peut être inférieur à l'impôt calculé sans les enfants,
    diminué d'un gain maximal par demi-part.
    """
    if enfants == 0:
        return impot_brut_avec_enfants

    # Calcul de l'impôt sans les parts des enfants
    parts_sans_enfants = calculer_nombre_parts(adultes, 0)
    impot_sans_enfants = calculer_impot_brut_base(revenu_imposable, parts_sans_enfants)

    # Calcul du gain maximal lié aux enfants
    parts_avec_enfants = calculer_nombre_parts(adultes, enfants)
    demi_parts_enfants = (parts_avec_enfants - parts_sans_enfants) * 2
    gain_maximal = demi_parts_enfants * GAIN_MAX_DEMI_PART

    impot_minimal_plafone = impot_sans_enfants - gain_maximal

    # L'impôt retenu est le plus élevé des deux calculs
    return max(impot_brut_avec_enfants, impot_minimal_plafone)


def appliquer_decote(impot_avant_decote: float, adultes: int) -> tuple[float, float]:
    """
    Applique la décote si l'impôt est inférieur à certains seuils.
    La décote est arrondie à l'euro supérieur.
    """
    statut = "couple" if adultes == 2 else "celibataire"
    seuil_application = SEUIL_APPLICATION_DECOTE[statut]
    seuil_calcul = SEUIL_CALCUL_DECOTE[statut]

    decote = 0.0
    # La décote s'applique si l'impôt est sous le seuil d'application
    if impot_avant_decote < seuil_application:
        # Formule de la décote : seuil - 0.75 * Impôt brut
        decote_calculee = seuil_calcul - (0.75 * impot_avant_decote)

        # Arrondi à l'euro supérieur
        decote = math.ceil(decote_calculee)

        # La décote ne peut être négative ni supérieure à l'impôt
        decote = max(0.0, min(decote, impot_avant_decote))

    impot_apres_decote = impot_avant_decote - decote
    return impot_apres_decote, decote


def appliquer_reduction_20_pourcent(impot_avant_reduction: float, revenu_imposable: float, adultes: int,
                                    enfants: int) -> tuple[float, float]:
    """
    Applique la réduction de 20% sous condition de revenus.
    La réduction est arrondie à l'euro supérieur.
    """
    statut = "couple" if adultes == 2 else "celibataire"
    seuil_base = SEUIL_BASE_REDUCTION_20[statut]

    # Le seuil est augmenté pour chaque demi-part liée aux enfants
    parts_avec_enfants = calculer_nombre_parts(adultes, enfants)
    parts_adultes = calculer_nombre_parts(adultes, 0)
    demi_parts_enfants = (parts_avec_enfants - parts_adultes) * 2
    seuil_final = seuil_base + (demi_parts_enfants * MAJORATION_SEUIL_REDUCTION_PAR_DEMI_PART)

    reduction = 0.0
    # La réduction s'applique si le revenu imposable est sous le seuil
    if revenu_imposable < seuil_final:
        reduction_calculee = impot_avant_reduction * 0.20

        # Arrondi à l'euro supérieur
        reduction = math.ceil(reduction_calculee)

    impot_apres_reduction = impot_avant_reduction - reduction
    return max(0.0, impot_apres_reduction), reduction


def calculer_impot(adultes: int, revenus: float, enfants: int) -> dict:
    """
    Orchestre le calcul complet de l'impôt net à payer.
    """
    # Étape 1: Calcul du revenu imposable
    revenu_imposable = calculer_revenu_imposable(revenus)

    # Étape 2: Calcul du nombre de parts
    nombre_parts = calculer_nombre_parts(adultes, enfants)

    # Étape 3: Calcul de l'impôt brut
    impot_brut_initial = calculer_impot_brut_base(revenu_imposable, nombre_parts)

    # Étape 4: Application du plafonnement du QF
    impot_apres_plafonnement = appliquer_plafonnement_qf(impot_brut_initial, revenu_imposable, adultes, enfants)

    # Étape 5: Application de la décote
    impot_apres_decote, decote_calculee = appliquer_decote(impot_apres_plafonnement, adultes)

    # Étape 6: Application de la réduction de 20%
    impot_avant_arrondi_final, reduction_calculee = appliquer_reduction_20_pourcent(impot_apres_decote,
                                                                                    revenu_imposable, adultes, enfants)

    # Étape 7: Arrondi final de l'impôt à l'euro inférieur
    impot_final = math.floor(impot_avant_arrondi_final)

    return {
        "impot": impot_final,
        "decote": decote_calculee,
        "reduction": reduction_calculee
    }


# --- TESTS UNITAIRES ---
# Validation du script avec les cas fournis
class TestCalculImpot2019(unittest.TestCase):

    def _verifier_resultat(self, adultes, enfants, revenus, impot_attendu, decote_attendue, reduction_attendue):
        """Fonction utilitaire pour exécuter un test et vérifier les résultats à 1 euro près."""
        resultat = calculer_impot(adultes=adultes, revenus=revenus, enfants=enfants)

        self.assertAlmostEqual(resultat["impot"], impot_attendu, delta=1,
                               msg=f"Test ({adultes}, {enfants}, {revenus}): Impôt attendu {impot_attendu}, obtenu {resultat['impot']}")

        self.assertAlmostEqual(resultat["decote"], decote_attendue, delta=1,
                               msg=f"Test ({adultes}, {enfants}, {revenus}): Décote attendue {decote_attendue}, obtenue {resultat['decote']}")

        self.assertAlmostEqual(resultat["reduction"], reduction_attendue, delta=1,
                               msg=f"Test ({adultes}, {enfants}, {revenus}): Réduction attendue {reduction_attendue}, obtenue {resultat['reduction']}")

    def test_cas_1(self):
        # (2, 2, 55555) -> (2815, 0, 0)
        self._verifier_resultat(2, 2, 55555, 2815, 0, 0)

    def test_cas_2(self):
        # (2, 2, 50000) -> (1385, 384, 346)
        self._verifier_resultat(2, 2, 50000, 1385, 384, 346)

    def test_cas_3(self):
        # (2, 3, 50000) -> (0, 720, 0)
        self._verifier_resultat(2, 3, 50000, 0, 720, 0)

    def test_cas_4(self):
        # (1, 2, 100000) -> (19884, 0, 0)
        self._verifier_resultat(1, 2, 100000, 19884, 0, 0)

    def test_cas_5(self):
        # (1, 3, 100000) -> (16782, 0, 0)
        self._verifier_resultat(1, 3, 100000, 16782, 0, 0)

    def test_cas_6(self):
        # (2, 3, 100000) -> (9200, 0, 0)
        self._verifier_resultat(2, 3, 100000, 9200, 0, 0)

    def test_cas_7(self):
        # (2, 5, 100000) -> (4230, 0, 0)
        self._verifier_resultat(2, 5, 100000, 4230, 0, 0)

    def test_cas_8(self):
        # (1, 0, 100000) -> (22986, 0, 0)
        self._verifier_resultat(1, 0, 100000, 22986, 0, 0)

    def test_cas_9(self):
        # (2, 2, 30000) -> (0, 0, 0)
        self._verifier_resultat(2, 2, 30000, 0, 0, 0)

    def test_cas_10(self):
        # (1, 0, 200000) -> (64211, 0, 0)
        self._verifier_resultat(1, 0, 200000, 64211, 0, 0)

    def test_cas_11(self):
        # (2, 3, 200000) -> (42843, 0, 0)
        self._verifier_resultat(2, 3, 200000, 42843, 0, 0)


if __name__ == '__main__':
    print("Exécution des tests unitaires...")
    unittest.main(argv=['first-arg-is-ignored'], exit=False)

    # Exemple d'utilisation du calculateur pour un cas précis
    print("\n--- Exemple de calcul ---")
    revenus_annuels = 50000
    nombre_adultes = 2
    nombre_enfants = 2

    resultat_calcul = calculer_impot(adultes=nombre_adultes, revenus=revenus_annuels, enfants=nombre_enfants)

    print(f"Pour un couple ({nombre_adultes} adultes) avec {nombre_enfants} enfants et {revenus_annuels}€ de revenus :")
    print(f"  - Impôt à payer : {resultat_calcul['impot']}€")
    print(f"  - Montant de la décote : {resultat_calcul['decote']}€")
    print(f"  - Montant de la réduction : {resultat_calcul['reduction']}€")

Je n’ai pas vérifié ce code. Puisque les 11 tests unitaires sont passés, je considère qu’il est « probablement correct ». Je n’ai pas fait davantage pour mon propre code que de vérifier ces 11 tests.

6-4. Le problème 3

Le problème 3 est identique au problème 2, si ce n’est qu’on ne donne plus à l’IA le PDF qui donnait les règles de calcul à observer.

La question initiale à Gemini est la suivante :

Image non disponible

 

Le fichier des instructions en [1] est quasiment le même que pour le problème 2 avec les différences suivantes :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
1 - Exprime-toi en français.

2 - Peux-tu générer un script Python permettant de calculer l'impôt payé par les familles en 2019 sur leurs revenus de 2018.

3 - Tu t'aideras des sources que tu trouveras sur internet. Dans ta réponse indique-moi ces sources.

4 - Tu dois faire attention aux points suivants :
…
  • En [3], on lui dit de trouver sur internet les règles de calcul de l’impôt 2019 sur les revenus 2018. C’est un exercice plus difficile que le précédent ;

    Je ne donne ci-dessous que des parties de la première réponse de Gemini :

    Image non disponible

     

    Image non disponible

     

    Le temps estimé est plausible. On attend longtemps la réponse de Gemini.

    Comme précédemment, Gemini a fourni un lien de téléchargement du script généré, lien qui ne marche pas. On le lui dit :

    Image non disponible

     

    La réponse de Gemini :

    Image non disponible

     

    On charge le script dans PyCharm sous le nom [gemini2]:

    Image non disponible

     

    On l’exécute et… ça ne marche pas. Les logs de l’exécution sont les suivants :

     
    Sélectionnez
    1.
    2.
    3.
    4.
    5.
    6.
    7.
    8.
    9.
    10.
    11.
    12.
    13.
    14.
    15.
    16.
    17.
    18.
    19.
    20.
    21.
    22.
    23.
    24.
    25.
    26.
    27.
    28.
    29.
    30.
    31.
    32.
    33.
    34.
    35.
    36.
    37.
    38.
    39.
    40.
    41.
    42.
    43.
    44.
    45.
    46.
    47.
    48.
    49.
    50.
    "C:\Program Files\Python313\python.exe" "C:/Program Files/JetBrains/PyCharm 2025.2.0.1/plugins/python-ce/helpers/pycharm/_jb_unittest_runner.py" --path "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py" 
    Testing started at 17:23 ...
    Launching unittests with arguments python -m unittest C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py in C:\Data\st-2025\dev\python\code\python-flask-2025-cours
    
    
    Failure
    Traceback (most recent call last):
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 278, in test_cas_2
        self.assertAlmostEqual(impot, 1385, delta=1)
        ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
    AssertionError: 1691 != 1385 within 1 delta (306 difference)
    
    
    Error
    Traceback (most recent call last):
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 291, in test_cas_3
        impot, _, _ = calculer_impot_final(2, 3, 50000)
                      ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 187, in calculer_impot_final
        decote, impot_apres_decote = calculer_decote(impot_apres_plafonnement, adultes)
                                     ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 134, in calculer_decote
        decote = seuil_decote - (impot_avant_decote * COFFICIENT_DECOTE)
                                                      ^^^^^^^^^^^^^^^^^
    NameError: name 'COFFICIENT_DECOTE' is not defined. Did you mean: 'COEFFICIENT_DECOTE'?
    
    
    Error
    Traceback (most recent call last):
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 316, in test_cas_9
        self._verifier_cas(2, 2, 30000, (0, 0, 0))
        ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 216, in _verifier_cas
        impot_calcule, decote_calculee, reduction_calculee = calculer_impot_final(adultes, enfants, revenus)
                                                             ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 187, in calculer_impot_final
        decote, impot_apres_decote = calculer_decote(impot_apres_plafonnement, adultes)
                                     ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini2.py", line 134, in calculer_decote
        decote = seuil_decote - (impot_avant_decote * COFFICIENT_DECOTE)
                                                      ^^^^^^^^^^^^^^^^^
    NameError: name 'COFFICIENT_DECOTE' is not defined. Did you mean: 'COEFFICIENT_DECOTE'?
    
    
    
    Ran 11 tests in 0.038s
    
    FAILED (failures=1, errors=2)
    
    Process finished with exit code 1
    
  • Ligne 11, un test a échoué ;

  • Lignes 25, 42 : une même erreur de compilation ;

On met ces logs dans un fichier texte qu’on donne à Gemini :

Image non disponible

 

La réponse de Gemini :

Image non disponible

 

Image non disponible

 

On charge dans PyCharm le script et on l’exécute. Encore des erreurs. On le dit à Gemini en joignant de nouveau les logs de l’exécution :

Image non disponible

 

La réponse de Gemini :

Image non disponible

 

Image non disponible

 

Image non disponible

 

On charge ce nouveau script dans PyCharm et on l’exécute. Cette fois les 11 tests unitaires passent :

Le code généré par Gemini est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
# -*- coding: utf-8 -*-
import math
import unittest

# ==============================================================================
# CONSTANTES POUR L'IMPOSITION DES REVENUS 2018 (PAYÉE EN 2019)
# ==============================================================================
BAREME_IMPOT_2019 = [
    {'seuil': 0, 'taux': 0.0},
    {'seuil': 9964, 'taux': 0.14},
    {'seuil': 27519, 'taux': 0.30},
    {'seuil': 73779, 'taux': 0.41},
    {'seuil': 156244, 'taux': 0.45},
]
ABATTEMENT_FORFAITAIRE_TAUX = 0.10
ABATTEMENT_FORFAITAIRE_MINIMUM = 437
ABATTEMENT_FORFAITAIRE_PLAFOND = 12502
PLAFONNEMENT_AVANTAGE_QF_DEMI_PART = 1551
SEUIL_DECOTE_CELIBATAIRE = 1196
SEUIL_DECOTE_COUPLE = 1970
COEFFICIENT_DECOTE = 0.75
TAUX_REDUCTION_20_POURCENT = 0.20
SEUIL_RFR_REDUCTION_CELIBATAIRE = 18985
SEUIL_RFR_REDUCTION_COUPLE = 37970
MAJORATION_RFR_REDUCTION_PAR_DEMI_PART = 3803


# ==============================================================================
# FONCTIONS DE CALCUL
# ==============================================================================

def calculer_nombre_parts(adultes: int, enfants: int) -> float:
    """Calcule le nombre de parts du foyer fiscal."""
    if adultes < 1: return 0
    parts = float(adultes)
    if enfants >= 1: parts += 0.5
    if enfants >= 2: parts += 0.5
    if enfants >= 3: parts += (enfants - 2) * 1.0
    return parts


def calculer_revenu_imposable(revenus_bruts: float) -> float:
    """Calcule le revenu net imposable après abattement de 10%."""
    if revenus_bruts == 0: return 0.0
    abattement = revenus_bruts * ABATTEMENT_FORFAITAIRE_TAUX
    if abattement < ABATTEMENT_FORFAITAIRE_MINIMUM: abattement = ABATTEMENT_FORFAITAIRE_MINIMUM
    if abattement > ABATTEMENT_FORFAITAIRE_PLAFOND: abattement = ABATTEMENT_FORFAITAIRE_PLAFOND
    abattement = math.ceil(abattement)
    revenu_imposable = revenus_bruts - abattement
    return revenu_imposable if revenu_imposable > 0 else 0


def calculer_impot_brut_par_tranche(revenu_imposable: float, nombre_parts: float) -> float:
    """Calcule l'impôt brut en appliquant le barème progressif."""
    if nombre_parts <= 0 or revenu_imposable <= 0: return 0.0
    quotient_familial = revenu_imposable / nombre_parts
    impot_par_part = 0.0
    for i in range(len(BAREME_IMPOT_2019)):
        tranche = BAREME_IMPOT_2019[i]
        seuil_actuel = tranche['seuil']
        taux = tranche['taux']
        if quotient_familial > seuil_actuel:
            base_imposable_tranche = 0
            if i < len(BAREME_IMPOT_2019) - 1:
                seuil_suivant = BAREME_IMPOT_2019[i + 1]['seuil']
                base_imposable_tranche = min(quotient_familial, seuil_suivant) - seuil_actuel
            else:
                base_imposable_tranche = quotient_familial - seuil_actuel
            impot_par_part += base_imposable_tranche * taux
    return impot_par_part * nombre_parts


def appliquer_plafonnement_qf(revenu_imposable: float, nombre_parts: float, adultes: int,
                              impot_brut_famille: float) -> float:
    """Applique le plafonnement des effets du quotient familial."""
    if nombre_parts <= adultes: return impot_brut_famille
    impot_base = calculer_impot_brut_par_tranche(revenu_imposable, float(adultes))
    demi_parts_enfants = (nombre_parts - adultes) * 2
    avantage_qf_max = PLAFONNEMENT_AVANTAGE_QF_DEMI_PART * demi_parts_enfants
    avantage_qf_reel = impot_base - impot_brut_famille
    if avantage_qf_reel > avantage_qf_max:
        return impot_base - avantage_qf_max
    return impot_brut_famille


def calculer_impot_final(adultes: int, enfants: int, revenus: float) -> (int, int, int):
    """Orchestre le calcul complet de l'impôt."""
    revenu_imposable = calculer_revenu_imposable(revenus)
    nombre_parts = calculer_nombre_parts(adultes, enfants)
    impot_brut = calculer_impot_brut_par_tranche(revenu_imposable, nombre_parts)
    impot_apres_plafonnement = appliquer_plafonnement_qf(revenu_imposable, nombre_parts, adultes, impot_brut)

    # CORRECTION : Si l'impôt est déjà 0, pas de décote ni de réduction.
    if impot_apres_plafonnement == 0:
        return 0, 0, 0

    # --- LOGIQUE CORRIGÉE POUR L'INTERACTION DÉCOTE / RÉDUCTION ---
    decote_calculee = 0.0
    reduction_calculee = 0.0
    impot_a_traiter = impot_apres_plafonnement

    # 1. Déterminer l'éligibilité à la réduction de 20%
    est_eligible_reduction = False
    if adultes >= 2:
        seuil_rfr = SEUIL_RFR_REDUCTION_COUPLE + max(0, (nombre_parts - 2) * 2) * MAJORATION_RFR_REDUCTION_PAR_DEMI_PART
    else:
        seuil_rfr = SEUIL_RFR_REDUCTION_CELIBATAIRE + max(0, (
                nombre_parts - 1) * 2) * MAJORATION_RFR_REDUCTION_PAR_DEMI_PART
    if revenu_imposable < seuil_rfr:
        est_eligible_reduction = True

    # 2. Déterminer l'éligibilité à la décote
    seuil_decote_foyer = SEUIL_DECOTE_COUPLE if adultes >= 2 else SEUIL_DECOTE_CELIBATAIRE
    reduction_theorique = math.ceil(impot_a_traiter * TAUX_REDUCTION_20_POURCENT) if est_eligible_reduction else 0

    if (impot_a_traiter - reduction_theorique) < seuil_decote_foyer:
        decote_calculee = seuil_decote_foyer - (impot_a_traiter * COEFFICIENT_DECOTE)
        decote_calculee = math.ceil(decote_calculee)
        # CORRECTION : La décote retournée ne peut excéder l'impôt qu'elle annule
        decote_calculee = min(decote_calculee, math.ceil(impot_a_traiter))
        impot_a_traiter -= decote_calculee
        impot_a_traiter = max(0.0, impot_a_traiter)

    # 3. Appliquer la réduction de 20% si éligible
    if est_eligible_reduction:
        reduction_calculee = math.ceil(impot_a_traiter * TAUX_REDUCTION_20_POURCENT)
        impot_a_traiter -= reduction_calculee
        impot_a_traiter = max(0.0, impot_a_traiter)

    impot_final = math.floor(impot_a_traiter)

    return impot_final, int(decote_calculee), int(reduction_calculee)


# ==============================================================================
# TESTS UNITAIRES
# ==============================================================================

class TestCalculImpot2019(unittest.TestCase):
    def _verifier_cas(self, adultes, enfants, revenus, attendu):
        impot_attendu, decote_attendue, reduction_attendue = attendu
        impot_calcule, decote_calculee, reduction_calculee = calculer_impot_final(adultes, enfants, revenus)
        self.assertAlmostEqual(impot_calcule, impot_attendu, delta=1, msg=f"Impôt ({impot_calcule} vs {impot_attendu})")
        self.assertAlmostEqual(decote_calculee, decote_attendue, delta=1,
                               msg=f"Décote ({decote_calculee} vs {decote_attendue})")
        self.assertAlmostEqual(reduction_calculee, reduction_attendue, delta=1,
                               msg=f"Réduction ({reduction_calculee} vs {reduction_attendue})")

    def test_cas_1(self): self._verifier_cas(2, 2, 55555, (2815, 0, 0))

    def test_cas_2(self): self._verifier_cas(2, 2, 50000, (1385, 384, 346))

    def test_cas_3(self): self._verifier_cas(2, 3, 50000, (0, 720, 0))

    def test_cas_4(self): self._verifier_cas(1, 2, 100000, (19884, 0, 0))

    def test_cas_5(self): self._verifier_cas(1, 3, 100000, (16782, 0, 0))

    def test_cas_6(self): self._verifier_cas(2, 3, 100000, (9200, 0, 0))

    def test_cas_7(self): self._verifier_cas(2, 5, 100000, (4230, 0, 0))

    def test_cas_8(self): self._verifier_cas(1, 0, 100000, (22986, 0, 0))

    def test_cas_9(self): self._verifier_cas(2, 2, 30000, (0, 0, 0))

    def test_cas_10(self): self._verifier_cas(1, 0, 200000, (64211, 0, 0))

    def test_cas_11(self): self._verifier_cas(2, 3, 200000, (42843, 0, 0))


if __name__ == '__main__':
    print("Lancement des tests unitaires pour le calcul de l'impôt 2019...")
    unittest.main(argv=['first-arg-is-ignored'], exit=False)

De nouveau je n’ai pas inspecté ce code. J’ai simplement constaté qu’il passait les 11 tests avec succès.

Mais on peut être curieux de connaître son raisonnement, notamment pour les cas particuliers du calcul de l’impôt. On le lui demande :

Image non disponible

 

C’est un cas de hauts revenus avec à la fois un plafonnement possible de l’abattement de 10% et un plafonnement possible du quotient familial.

La réponse de Gemini est la suivante :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Ces deux dernières copies d’écran sont intéressantes. Gemini utilise une méthode de calcul différente de celle expliquée dans le PDF. On trouve effectivement cette méthode de calcul sur internet. Les deux méthodes sont équivalentes.

Image non disponible

 

Image non disponible

 

Image non disponible

 

L’explication est remarquable par sa clarté. On pourrait la donner telle-quelle à des étudiants pour expliquer la méthode de calcul de l’impôt.

Maintenant prenons un autre exemple cette fois-ci avec des faibles revenus. Dans ce cas, il peut y avoir décote et réduction :

Image non disponible

 

La réponse de Gemini est la suivante :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Ici, on constate que Gemini applique une règle qui n’est pas dans le PDF. Il l’a probablement trouvée sur internet, mais la source est-elle fiable ?

Image non disponible

 

Ici, Gemini continue d’appliquer une règle inconnue (la règle spéciale ci-dessus).

Image non disponible

 

Image non disponible

 

Image non disponible

 

Donc les résultats de Gemini collent avec le résultat du simulateur officiel des impôts. Mais il a utilisé une règle non présente dans le PDF. Où est l’erreur ? On le lui demande en lui joignant le PDF :

Image non disponible

 

La réponse de Gemini :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Je pense que Gemini a raison et que mon PDF est erroné. Pour le vérifier, je lui demande un test :

  • Où son raisonnement donnerait les mêmes résultats que le simulateur d’impôt officiel ;
  • Où le raisonnement du PDF donnerait lui des résultats différents de ceux du simulateur ;

Image non disponible

 

La réponse de Gemini est la suivante :

Image non disponible

 

Ici Gemini se trompe. J’ai lancé le simulateur sur cet exemple et j’ai trouvé la chose suivante :

Image non disponible

 

Cependant, on va découvrir que le raisonnement de Gemini donne bien les résultats ci-dessus. On continue :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Très bien. C’est noté. On continue :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Donc Gemini a trouvé (impôt, décote, réduction)= (431, 325, 1296) alors que le simulateur utilisé par mes soins donne (431, 324, 1297). Gemini a trouvé les bons résultats à 1 euro près mais il ne le sait pas. On le lui dit :

Image non disponible

 

Gemini répond :

Image non disponible

 

Image non disponible

 

Maintenant, on se demande si Gemini pourrait générer un PDF corrigé :

Image non disponible

 

La réponse de Gemini :

Image non disponible

 

Gemini ne m’a donc pas donné de lien vers un PDF, mais il a généré un texte pour générer moi-même ce PDF. Bien que ce soit encombrant de donner ici, les copies d’écran du PDF, je le fais pour que le lecteur voie le côté génératif de l’IA :

Image non disponible

 

Une image contenant texte, capture d’écran, Police, document

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, document

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, ligne

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, nombre

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, capture d’écran, blanc

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, document

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, blanc, reçu

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, capture d’écran, Police, document

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, Police, capture d’écran, blanc

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, nombre, capture d’écran, Police

Le contenu généré par l’IA peut être incorrect.

Une image contenant texte, nombre, capture d’écran, Police

Le contenu généré par l’IA peut être incorrect.

Honnêtement je n’ai pas vérifié si tout ce qui est dit dans ce PDF est vrai. En tout cas, c’est un document parfait pour un TD, généré en quelques secondes.

Néanmoins, on peut faire vérifier par Gemini lui-même que son PDF est bon. On démarre une nouvelle conversation :

Image non disponible

 
  • en [1], on a mis le PDF généré par Gemini [Le problème selon Gemini.pdf] ;
  • en [2], [instructionsAvecPDF2.txt] est identique aux instructions de [instructionsAvecPDF.txt], si ce n’est qu’on a ajouté un douzième test unitaire, celui-là même qui a montré que le PDF initial était erroné :
 
Sélectionnez
test12 : (2, 2, 49500) -> (1297, 431, 324)

Curieusement il a fallu plusieurs allers-retours avant que Gemini génère le bon script :

Question 2

Image non disponible

 

Question 3

Image non disponible

 

Comme il a été fait maintenant plusieurs fois, lorsque le script généré et chargé dans PyCharm échoue, on donne à Gemini le fichier texte des logs de l’exécution. Gemini les comprend très bien.

Question 4

Image non disponible

 

Question 5

Image non disponible

 

Question 6 et fin

Image non disponible

Image non disponible

Maintenant nous sommes rassurés sur la validité du PDF généré par Gemini. Les règles de calcul qui y sont données sont correctes.

Nous allons maintenant faire la même chose pour les cinq autres IA mais nous serons très brefs dans nos explications, sauf pour ChatGPT l’IA leader du moment. Ce qui nous intéresse c’est de savoir si l’IA résoud ou non les trois problèmes qu’on lui pose. En effet, les interfaces de toutes ces IA sont très analogues et j’ai procédé avec elles comme avec Gemini. Le lecteur est encouragé à rejouer les conversations Gemini avec l’IA de son choix.

7. Résolution des trois problèmes avec ChatGPT

7-1. Introduction

Voici une première copie d’écran d’une session ChatGPT :

Image non disponible Image non disponible

 
  • En [1-3], les trois problèmes posés à ChatGPT ;
  • En [4], l’URL de ChatGPT ;
  • En [5], la version de ChatGPT utilisée ;

ChatGPT est un produit de OpenAI disponible à l’URL [https://chatgpt.com/]. Pour avoir un historique de vos sessions de questions / réponses comme ci-dessus, il vous faut créer un compte. Par ailleurs, comme toutes les autres IA testées, ChatGPT limite le nombre de vos questions et le nombre de fichiers téléchargés. Quand cette limite est atteinte, la session est terminée et on vous propose de la continuer plus tard dans le temps. Les limites imposées par ChatGPT sont atteintes très rapidement. Pour faire ce tutoriel, j’ai du prendre un abonnement payant d’un mois.

L’interface de ChatGPT est la suivante :

Image non disponible

 
  • En [1], pour joindre des fichiers à la question posée ;
  • En [2], la question posée ;
  • En [3], pour lancer l’exécution de l’IA ;

7-2. Le problème 1

La question à ChatGPT :

   

Image non disponible

 

ChatGPT répond correctement.

7-3. Le problème 2

C’est le calcul de l’impôt avec le PDF. Pour être honnête, on va utiliser le PDF généré par Gemini qui corrige des erreurs du PDF initial.

Image non disponible

 
  • En [1], on a donné le PDF généré par Gemini ;
  • En [2], on a ajouté le test unitaire par lequel Gemini a démontré sa supériorité :
 
Sélectionnez
test12 : (2, 2, 49500) -> (1297, 431, 324)

On lance ChatGPT. Il met environ 3 minutes pour générer sa réponse. Contrairement à Gemini, il livre bien un lien qui marche pour récupérer le script généré. On charge celui-ci dans PyCharm :

Image non disponible

 

Le script [chatGPT1] fonctionne du premier coup. Là il n’y a pas photo, sur ce problème ChatGPT a été plus performant que Gemini.

Le script [chatGPT1] fourni par ChatGPT est le suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
# -*- coding: utf-8 -*-
"""
Calcul de l'impôt 2019 (revenus 2018) en Python.

Hypothèses et règles (d'après le PDF fourni) :
- Tous les revenus sont portés sur le déclarant 1 (même pour un couple).
- Abattement forfaitaire de 10 % encadré par un minimum et un maximum.
- Barème progressif 2018 appliqué au quotient familial (QF).
- Plafonnement du quotient familial : avantage par demi-part enfant limité.
- Décote et réduction de 20 % pour faibles revenus, avec la règle de repêchage.
- Ordre des correctifs : plafonnement QF -> décote -> réduction 20 %.
- Arrondis : abattement (↑), décote (↑), réduction (↑), impôt final (↓).
- On renvoie l'impôt à payer (arrondi à l'euro inf.), la décote et la réduction
  (arrondies à l'euro sup.).

Les nombres “magiques” sont regroupés en constantes, et chaque étape est isolée
dans des fonctions pour la clarté.
"""

from dataclasses import dataclass
from math import ceil, floor

# ---------- Constantes réglementaires ----------

# Abattement frais pro (plancher/plafond) pour revenus 2018
ABATTEMENT_TAUX = 0.10
ABATTEMENT_MIN = 437
ABATTEMENT_MAX = 12502

# Barème 2018 (QF)
# Chaque tranche est (borne_sup, taux). La première tranche 0% se termine à 9 964 €.
BAREME_2018 = [
    (9964, 0.00),
    (27519, 0.14),
    (73779, 0.30),
    (156244, 0.41),
    (float("inf"), 0.45),
]

# Plafonnement du quotient familial
PF_QF_AVANTAGE_PAR_DEMI_PART = 1551  # avantage max par 1/2 part ENFANT

# Décote (seuils selon le nombre d'adultes / statut couple)
DECOTE_SEUIL_CELIB = 1196
DECOTE_SEUIL_COUPLE = 1970

# Réduction de 20 % : seuils en fonction des parts
REDUCTION_BASE_1_PART = 18985
REDUCTION_BASE_2_PARTS = 37970
REDUCTION_PAR_DEMI_PART_SUP = 3803  # ajout par 1/2 part au-delà du socle de 1 ou 2 parts


# ---------- Structures de données ----------

@dataclass
class ResultatImpot:
    impot: int  # impôt final à payer, arrondi à l'euro inférieur
    decote: int  # décote arrondie à l'euro supérieur
    reduction: int  # réduction 20 % arrondie à l'euro supérieur


# ---------- Fonctions utilitaires ----------

def arrondi_sup(euros: float) -> int:
    """Arrondi à l'euro supérieur (ceil)."""
    return int(ceil(euros))


def arrondi_inf(euros: float) -> int:
    """Arrondi à l'euro inférieur (floor)."""
    return int(floor(euros))


# ---------- Étape 1 : Revenu Net Imposable (RNI) ----------

def calcul_abattement(revenus_bruts: float) -> int:
    """
    Calcule l'abattement de 10 %, plafonné/planche, ARRONDI À L'EURO SUPÉRIEUR.
    """
    abattement_calcule = revenus_bruts * ABATTEMENT_TAUX
    abattement_calcule = max(ABATTEMENT_MIN, min(ABATTEMENT_MAX, abattement_calcule))
    return arrondi_sup(abattement_calcule)


def revenu_net_imposable(revenus_bruts: float) -> int:
    """RNI = revenus bruts - abattement (abattement arrondi ↑)."""
    return int(round(revenus_bruts - calcul_abattement(revenus_bruts)))


# ---------- Étape 2 : Nombre de parts ----------

def nombre_parts(adultes: int, enfants: int) -> float:
    """
    Règles : 1 part si 1 adulte, 2 parts si 2 adultes.
    Enfants : +0,5 pour les 2 premiers, +1 par enfant à partir du 3e.
    (On ignore ici tout cas particulier type parent isolé, conformément au PDF.)
    """
    parts = 1.0 if adultes == 1 else 2.0
    if enfants <= 0:
        return parts
    if enfants == 1:
        return parts + 0.5
    # enfants >= 2
    parts += 1.0  # +0,5 +0,5 pour les deux premiers
    if enfants > 2:
        parts += (enfants - 2) * 1.0  # +1 par enfant à partir du 3e
    return parts


def demi_parts_enfants(enfants: int) -> int:
    """Nombre de DEMI-parts dû aux enfants (utile pour le plafonnement QF)."""
    if enfants <= 0:
        return 0
    if enfants == 1:
        return 1  # 0,5 part
    # Deux premiers enfants = 2 * demi-part, puis +2 demi-parts par enfant à partir du 3e
    return 2 + (enfants - 2) * 2


# ---------- Étape 3 : Impôt brut via QF ----------

def impot_brut_par_parts(qf: float) -> float:
    """Impôt par part via barème progressif 2018 (sans arrondi)."""
    imp = 0.0
    previous = 0.0
    for borne_sup, taux in BAREME_2018:
        montant_tranche = max(0.0, min(qf, borne_sup) - previous)
        imp += montant_tranche * taux
        if qf <= borne_sup:
            break
        previous = borne_sup
    return imp


def impot_brut_total(rni: float, parts: float) -> float:
    """Impôt brut total = impôt par part * nombre de parts (sans arrondi)."""
    if parts <= 0:
        return 0.0
    qf = rni / parts
    return impot_brut_par_parts(qf) * parts


# ---------- Étape 4.1 : Plafonnement du quotient familial ----------

def apply_plafonnement_qf(impot_avec_enfants: float, rni: float, adultes: int, enfants: int) -> float:
    """
    Calcule l'impôt après plafonnement QF si l'avantage des enfants dépasse le plafond.
    - Impôt A : avec parts incluant enfants
    - Impôt B : avec seulement parts des adultes (1 ou 2)
    - Avantage réel = B - A
    - Avantage maximal = 1551 € par 1/2 part ENFANT
    Si avantage réel > avantage max, impôt = B - avantage max, sinon impôt = A.
    """
    parts_adultes = 1.0 if adultes == 1 else 2.0
    imp_b = impot_brut_total(rni, parts_adultes)
    imp_a = impot_avec_enfants
    avantage_reel = max(0.0, imp_b - imp_a)
    avantage_max = PF_QF_AVANTAGE_PAR_DEMI_PART * demi_parts_enfants(enfants)
    if avantage_reel > avantage_max:
        return imp_b - avantage_max
    return imp_a


# ---------- Étape 4.2 : Décote et Réduction 20 % ----------

def seuil_decote(adultes: int) -> int:
    return DECOTE_SEUIL_COUPLE if adultes >= 2 else DECOTE_SEUIL_CELIB


def seuil_reduction_20(rni: int, adultes: int, parts: float) -> int:
    """
    Seuil d'éligibilité à la réduction de 20 % :
    - Base : 18 985 € pour 1 part, 37 970 € pour 2 parts
    - + 3 803 € par 1/2 part supplémentaire au-delà de la base correspondante.
    """
    base = REDUCTION_BASE_2_PARTS if adultes >= 2 else REDUCTION_BASE_1_PART
    base_parts = 2.0 if adultes >= 2 else 1.0
    demi_sup = max(0, int(round((parts - base_parts) * 2)))
    return base + demi_sup * REDUCTION_PAR_DEMI_PART_SUP


def calc_decote_reduction(impot_apres_plaf: float, rni: int, adultes: int, parts: float):
    """
    Calcule (decote_arrondie, reduction_arrondie, impot_apres_correctifs).
    Règle d'interaction : la décote peut s'appliquer via repêchage si, après
    application THÉORIQUE de la réduction de 20 %, l'impôt passerait sous le seuil.
    Ordre : décote -> réduction.
    """
    imp = max(0.0, impot_apres_plaf)
    decote = 0
    reduction = 0

    # Éligibilité réduction 20 % basée sur RNI
    seuil_red = seuil_reduction_20(rni, adultes, parts)
    eligible_reduction = rni < seuil_red  # "inférieur à un seuil" dans le PDF

    # Éligibilité décote : sous le seuil directement, ou repêchage si réduction ferait passer sous le seuil
    s_dec = seuil_decote(adultes)
    direct_decote = imp <= s_dec
    repechage = False
    if not direct_decote and eligible_reduction:
        imp_theorique_apres_red = imp * 0.80  # réduction théorique 20%
        if imp_theorique_apres_red <= s_dec:
            repechage = True

    elig_decote = (direct_decote or repechage) and (imp > 0)

    # Appliquer la décote en premier (si éligible)
    if elig_decote:
        montant_decote = s_dec - (imp * 0.75)
        decote_calc = max(0, arrondi_sup(montant_decote))
        # La décote ne peut pas excéder l'impôt restant : on la borne
        decote = min(decote_calc, arrondi_sup(imp))
        imp = max(0.0, imp - decote)

    # Puis appliquer la réduction si éligible
    if eligible_reduction and imp > 0:
        montant_reduction = imp * 0.20
        reduction = max(0, arrondi_sup(montant_reduction))
        imp = max(0.0, imp - reduction)

    return decote, reduction, imp


# ---------- API principale ----------

def calcule_impot(adultes: int, enfants: int, revenus_bruts: float) -> ResultatImpot:
    """
    Calcule l'impôt 2019 (revenus 2018) pour un foyer.
    Retourne ResultatImpot(impot, decote, reduction).
    """
    # 1) RNI
    rni = revenu_net_imposable(revenus_bruts)

    # 2) Parts
    parts = nombre_parts(adultes, enfants)

    # 3) Impôt brut via barème (avec toutes parts)
    imp_brut_A = impot_brut_total(rni, parts)

    # 4.1) Plafonnement du quotient familial
    imp_apres_plaf = apply_plafonnement_qf(imp_brut_A, rni, adultes, enfants)

    # 4.2) Décote puis réduction 20 % (avec repêchage)
    decote, reduction, imp_corrige = calc_decote_reduction(imp_apres_plaf, rni, adultes, parts)

    # 5) Arrondi final impôt (↓) et bornage à 0
    imp_final = max(0, arrondi_inf(imp_corrige))

    return ResultatImpot(impot=imp_final, decote=decote, reduction=reduction)


# ---------- Petit exécutable de test ----------

def _nearly_equal(a: int, b: int, tol: int = 1) -> bool:
    return abs(a - b) <= tol


def tests_unitaires():
    """
    Renvoie une liste de tuples (inputs, attendu, obtenu, ok) pour chaque test.
    Tolérance : ±1 € sur chaque valeur (impôt, décote, réduction).
    """
    cas = [
        # (adultes, enfants, revenus) -> (impot, decote, reduction)
        ((2, 2, 55555), (2815, 0, 0)),
        ((2, 2, 50000), (1385, 384, 346)),
        ((2, 3, 50000), (0, 720, 0)),
        ((1, 2, 100000), (19884, 0, 0)),
        ((1, 3, 100000), (16782, 0, 0)),
        ((2, 3, 100000), (9200, 0, 0)),
        ((2, 5, 100000), (4230, 0, 0)),
        ((1, 0, 100000), (22986, 0, 0)),
        ((2, 2, 30000), (0, 0, 0)),
        ((1, 0, 200000), (64211, 0, 0)),
        ((2, 3, 200000), (42843, 0, 0)),
        ((2, 2, 49500), (1297, 431, 324)),
    ]

    resultats = []
    for (adultes, enfants, revenus), attendu in cas:
        res = calcule_impot(adultes, enfants, revenus)
        obtenu = (res.impot, res.decote, res.reduction)
        ok = _nearly_equal(obtenu[0], attendu[0]) and _nearly_equal(obtenu[1], attendu[1]) and _nearly_equal(obtenu[2],
                                                                                                             attendu[2])
        resultats.append(((adultes, enfants, revenus), attendu, obtenu, ok))
    return resultats


if __name__ == "__main__":
    for inputs, attendu, obtenu, ok in tests_unitaires():
        print(f"{inputs} -> attendu={attendu}, obtenu={obtenu} : {'OK' if ok else 'ECHEC'}")

7-4. Le problème 3

Maintenant on demande à ChatGPT de chercher les règles de calcul de l’impôt sur internet :

Image non disponible

 

Cette fois-ci on ne fournit pas le PDF qui donnait les règles de calcul à observer. On donne seulement nos instructions dans le fichier texte. On rappelle que ce fichier texte contient maintenant 12 tests unitaires après avoir ajouté aux 11 tests initiaux, celui utilisé par Gemini pour démontrer que mon PDF initial était erroné.

ChatGPT répond en 8 minutes, donne un lien pour télécharger le script généré. Une fois chargé dans PyCharm, ce script passe les 12 tests. Donc aux deux problèmes posés, ChatGPT a répondu juste du premier coup, surpassant ainsi Gemini.

ChatGPT donne ses sources dans sa réponse :

Image non disponible

 

Il n’y a rien à dire, c’est du beau travail.

Maintenant, on peut lui demander, comme on l’a fait avec Gemini de générer un PDF pour des étudiants.

Image non disponible

 

La réponse de ChatGPT a été obtenue après plusieurs allers-retours car le PDF généré utilisait une police qui remplaçait des caractères par un carré. Mais finalement, il a généré le PDF. Je le donne car il donne des règles différentes du PDF de Gemini et je me suis demandé alors qui avait raison. On va enquêter.

Image non disponible

 

Image non disponible

 

Image non disponible

Image non disponible

Image non disponible

 

La différence avec le PDF de Gemini est dans le calcul de la décote. Les deux IA n’ont pas la même approche. Gemini avait écrit :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Les deux IA ont deux approches différentes. Qui a raison ?

7-5. Le problème 4

On va demander à ChatGPT de s’appuyer sur son PDF pour faire le calcul de l’impôt :

Image non disponible

Image non disponible

Comme les fois précédentes, il génère un script Python qui marche du premier coup. On avait ajouté dans les instructions un test supplémentaire :

 
Sélectionnez
test13 : (1, 0, 18535) -> (359, 491, 90)

Les 13 tests ont été passés avec succès.

7-6. Retour sur Gemini

Maintenant, on revient dans Gemini à qui on va présenter le PDF de ChatGPT. Vu que les règles implémentées dans ce PDF sont différentes de celles implémentées dans le PDF de Gemini, on peut se demander ce qui va se passer :

Image non disponible

 

Gemini a tout d’abord généré un script Python qui ratait des tests. On lui a présenté les logs :

Question 2

Image non disponible

 

Question 3

Il y a encore des erreurs. On continue.

Image non disponible

 

Question 4

Toujours des erreurs à l’exécution :

Image non disponible

 

Cette fois-ci c’est bon.

On est quand même intrigués qu’avec des PDF ayant des règles de calcul assez différentes les IA génèrent toutes deux des résultats corrects.

On pose la question suivante à Gemini :

Image non disponible

 

La question complète est la suivante :

 
Sélectionnez
Après tout ce qu'on a fait, compare les deux approches, la tienne et celle de ChatGPT dans les pDF que je te joins [.. selon Gemini] pour toi, [.. selon ChatGPT] pour ChatGPT. Dis-moi laquelle on doit préférer vu que sur les 13 tests générés tu les réussis tous avec l'un ou avec l'autre PDF.

La réponse de Gemini est catégorique :

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

Image non disponible

 

8. Qu’en pense ChatGPT ?

On pose à ChatGPT la même question posée à Gemini.

Image non disponible

 

La réponse de ChatGPT est la suivante :

Image non disponible

 

Image non disponible

 

Du coup, ChatGPT nous propose un test unitaire pour départager les deux méthodes. Nous dupliquons :

  • Le script [gemini3] généré par Gemini en prenant comme source son PDF [Le problème selon Gemini] est dupliqué dans le script [gemini4] ;
  • Le script [chatGPT3] généré par ChatGPT en prenant comme source son PDF [Le problème selon ChatGPT] est dupliqué dans le script [chatGPT4] ;

Image non disponible

Image non disponible

Par ailleurs, on ajoute dans chacun des scripts [gemini4, chatGPT4] le test unitaire proposé par ChatGPT pour départager les deux IA.

L’exécution de [gemini4] donne les résultats suivants :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
C:\Data\st-2025\dev\python\code\python-flask-2025-cours\.venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm 2025.2.1.1/plugins/python-ce/helpers/pycharm/_jb_unittest_runner.py" --path "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini4.py" 
Testing started at 17:45 ...
Launching unittests with arguments python -m unittest C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini4.py in C:\Data\st-2025\dev\python\code\python-flask-2025-cours

SubTest failure: Traceback (most recent call last):
  File "C:\Program Files\Python313\Lib\unittest\case.py", line 58, in testPartExecutor
    yield
  File "C:\Program Files\Python313\Lib\unittest\case.py", line 556, in subTest
    yield
  File "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\gemini\gemini4.py", line 234, in test_cas_verifies_simulateur_officiel
    self.assertAlmostEqual(calcul_impot, attendu_impot, delta=1, msg="Échec sur le montant de l'impôt")
    ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: 2669 != 2270 within 1 delta (399 difference) : Échec sur le montant de l'impôt




Ran 1 test in 0.010s

FAILED (failures=1)

One or more subtests failed
Failed subtests list: [Test 'test12' avec entrée (2, 0, 43333)]

Process finished with exit code 1

Donc Gemini échoue au test rajouté par ChatGPT.

L’exécution de [chatGPT4] donne les résultats suivants :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
C:\Data\st-2025\dev\python\code\python-flask-2025-cours\.venv\Scripts\python.exe "C:\Data\st-2025\dev\python\code\python-flask-2025-cours\outils ia\chatGPT\chatGPT4.py" 
Test (2, 2, 55555) -> obtenu (impôt=2814, décote=0, réduction=0) | attendu (2815, 0, 0) | OK
Test (2, 2, 50000) -> obtenu (impôt=1384, décote=384, réduction=347) | attendu (1385, 384, 346) | OK
Test (2, 3, 50000) -> obtenu (impôt=0, décote=721, réduction=0) | attendu (0, 720, 0) | OK
Test (1, 2, 100000) -> obtenu (impôt=19884, décote=0, réduction=0) | attendu (19884, 0, 0) | OK
Test (1, 3, 100000) -> obtenu (impôt=16782, décote=0, réduction=0) | attendu (16782, 0, 0) | OK
Test (2, 3, 100000) -> obtenu (impôt=9200, décote=0, réduction=0) | attendu (9200, 0, 0) | OK
Test (2, 5, 100000) -> obtenu (impôt=4230, décote=0, réduction=0) | attendu (4230, 0, 0) | OK
Test (1, 0, 100000) -> obtenu (impôt=22986, décote=0, réduction=0) | attendu (22986, 0, 0) | OK
Test (2, 2, 30000) -> obtenu (impôt=0, décote=0, réduction=0) | attendu (0, 0, 0) | OK
Test (1, 0, 200000) -> obtenu (impôt=64210, décote=0, réduction=0) | attendu (64211, 0, 0) | OK
Test (2, 3, 200000) -> obtenu (impôt=42842, décote=0, réduction=0) | attendu (42843, 0, 0) | OK
Test (2, 2, 49500) -> obtenu (impôt=1296, décote=431, réduction=325) | attendu (1297, 431, 324) | OK
Test (1, 0, 18535) -> obtenu (impôt=359, décote=491, réduction=90) | attendu (359, 491, 90) | OK
Test (2, 0, 43333) -> obtenu (impôt=2268, décote=0, réduction=401) | attendu (2270, 0, 400) | ECHEC
 Détails tolérance ±1€ : impôt ok? False, décote ok? True, réduction ok? True

Résultat global : AU MOINS UN TEST ÉCHOUE ❌

Process finished with exit code 0

ChatGPT échoue lui aussi sur le test rajouté mais pas pour les mêmes raisons que Gemini. ChatGPT a trouvé les bons résultats mais à 2 euros près au lieu des 1 euro imposés.

Donc désormais c’est le PDF généré par ChatGPT que nous utiliserons avec les IA suivantes. Il faut noter que c’est à cause du manque de tests unitaires proposés dans mes instructions que les deux IA ont toutes deux réussi les premiers tests. D’où dans cet exemple précis, l’importance de mettre des tests unitaires pour les cas limites du calcul de l’impôt. Comme c’est plutôt difficile d’imaginer soi-même ces tests. On va demander aux IA d’en rajouter eux-mêmes.

8-1. Le problème 3 avec des test unitaires générés par les IA

Les résultats obtenus avec Gemini et ChatGPT laissent un doute. Les IA ont-elles trouvé une solution générale qui valide tous les tests imaginables ou ont-elles trouvé une solution qui valide les seuls tests imposés. On va repartir sur une solution sans PDF pour obliger les IA à aller sur internet rechercher les informations dont elles ont besoin. Et on modifie nos instructions de la façon suivante :

Image non disponible

 

Le fichier texte [instructionsSansPDF4.txt] contient déjà 14 tests imposés. A ces tests, on rajoute les instructions suivantes :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
7 - tu ajouteras autant de tests unitaires que nécessaires pour vérifier les cas limites du calcul de l'impôt.

Pour le code tu complèteras le script suivant auquel tu auras rajouté tes propres tests.

# =========================
# Tests unitaires (tolérance de ±1 €)
# =========================

TESTS = [
    # (adultes, enfants, revenus) -> (impot, decote, reduction)
    ((2, 2, 55555), (2815, 0, 0)),
    ((2, 2, 50000), (1385, 384, 346)),
    ((2, 3, 50000), (0, 720, 0)),
    ((1, 2, 100000), (19884, 0, 0)),
    ((1, 3, 100000), (16782, 0, 0)),
    ((2, 3, 100000), (9200, 0, 0)),
    ((2, 5, 100000), (4230, 0, 0)),
    ((1, 0, 100000), (22986, 0, 0)),
    ((2, 2, 30000), (0, 0, 0)),
    ((1, 0, 200000), (64211, 0, 0)),
    ((2, 3, 200000), (42843, 0, 0)),
    ((2, 2, 49500), (1297, 431, 324)),
    ((1, 0, 18535), (359, 491, 90)),
    ((2, 0, 43333), (2270, 0, 400)),
]


def _ok(a, b, tol=1):
    return abs(a - b) <= tol


def run_tests(verbose: bool = True) -> bool:
    all_ok = True
    for (params, expected) in TESTS:
        a, e, r = params
        exp_impot, exp_decote, exp_reduc = expected
        res = calcul_impot_2019(a, e, r)
        ok_impot = _ok(res.impot, exp_impot)
        ok_decote = _ok(res.decote, exp_decote)
        ok_reduc = _ok(res.reduction, exp_reduc)
        test_ok = ok_impot and ok_decote and ok_reduc
        if verbose:
            print(
                f"Test {params} -> obtenu (impôt={res.impot}, décote={res.decote}, réduction={res.reduction}) | attendu {expected} | {'OK' if test_ok else 'ECHEC'}")
            if not test_ok:
                print(
                    f" Détails tolérance ±1€ : impôt ok? {ok_impot}, décote ok? {ok_decote}, réduction ok? {ok_reduc}")
        all_ok &= test_ok
    if verbose:
        print("\nRésultat global :", "TOUS LES TESTS PASSENT ✅" if all_ok else "AU MOINS UN TEST ÉCHOUE ❌")
    return all_ok


if __name__ == "__main__":
    run_tests()
  • Lignes 11-24, les 14 tests imposés ;
  • Lignes 5-55 : ce code vient du script généré par ChatGPT. On va imposer à Gemini d’utiliser ce code pour faciliter les comparaisons entre les deux scripts générés.

On commence par ChatGPT :

Image non disponible

 

Sa première réponse est incorrecte. Je le lui dis en lui donnant les logs de l’exécution :

Image non disponible

Image non disponible

Sa deuxième réponse est la bonne. ChatGPT a rajouté les 11 tests suivants aux 14 tests imposés :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
# Cas limites supplémentaires (bords de paliers/arrondis)
TESTS += [
    # Abattement 10 % : plancher et plafond
    ((1, 0, 3000), (0, 0, 0)),  # 10 % = 300 < plancher 437 => RNI faible -> impôt nul
    ((1, 0, 200000), (64211, 0, 0)),  # plafond abattement déjà couvert dans tests initiaux

    # Décote : juste en dessous / au-dessus des seuils
    ((1, 0, 25000), None),  # diagnostique
    ((2, 0, 35000), None),  # diagnostique

    # Réduction 20 % : plein droit vs écrêtement
    ((1, 0, 17000), None),  # diagnostique
    ((2, 0, 34000), None),  # diagnostique
    ((1, 0, 20000), None),  # diagnostique
    ((2, 0, 40000), None),  # diagnostique

    # Changement de parts (plafonnement QF)
    ((2, 1, 80000), None),
    ((2, 2, 80000), None),
    ((2, 3, 80000), None),
]

Il y a maintenant 25 tests unitaires. J’ai vérifié manuellement les 11 nouveaux tests avec le simulateur officiel de la DGIP et c’est bon.

Maintenant, on passe à Gemini. Cela va être beaucoup plus compliqué. Il va réussir à générer un script qui passe les 25 tests de ChatGPT mais après un long débogage.

Image non disponible

 

Ci-dessous, la liste du débogage :

Image non disponible

 

Bizarrement, une majorité de tests a échoué même parmi les 14 imposés alors que par le passé Gemini avait généré du code qui les passait tous.

La réponse suivante de Gemini n’est toujours pas correcte :

Image non disponible

 

La réponse suivante non plus :

Image non disponible

 

La réponse suivante non plus. Du coup je change mon fusil d’épaule. Je lui demande de réussir les 25 tests qu’a réussis ChatGPT en lui joignant les logs de ChatGPT :

Image non disponible

 

Gemini échoue. Il a bien ajouté les tests de ChatGPT. Je lui joins les logs de son exécution :

Image non disponible

 

Toujours pas :

Image non disponible

 

Toujours pas :

Image non disponible

 

Toujours pas :

Image non disponible

 

Toujours pas mais c’est mieux :

Image non disponible

 

Gemini fait de nouvelles erreurs :

Image non disponible

 

Il s’améliore de nouveau :

Image non disponible

 

Cette fois, c’est bon :

Image non disponible

Image non disponible

Indiscutablement, sur cet exemple précis du calcul de l’impôt 2019 avec les contraintes placées dans le fichier des instructions, ChatGPT a été plus pertinent que Gemini. Mais ce n’est qu’un exemple.

On peut aller plus loin. On peut demander à Gemini de régénérer un PDF selon les règles de calcul qu’il a utilisées pour réussir les 25 tests. On veut voir s’il a changé son raisonnement premier sur les calculs de la décote et de la réduction de 20% :

Image non disponible

Image non disponible

Cette fois-ci, Gemini a généré un fichier MarkDown que j’ai ensuite transformé en PDF [Le problème selon Gemini version 2]. Et Gemini a effectivement changé son raisonnement :

Image non disponible

 

Image non disponible

 

On constate qu’il n’y a plus le calcul particulier de la décote ni la règle de repêchage. Gemini a désormais adopté le raisonnement de ChatGPT.

9. Résolution des trois problèmes avec Grok

9-1. Introduction

Image non disponible

 
  • En [1], l’URL de l’IA Grok propriété de l’entreprise xAI [https://x.ai/company] ;
  • En [2], l’historique de vos conversations. Pour l’avoir, il faut vous créer un compte ;
  • En [3], posez votre question ;
  • En [4], vous pouvez joindre des fichiers ;
  • En [5], vous lancez l’exécution de l’IA ;

Contrairement à Gemini et ChatGPT, je n’ai pas rencontré de limites de questions, de temps ou de nombre de fichiers joints. Cela ne veut pas dire que ces limites n’existent pas.

9-2. Le problème 1

Image non disponible

 

Grok répond correctement à cette question.

9-3. Le problème 2

On propose à Grok de résoudre le calcul de l’impôt à l’aide du PDF généré par ChatGPT et on lui donne nos instructions dans un fichier texte.

Image non disponible

 

Le fichier texte est celui déjà utilisé avec les deux IA testées, mais on y a mis les 25 tests validés par ChatGPT et Gemini. Le PDF utilisé est celui généré par ChatGPT :

Grok fournit alors un script très propre mais porté dans PyCharm, pratiquement aucun test ne passe. Je lui fournis alors les logs de ses erreurs :

Image non disponible

Image non disponible

Cette fois-ci, Grok réussit les 25 tests. En [1-3], on montre le script [grok1] généré ainsi que les deux fichiers joints à la question.

9-4. Le problème 3

Cette fois-ci, on ne donne pas de PDF pour les règles de calcul. Grok devra les trouver sur internet. Les instructions texte [instructionsSansPDF5.txt] lui donnent les mêmes 25 tests que précédemment à vérifier.

Image non disponible

 

Grok réussit presque du premier coup. Il génère un script qui réussit 24 tests sur 25. On lui donne ses logs.

Image non disponible

Image non disponible

Au deuxième coup ça marche. En [1], le script généré par Grok, en [2] les instructions à suivre.

On lui demande maintenant de générer un PDF qui explique les règles de calcul qu’il a utilisées pour réussir les 25 tests :

Image non disponible

 

Grok ne génère alors pas un PDF mais un fichier [MarkDown]. J’ai utilisé un outil gratuit pour le transformer en PDF. Par ailleurs, PyCharm sait lire les fichiers [MarkDown] :

Image non disponible

 

9-5. Le problème 4

Pour valider le PDF généré précédemment, on le donne à Grok.

Image non disponible

 

Sa première mouture est correcte. Le script passe les 25 tests. En fait les IA ne semblent pas déterministes. On peut leur poser deux fois la même question et voir leurs réponses diverger. Cela a été le cas ici avec Grok. La première fois, j’avais omis qu’il ne devait pas aller sur internet et utiliser uniquement son PDF. Il a alors produit un script erroné. Je lui ai donné ses logs et là j’ai vu qu’il allait sur internet vérifier des choses. Dans la question ci-dessus, j’ai demandé à ce qu’il ne le fasse pas. Du coup, globalement Grok a été performant.

Résolution des trois problèmes avec ClaudeAI

9-6. Introduction

Image non disponible

Image non disponible

  • En [1], l’URL de l’IA ClaudeAI [https://claude.ai/chat] produit de l’entreprise Anthropic [https://www.anthropic.com/] ;
  • En [2], l’historique de vos chats. Les sessions gratuites de ClaudeAI sont très limitées. J’ai pris un abonnement payant d’un mois pour faire les tests qui suivent ;
  • En [3], votre question ;
  • En [4], pour joindre des fichiers à votre question ;
  • En [5], pour exécuter votre question ;

9-7. Le problème 1

La question :

Image non disponible

 

ClaudeAI répond correctement.

10. Le problème 2

La question :

Image non disponible

 

J’ai joint deux fichiers à ma question :

  • Le PDF généré par ChatGPT [Le problème selon ChatGPT.pdf] ;
  • Mes instructions dans le fichier texte [InstructionsAvecPDF4.txt]. C’est celui qui impose les 25 tests unitaires proposés par ChatGPT ;

La première réponse est incorrecte. On donne les logs de l’exécution :

Image non disponible

Image non disponible

La réponse comporte encore une erreur mais minime. ClaudeAI rate un test à 2 euros près alors que la précision demandée aux tests est de 1 euro. En fait, en leur temps, aussi bien Gemini que ChatGPT avaient raté ce test pour la même raison. Il est probable que la contrainte à 1 euro près est trop forte à cause des problèmes d’arrondis dont on ne connaît pas les règles officielles.

Toujours est-il qu’après deux aller / retour supplémentaires, ClaudeAI donne la bonne solution.

10-1. Le problème 3

La question :

Image non disponible

 

En [2], on a joint un fichier texte déjà utilisé avec les IA précédentes. Il oblige l’IA à chercher ses informations sur internet et impose là encore les 25 tests unitaires.

La première réponse a beaucoup d’erreurs. On transmet les logs à l’IA :

Image non disponible

 

Encore des erreurs :

Image non disponible

 

Toujours pas. On l’encourage :

Image non disponible

 

Toujours pas :

Image non disponible

 

Toujours pas :

Image non disponible

 

Rien à faire :

Image non disponible

 

Encore beaucoup d’échecs. On va considérer que ClaudeAI n’a pas su résoudre le problème 3 dans un délai raisonnable.

11. Résolution des trois problèmes avec MistralAI

11-1. Introduction

Image non disponible

Image non disponible

  • En [1], l’URL de l’IA MistralAI [https://chat.mistral.ai/chat] produit de l’entreprise Mistral AI [https://mistral.ai/] ;
  • En [2], l’historique de vos questions. Les sessions gratuites de MistralAI sont très limitées en nombre de questions, nombre de fichiers joints, temps passé. J’ai dû prendre un abonnement payant d’un mois pour faire les tests sui suivent ;
  • En [3], votre question ;
  • En [4], pour joindre des fichiers à votre question ;
  • En [5], pour exécuter votre question ;

11-2. Le problème 1

La question :

Image non disponible

 

MistralAI répond correctement à la question.

11-3. Le problème 2

La question :

Image non disponible

 

On propose à MistralAI de résoudre le problème de calcul de l’impôt 2019 avec les règles de calcul générées par ChatGPT dans le PDF. Le fichier texte donne mes instructions avec les 25 tests à réaliser.

En fait, je n’arriverai à rien avec MistralAI. Le problème principal est qu’il ne lit pas (ou ne veut pas lire) les instructions du fichier texte [instructionsAvecPDF4.txt]. Il génère un code qui ne respecte pas mes exigences et ne génère pas non plus les 25 tests unitaires demandés.

12. Résolution des trois problèmes avec DeepSeek

12-1. Introduction

Image non disponible

Image non disponible

  • En [1], l’URL de DeepSeek [https://chat.deepseek.com/] ;
  • En [2], votre historique. Pour l’avoir il faut vous créer un compte (gratuit en sept. 2025) ;
  • En [3], votre question ;
  • En [4], pour joindre des fichiers à votre question ;
  • En [5], pour exécuter votre question ;

12-2. Le problème 1

La question :

Image non disponible

 

La réponse de DeepSeek laisse à désirer. Elle est moins précise que celles générées par les autres IA.

12-3. Le problème 2

La question :

Image non disponible

 

La première réponse est incorrecte. On relance :

Image non disponible

 

La réponse suivante est un peu meilleure :

Image non disponible

 

La réponse suivante est très décevante. Quasiment tous les tests échouent. Dans les réponses de DeepSeek, on ne sent pas la certitude des premières IA testées. On dirait que l’IA doute elle-même de l’exactitude de ses réponses. Par ailleurs, on a l’impression que DeepSeek ne réfléchit pas. Elle donne une réponse très rapidement alors que ChatGPT mettait des minutes à réfléchir. Peut-être un problème de configuration.

Image non disponible

Image non disponible

Cette fois-ci c’est mieux. Il ne reste plus qu’un échec à 2 euros près. D’autres IA ont chuté sur ce même test avec ces mêmes deux euros d’écart. On va considérer que le script de DeepSeek est correct.

12-4. Le problème 3

La question

Image non disponible

 

Cette fois, plus de PDF. DeepSeek va devoir chercher les règles de calcul sur internet.

Première réponse : les 25 tests échouent. On recommence.

Image non disponible

 

Les 25 tests échouent de nouveau.

Image non disponible

 

De nouveau, 25 tests échoués. On abandonne et on considère que DeepSeek n’a pas su résoudre le problème 3 dans un temps raisonnable.

13. Conclusion

Des paragraphes qui précèdent, on retiendra que seules les IA [ChatGPT, Grok, Gemini] ont su résoudre les trois problèmes proposés. On retiendra également que ce test a été fait sur un exemple précis et qu’il ne faut donc pas généraliser cette conclusion.


précédentsommaire

Licence Creative Commons
Le contenu de cet article est rédigé par Serge Tahé et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2025 Developpez.com.