Skip to content

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

5.1. مقدمة

فيما يلي لقطة شاشة أولى لجلسة ChatGPT:

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

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

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

 
  • في [1]، لإرفاق ملفات بالسؤال المطروح؛
  • في [2]، السؤال المطروح؛
  • في [3]، لبدء تنفيذ IA؛

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

# ---------- الثوابت التنظيمية ----------

# الخصم على المصاريف المهنية (الحد الأدنى/الحد الأقصى) للدخل لعام 2018
ABATTEMENT_TAUX = 0.10
ABATTEMENT_MIN = 437
ABATTEMENT_MAX = 12502

# جدول الضرائب لعام 2018 (QF)
# كل شريحة هي (borne_sup، المعدل). تنتهي الشريحة الأولى بنسبة 0% عند 9 964 يورو.
BAREME_2018 = [
    (9964, 0.00),
    (27519, 0.14),
    (73779, 0.30),
    (156244, 0.41),
    (float("inf"), 0.45),
]

# الحد الأقصى للمعامل الأسري
PF_QF_AVANTAGE_PAR_DEMI_PART = 1551  # الحد الأقصى للمزايا لكل نصف حصة ENFANT

# الخصم (الحدود الدنيا وفقًا لعدد البالغين / حالة الزوجين)
DECOTE_SEUIL_CELIB = 1196
DECOTE_SEUIL_COUPLE = 1970

# تخفيض بنسبة 20%: الحدود الدنيا حسب الحصص
REDUCTION_BASE_1_PART = 18985
REDUCTION_BASE_2_PARTS = 37970
REDUCTION_PAR_DEMI_PART_SUP = 3803  # إضافة لكل نصف حصة تتجاوز الحد الأدنى المكون من حصة واحدة أو حصتين


# ---------- هياكل البيانات ----------

@dataclass
class ResultatImpot:
    impot: int  # الضريبة النهائية المستحقة، مقربة إلى اليورو الأدنى
    decote: int  # الخصم مقربًا إلى اليورو الأعلى
    reduction: int  # تخفيض بنسبة 20٪ مقربًا إلى اليورو الأعلى


# ---------- وظائف مساعدة ----------

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


# ---------- الخطوة 1: الدخل الصافي الخاضع للضريبة (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)))


# ---------- الخطوة 2: عدد الحصص ----------

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
     # الأطفال >= 2
    parts += 1.0  # +0,5 +0,5 للطفلين الأولين
    if enfants > 2:
        parts += (enfants - 2) * 1.0  # +1 لكل طفل ابتداءً من الطفل الثالث
    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 حصة
     # الطفلان الأولان = 2 * نصف حصة، ثم +2 نصف حصة لكل طفل ابتداءً من الطفل الثالث
    return 2 + (enfants - 2) * 2


# ---------- الخطوة 3: الضريبة الإجمالية عبر 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


# ---------- الخطوة 4.1: الحد الأقصى لمعدل الإعالة العائلية ----------

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


# ---------- الخطوة 4.2: الخصم والتخفيض بنسبة 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

     # الأهلية للحصول على التخفيض بنسبة 20% بناءً على RNI
    seuil_red = seuil_reduction_20(rni, adultes, parts)
    eligible_reduction = rni < seuil_red  # "أقل من عتبة" في PDF

     # أهلية الخصم: أقل من الحد الأدنى مباشرةً، أو إعادة النظر إذا كان الخصم سيؤدي إلى انخفاض القيمة إلى ما دون الحد الأدنى
    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  # التخفيض النظري 20%
        if imp_theorique_apres_red <= s_dec:
            repechage = True

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

     # تطبيق الخصم أولاً (إذا كان مؤهلاً)
    if elig_decote:
        montant_decote = s_dec - (imp * 0.75)
        decote_calc = max(0, arrondi_sup(montant_decote))
         # لا يمكن أن يتجاوز الخصم الضريبة المتبقية: يتم تحديد الحد الأقصى له
        decote = min(decote_calc, arrondi_sup(imp))
        imp = max(0.0, imp - decote)

     # ثم تطبيق التخفيض إذا كان مستحقًا
    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 الرئيسية ----------

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

     # 3) الضريبة الإجمالية وفقًا للجدول (مع جميع الحصص)
    imp_brut_A = impot_brut_total(rni, parts)

     # 4.1) الحد الأقصى لحصة الأسرة
    imp_apres_plaf = apply_plafonnement_qf(imp_brut_A, rni, adultes, enfants)

     # 4.2) الخصم ثم التخفيض بنسبة 20% (مع إعادة التقييم)
    decote, reduction, imp_corrige = calc_decote_reduction(imp_apres_plaf, rni, adultes, parts)

     # 5) التقريب النهائي للضريبة (↓) والتحديد بـ 0
    imp_final = max(0, arrondi_inf(imp_corrige))

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


