Skip to content

5. حل المشكلات الثلاث باستخدام ChatGPT

5.1. مقدمة

إليكم أول لقطة شاشة لجلسة ChatGPT:

 
  • في [1-3]، المشاكل الثلاث التي طرحت على ChatGPT؛
  • في [4]، عنوان URL لـ ChatGPT؛
  • في [5]، إصدار ChatGPT المستخدم؛

ChatGPT هو أحد منتجات OpenAI المتاحة على الرابط [https://chatgpt.com/]. لعرض سجل جلسات الأسئلة والأجوبة الخاصة بك مثل تلك المذكورة أعلاه، تحتاج إلى إنشاء حساب. علاوة على ذلك، مثل جميع أنظمة الذكاء الاصطناعي الأخرى التي تم اختبارها، يحدد ChatGPT عدد الأسئلة التي يمكنك طرحها وعدد الملفات التي يمكنك تحميلها. عند الوصول إلى هذا الحد، تنتهي الجلسة، ويتم عرض خيار عليك للمتابعة لاحقًا. يتم الوصول إلى الحدود التي يفرضها ChatGPT بسرعة كبيرة. لإنشاء هذا البرنامج التعليمي، اضطررت إلى شراء اشتراك مدفوع لمدة شهر واحد.

واجهة ChatGPT هي كما يلي:

 
  • في [1]، لإرفاق ملفات بالسؤال المطروح؛
  • في [2]، السؤال المطروح؛
  • في [3]، لتشغيل الذكاء الاصطناعي؛

5.2. المشكلة 1

السؤال الموجه إلى ChatGPT:

  
 

يقدم ChatGPT إجابة صحيحة.

5.3. المشكلة 2

يتضمن هذا حساب الضريبة باستخدام ملف PDF. بصراحة، سنستخدم ملف PDF الذي أنشأته Gemini، والذي يصحح الأخطاء الموجودة في ملف PDF الأصلي.

 
  • في [1]، قدمنا ملف PDF الذي أنشأه Gemini؛
  • في [2]، أضفنا الاختبار الوحدوي الذي أظهر من خلاله Gemini تفوقه:
test12 : (2, 2, 49500) -> (1297, 431, 324)

نقوم بتشغيل ChatGPT. يستغرق الأمر حوالي 3 دقائق لتوليد الرد. على عكس Gemini، فإنه يوفر رابطًا فعالاً لاسترداد البرنامج النصي الذي تم إنشاؤه. نقوم بتحميل هذا في PyCharm:

 

يعمل البرنامج النصي [chatGPT1] من المحاولة الأولى. لا مجال للمنافسة هنا؛ في هذه المشكلة، تفوق ChatGPT على Gemini.

النص البرمجي [chatGPT1] المقدم من ChatGPT هو كما يلي:

#  -*- 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

#  ---------- Regulatory constants ----------

#  Professional expense allowance (floor/ceiling) for 2018 income
ABATTEMENT_TAUX = 0.10
ABATTEMENT_MIN = 437
ABATTEMENT_MAX = 12502

#  Scale 2018 (QF)
#  Each band is (borne_sup, rate). The first 0% bracket ends at €9,964.
BAREME_2018 = [
    (9964, 0.00),
    (27519, 0.14),
    (73779, 0.30),
    (156244, 0.41),
    (float("inf"), 0.45),
]

#  Family allowance ceiling
PF_QF_AVANTAGE_PAR_DEMI_PART = 1551  #  max benefit per 1/2 share ENFANT

#  Discount (thresholds according to number of adults / couple status)
DECOTE_SEUIL_CELIB = 1196
DECOTE_SEUIL_COUPLE = 1970

#  20% reduction: share-based thresholds
REDUCTION_BASE_1_PART = 18985
REDUCTION_BASE_2_PARTS = 37970
REDUCTION_PAR_DEMI_PART_SUP = 3803  #  addition of 1/2 share above the base of 1 or 2 shares


#  ---------- Data structures ----------

@dataclass
class ResultatImpot:
    impot: int  #  final tax payable, rounded down to the nearest euro
    decote: int  #  discount rounded up to the nearest euro
    reduction: int  #  20% discount rounded up to the nearest euro


#  ---------- Utility functions ----------

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))


