Skip to content

4. Resolução dos três problemas com o Google Gemini

Apresentaremos as capturas de tela das três sessões do Gemini que permitiram resolver os três problemas apresentados. Entraremos em detalhes. Feito isso, não repetiremos o processo para os outros IA testados. Eles funcionam de maneira semelhante. Apresentaremos apenas os detalhes mais relevantes.

4.1. Introdução

Recordamos a primeira captura de tela do Gemini apresentada anteriormente:

 
  • No [1], o URL do Gemini;
  • Em [2], a versão do Gemini utilizada;
  • Em [3-5], os três problemas apresentados ao Gemini;

O Gemini é um produto do Google disponível no URL [https://gemini.google.com/]. Para ter um histórico de suas sessões de perguntas e respostas como o mostrado acima, é necessário criar uma conta. Além disso, assim como todos os outros IA testados, o Gemini limita o número de perguntas e o número de arquivos baixados. Quando esse limite é atingido, a sessão é encerrada e é sugerido que você a continue mais tarde. Como é bastante frustrante ter que parar no meio de uma sessão, eu fiz uma assinatura. Felizmente, o primeiro mês da assinatura do Gemini é gratuito. Fiz o mesmo com os outros IA que apresentavam essas limitações, a saber: ChatGPT, MistralAI e ClaudeAI. Fiz uma assinatura de um mês, mas, nesse caso, o primeiro mês era pago. Não encontrei limites com o Grok. O DeepSeek não anuncia limites, mas às vezes responde como [Server busy] e interrompe a sessão. Isso equivale a impor limites sem avisar.

Daqui em diante, vou me referir à sessão de perguntas e respostas simplesmente como “sessão”. Os IA costumam usar o termo em inglês “chat” (conversa) ou “conversa”.

A interface do Gemini para fazer uma pergunta é a seguinte:

  • No [1], sua pergunta;
  • Em [2], o ícone que inicia o IA para o cálculo da resposta;
  • Em [3-4], você pode anexar arquivos;

4.2. Problema 1

A sessão para o problema 1 é a seguinte:

 
  • No [1], a pergunta;
  • No [2], o início da resposta do Gemini;

A continuação da resposta é a seguinte:

 
 
 
 

A resposta está correta. Os outros cinco IA também darão a resposta correta de forma semelhante.

4.3. Problema 2

4.3.1. Introdução

Recordamos aqui o problema inicial da aula [python3-flask-2020]. Trata-se de um texto fornecido aos alunos em TD.

 

A tabela acima permite calcular o imposto no caso simplificado de um contribuinte que tenha apenas seu salário para declarar. Conforme indicado na nota (1), o imposto assim calculado é o imposto antes da aplicação de três mecanismos:

  • O teto do quociente familiar, que se aplica a rendas elevadas;
  • O abatimento e a redução de impostos, que se aplicam a rendas baixas;

Assim, o cálculo do imposto compreende as seguintes etapas [http://impotsurlerevenu.org/comprendre-le-calcul-de-l-impot/1217-calcul-de-l-impot-2019.php]:

 

Propõe-se escrever um programa que permita calcular o imposto de um contribuinte em 2019, no caso simplificado de um contribuinte que tenha apenas seu salário a declarar.

4.3.1.1. Cálculo do imposto bruto

O imposto bruto pode ser calculado da seguinte maneira:

Primeiro, calcula-se o número de cotas do contribuinte:

  • Cada pai ou mãe contribui com 1 parte;
  • Os dois primeiros filhos contribuem com 1/2 parte cada um;
  • Os filhos seguintes contribuem com uma parte cada:

O número de partes é, portanto:

  • nbParts=1+nbEnfants*0,5+(nbEnfants-2)*0,5 se o empregado não for casado;
  • nbParts = 2 + nbEnfants * 0,5 + (nbEnfants - 2) * 0,5 se ele for casado;
  • onde nbEnfants é o número de filhos;
  • Calcula-se a renda tributável R = 0,9 * S, onde S é o salário anual;
  • Calcula-se o quociente familiar QF = R / nbParts;
  • Calcula-se o imposto bruto I com base nos seguintes dados (2019):
9964
0
0
27.519
0,14
1.394,96
73.779
0,3
5.798
156.244
0,4
13.913,69
0
0,45
20163,45

Cada linha possui 3 campos: champ1, champ2, champ3. Para calcular o imposto I, procura-se a primeira linha em que QF ≤ campo1 e utilizam-se os valores dessa linha. Por exemplo, para um funcionário casado, com dois filhos e um salário anual S de 50.000 euros:

Renda tributável: R = 0,9 * S = 45.000

Número de cotas: nbParts = 2 + 2 * 0,5 = 3

Quociente familiar: QF = 45.000 / 3 = 15.000

A primeira linha em que QF <= campo1 é a seguinte:

    27519    0.14    1394.96

O imposto I é, portanto, igual a 0,14*R – 1.394,96*nbParts = [0,14*45000-1394,96*3] = 2.115. O imposto é arredondado para o euro inferior.

Se a relação QF <= campo1 for verdadeira já na primeira linha, então o imposto é zero.

Se QF for tal que a relação QF <= campo1 nunca for verificada, então são utilizados os coeficientes da última linha. Aqui:

    0    0.45    20163.45

o que resulta no imposto bruto I = 0,45 * R – 20.163,45 * nbParts.

4.3.1.2. Limite máximo do quociente familiar

 

Para saber se o limite máximo do quociente familiar QF se aplica, refaz-se o cálculo do imposto bruto sem os filhos. Ainda para o empregado casado com dois filhos e um salário anual S de 50.000 euros:

Renda tributável: R = 0,9 * S = 45.000

Número de faixas: nbParts=2 (os filhos não são mais contabilizados)

Quociente familiar: QF = 45.000 / 2 = 22.500

A primeira linha em que QF <= campo1 é a seguinte:

    27519    0.14    1394.96

O imposto I é, então, igual a 0,14*R – 1.394,96*nbParts = [0,14*45000-1394,96*2] = 3.510.

Ganho máximo relacionado aos filhos: 1551 * 2 = 3102 euros

Imposto mínimo: 3.510 – 3.102 = 408 euros

O imposto bruto com 2 cotas, já calculado no parágrafo anterior (2.115 euros), é superior ao imposto mínimo (408 euros); portanto, o teto familiar não se aplica neste caso.

De modo geral, o imposto bruto é maior que (imposto1, imposto2), onde:

  • [impôt1]: é o imposto bruto calculado com os filhos;
  • [impôt2]: é o imposto bruto calculado sem os filhos e deduzido do ganho máximo (aqui, 1.551 euros por meia parcela) relacionado aos filhos;

4.3.1.3. Cálculo da redução

 

Ainda para o trabalhador casado com dois filhos e um salário anual S de 50.000 euros:

O imposto bruto (2.115 euros) resultante da etapa anterior é inferior a 2.627 euros para um casal (1.595 euros para um solteiro): portanto, a redução se aplica. Ela é obtida pelo seguinte cálculo:

abatimento = limite (casal = 1.970 / solteiro = 1.196) – 0,75 * Imposto bruto

abatimento = 1.970 – 0,75 * 2.115 = 383,75, arredondado para 384 euros.

Novo imposto bruto = 2.115 – 384 = 1.731 euros

É preciso observar duas regras no cálculo da redução (algumas ferramentas de IA tiveram dificuldades com essa questão):

  • A dedução não pode ser negativa;
  • A redução não pode ser superior ao imposto já calculado;

4.3.1.4. Cálculo da redução de impostos

 

Abaixo de um determinado limite, é aplicada uma redução de 20% sobre o imposto bruto resultante dos cálculos anteriores. Em 2019, os limites são os seguintes:

  • solteiro: 21.037 euros;
  • casal: 42.074 euros; (o valor 37.968 utilizado no exemplo acima parece estar incorreto);

Esse limite é aumentado pelo valor: 3.797 * (número de meias-partes trazidas pelos filhos).

Ainda no caso do trabalhador casado com dois filhos e um salário anual S de 50.000 euros:

  • Seu rendimento tributável (45.000 euros) é inferior ao limite (42.074 + 2 × 3.797) = 49.668 euros;
  • Portanto, ele tem direito a uma redução de 20% do seu imposto: 1.731 * 0,2 = 346,2 euros, arredondado para 347 euros;
  • O imposto bruto do contribuinte passa a ser: 1.731 – 347 = 1.384 euros;

4.3.1.5. Cálculo do imposto líquido

Nosso cálculo termina aqui: o imposto líquido a pagar será de 1.384 euros. Na prática, o contribuinte pode se beneficiar de outras deduções, especialmente por doações a instituições de interesse público ou geral.

4.3.1.6. Caso dos rendimentos elevados

Nosso exemplo anterior corresponde à maioria dos casos de assalariados. No entanto, o cálculo do imposto é diferente no caso de rendas elevadas.

4.3.1.6.1. Limite máximo da redução de 10% sobre a renda anual

Na maioria dos casos, a renda tributável é obtida pela fórmula: R = 0,9 * S, em que S é o salário anual. Isso é chamado de redução de 10%. Essa redução tem um limite máximo. Em 2019:

  • Ela não pode ser superior a 12.502 euros;
  • Não pode ser inferior a 437 euros;

Consideremos o caso de um trabalhador solteiro, sem filhos, com um salário anual de 200.000 euros:

  • A redução de 10% é de 20.000 euros > 12.502 euros. Portanto, ela é reduzida para 12.502 euros;

4.3.1.6.2. Limite máximo do quociente familiar

Consideremos um caso em que se aplica o limite máximo familiar apresentado no parágrafo |Limite máximo do quociente familiar|. Tomemos o caso de um casal com três filhos e renda anual de 100.000 euros. Repassemos as etapas do cálculo:

  • A dedução de 10% é de 100.000 euros < 12.502 euros. O rendimento tributável R é, portanto, 100.000 – 10.000 = 90.000 euros;
  • O casal tem nbParts = 2 + 0,5 × 2 + 1 = 4 cotas;
  • Seu quociente familiar é, portanto, QF = R / nbParts = 90.000 / 4 = 22.500 euros;
  • Seu imposto bruto I1 com filhos é I1 = 0,14 × 90.000 – 1.394,96 × 4 = 7.020 euros;
  • Seu imposto bruto I2 sem filhos:
    • QF = 90.000 / 2 = 45.000 euros;
    • I2 = 0,3 × 90.000 – 5.798 × 2 = 15.404 euros;
  • A regra do teto do quociente familiar estabelece que o ganho gerado pelos filhos não pode ultrapassar (1.551 × 4 meias-partes) = 6.204 euros. No entanto, neste caso, ele é I2-I1 = 15.404 – 7.020 = 8.384 euros, portanto, superior a 6.204 euros;
  • O imposto bruto é, portanto, recalculado como I3 = I2-6204 = 15.404 – 6.204 = 9.200 euros;
  • Como I3 > I1, será o imposto I3 que será mantido;

Esse casal não terá abatimento nem redução, e seu imposto final será de 9.200 euros.

4.3.1.7. Números oficiais

O cálculo do imposto é complexo. Ao longo do documento, os testes serão realizados com os exemplos a seguir. Os resultados são os do simulador da administração tributária |https://www3.impots.gouv.fr/simulateur/calcul_impot/2019/simplifie/index.htm|:

Contribuinte
Resultados oficiais
Resultados do algoritmo do documento
Casal com 2 filhos e renda anual de 55.555 euros
Imposto = 2.815 euros
Alíquota de imposto = 14%
Imposto = 2.814 euros
Alíquota de imposto = 14%
Casal com 2 filhos e renda anual de 50.000 euros
Imposto = 1.385 euros
Abatimento = 384 euros
Redução = 346 euros
Alíquota de imposto = 14%
Imposto = 1.384 euros
Abatimento = 384 euros
Redução = 347 euros
Alíquota de imposto = 14%
Casal com 3 filhos e renda anual de 50.000 euros
Imposto = 0 euro
Abatimento = 720 euros
Redução = 0 euros
Alíquota de imposto = 14%
Imposto = 0 euro
desconto = 720 euros
Redução = 0 euros
Alíquota de imposto = 14%
Solteiro, com 2 filhos e renda anual de 100.000 euros
Imposto = 19.884 euros
Abatimento = 0 euros
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 19.884 euros
Sobretaxa = 4.480 euros
abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Solteiro, com 3 filhos e renda anual de 100.000 euros
Imposto = 16.782 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 16.782 euros
Sobretaxa = 7.176 euros
abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Casal com 3 filhos e renda anual de 100.000 euros
Imposto = 9.200 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 30%
Imposto = 9.200 euros
Sobretaxa = 2.180 euros
abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 30%
Casal com 5 filhos e renda anual de 100.000 euros
Imposto = 4.230 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 14%
Imposto = 4.230 euros
abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 14%
Solteiro, sem filhos e com renda anual de 100.000 euros
Imposto = 22.986 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 22.986 euros
Sobretaxa = 0 euro
abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Casal com 2 filhos e renda anual de 30.000 euros
Imposto = 0 euro
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 0%
Imposto = 0 euro
desconto = 0 euro
Redução = 0 euro
Alíquota de imposto = 0%
Solteiro, sem filhos e com renda anual de 200.000 euros
Imposto = 64.211 euros
Abatimento = 0 euro
Redução = 0 euros
Alíquota de imposto = 45%
Imposto = 64.210 euros
Sobretaxa = 7.498 euros
abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 45%
Casal com 3 filhos e renda anual de 200.000 euros
Imposto = 42.843 euros
Abatimento = 0 euro
Redução = 0 euro
Alíquota de imposto = 41%
Imposto = 42.842 euros
Sobrevalorização = 17.283 euros
Desconto = 0 euro
Redução = 0 euros
Alíquota de imposto = 41%

No exemplo acima, denomina-se “sobretaxa” o valor adicional que os rendimentos mais elevados pagam devido a dois fatores:

  • O teto de 10% para a dedução sobre a renda anual;
  • O limite máximo do quociente familiar;

Esse indicador não pôde ser verificado, pois o simulador da administração tributária não o fornece.

Percebe-se que o algoritmo do documento calcula o imposto correto em todas as ocasiões, embora com uma margem de erro de 1 euro. Essa margem de erro decorre dos arredondamentos. Todos os valores monetários são arredondados, ora para o euro superior, ora para o euro inferior. Como eu não conhecia as regras oficiais, os valores monetários do algoritmo do documento foram arredondados:

  • Para o euro superior, no caso de descontos e reduções;
  • Para o euro inferior, no caso das sobretaxas e do imposto final;

Vamos solicitar ao IA que faça esse cálculo de imposto.

4.3.2. Configuração da sessão do Gemini

A consulta feita ao Gemini é acompanhada por dois arquivos:

 
  • No [1], o cálculo que acabamos de detalhar foi inserido em um PDF, que é fornecido ao Gemini. O Gemini encontrará nele as regras exatas para o cálculo simplificado do imposto de 2019 sobre os rendimentos de 2018;
  • No [2], nossas instruções;
  • No arquivo [3], para executar o arquivo IA;

Nossas instruções no arquivo de texto [instructionsAvecPDF.txt] são as seguintes:

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/simulador/calcul_impot/2019/simplifica/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é.

Essas instruções são o resultado de inúmeras perguntas feitas ao Gemini. Rapidamente, percebemos que o IA precisa ser muito bem definido se quisermos obter o que desejamos. Foi por causa de todas essas tentativas e erros que a sessão do Gemini acabou sendo interrompida por exceder os limites. Vamos examinar o restante dessas instruções:

  • Linha 1: solicitamos que a conversa seja em francês. Essa indicação é para o DeepSeek, que tinha a tendência de falar inglês;
  • Linha 3: o que queremos;
  • Linha 5: diz-se ao IA para usar o PDF que lhe foi fornecido;
  • Linhas 7-14: algumas dicas úteis, especialmente para o problema 3 sem o PDF. Vários IA se perderam no cálculo do imposto;
  • Linhas 15-44: os 11 testes unitários que queremos que sejam incluídos no script gerado. Quando o script for gerado, vamos executá-lo no PyCharm e veremos se os 11 testes são aprovados;
  • Linhas 46-53: sem essas instruções, o IA gerava testes unitários que buscavam resultados exatos e falhavam;
  • Linhas 55-56: instruo o IA a não acessar a internet. A solução mais simples é usar o PDF;
  • Linhas 58-59: essa instrução não foi seguida pelo IA. Fui obrigado a escrevê-la explicitamente em uma pergunta, quando constatei que um teste havia falhado;
  • Linhas 61-65: indico que tipo de script Python desejo;
  • Linhas 67-69: eu teria preferido um link para baixar o script gerado, pois a exibição do código na tela demora. Verificou-se que a maioria dos IA não sabe fazer isso. Os links fornecidos não funcionavam;
  • Linhas 71-72: eu gostaria de saber o tempo que o IA levou para responder à pergunta. Apenas o Gemini conseguiu me fornecer essa informação. Os demais IA ou não atendiam a essa instrução, ou forneciam números aleatórios, demonstrando que não compreendiam a instrução;

4.3.3. A resposta da Gemini

A primeira resposta da Gemini é a seguinte:

 
  • Em [1-4], o Gemini fornece links para a parte do PDF ou do arquivo de texto com as instruções que ele utiliza em determinado momento;

A continuação é a seguinte:

 
  • No [1], o Gemini afirma que executou os 11 testes unitários com sucesso. A maioria dos IA também afirmou isso tanto no problema 2 quanto no problema 3 e, frequentemente, ao carregar o script gerado, ele não funcionava. Portanto, é preciso ter cautela com essa afirmação. No caso do Gemini, isso se confirmará como verdadeiro;
  • No [2], um link que acabará não funcionando;
  • No [3], apenas o Gemini forneceu um tempo de execução realista;

Portanto, o link [2] não funciona. Informamos isso ao Gemini:

 

A resposta do Gemini:

 
  • No [1], o script Python gerado pelo Gemini;

Carregamos esse script em PyCharm e o executamos:

 
  • Em [1], [gemini1] é o script gerado pelo Gemini;

Ao executar o script, aparecem erros de compilação:


"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
  • Linha 30, o erro de compilação. [cite_start] é um marcador para gerar um determinado tipo de texto;

Colocamos os logs acima em um arquivo [logs gemini1.txt] e o fornecemos ao Gemini:

 

A resposta do Gemini é então a seguinte:

 

Carregado no arquivo PyCharm, a execução do novo script gera exatamente o mesmo erro. Informamos isso ao Gemini, fornecendo novamente os logs da execução:

 

A resposta do Gemini é a seguinte:

 

Desta vez deu certo. Os 11 testes unitários foram bem-sucedidos. Informamos isso ao Gemini:

 

Que responde:

 

O script gerado pelo Gemini seguiu as instruções fornecidas no arquivo de texto [instructionsAvecPDF.txt]:

# -*- 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 ---
# Todos os valores são extraídos do documento PDF fornecido.

# Limites máximos para a dedução de 10% sobre a renda anual
PLAFOND_ABATTEMENT_10_POURCENT = 12502.0
MINIMUM_ABATTEMENT_10_POURCENT = 437.0

# Tabela de alíquotas do imposto de renda de 2019
# Estrutura: (Limite máximo da faixa, Alíquota de imposto, Valor a deduzir por parcela)
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}
]

