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.7k
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# --- کش دادههای گلوبال ---15DATA = {16 "users": {},17 "banned_users": set(),18 "stats": {19 "total_messages": 0,20 "total_users": 0,21 "avg_response_time": 0.0,22 "max_response_time": 0.0,23 "min_response_time": float('inf'),24 "total_responses": 025 },26 "welcome_message": "سلام {user_mention}! 🤖\n\nمن یک ربات هوشمند هستم. هر سوالی دارید بپرسید.",27 "goodbye_message": "کاربر {user_mention} گروه را ترک کرد. خداحافظ!",28 "maintenance_mode": False,29 "blocked_words": [],30 "scheduled_broadcasts": [],31 "bot_start_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S')32}33 34logger = logging.getLogger(__name__)35 36# تابع برای شمارش توکنها37def count_tokens(text: str) -> int:38 """شمارش تعداد توکنهای متن با استفاده از tokenizer"""39 try:40 # استفاده از tokenizer برای gpt-3.5-turbo41 encoding = tiktoken.get_encoding("cl100k_base")42 return len(encoding.encode(text))43 except Exception as e:44 logger.warning(f"Error counting tokens: {e}, using fallback")45 # تقریب: هر 4 کاراکتر = 1 توکن46 return max(1, len(text) // 4)47 48def load_data():49 """دادهها را از فایل JSON بارگذاری کرده و در کش گلوبال ذخیره میکند."""50 global DATA51 try:52 if not os.path.exists(DATA_FILE):53 logger.info(f"فایل داده در {DATA_FILE} یافت نشد. یک فایل جدید ایجاد میشود.")54 save_data()55 return56 57 with open(DATA_FILE, 'r', encoding='utf-8') as f:58 loaded_data = json.load(f)59 loaded_data['banned_users'] = set(loaded_data.get('banned_users', []))60 61 # اطمینان از وجود کلیدهای جدید در فایلهای قدیمی62 if 'blocked_words' not in loaded_data: loaded_data['blocked_words'] = []63 if 'scheduled_broadcasts' not in loaded_data: loaded_data['scheduled_broadcasts'] = []64 if 'maintenance_mode' not in loaded_data: loaded_data['maintenance_mode'] = False65 if 'bot_start_time' not in loaded_data: loaded_data['bot_start_time'] = datetime.now().strftime('%Y-%m-%d %H:%M:%S')66 if 'avg_response_time' not in loaded_data['stats']:67 loaded_data['stats']['avg_response_time'] = 0.068 loaded_data['stats']['max_response_time'] = 0.069 loaded_data['stats']['min_response_time'] = float('inf')70 loaded_data['stats']['total_responses'] = 071 72 # اطمینان از وجود context برای کاربران قدیمی73 for user_id in loaded_data.get('users', {}):74 if 'context' not in loaded_data['users'][user_id]:75 loaded_data['users'][user_id]['context'] = []76 77 DATA.update(loaded_data)78 logger.info(f"دادهها با موفقیت از {DATA_FILE} بارگذاری شدند.")79 80 except json.JSONDecodeError as e:81 logger.error(f"خطا در خواندن JSON از {DATA_FILE}: {e}. ربات با دادههای اولیه شروع به کار میکند.")82 except Exception as e:83 logger.error(f"خطای غیرمنتظره هنگام بارگذاری دادهها: {e}. ربات با دادههای اولیه شروع به کار میکند.")84 85def save_data():86 """کش گلوبال دادهها را در فایل JSON ذخیره میکند."""87 global DATA88 try:89 data_to_save = DATA.copy()90 data_to_save['banned_users'] = list(DATA['banned_users'])91 92 with open(DATA_FILE, 'w', encoding='utf-8') as f:93 json.dump(data_to_save, f, indent=4, ensure_ascii=False)94 logger.debug(f"دادهها با موفقیت در {DATA_FILE} ذخیره شدند.")95 except Exception as e:96 logger.error(f"خطای مهلک: امکان ذخیره دادهها در {DATA_FILE} وجود ندارد. خطا: {e}")97 98def update_user_stats(user_id: int, user):99 """آمار کاربر را پس از هر پیام بهروز کرده و دادهها را ذخیره میکند."""100 global DATA101 now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')102 user_id_str = str(user_id)103 104 if user_id_str not in DATA['users']:105 DATA['users'][user_id_str] = {106 'first_name': user.first_name,107 'username': user.username,108 'first_seen': now_str,109 'message_count': 0,110 'context': [] # اضافه کردن context خالی برای کاربر جدید111 }112 DATA['stats']['total_users'] += 1113 logger.info(f"کاربر جدید ثبت شد: {user_id} ({user.first_name})")114 115 DATA['users'][user_id_str]['last_seen'] = now_str116 DATA['users'][user_id_str]['message_count'] += 1117 DATA['stats']['total_messages'] += 1118 119 save_data()120 121def update_response_stats(response_time: float):122 """آمار زمان پاسخگویی را بهروز میکند."""123 global DATA124 125 if DATA['stats']['total_responses'] == 0:126 DATA['stats']['min_response_time'] = response_time127 128 DATA['stats']['total_responses'] += 1129 130 # محاسبه میانگین جدید131 current_avg = DATA['stats']['avg_response_time']132 total_responses = DATA['stats']['total_responses']133 new_avg = ((current_avg * (total_responses - 1)) + response_time) / total_responses134 DATA['stats']['avg_response_time'] = new_avg135 136 # بهروزرسانی حداکثر و حداقل زمان پاسخگویی137 if response_time > DATA['stats']['max_response_time']:138 DATA['stats']['max_response_time'] = response_time139 140 if response_time < DATA['stats']['min_response_time']:141 DATA['stats']['min_response_time'] = response_time142 143 save_data()144 145def is_user_banned(user_id: int) -> bool:146 """بررسی میکند آیا کاربر مسدود شده است یا خیر."""147 return user_id in DATA['banned_users']148 149def ban_user(user_id: int):150 """کاربر را مسدود کرده و ذخیره میکند."""151 DATA['banned_users'].add(user_id)152 save_data()153 154def unban_user(user_id: int):155 """مسدودیت کاربر را برداشته و ذخیره میکند."""156 DATA['banned_users'].discard(user_id)157 save_data()158 159def contains_blocked_words(text: str) -> bool:160 """بررسی میکند آیا متن حاوی کلمات مسدود شده است یا خیر."""161 if not DATA['blocked_words']:162 return False163 164 text_lower = text.lower()165 for word in DATA['blocked_words']:166 if word in text_lower:167 return True168 169 return False170 171def get_active_users(days: int) -> list:172 """لیست کاربران فعال در بازه زمانی مشخص را برمیگرداند."""173 now = datetime.now()174 cutoff_date = now - timedelta(days=days)175 176 active_users = []177 for user_id, user_info in DATA['users'].items():178 if 'last_seen' in user_info:179 try:180 last_seen = datetime.strptime(user_info['last_seen'], '%Y-%m-%d %H:%M:%S')181 if last_seen >= cutoff_date:182 active_users.append(int(user_id))183 except ValueError:184 continue185 186 return active_users187 188def get_users_by_message_count(min_count: int) -> list:189 """لیست کاربران با تعداد پیام بیشتر یا مساوی مقدار مشخص را برمیگرداند."""190 users = []191 for user_id, user_info in DATA['users'].items():192 if user_info.get('message_count', 0) >= min_count:193 users.append(int(user_id))194 195 return users196 197# --- توابع مدیریت context ---198 199def add_to_user_context(user_id: int, role: str, content: str):200 """اضافه کردن پیام به context کاربر و محدود کردن به ۱۰۲۴ توکن""" # از 512 به 1024 تغییر یافت201 user_id_str = str(user_id)202 203 if user_id_str not in DATA['users']:204 return205 206 if 'context' not in DATA['users'][user_id_str]:207 DATA['users'][user_id_str]['context'] = []208 209 # اضافه کردن پیام جدید210 message = {211 'role': role, # 'user' یا 'assistant'212 'content': content,213 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')214 }215 216 DATA['users'][user_id_str]['context'].append(message)217 218 # محدود کردن context به ۱۰۲۴ توکن # از 512 به 1024 تغییر یافت219 trim_user_context(user_id)220 221 save_data()222 223# خط 165 را پیدا کنید و تغییر دهید:224def trim_user_context(user_id: int, max_tokens: int = 1024): # از 512 به 1024 تغییر یافت225 """کوتاه کردن context کاربر به تعداد توکن مشخص"""226 user_id_str = str(user_id)227 228 if user_id_str not in DATA['users'] or 'context' not in DATA['users'][user_id_str]:229 return230 231 context = DATA['users'][user_id_str]['context']232 233 if not context:234 return235 236 # محاسبه توکنهای کل237 total_tokens = sum(count_tokens(msg['content']) for msg in context)238 239 # حذف قدیمیترین پیامها تا زمانی که توکنها زیر حد مجاز باشد240 while total_tokens > max_tokens and len(context) > 1:241 removed_message = context.pop(0) # حذف قدیمیترین پیام242 total_tokens -= count_tokens(removed_message['content'])243 244 # اگر هنوز بیشتر از حد مجاز است، از محتوای پیامها کم کن245 if total_tokens > max_tokens and context:246 # از آخرین پیام (جدیدترین) شروع به کوتاه کردن کن247 last_message = context[-1]248 content = last_message['content']249 250 # کوتاه کردن محتوا251 tokens = count_tokens(content)252 if tokens > max_tokens:253 # اگر یک پیام به تنهایی بیشتر از حد مجاز باشد، آن را حذف کن254 context.pop()255 else:256 # در غیر این صورت، محتوای پیام را کوتاه کن257 while tokens > (max_tokens - (total_tokens - tokens)) and content:258 # حذف کلمات از انتها259 words = content.split()260 if len(words) > 1:261 content = ' '.join(words[:-1])262 else:263 content = content[:-1] if len(content) > 1 else ''264 tokens = count_tokens(content)265 266 if content: # اگر محتوایی باقی مانده267 context[-1]['content'] = content268 else: # اگر تمام محتوا حذف شد269 context.pop()270 271 save_data()272 273def get_user_context(user_id: int) -> list:274 """دریافت context کاربر"""275 user_id_str = str(user_id)276 277 if user_id_str not in DATA['users']:278 return []279 280 return DATA['users'][user_id_str].get('context', [])281 282def clear_user_context(user_id: int):283 """پاک کردن context کاربر"""284 user_id_str = str(user_id)285 286 if user_id_str in DATA['users']:287 if 'context' in DATA['users'][user_id_str]:288 DATA['users'][user_id_str]['context'] = []289 save_data()290 logger.info(f"Context cleared for user {user_id}")291 292def get_context_summary(user_id: int) -> str:293 """خلاصهای از context کاربر"""294 context = get_user_context(user_id)295 if not context:296 return "بدون تاریخچه"297 298 total_messages = len(context)299 total_tokens = sum(count_tokens(msg['content']) for msg in context)300 301 # نمایش آخرین پیام302 last_message = context[-1] if context else {}303 last_content = last_message.get('content', '')[:50]304 if len(last_message.get('content', '')) > 50:305 last_content += "..."306 307 return f"{total_messages} پیام ({total_tokens} توکن) - آخرین: {last_message.get('role', '')}: {last_content}"308 309def get_context_for_api(user_id: int) -> list:310 """فرمت context برای ارسال به API"""311 context = get_user_context(user_id)312 313 # تبدیل به فرمت مورد نیاز API314 api_context = []315 for msg in context:316 api_context.append({317 'role': msg['role'],318 'content': msg['content']319 })320 321 return api_context322 323def get_context_token_count(user_id: int) -> int:324 """تعداد کل توکنهای context کاربر"""325 context = get_user_context(user_id)326 return sum(count_tokens(msg['content']) for msg in context)327 328# بارگذاری اولیه دادهها در زمان ایمپورت شدن ماژول329load_data()