#  ---------- Step 1: Net taxable income (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)))


#  ---------- Step 2: Number of units ----------

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
    #  children >= 2
    parts += 1.0  #  +0.5 +0.5 for the first two
    if enfants > 2:
        parts += (enfants - 2) * 1.0  #  +1 per child from the 3rd
    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
    #  First two children = 2 * half-parts, then +2 half-parts per child from the 3rd onwards
    return 2 + (enfants - 2) * 2


#  ---------- Step 3: Gross tax 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


#  ---------- Step 4.1: Capping the family quotient ----------

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


#  ---------- Step 4.2: Discount and 20% reduction ----------

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

    #  Eligible for 20% discount based on RNI
    seuil_red = seuil_reduction_20(rni, adultes, parts)
    eligible_reduction = rni < seuil_red  #  "below a threshold" in PDF

    #  Eligible for discount: directly below threshold, or if reduction would cause the threshold to be lowered
    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  #  theoretical 20% reduction
        if imp_theorique_apres_red <= s_dec:
            repechage = True

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

    #  Apply discount first (if eligible)
    if elig_decote:
        montant_decote = s_dec - (imp * 0.75)
        decote_calc = max(0, arrondi_sup(montant_decote))
        #  The discount cannot exceed the remaining tax: it is limited to
        decote = min(decote_calc, arrondi_sup(imp))
        imp = max(0.0, imp - decote)

    #  Then apply the reduction if eligible
    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 main ----------

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) Units
    parts = nombre_parts(adultes, enfants)

    #  3) Gross tax via tax scale (with all shares)
    imp_brut_A = impot_brut_total(rni, parts)

    #  4.1) Family allowance ceiling
    imp_apres_plaf = apply_plafonnement_qf(imp_brut_A, rni, adultes, enfants)

    #  4.2) Discount then 20% reduction (with draft)
    decote, reduction, imp_corrige = calc_decote_reduction(imp_apres_plaf, rni, adultes, parts)

    #  5) Final tax rounding (↓) and bounding to 0
    imp_final = max(0, arrondi_inf(imp_corrige))

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


