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. مسئله ۱

سؤال در ChatGPT:

  
 

ChatGPT پاسخ درستی می‌دهد.

5.3. مسئله ۲

این شامل محاسبه مالیات با استفاده از PDF است. راستش را بخواهید، ما از PDF که توسط Gemini تولید شده و خطاهای نسخه اصلی PDF را اصلاح می‌کند، استفاده خواهیم کرد.

 
  • در [1]، ما PDF تولیدشده توسط جمینای را ارائه دادیم؛
  • در [2]، ما تست واحد را اضافه کرده‌ایم که از طریق آن Gemini برتری خود را نشان داد:
test12 : (2, 2, 49500) -> (1297, 431, 324)

ما ChatGPT را اجرا می‌کنیم. تولید پاسخ آن حدود ۳ دقیقه طول می‌کشد. برخلاف جمینای، لینک کارآمدی برای دریافت اسکریپت تولیدشده ارائه می‌دهد. ما آن را در PyCharm بارگذاری می‌کنیم:

 

اسکریپت [chatGPT1] در اولین اجرا کار می‌کند. در اینجا بحثی وجود ندارد؛ در این مورد، ChatGPT بهتر از جمینای عمل کرد.

اسکریپت [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

# ---------- ثابت‌های نظارتی ----------

# مبلغ کمک‌هزینه مخارج حرفه‌ای (حداقل/حداکثر) برای درآمد سال ۲۰۱۸
ABATTEMENT_TAUX = 0.10
ABATTEMENT_MIN = 437
ABATTEMENT_MAX = 12502

# جدول مالیاتی ۲۰۱۸ (QF)
# هر برکت عبارت است از (borne_sup, rate). برکت اول با نرخ ۰٪ در €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

# کاهش ۲۰٪: آستانه‌ها بر اساس سهم‌ها
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  # کاهش ۲۰ درصدی، گرد شده به نزدیک‌ترین یورو


# ---------- توابع کمکی ----------

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


# ---------- مرحله ۱: درآمد مشمول مالیات خالص (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)))


# ---------- مرحله ۲: تعداد سهام ----------

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  # +۱ به ازای هر کودک از سوم به بعد
    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  # ۰.۵ سهم
     # دو فرزند اول = ۲ * نیم‌سهم، سپس به ازای هر فرزند از سوم به بعد +۲ نیم‌سهم
    return 2 + (enfants - 2) * 2


# ---------- مرحله ۳: مالیات ناخالص از طریق 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


# ---------- مرحله ۴.۱: سقف ضریب خانوادگی ----------

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


# ---------- مرحله ۴.۲: تخفیف و کاهش ۲۰ درصدی ----------

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

     # شایستگی برای کاهش ۲۰٪ بر اساس 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  # کاهش نظری: ۲۰ درصد
        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).
    """
     # ۱) RNI
    rni = revenu_net_imposable(revenus_bruts)

     # ۲) سهام
    parts = nombre_parts(adultes, enfants)

     # ۳) مالیات ناخالص بر اساس جدول مالیاتی (شامل تمام سهام)
    imp_brut_A = impot_brut_total(rni, parts)

     # 4.1) سقف ضریب خانوادگی
    imp_apres_plaf = apply_plafonnement_qf(imp_brut_A, rni, adultes, enfants)

     # ۴.۲) تخفیف به دنبال کاهش ۲۰٪ (با انتقال)
    decote, reduction, imp_corrige = calc_decote_reduction(imp_apres_plaf, rni, adultes, parts)

     # ۵) گرد کردن مالیات نهایی (↓) و سقف‌گذاری روی ۰
    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. مسئله ۳

اکنون از ChatGPT می‌خواهیم تا در اینترنت به جستجوی قوانین محاسبه مالیات بپردازد:

 

این بار، ما فایل PDF را که حاوی قوانین محاسباتی بود که باید رعایت می‌شد، ارائه نمی‌دهیم. ما به سادگی دستورالعمل‌های خود را در فایل متنی ارائه می‌کنیم. به عنوان یادآوری، این فایل متنی اکنون شامل ۱۲ تست واحد است، که با افزودن تستی که جمینای برای نشان دادن نادرست بودن PDF اصلی من استفاده کرد، به ۱۱ تست اولیه اضافه شده است.

ChatGPT ظرف ۸ دقیقه پاسخ می‌دهد و لینکی برای دانلود اسکریپت تولیدشده ارائه می‌کند. پس از بارگذاری این اسکریپت در PyCharm، این اسکریپت در تمام ۱۲ آزمون موفق می‌شود. بنابراین، ChatGPT برای هر دو مسئله مطرح‌شده در اولین تلاش پاسخ صحیح را ارائه داد و بدین ترتیب از Gemini عملکرد بهتری داشت.

ChatGPT منابع خود را در پاسخش ارائه می‌دهد:

 

دیگر حرفی برای گفتن نیست – این یک کار عالی است.

اکنون می‌توانیم از آن بخواهیم، همان‌طور که با جمینای انجام دادیم، یک PDF برای دانشجویان تولید کند.

 

پاسخ ChatGPT پس از چندین دور رفت و برگشت به دست آمد، زیرا PDF تولید شده از فونتی استفاده می‌کرد که کاراکترها را با یک مربع جایگزین می‌کرد. اما در نهایت، PDF تولید شد. من این را اضافه می‌کنم چون قوانین متفاوتی نسبت به PDF جمینای تولید می‌کند و برایم سؤال بود که کدام یک درست است. به آن خواهیم پرداخت.

 
 
 

تفاوت در مقایسه با PDF جمینی در محاسبه تخفیف نهفته است. دو ورودی IA از رویکرد یکسانی پیروی نمی‌کنند. جمینی نوشته بود:

 
 
 

دو ورودی IA دو رویکرد متفاوت دارند. کدام یک صحیح است؟

5.5. مسئله ۴

ما از ChatGPT می‌خواهیم تا از PDF خود برای محاسبه مالیات استفاده کند:

مانند دفعات قبل، یک اسکریپت پایتون تولید می‌کند که دفعه اول به درستی کار می‌کند. ما یک تست اضافی به دستورالعمل‌ها اضافه کرده بودیم:

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

تمام ۱۳ آزمون با موفقیت پاس شدند.

5.6. بازگشت به جمینای

اکنون به جمینای بازمی‌گردیم تا PDF را از ChatGPT به آن ارائه دهیم. با توجه به اینکه قواعد پیاده‌سازی‌شده در این PDF با قواعد پیاده‌سازی‌شده در PDF جمینای متفاوت است، ممکن است این سؤال پیش بیاید که چه اتفاقی خواهد افتاد:

 

جمینای در ابتدا یک اسکریپت پایتون تولید کرد که در آزمون‌ها شکست خورد. ما لاگ‌ها را به آن نشان دادیم:

سؤال ۲

 

سؤال ۳

هنوز چند خطا وجود دارد. ادامه می‌دهیم.

 

سؤال ۴

هنوز در زمان اجرا خطاهایی دریافت می‌شود:

 

این بار دارد کار می‌کند.

با این حال، همچنان برایمان جالب است که در حالی که PDF قواعد محاسباتی کاملاً متفاوتی دارد، هر دو IA نتایج صحیحی تولید می‌کنند.

ما سؤال زیر را از جمینای پرسیدیم:

 

سؤال کامل به شرح زیر است:

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 همان سؤالی را می‌پرسیم که از جمینای پرسیدیم.

 

پاسخ ChatGPT به شرح زیر است:

 
 

در نتیجه، ChatGPT یک تست واحد پیشنهاد می‌کند تا بین این دو روش تصمیم‌گیری شود. ما تکرار می‌کنیم:

  • اسکریپت [gemini3] که توسط جمینای تولید شده و از 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

بنابراین، جمینای در آزمونی که توسط 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 نتایج صحیح را یافت اما به جای ۱ یوروی مورد نیاز، ۲ یورو اختلاف داشت.

بنابراین از این پس، ما از PDF تولید شده توسط ChatGPT با نمونه‌های بعدی IA استفاده خواهیم کرد. شایان ذکر است که به دلیل عدم درج تست‌های واحد در دستورالعمل‌های من، هر دو نمونه IA تست‌های اولیه را با موفقیت پشت سر گذاشتند. بنابراین، در این مثال خاص، اهمیت درج تست‌های واحد برای موارد حاشیه‌ای در محاسبه مالیات روشن می‌شود. از آنجا که طراحی این تست‌ها به تنهایی نسبتاً دشوار است. ما از IA خواهیم خواست که خودشان چند تست اضافه کنند.

5.8. مسئله ۳ با تست‌های واحد تولید شده توسط IA

نتایج به‌دست‌آمده با Gemini و ChatGPT برخی تردیدها را برمی‌انگیزد. آیا IA یک راه‌حل کلی یافته‌اند که از هر آزمون قابل تصوری عبور کند، یا راه‌حلی یافته‌اند که تنها آزمون‌های مشخص‌شده را پشت سر می‌گذارد؟ ما دوباره با راه‌حلی که از PDF استفاده نمی‌کند شروع می‌کنیم تا IA مجبور شود آنلاین شود و اطلاعات مورد نیازش را جستجو کند. و دستورالعمل‌هایمان را به شرح زیر اصلاح خواهیم کرد:

 

فایل متنی [instructionsSansPDF4.txt] در حال حاضر شامل ۱۴ آزمون اجباری است. به این آزمون‌ها، دستورالعمل‌های زیر را اضافه می‌کنیم:


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 = [
     # (بزرگسالان، کودکان، درآمد) -> (مالیات، تخفیف، کاهش)
    ((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()
  • خطوط ۱۱–۲۴: ۱۴ تست از پیش تعریف‌شده؛
  • خطوط ۵–۵۵: این کد از اسکریپت تولیدشده توسط ChatGPT آمده است. ما به Gemini دستور می‌دهیم تا از این کد برای تسهیل مقایسه بین دو اسکریپت تولیدشده استفاده کند.

با ChatGPT شروع می‌کنیم:

 

اولین پاسخ آن نادرست است. من این را به آن می‌گویم و لاگ‌های اجرا را ارائه می‌کنم:

پاسخ دوم او صحیح است. ChatGPT یازده تست زیر را به ۱۴ تست مورد نیاز اضافه کرد:

# موارد مرزی اضافی (حالات حاشیه‌ای/گرد کردن)
TESTS += [
     # معافیت ۱۰٪: محدودیت‌های پایین و بالا
    ((1, 0, 3000), (0, 0, 0)),  # ۱۰٪ = ۳۰۰ < حد پایین ۴۳۷ => RNI مالیات کم -> صفر
    ((1, 0, 200000), (64211, 0, 0)),  #سقف کسورات در آزمایش‌های اولیه پوشش داده شده است

     # تخفیف: درست زیر/بالای آستانه‌ها
    ((1, 0, 25000), None),  #تشخیص
    ((2, 0, 35000), None),  #تشخیص

     # کاهش ۲۰٪: حق کامل در مقابل سقف‌گذاری
    ((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),
]

اکنون ۲۵ تست واحد وجود دارد. من ۱۱ تست جدید را به‌صورت دستی با استفاده از شبیه‌ساز رسمی DGIP بررسی کرده‌ام و همگی صحیح هستند.

حالا به سراغ جمینای می‌رویم. این کار بسیار پیچیده‌تر خواهد بود. این مدل قادر خواهد بود اسکریپتی تولید کند که تمام ۲۵ تست ChatGPT را پاس کند، اما تنها پس از یک فرآیند طولانی عیب‌یابی.

 

در زیر لاگ اشکال‌زدایی آمده است:

 

عجیب است که اکثریت تست‌ها، حتی در میان ۱۴ تست الزامی، شکست خوردند، در حالی که در گذشته جمینای کدی تولید کرده بود که همه آن‌ها را پاس می‌کرد.

پاسخ زیر از جمینای هنوز نادرست است:

 

پاسخ زیر نیز صحیح نیست:

 

پاسخ زیر هم درست نیست. بنابراین مسیرم را تغییر می‌دهم. از آن می‌خواهم ۲۵ تستی را که ChatGPT پاس کرده است، پاس کند و لاگ‌های ChatGPT را پیوست می‌کنم:

 

جمینای شکست خورد. با این حال، تست‌های ChatGPT را اضافه کرد. لاگ‌های اجرای آن را پیوست کرده‌ام:

 

هنوز کار نمی‌کند:

 

هنوز کار نمی‌کند:

 

هنوز آنجا نیست:

 

هنوز به آن نقطه نرسیده، اما بهتر است:

 

جمینای در حال مرتکب شدن اشتباهات جدیدی است:

 

دوباره در حال بهبود است:

 

این بار درست است:

بدون شک، در این مثال خاص که مربوط به محاسبه مالیات سال ۲۰۱۹ با استفاده از محدودیت‌های تعیین‌شده در فایل دستورالعمل‌ها است، ChatGPT عملکرد بهتری نسبت به جمینای داشته است. اما این تنها یک مثال است.

ما می‌توانیم این موضوع را فراتر ببریم. می‌توانیم از جمینای بخواهیم یک PDF را بر اساس قوانین محاسبه‌ای که برای گذراندن ۲۵ آزمون استفاده کرده، دوباره تولید کند. ما می‌خواهیم ببینیم که آیا استدلال اولیه خود را در مورد محاسبات مربوط به تخفیف و کاهش ۲۰ درصدی تغییر داده است یا خیر:

این بار، جمینای فایلی به نام MarkDown تولید کرد که من آن را به PDF و [Le problème selon Gemini version 2] تبدیل کردم. و جمینای واقعاً استدلال خود را تغییر داده است:

 
 

می‌توانیم ببینیم که نه محاسبهٔ تخفیف خاص و نه قاعدهٔ انتقال دیگر وجود ندارند. جمینای اکنون استدلال ChatGPT را پذیرفته است.