# ---------- برنامج اختبار صغير ----------

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 = [
         # (البالغون، الأطفال، الدخل) -> (الضريبة، الخصم، التخفيض)
        ((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 في حساب الخصم. لا يتبع كلا النموذجين IA نفس النهج. كانت Gemini قد كتبت:

 
 
 

يتم اتباع نهجين مختلفين في حساب IA. من على صواب؟

5.5. المسألة 4

سنطلب من ChatGPT الاعتماد على PDF لإجراء حساب الضريبة:

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

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

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

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

الآن، نعود إلى Gemini حيث سنقدم له PDF من ChatGPT. ونظرًا لأن القواعد المُطبَّقة في هذا الاختبار PDF تختلف عن تلك المُطبَّقة في اختبار Gemini PDF، فقد نتساءل عما سيحدث:

 

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

السؤال 2

 

السؤال 3

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

 

السؤال 4

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

 

هذه المرة كل شيء على ما يرام.

ومع ذلك، فإننا نشعر بالفضول لمعرفة كيف أن كل من PDF و IA، اللذين لهما قواعد حسابية مختلفة إلى حد ما، يولدان نتائج صحيحة.

نطرح السؤال التالي على 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.

إجابة جيميني قاطعة:

 
 
 
 
 
 

5.7. ما رأي ChatGPT في ذلك؟

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

 

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

 
 

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

  • البرنامج النصي [gemini3] الذي أنشأه Gemini باستخدام PDF كمصدر له، حيث تم تكرار [Le problème selon Gemini] في البرنامج النصي [gemini4
  • يتم نسخ البرنامج النصي [chatGPT3] الذي تم إنشاؤه بواسطة ChatGPT باستخدام PDF و[Le problème selon ChatGPT] كمصدرين، إلى البرنامج النصي [chatGPT4

بالإضافة إلى ذلك، تمت إضافة الاختبار الوحدوي المقترح بواسطة ChatGPT إلى كل من البرامج النصية [gemini4, chatGPT4] من أجل التمييز بين البرنامجين النصيين IA.

يؤدي تنفيذ [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 مع IA التالية. تجدر الإشارة إلى أن السبب في نجاح كل من IA في الاختبارات الأولى هو عدم وجود اختبارات وحدة في تعليماتي. ومن هنا تأتي أهمية وضع اختبارات وحدة للحالات الحدية لحساب الضريبة في هذا المثال بالتحديد. حيث إن تصور هذه الاختبارات بنفسك أمر صعب إلى حد ما. سنطلب من IA إضافة هذه الاختبارات بنفسها.

5.8. المشكلة 3 مع الاختبارات الفردية التي أنشأها فريق IA

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

 

يحتوي الملف النصي [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.

# =========================
# اختبارات فردية (تفاوت مسموح به ±1 يورو)
# =========================

TESTS = [
     # (البالغون، الأطفال، الدخل) -> (الضريبة، الخصم، التخفيض)
    ((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 المطلوبة:

# حالات حدية إضافية (حدود الدرجات/التقريب)
TESTS += [
     # الخصم بنسبة 10%: الحد الأدنى والحد الأقصى
    ((1, 0, 3000), (0, 0, 0)),  # 10% = 300 < الحد الأدنى 437 => RNI منخفض -> ضريبة صفرية
    ((1, 0, 200000), (64211, 0, 0)),  # الحد الأقصى للخصم تم تغطيته بالفعل في الاختبارات الأولية

     # التخفيض: أقل بقليل / أعلى بقليل من الحدود
    ((1, 0, 25000), None),  # التشخيص
    ((2, 0, 35000), None),  # التشخيص

     # تخفيض بنسبة 20%: الاستحقاق الكامل مقابل الحد الأقصى
    ((1, 0, 17000), None),  # التشخيص
    ((2, 0, 34000), None),  # التشخيص
    ((1, 0, 20000), None),  # التشخيص
    ((2, 0, 40000), None),  # التشخيص

     # تغيير الحصص (الحد الأقصى QF)
    ((2, 1, 80000), None),
    ((2, 2, 80000), None),
    ((2, 3, 80000), None),
]

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

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

 

فيما يلي قائمة عمليات تصحيح الأخطاء:

 

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

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

 

كما أن الإجابة التالية غير صحيحة أيضًا:

 

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

 

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

 

ما زال غير ناجح:

 

ما زال الفشل مستمرًا:

 

ما زال غير متوفر:

 

ما زال غير متاح، لكن الوضع أفضل:

 

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

 

يتحسن مرة أخرى:

 

هذه المرة، كل شيء على ما يرام:

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

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

هذه المرة، أنشأ Gemini ملفًا باسم MarkDown، ثم قمت بتحويله إلى PDF و[Le problème selon Gemini version 2]. وقد غيّر Gemini بالفعل طريقة تفكيره:

 
 

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