#  ---------- Small test executable ----------

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 = [
        #  (adults, children, income) -> (tax, discount, 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'}")

5.4. المشكلة 3

الآن نطلب من ChatGPT البحث عن قواعد حساب الضرائب على الإنترنت:

 

هذه المرة، لا نقدم ملف PDF الذي يحتوي على قواعد الحساب التي يجب اتباعها. نقدم تعليماتنا فقط في ملف نصي. لاحظ أن هذا الملف النصي يحتوي الآن على 12 اختبارًا وحدة بعد إضافة الاختبار الذي استخدمه Gemini لإثبات أن ملف PDF الأولي الخاص بي كان غير صحيح إلى الاختبارات الـ 11 الأولية.

يستجيب ChatGPT في غضون 8 دقائق، ويقدم رابطًا لتنزيل البرنامج النصي الذي تم إنشاؤه. وبمجرد تحميله في PyCharm، يجتاز هذا البرنامج النصي جميع الاختبارات الـ 12. لذا، بالنسبة للمشكلتين المطروحتين، حصل ChatGPT على الإجابات الصحيحة من المحاولة الأولى، متفوقًا بذلك على Gemini.

يقدم ChatGPT مصادره في رده:

 

لا يوجد ما يقال أكثر من ذلك — إنها مهمة تم إنجازها على أكمل وجه.

الآن، يمكننا أن نطلب منه، تمامًا كما فعلنا مع Gemini، إنشاء ملف PDF للطلاب.

 

جاء رد ChatGPT بعد عدة تبادلات للرسائل لأن ملف PDF الذي تم إنشاؤه استخدم خطًا استبدل الأحرف بمربعات. لكنه في النهاية أنشأ ملف PDF. أشارك هذا لأن الملف يقدم قواعد مختلفة عن ملف PDF الخاص بـ Gemini، وتساءلت أيهما صحيح. دعونا نتحقق من ذلك.

 
 
 

يكمن الاختلاف عن ملف PDF الخاص بـ Gemini في طريقة حساب الخصم. تتبع كلتا الشركتين نهجين مختلفين. وقد كتبت Gemini:

 
 
 

يتبع الذكاءان الاصطناعيان نهجين مختلفين. أيهما الصحيح؟

5.5. المسألة 4

سنطلب من ChatGPT استخدام ملف PDF الخاص به لحساب الضريبة:

كما في الحالات السابقة، يقوم بإنشاء برنامج نصي بلغة Python يعمل من المحاولة الأولى. وقد أضفنا اختبارًا إضافيًا إلى التعليمات:

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

تم اجتياز جميع الاختبارات الـ 13 بنجاح.

5.6. العودة إلى Gemini

والآن، نعود إلى Gemini، حيث سنقدم ملف PDF الخاص بـ ChatGPT. وبما أن القواعد المطبقة في ملف PDF هذا تختلف عن تلك الموجودة في ملف PDF الخاص بـ Gemini، فإننا نتساءل عما سيحدث:

 

قام Gemini أولاً بإنشاء برنامج نصي بلغة Python فشل في بعض الاختبارات. قدمنا له السجلات:

السؤال 2

 

السؤال 3

لا تزال هناك أخطاء. لنكمل.

 

السؤال 4

لا تزال هناك أخطاء أثناء التنفيذ:

 

هذه المرة الأمر صحيح.

ما زلنا مندهشين من أن كلا الذكاءين الاصطناعيين يولدان نتائج صحيحة، حتى مع ملفات PDF التي لها قواعد حسابية مختلفة تمامًا.

نطرح على Gemini السؤال التالي:

 

والسؤال الكامل هو كما يلي:

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.

إجابة Gemini لا لبس فيها:

 
 
 
 
 
 

5.7. ما رأي ChatGPT؟

نسأل ChatGPT نفس السؤال الذي طرحناه على Gemini.

 

إجابة ChatGPT هي كما يلي:

 
 

لذا، يقترح ChatGPT إجراء اختبار وحدة للتفريق بين الطريقتين. نقوم بالتكرار:

  • يتم نسخ البرنامج النصي [gemini3] الذي أنشأته Gemini باستخدام ملف PDF الخاص بها [المشكلة وفقًا لـ Gemini] كمصدر في البرنامج النصي [gemini4
  • يتم نسخ البرنامج النصي [chatGPT3] الذي أنشأه ChatGPT باستخدام ملف PDF الخاص به [The Problem According to ChatGPT] كمصدر في البرنامج النصي [chatGPT4

بالإضافة إلى ذلك، نضيف الاختبار الوحدوي الذي اقترحه ChatGPT إلى كل من النصين [gemini4، chatGPT4] للتمييز بين الذكائين الاصطناعيين.

يؤدي تشغيل [gemini4] إلى النتائج التالية:


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

لذا فشل Gemini في الاختبار الذي أضافه ChatGPT.

يؤدي تشغيل [chatGPT4] إلى النتائج التالية:


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 أيضًا في الاختبار الإضافي، ولكن ليس للأسباب نفسها التي أدت إلى فشل Gemini. فقد توصل ChatGPT إلى النتائج الصحيحة، لكن الفرق كان 2 يورو بدلاً من 1 يورو المطلوب.

لذلك، من الآن فصاعدًا، سنستخدم ملف PDF الذي أنشأه ChatGPT مع الذكاءات الاصطناعية التالية. تجدر الإشارة إلى أن كلا الذكاءين الاصطناعيين اجتازا الاختبارات الأولى بسبب عدم وجود اختبارات وحدة في تعليماتي. ومن ثم، في هذا المثال المحدد، تبرز أهمية تضمين اختبارات وحدة للحالات الحدية في حساب الضرائب. نظرًا لأنه من الصعب جدًا ابتكار هذه الاختبارات بنفسك. سنطلب من الذكاءات الاصطناعية إضافتها بنفسها.

5.8. المشكلة 3 مع اختبارات الوحدة التي أنشأتها أنظمة الذكاء الاصطناعي

تترك النتائج التي تم الحصول عليها باستخدام Gemini و ChatGPT مجالًا للشك. هل وجدت الذكاءات الاصطناعية حلاً عامًا يجتاز كل الاختبارات الممكنة، أم أنها وجدت حلاً يجتاز الاختبارات المطلوبة فقط؟ سنبدأ من جديد بحل بدون ملف PDF لإجبار الذكاءات الاصطناعية على الاتصال بالإنترنت والبحث عن المعلومات التي تحتاجها. وسنقوم بتعديل تعليماتنا على النحو التالي:

 

يحتوي الملف النصي [instructionsSansPDF4.txt] بالفعل على 14 اختبارًا مطلوبًا. نضيف إلى هذه الاختبارات التعليمات التالية:


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()
  • الأسطر 11–24: الاختبارات الـ 14 المطلوبة؛
  • الأسطر 5-55: هذا الكود مأخوذ من البرنامج النصي الذي أنشأه ChatGPT. سنطلب من Gemini استخدام هذا الكود لتسهيل المقارنات بين البرنامجين النصيين اللذين تم إنشاؤهما.

سنبدأ بـ ChatGPT:

 

ردها الأول غير صحيح. وأخبرها بذلك من خلال تقديم سجلات التنفيذ:

إجابته الثانية صحيحة. أضاف ChatGPT الاختبارات الـ 11 التالية إلى الاختبارات الـ 14 المطلوبة:

# 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),
]

يوجد الآن 25 اختبارًا وحدة. قمت بالتحقق يدويًا من الاختبارات الـ 11 الجديدة باستخدام محاكي DGIP الرسمي، وقد نجحت جميعها.

الآن، ننتقل إلى Gemini. سيكون هذا أكثر تعقيدًا بكثير. سيتمكن من إنشاء نص برمجي يجتاز جميع اختبارات ChatGPT الـ 25، ولكن فقط بعد عملية تصحيح أخطاء طويلة.

 

فيما يلي سجل تصحيح الأخطاء:

 

الغريب أن غالبية الاختبارات فشلت، حتى من بين الاختبارات الـ 14 المطلوبة، في حين أن Gemini كانت قد أنتجت في الماضي كودًا اجتازها جميعًا.

الرد التالي من Gemini لا يزال غير صحيح:

 

كما أن الرد التالي غير صحيح أيضًا:

 

ولا الرد التالي. لذا سأغير طريقتي. سأطلب منه اجتياز الاختبارات الـ25 التي اجتازها ChatGPT، مع إرفاق سجلات ChatGPT:

 

فشل Gemini. لقد أضاف اختبارات ChatGPT بالفعل. أرفق سجلات تنفيذه:

 

لا يزال لا:

 

لا يزال الرد بالنفي:

 

لا يزال لا:

 

لا يزال لا، لكنه أفضل:

 

جيميني ترتكب أخطاء جديدة:

 

الوضع يتحسن مرة أخرى:

 

هذه المرة، الأمر صحيح:

مما لا شك فيه أن ChatGPT كان أكثر دقة من Gemini في هذا المثال المحدد لحساب ضريبة عام 2019 مع القيود المحددة في ملف التعليمات. لكن هذا مجرد مثال واحد.

يمكننا المضي أبعد من ذلك. يمكننا أن نطلب من Gemini إعادة إنشاء ملف PDF بناءً على قواعد الحساب التي استخدمها لاجتياز الاختبارات الـ 25. نريد أن نرى ما إذا كان قد غيّر استدلاله الأولي فيما يتعلق بحسابات الخصم والتخفيض بنسبة 20%:

هذه المرة، أنشأ Gemini ملف Markdown قمت بتحويله بعد ذلك إلى ملف PDF [المشكلة وفقًا لـ Gemini الإصدار 2]. وقد غيّر Gemini بالفعل استنتاجه:

 
 

يمكننا أن نلاحظ أن حساب الخصم المحدد وقاعدة الترحيل لم يعودا موجودين. فقد اعتمدت Gemini الآن طريقة التفكير التي يستخدمها ChatGPT.