from openai import OpenAI import json import re API_KEY = "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" # ⚠️ جایگزین با کلیدت کن client = OpenAI(api_key=API_KEY, timeout=60) MODELS_SCHEMA = { "Poultry": { "fields": { "UserName": "string", "Password": "string", "FirstName": "string", "LastName": "string", "UserGroupName": "string", "UserRoleName": "string", "UserGroupId": "string", "UserRoleId": "string", "Mobile": "string", "Email": "string", "UserIsActive": "boolean", "UserIsActiveDescription": "string", "RegDate": "string", "RegDateShamsi": "string", "RegDateShamsiWithTime": "string", "RegDateShamsiOnlyTime": "string", "StringId": "string", "IsPersisted": "boolean", "AllowInsert": "boolean", "AllowUpdate": "boolean", "ModalCss": "string", "GridContainerParametersModel": "string", "MenuUserAccess": "string", "MenuUserAccessId": "string", "LogTableName": "string", "LogTableAlias": "string", "PageTitle": "string", "UnitName": "string", "SystemCode": "string", "TrackingCode": "string", "EpidemiologicCode": "string", "PartIdCode": "string", "PostalCode": "string", "UnitId": "string", "UnitTypeId": "string", "UnitTypeName": "string", "LocationIdProvince": "string", "LocationIdCity": "string", "LocationNameProvince": "string", "LocationNameCity": "string", "UnitIsActive": "boolean", "UnitIsActiveDescription": "string", "PId": "string", "Province": "string", "City": "string", } }, "Hatching": { "fields": { "poultry": "ForeignKey(Poultry)", "Date": "datetime", "ArchiveDate": "datetime", "BroilerFlockRequestId": "integer", "InsertDate": "string", "LastChangeStatusDate": "string", "LastChangeStatusDateShamsi": "string", "FlockRequestUnitName": "string", "PedigreeName": "string", "StatusId": "integer", "Status": "integer", "StatusName": "string", "PedigreeType": "integer", "BroilerPedigreeTypeName": "string", "StatusColor": "string", "SystemRevocationDate": "string", "RemindDays": "integer", "PartyCount": "integer", "GoodCount": "integer", "ShowButtons": "boolean", "HasSync": "boolean", "BroilerFlockRequestExpireStatus": "integer", "IdWithFormat": "string", "ProvinceName": "string", "CityName": "string", "Address": "string", "UnitTel": "string", "UnitPostalCode": "string", "UnitName": "string", "SystemCode": "string", "CapacityFemale": "integer", "EpidemiologicCode": "string", "RequestCode": "string", "RequestDate": "string", "RequestDateFa": "string", "RequestCount": "integer", "DeliverDate": "string", "DeliverDateFa": "string", "UnionName": "string", "PersonTypeId": "integer", "PersonType": "integer", "PersonTypeName": "string", "PersonFullName": "string", "NationalCode": "string", "InteractType": "integer", "InteractTypeName": "string", "UnionTypeId": "integer", "UnionTypeName": "string", "SendDate": "string", "SendDateFa": "string", "ChickCountSum": "integer", "CalculatedDate": "string", "CalculatedDateFa": "string", "PartIdCode": "string", "CertId": "string", "StartDate": "string", "StartDateFa": "string", "EndDate": "string", "EndDateFa": "string", "RemainCredit": "integer", "StrRemainCredit": "string", "ShowStatus": "string", "ValidStatus": "string", "ValidStatusName": "string", "RegDate": "string", "RegDateShamsi": "string", "RegDateShamsiWithTime": "string", "RegDateShamsiOnlyTime": "string", "HatchingId": "string", "StringId": "string", "IsPersisted": "boolean", "AllowInsert": "boolean", "AllowUpdate": "boolean", "ModalCss": "string", "GridContainerParametersModel": "string", "MenuUserAccess": "string", "MenuUserAccessId": "integer", "LogTableName": "string", "LogTableAlias": "string", "PageTitle": "string", "Evacuation": "integer", "Age": "integer", "KillingAve": "integer", "Period": "integer", "LeftOver": "integer", "samasat_discharge_percentage": "integer", "GoodSum": "integer", } } } def clean_gpt_json(text): """ بک‌تیک‌ها و پیشوندهای GPT را پاک می‌کند """ # پاک کردن ```json یا ``` یا ```text text = re.sub(r"^```(?:json)?\s*", "", text) text = re.sub(r"\s*```$", "", text) return text.strip() def get_filters_from_question(question): prompt = f""" شما مدل‌های زیر را دارید و فیلدهایشان را می‌دانید: {MODELS_SCHEMA} سوال کاربر: "{question}" لطفاً یک JSON بازگردانید که فیلترهای Django ORM را نشان می‌دهد. JSON باید فقط شامل کلید زیر باشد: - "models": لیستی از مدل‌هایی که برای پاسخ به سوال کاربر نیاز است. هر آیتم داخل "models" باید شامل این کلیدها باشد: - "model": نام مدل (مثلا "Hatching" یا "Poultry") - "filters": دیکشنری فیلدها و مقادیر برای filter(**filters) - "aggregations": - اگر کاربر عملیات آماری خواسته، لیستی از نام عملیات‌ها مثل ["count", "sum"] - اگر عملیات آماری ندارد، مقدار null - "fields_to_return": - اگر کاربر اطلاعات توصیفی خواسته، لیستی از فیلدها - در غیر این صورت null اگر سوال شامل زمان نسبی بود (مثل امروز، دیروز، دو روز پیش، یک هفته پیش و ...): - به جای مقدار مستقیم تاریخ، - یک key به نام "date_filter" اضافه کن. ساختار date_filter باید این باشد: {{ "field": "Date", "type": یکی از این مقادیر: "today" "yesterday" "last_n_days" "this_week" "this_month", "last_n_month" "this_year", "last_n_year", "value": فقط در صورتی که لازم بود (مثلا برای last_n_days عدد روز) }} ❗️هرگز تاریخ میلادی یا شمسی ننویس. ❗️هرگز از today یا now به عنوان مقدار فیلتر استفاده نکن. قوانین بسیار مهم: - اگر سوال کاربر ترکیبی است، باید چند مدل در لیست "models" بازگردانده شود. - اگر فقط یک مدل لازم است، باز هم آن را داخل لیست قرار دهید. - مقدار aggregations فقط نام ساده عملیات‌ها باشد (بدون ":"، بدون نام فیلد، بدون دیکشنری). - هیچ کلید اضافه‌ای ننویسید. - خروجی فقط JSON معتبر باشد، بدون توضیح اضافی. """ try: response = client.chat.completions.create( model="gpt-4.1-mini", messages=[{"role": "user", "content": prompt}] ) gpt_output = response.choices[0].message.content.strip() gpt_output = clean_gpt_json(gpt_output) # پاک کردن بک‌تیک‌ها و متن اضافی try: filters_json = json.loads(gpt_output) except json.JSONDecodeError: print("GPT output is not valid JSON after cleaning:", gpt_output) filters_json = {} except Exception as e: print("Error calling OpenAI API:", e) filters_json = {} return filters_json