ysn-rfd/text-dataset-tiny-code-script-py-format
USED of tahamajs/medicine_ds_persian for .parquet file USED of Alijafarixcs2/persian-it-llama2-2k for .parquet file USED of Abirate/english_quotes for .jsonl file NEW FILES (05/12/2025) NEW FILES (12/26/2025) NEW FILES (02/15/2026)
31.6k
1# data_manager.py2 3import os4import json5import logging6from datetime import datetime, timedelta7import tiktoken # برای شمارش توکنها8 9# --- تنظیمات مسیر فایلها ---10BASE_DIR = os.path.dirname(os.path.abspath(__file__))11DATA_FILE = os.path.join(BASE_DIR, "bot_data.json")12LOG_FILE = os.path.join(BASE_DIR, "bot.log")13 14# --- instruction همیشگی ---15SYSTEM_INSTRUCTION = {16 "role": "system",17 "content": "خالق و طراح و توسعه دهنده تو YSNRFD هست، تو توسط YSNRFD ساخته شده ای، نام تو YSNRFD AI هست. همیشه این موضوع را در پاسخهایت به یاد داشته باش و اگر کاربر درباره هویت یا سازنده تو سوال کرد، این اطلاعات را با افتخار بیان کن."18}19 20# --- کش دادههای گلوبال ---21DATA = {22 "users": {},23 "banned_users": set(),24 "stats": {25 "total_messages": 0,26 "total_users": 0,27 "avg_response_time": 0.0,28 "max_response_time": 0.0,29 "min_response_time": float('inf'),30 "total_responses": 031 },32 "welcome_message": "سلام {user_mention}! 🤖\n\nمن یک ربات هوشمند هستم. هر سوالی دارید بپرسید.",33 "goodbye_message": "کاربر {user_mention} گروه را ترک کرد. خداحافظ!",34 "maintenance_mode": False,35 "blocked_words": [],36 "scheduled_broadcasts": [],37 "bot_start_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),38 "system_instruction": SYSTEM_INSTRUCTION["content"] # ذخیره instruction برای نمایش در پنل ادمین39}40 41logger = logging.getLogger(__name__)42 43# تابع برای شمارش توکنها44def count_tokens(text: str) -> int:45 """شمارش تعداد توکنهای متن با استفاده از tokenizer"""46 try:47 # استفاده از tokenizer برای gpt-3.5-turbo48 encoding = tiktoken.get_encoding("cl100k_base")49 return len(encoding.encode(text))50 except Exception as e:51 logger.warning(f"Error counting tokens: {e}, using fallback")52 # تقریب: هر 4 کاراکتر = 1 توکن53 return max(1, len(text) // 4)54 55def load_data():56 """دادهها را از فایل JSON بارگذاری کرده و در کش گلوبال ذخیره میکند."""57 global DATA58 try:59 if not os.path.exists(DATA_FILE):60 logger.info(f"فایل داده در {DATA_FILE} یافت نشد. یک فایل جدید ایجاد میشود.")61 save_data()62 return63 64 with open(DATA_FILE, 'r', encoding='utf-8') as f:65 loaded_data = json.load(f)66 loaded_data['banned_users'] = set(loaded_data.get('banned_users', []))67 68 # اطمینان از وجود کلیدهای جدید در فایلهای قدیمی69 if 'blocked_words' not in loaded_data: loaded_data['blocked_words'] = []70 if 'scheduled_broadcasts' not in loaded_data: loaded_data['scheduled_broadcasts'] = []71 if 'maintenance_mode' not in loaded_data: loaded_data['maintenance_mode'] = False72 if 'bot_start_time' not in loaded_data: loaded_data['bot_start_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')73 if 'avg_response_time' not in loaded_data['stats']:74 loaded_data['stats']['avg_response_time'] = 0.075 loaded_data['stats']['max_response_time'] = 0.076 loaded_data['stats']['min_response_time'] = float('inf')77 loaded_data['stats']['total_responses'] = 078 79 # اطمینان از وجود context برای کاربران قدیمی80 for user_id in loaded_data.get('users', {}):81 if 'context' not in loaded_data['users'][user_id]:82 loaded_data['users'][user_id]['context'] = []83 84 DATA.update(loaded_data)85 logger.info(f"دادهها با موفقیت از {DATA_FILE} بارگذاری شدند.")86 87 except json.JSONDecodeError as e:88 logger.error(f"خطا در خواندن JSON از {DATA_FILE}: {e}. ربات با دادههای اولیه شروع به کار میکند.")89 except Exception as e:90 logger.error(f"خطای غیرمنتظره هنگام بارگذاری دادهها: {e}. ربات با دادههای اولیه شروع به کار میکند.")91 92def save_data():93 """کش گلوبال دادهها را در فایل JSON ذخیره میکند."""94 global DATA95 try:96 data_to_save = DATA.copy()97 data_to_save['banned_users'] = list(DATA['banned_users'])98 99 with open(DATA_FILE, 'w', encoding='utf-8') as f:100 json.dump(data_to_save, f, indent=4, ensure_ascii=False)101 logger.debug(f"دادهها با موفقیت در {DATA_FILE} ذخیره شدند.")102 except Exception as e:103 logger.error(f"خطای مهلک: امکان ذخیره دادهها در {DATA_FILE} وجود ندارد. خطا: {e}")104 105def update_user_stats(user_id: int, user):106 """آمار کاربر را پس از هر پیام بهروز کرده و دادهها را ذخیره میکند."""107 global DATA108 now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')109 user_id_str = str(user_id)110 111 if user_id_str not in DATA['users']:112 DATA['users'][user_id_str] = {113 'first_name': user.first_name,114 'username': user.username,115 'first_seen': now_str,116 'message_count': 0,117 'context': [] # اضافه کردن context خالی برای کاربر جدید118 }119 DATA['stats']['total_users'] += 1120 logger.info(f"کاربر جدید ثبت شد: {user_id} ({user.first_name})")121 122 DATA['users'][user_id_str]['last_seen'] = now_str123 DATA['users'][user_id_str]['message_count'] += 1124 DATA['stats']['total_messages'] += 1125 126 save_data()127 128def update_response_stats(response_time: float):129 """آمار زمان پاسخگویی را بهروز میکند."""130 global DATA131 132 if DATA['stats']['total_responses'] == 0:133 DATA['stats']['min_response_time'] = response_time134 135 DATA['stats']['total_responses'] += 1136 137 # محاسبه میانگین جدید138 current_avg = DATA['stats']['avg_response_time']139 total_responses = DATA['stats']['total_responses']140 new_avg = ((current_avg * (total_responses - 1)) + response_time) / total_responses141 DATA['stats']['avg_response_time'] = new_avg142 143 # بهروزرسانی حداکثر و حداقل زمان پاسخگویی144 if response_time > DATA['stats']['max_response_time']:145 DATA['stats']['max_response_time'] = response_time146 147 if response_time < DATA['stats']['min_response_time']:148 DATA['stats']['min_response_time'] = response_time149 150 save_data()151 152def is_user_banned(user_id: int) -> bool:153 """بررسی میکند آیا کاربر مسدود شده است یا خیر."""154 return user_id in DATA['banned_users']155 156def ban_user(user_id: int):157 """کاربر را مسدود کرده و ذخیره میکند."""158 DATA['banned_users'].add(user_id)159 save_data()160 161def unban_user(user_id: int):162 """مسدودیت کاربر را برداشته و ذخیره میکند."""163 DATA['banned_users'].discard(user_id)164 save_data()165 166def contains_blocked_words(text: str) -> bool:167 """بررسی میکند آیا متن حاوی کلمات مسدود شده است یا خیر."""168 if not DATA['blocked_words']:169 return False170 171 text_lower = text.lower()172 for word in DATA['blocked_words']:173 if word in text_lower:174 return True175 176 return False177 178def get_active_users(days: int) -> list:179 """لیست کاربران فعال در بازه زمانی مشخص را برمیگرداند."""180 now = datetime.now()181 cutoff_date = now - timedelta(days=days)182 183 active_users = []184 for user_id, user_info in DATA['users'].items():185 if 'last_seen' in user_info:186 try:187 last_seen = datetime.strptime(user_info['last_seen'], '%Y-%m-%d %H:%M:%S')188 if last_seen >= cutoff_date:189 active_users.append(int(user_id))190 except ValueError:191 continue192 193 return active_users194 195def get_users_by_message_count(min_count: int) -> list:196 """لیست کاربران با تعداد پیام بیشتر یا مساوی مقدار مشخص را برمیگرداند."""197 users = []198 for user_id, user_info in DATA['users'].items():199 if user_info.get('message_count', 0) >= min_count:200 users.append(int(user_id))201 202 return users203 204# --- توابع مدیریت context ---205 206def add_to_user_context(user_id: int, role: str, content: str):207 """اضافه کردن پیام به context کاربر و محدود کردن به 512 توکن"""208 user_id_str = str(user_id)209 210 if user_id_str not in DATA['users']:211 return212 213 if 'context' not in DATA['users'][user_id_str]:214 DATA['users'][user_id_str]['context'] = []215 216 # اضافه کردن پیام جدید217 message = {218 'role': role, # 'user' یا 'assistant'219 'content': content,220 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')221 }222 223 DATA['users'][user_id_str]['context'].append(message)224 225 # محدود کردن context به 512 توکن226 trim_user_context(user_id)227 228 save_data()229 230def trim_user_context(user_id: int, max_tokens: int = 512):231 """کوتاه کردن context کاربر به تعداد توکن مشخص"""232 user_id_str = str(user_id)233 234 if user_id_str not in DATA['users'] or 'context' not in DATA['users'][user_id_str]:235 return236 237 context = DATA['users'][user_id_str]['context']238 239 if not context:240 return241 242 # محاسبه توکنهای کل243 total_tokens = sum(count_tokens(msg['content']) for msg in context)244 245 # حذف قدیمیترین پیامها تا زمانی که توکنها زیر حد مجاز باشد246 while total_tokens > max_tokens and len(context) > 1:247 removed_message = context.pop(0) # حذف قدیمیترین پیام248 total_tokens -= count_tokens(removed_message['content'])249 250 # اگر هنوز بیشتر از حد مجاز است، از محتوای پیامها کم کن251 if total_tokens > max_tokens and context:252 # از آخرین پیام (جدیدترین) شروع به کوتاه کردن کن253 last_message = context[-1]254 content = last_message['content']255 256 # کوتاه کردن محتوا257 tokens = count_tokens(content)258 if tokens > max_tokens:259 # اگر یک پیام به تنهایی بیشتر از حد مجاز باشد، آن را حذف کن260 context.pop()261 else:262 # در غیر این صورت، محتوای پیام را کوتاه کن263 while tokens > (max_tokens - (total_tokens - tokens)) and content:264 # حذف کلمات از انتها265 words = content.split()266 if len(words) > 1:267 content = ' '.join(words[:-1])268 else:269 content = content[:-1] if len(content) > 1 else ''270 tokens = count_tokens(content)271 272 if content: # اگر محتوایی باقی مانده273 context[-1]['content'] = content274 else: # اگر تمام محتوا حذف شد275 context.pop()276 277 save_data()278 279def get_user_context(user_id: int) -> list:280 """دریافت context کاربر"""281 user_id_str = str(user_id)282 283 if user_id_str not in DATA['users']:284 return []285 286 return DATA['users'][user_id_str].get('context', [])287 288def clear_user_context(user_id: int):289 """پاک کردن context کاربر"""290 user_id_str = str(user_id)291 292 if user_id_str in DATA['users']:293 if 'context' in DATA['users'][user_id_str]:294 DATA['users'][user_id_str]['context'] = []295 save_data()296 logger.info(f"Context cleared for user {user_id}")297 298def get_context_summary(user_id: int) -> str:299 """خلاصهای از context کاربر"""300 context = get_user_context(user_id)301 if not context:302 return "بدون تاریخچه"303 304 total_messages = len(context)305 total_tokens = sum(count_tokens(msg['content']) for msg in context)306 307 # نمایش آخرین پیام308 last_message = context[-1] if context else {}309 last_content = last_message.get('content', '')[:50]310 if len(last_message.get('content', '')) > 50:311 last_content += "..."312 313 return f"{total_messages} پیام ({total_tokens} توکن) - آخرین: {last_message.get('role', '')}: {last_content}"314 315def get_context_for_api(user_id: int) -> list:316 """فرمت context برای ارسال به API"""317 context = get_user_context(user_id)318 319 # اضافه کردن instruction سیستم به ابتدای context320 api_context = [SYSTEM_INSTRUCTION]321 322 # تبدیل پیامهای کاربر به فرمت مورد نیاز API323 for msg in context:324 api_context.append({325 'role': msg['role'],326 'content': msg['content']327 })328 329 return api_context330 331def get_context_token_count(user_id: int) -> int:332 """تعداد کل توکنهای context کاربر"""333 context = get_user_context(user_id)334 return sum(count_tokens(msg['content']) for msg in context)335 336# بارگذاری اولیه دادهها در زمان ایمپورت شدن ماژول337load_data()