# Limite máximo do quociente familiar
GAIN_MAX_DEMI_PART = 1551.0  # Ganho máximo por meia parcela adicional

# Limites e valores para o abatimento
SEUIL_APPLICATION_DECOTE = {"celibataire": 1595.0, "couple": 2627.0}
SEUIL_CALCUL_DECOTE = {"celibataire": 1196.0, "couple": 1970.0}

# Limites para a redução de imposto 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
     # A dedução está limitada entre um valor mínimo e um valor máximo
    abattement = min(PLAFOND_ABATTEMENT_10_POURCENT, max(MINIMUM_ABATTEMENT_10_POURCENT, abattement_calcule))

     # A questão pede para arredondar a dedução para o euro superior
    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

     # Se o QF for superior a todos os limites, utiliza-se a última faixa
    if tranche_applicable is None:
        tranche_applicable = BAREME_IMPOT_2019[-1]

     # Fórmula para o cálculo do imposto bruto
    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

     # Cálculo do imposto sem as parcelas dos filhos
    parts_sans_enfants = calculer_nombre_parts(adultes, 0)
    impot_sans_enfants = calculer_impot_brut_base(revenu_imposable, parts_sans_enfants)

     # Cálculo do ganho máximo relacionado aos filhos
    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

     # O imposto retido é o maior dos dois cálculos
    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
     # A redução é aplicada se o imposto estiver abaixo do limite de aplicação
    if impot_avant_decote < seuil_application:
         # Fórmula do abatimento: limite - 0,75 * Imposto bruto
        decote_calculee = seuil_calcul - (0.75 * impot_avant_decote)

         # Arredondamento para o euro superior
        decote = math.ceil(decote_calculee)

         # A redução não pode ser negativa nem superior ao imposto
        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]

     # O limite mínimo é aumentado para cada meia-parte relacionada aos filhos
    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
     # A redução se aplica se a renda tributável estiver abaixo do limite
    if revenu_imposable < seuil_final:
        reduction_calculee = impot_avant_reduction * 0.20

         # Arredondado para o euro superior
        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.
    """
     # Etapa 1: Cálculo da renda tributável
    revenu_imposable = calculer_revenu_imposable(revenus)

     # Etapa 2: Cálculo do número de cotas
    nombre_parts = calculer_nombre_parts(adultes, enfants)

     # Etapa 3: Cálculo do imposto bruto
    impot_brut_initial = calculer_impot_brut_base(revenu_imposable, nombre_parts)

     # Etapa 4: Aplicação do limite máximo do QF
    impot_apres_plafonnement = appliquer_plafonnement_qf(impot_brut_initial, revenu_imposable, adultes, enfants)

     # Etapa 5: Aplicação do abatimento
    impot_apres_decote, decote_calculee = appliquer_decote(impot_apres_plafonnement, adultes)

     # Etapa 6: Aplicação da redução de 20%
    impot_avant_arrondi_final, reduction_calculee = appliquer_reduction_20_pourcent(impot_apres_decote,
                                                                                    revenu_imposable, adultes, enfants)

     # Etapa 7: Arredondamento final do imposto para o euro inferior
    impot_final = math.floor(impot_avant_arrondi_final)

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


# --- TESTS UNITAIRES ---
# Validação do script com os casos fornecidos
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)

     # Exemplo de uso da calculadora para um caso específico
    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']}€")

Não verifiquei esse código. Como os 11 testes unitários foram aprovados, considero que ele está “provavelmente correto”. Não fiz nada além de verificar esses 11 testes no meu próprio código.

4.4. Problema 3

O problema 3 é idêntico ao problema 2, com a diferença de que não se fornece mais ao IA o PDF, que fornecia as regras de cálculo a serem seguidas.

A pergunta inicial para o Gemini é a seguinte:

 

O arquivo de instruções em [1] é praticamente o mesmo do problema 2, com as seguintes diferenças:


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 :

  • No [3], pede-se que ele encontre na internet as regras de cálculo do imposto de 2019 sobre os rendimentos de 2018. Esse é um exercício mais difícil do que o anterior;

A seguir, apresento apenas trechos da primeira resposta do Gemini:

 
 

O tempo estimado é plausível. Esperamos muito tempo pela resposta do Gemini.

Assim como anteriormente, o Gemini forneceu um link para baixar o script gerado, link esse que não funciona. Informamos isso a ele:

 

A resposta da Gemini:

 

Carregamos o script em PyCharm com o nome [gemini2]:

 

Executamos e… não funciona. Os logs da execução são os seguintes:


"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
  • Linha 11, um teste falhou;
  • Linhas 25 e 42: o mesmo erro de compilação;

Colocamos esses logs em um arquivo de texto que enviamos ao Gemini:

 

A resposta do Gemini:

 
 

Carregamos o script em PyCharm e o executamos. Mais erros. Informamos isso ao Gemini, anexando novamente os logs da execução:

 

A resposta da Gemini:

 
 
 

Carregamos esse novo script no PyCharm e o executamos. Desta vez, os 11 testes unitários foram aprovados:

O código gerado pelo Gemini é o seguinte:

# -*- coding: utf-8 -*-
import math
import unittest

# ==============================================================================
# CONSTANTES POUR OIMPOSITION 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: Se o imposto já for 0, não há desconto nem redução.
    if impot_apres_plafonnement == 0:
        return 0, 0, 0

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

     # 1. Determinar a elegibilidade para o desconto 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. Determinar a elegibilidade para o desconto
    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: O desconto devolvido não pode exceder o imposto que ele anula
        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. Aplicar a redução de 20% se for elegível
    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)

Mais uma vez, não examinei esse código. Apenas constatei que ele passou nos 11 testes com sucesso.

Mas pode ser interessante conhecer seu raciocínio, especialmente nos casos específicos do cálculo do imposto. Perguntamos a ele:

 

Trata-se de um caso de renda elevada, com um possível limite máximo de 10% para a dedução e um possível limite máximo para o quociente familiar.

A resposta do Gemini é a seguinte:

 
 
 
 
 

Essas duas últimas capturas de tela são interessantes. O Gemini utiliza um método de cálculo diferente daquele explicado no PDF. De fato, esse método de cálculo pode ser encontrado na internet. Os dois métodos são equivalentes.

 
 
 

A explicação se destaca pela clareza. Ela poderia ser apresentada tal como está aos alunos para explicar o método de cálculo do imposto.

Agora, vamos considerar outro exemplo, desta vez com rendimentos baixos. Nesse caso, pode haver abatimento e redução:

 

A resposta do Gemini é a seguinte:

 
 
 
 
 

Aqui, percebe-se que o Gemini aplica uma regra que não consta no PDF. Provavelmente ele a encontrou na internet, mas será que a fonte é confiável?

 

Aqui, o Gemini continua aplicando uma regra desconhecida (a regra especial mencionada acima).

 
 
 

Portanto, os resultados do Gemini coincidem com o resultado do simulador oficial de impostos. Mas ele utilizou uma regra que não consta no PDF. Onde está o erro? Perguntamos a ele, anexando o PDF:

 

A resposta do Gemini:

 
 
 
 

Acho que a Gemini está certa e que meu PDF está errado. Para verificar isso, peço a ela que faça um teste:

  • Em que seu raciocínio daria os mesmos resultados que o simulador oficial de impostos;
  • onde o raciocínio do PDF levaria a resultados diferentes dos do simulador;
 

A resposta do Gemini é a seguinte:

 

Aqui, o Gemini está errado. Eu executei o simulador com esse exemplo e obtive o seguinte resultado:

 

No entanto, vamos descobrir que o raciocínio do Gemini realmente leva aos resultados acima. Continuemos:

 
 
 
 

Muito bem. Anotado. Vamos continuar:

 
 
 
 

Portanto, o Gemini calculou (imposto, desconto, redução) = (431, 325, 1296), enquanto o simulador que utilizei apresentou (431, 324, 1297). Assim, o Gemini chegou aos resultados corretos com uma diferença de apenas 1 euro, mas ele não sabe disso. Vamos informá-lo:

 

O Gemini responde:

 
 

Agora, nos perguntamos se o Gemini poderia gerar um PDF corrigido:

 

A resposta do Gemini:

 

Portanto, o Gemini não me forneceu um link para um PDF, mas gerou um texto para que eu mesmo pudesse gerar esse PDF. Embora seja um pouco complicado incluir aqui as capturas de tela do PDF, estou fazendo isso para que o leitor perceba o aspecto gerativo do IA:

 

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Image

Sinceramente, não verifiquei se tudo o que está escrito neste PDF é verdade. De qualquer forma, é um documento perfeito para um TD, gerado em poucos segundos.

No entanto, podemos pedir ao próprio Gemini para verificar se o seu PDF está correto. Iniciamos uma nova conversa:

 
  • no [1], colocamos o PDF gerado pelo Gemini [Le problème selon Gemini.pdf];
  • no [2], o [instructionsAvecPDF2.txt] é idêntico às instruções do [instructionsAvecPDF.txt], exceto pelo fato de termos adicionado um décimo segundo teste unitário, justamente aquele que demonstrou que o PDF inicial estava incorreto:
test12 : (2, 2, 49500) -> (1297, 431, 324)

Curiosamente, foram necessárias várias tentativas antes que o Gemini gerasse o script correto:

Pergunta 2

 

Pergunta 3

 

Como já foi feito várias vezes, quando o script gerado e carregado no PyCharm falha, fornecemos ao Gemini o arquivo de texto com os logs da execução. O Gemini os compreende muito bem.

Pergunta 4

 

Pergunta 5

 

Pergunta 6 e fim

Agora estamos certos da validade do PDF gerado pelo Gemini. As regras de cálculo nele apresentadas estão corretas.

Agora faremos o mesmo com os outros cinco IA, mas seremos muito breves em nossas explicações, exceto no caso do ChatGPT, o IA líder no momento. O que nos interessa é saber se o IA resolve ou não os três problemas que lhe são apresentados. De fato, as interfaces de todos esses IA são muito semelhantes e procedi com elas da mesma forma que com o Gemini. O leitor é incentivado a reproduzir as conversas do Gemini com o IA de sua escolha.