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# admin_panel.py2 3import os4import json5import logging6import csv7import io8import asyncio9from datetime import datetime, timedelta10from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup11from telegram.ext import ContextTypes, CommandHandler, CallbackQueryHandler12from telegram.error import TelegramError13 14import matplotlib15matplotlib.use('Agg')16import matplotlib.pyplot as plt17import pandas as pd18import tempfile19import psutil20import platform21import time22 23# --- تنظیمات ---24ADMIN_IDS = list(map(int, os.environ.get("ADMIN_IDS", "").split(','))) if os.environ.get("ADMIN_IDS") else []25 26import data_manager27 28logger = logging.getLogger(__name__)29 30# --- دکوراتور برای دسترسی ادمین ---31def admin_only(func):32 async def wrapped(update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):33 if update.effective_user.id not in ADMIN_IDS:34 await update.message.reply_text("⛔️ شما دسترسی لازم برای اجرای این دستور را ندارید.")35 return36 return await func(update, context, *args, **kwargs)37 return wrapped38 39# --- هندلرهای دستورات ادمین ---40@admin_only41async def admin_commands(update: Update, context: ContextTypes.DEFAULT_TYPE):42 """نمایش تمام دستورات موجود ادمین."""43 commands_text = (44 "📋 **دستورات ادمین ربات:**\n\n"45 "📊 `/stats` - نمایش آمار ربات\n"46 "📢 `/broadcast [پیام]` - ارسال پیام به تمام کاربران\n"47 "🎯 `/targeted_broadcast [معیار] [مقدار] [پیام]` - ارسال پیام هدفمند\n"48 "📅 `/schedule_broadcast [YYYY-MM-DD] [HH:MM] [پیام]` - ارسال برنامهریزی شده\n"49 "📋 `/list_scheduled` - نمایش لیست ارسالهای برنامهریزی شده\n"50 "🗑️ `/remove_scheduled [شماره]` - حذف ارسال برنامهریزی شده\n"51 "🚫 `/ban [آیدی]` - مسدود کردن کاربر\n"52 "✅ `/unban [آیدی]` - رفع مسدودیت کاربر\n"53 "💌 `/direct_message [آیدی] [پیام]` - ارسال پیام مستقیم به کاربر\n"54 "ℹ️ `/user_info [آیدی]` - نمایش اطلاعات کاربر\n"55 "📝 `/logs` - نمایش آخرین لاگها\n"56 "📂 `/logs_file` - دانلود فایل کامل لاگها\n"57 "👥 `/users_list [صفحه]` - نمایش لیست کاربران\n"58 "🔍 `/user_search [نام]` - جستجوی کاربر بر اساس نام\n"59 "💾 `/backup` - ایجاد نسخه پشتیبان از دادهها\n"60 "📊 `/export_csv` - دانلود اطلاعات کاربران در فایل CSV\n"61 "🔧 `/maintenance [on/off]` - فعال/غیرفعال کردن حالت نگهداری\n"62 "👋 `/set_welcome [پیام]` - تنظیم پیام خوشامدگویی\n"63 "👋 `/set_goodbye [پیام]` - تنظیم پیام خداحافظی\n"64 "📈 `/activity_heatmap` - دریافت نمودار فعالیت کاربران\n"65 "⏱️ `/response_stats` - نمایش آمار زمان پاسخگویی\n"66 "🚫 `/add_blocked_word [کلمه]` - افزودن کلمه مسدود\n"67 "✅ `/remove_blocked_word [کلمه]` - حذف کلمه مسدود\n"68 "📜 `/list_blocked_words` - نمایش لیست کلمات مسدود\n"69 "💻 `/system_info` - نمایش اطلاعات سیستم\n"70 "🔄 `/reset_stats [messages/all]` - ریست کردن آمار\n"71 "🗑️ `/clear_context [آیدی]` - پاک کردن context کاربر\n"72 "📋 `/view_context [آیدی]` - مشاهده context کاربر\n"73 "📋 `/view_replies [user|group] [آیدی]` - مشاهده ریپلایها\n"74 "🔄 `/set_context_mode [separate|group_shared|hybrid]` - تغییر حالت context\n"75 "📊 `/group_info [آیدی]` - نمایش اطلاعات گروه\n"76 "🗑️ `/clear_group_context [آیدی]` - پاک کردن context گروه\n"77 "💾 `/memory_status` - نمایش وضعیت حافظه\n"78 "📋 `/commands` - نمایش این لیست دستورات"79 )80 await update.message.reply_text(commands_text, parse_mode='Markdown')81 82@admin_only83async def admin_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):84 """آمار ربات را نمایش میدهد."""85 total_users = len(data_manager.DATA['users'])86 total_groups = len(data_manager.DATA['groups'])87 total_messages = data_manager.DATA['stats']['total_messages']88 banned_count = len(data_manager.DATA['banned_users'])89 90 now = datetime.now()91 active_24h = sum(1 for user in data_manager.DATA['users'].values() 92 if 'last_seen' in user and 93 datetime.strptime(user['last_seen'], '%Y-%m-%d %H:%M:%S') > now - timedelta(hours=24))94 95 active_7d = sum(1 for user in data_manager.DATA['users'].values() 96 if 'last_seen' in user and 97 datetime.strptime(user['last_seen'], '%Y-%m-%d %H:%M:%S') > now - timedelta(days=7))98 99 active_users = sorted(100 data_manager.DATA['users'].items(),101 key=lambda item: item[1].get('last_seen', ''),102 reverse=True103 )[:5]104 105 active_users_text = "\n".join(106 [f"• {user_id}: {info.get('first_name', 'N/A')} (آخرین فعالیت: {info.get('last_seen', 'N/A')})"107 for user_id, info in active_users]108 )109 110 # آمار context111 users_with_context = sum(1 for user in data_manager.DATA['users'].values() 112 if user.get('context') and len(user['context']) > 0)113 total_context_messages = sum(len(user.get('context', [])) for user in data_manager.DATA['users'].values())114 115 # آمار ریپلایها116 total_replies = 0117 for user in data_manager.DATA['users'].values():118 if 'context' in user:119 total_replies += sum(1 for msg in user['context'] if msg.get('has_reply', False))120 121 # آمار گروهها122 groups_with_context = sum(1 for group in data_manager.DATA['groups'].values() 123 if group.get('context') and len(group['context']) > 0)124 125 text = (126 f"📊 **آمار ربات**\n\n"127 f"👥 **تعداد کل کاربران:** `{total_users}`\n"128 f"👥 **تعداد کل گروهها:** `{total_groups}`\n"129 f"📝 **تعداد کل پیامها:** `{total_messages}`\n"130 f"🚫 **کاربران مسدود شده:** `{banned_count}`\n"131 f"🟢 **کاربران فعال 24 ساعت گذشته:** `{active_24h}`\n"132 f"🟢 **کاربران فعال 7 روز گذشته:** `{active_7d}`\n"133 f"💭 **کاربران با context فعال:** `{users_with_context}`\n"134 f"💬 **گروههای با context فعال:** `{groups_with_context}`\n"135 f"📝 **کل پیامهای context:** `{total_context_messages}`\n"136 f"📎 **کل ریپلایهای ثبت شده:** `{total_replies}`\n"137 f"🔄 **حالت context فعلی:** `{data_manager.get_context_mode()}`\n\n"138 f"**۵ کاربر اخیر فعال:**\n{active_users_text}"139 )140 await update.message.reply_text(text, parse_mode='Markdown')141 142@admin_only143async def admin_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):144 """یک پیام را به تمام کاربران ارسال میکند."""145 if not context.args:146 await update.message.reply_text("⚠️ لطفاً پیامی برای ارسال بنویسید.\nمثال: `/broadcast سلام به همه!`")147 return148 149 message_text = " ".join(context.args)150 user_ids = list(data_manager.DATA['users'].keys())151 total_sent = 0152 total_failed = 0153 154 await update.message.reply_text(f"📣 در حال ارسال پیام به `{len(user_ids)}` کاربر...")155 156 for user_id_str in user_ids:157 try:158 await context.bot.send_message(chat_id=int(user_id_str), text=message_text)159 total_sent += 1160 await asyncio.sleep(0.05)161 except TelegramError as e:162 logger.warning(f"Failed to send broadcast to {user_id_str}: {e}")163 total_failed += 1164 165 result_text = (166 f"✅ **ارسال همگانی تمام شد**\n\n"167 f"✅ موفق: `{total_sent}`\n"168 f"❌ ناموفق: `{total_failed}`"169 )170 await update.message.reply_text(result_text, parse_mode='Markdown')171 172@admin_only173async def admin_targeted_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):174 """ارسال پیام به گروه خاصی از کاربران بر اساس معیارهای مشخص."""175 if len(context.args) < 3:176 await update.message.reply_text("⚠️ فرمت صحیح: `/targeted_broadcast [معیار] [مقدار] [پیام]`\n"177 "معیارهای موجود: `active_days`, `message_count`, `banned`")178 return179 180 criteria = context.args[0].lower()181 value = context.args[1]182 message_text = " ".join(context.args[2:])183 184 target_users = []185 186 if criteria == "active_days":187 try:188 days = int(value)189 target_users = data_manager.get_active_users(days)190 except ValueError:191 await update.message.reply_text("⚠️ مقدار روز باید یک عدد صحیح باشد.")192 return193 194 elif criteria == "message_count":195 try:196 min_count = int(value)197 target_users = data_manager.get_users_by_message_count(min_count)198 except ValueError:199 await update.message.reply_text("⚠️ تعداد پیام باید یک عدد صحیح باشد.")200 return201 202 elif criteria == "banned":203 if value.lower() == "true":204 target_users = list(data_manager.DATA['banned_users'])205 elif value.lower() == "false":206 for user_id in data_manager.DATA['users']:207 if int(user_id) not in data_manager.DATA['banned_users']:208 target_users.append(int(user_id))209 else:210 await update.message.reply_text("⚠️ مقدار برای معیار banned باید true یا false باشد.")211 return212 213 else:214 await update.message.reply_text("⚠️ معیار نامعتبر است. معیارهای موجود: active_days, message_count, banned")215 return216 217 if not target_users:218 await update.message.reply_text("هیچ کاربری با معیارهای مشخص شده یافت نشد.")219 return220 221 await update.message.reply_text(f"📣 در حال ارسال پیام به `{len(target_users)}` کاربر...")222 223 total_sent, total_failed = 0, 0224 for user_id in target_users:225 try:226 await context.bot.send_message(chat_id=user_id, text=message_text)227 total_sent += 1228 await asyncio.sleep(0.05)229 except TelegramError as e:230 logger.warning(f"Failed to send targeted broadcast to {user_id}: {e}")231 total_failed += 1232 233 result_text = f"✅ **ارسال هدفمند تمام شد**\n\n✅ موفق: `{total_sent}`\n❌ ناموفق: `{total_failed}`"234 await update.message.reply_text(result_text, parse_mode='Markdown')235 236@admin_only237async def admin_schedule_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):238 """تنظیم ارسال برنامهریزی شده پیام به همه کاربران."""239 if len(context.args) < 3:240 await update.message.reply_text("⚠️ فرمت صحیح: `/schedule_broadcast [YYYY-MM-DD] [HH:MM] [پیام]`")241 return242 243 try:244 date_str, time_str = context.args[0], context.args[1]245 message_text = " ".join(context.args[2:])246 247 scheduled_time = datetime.strptime(f"{date_str} {time_str}", '%Y-%m-%d %H:%M')248 249 if scheduled_time <= datetime.now():250 await update.message.reply_text("⚠️ زمان برنامهریزی شده باید در آینده باشد.")251 return252 253 data_manager.DATA['scheduled_broadcasts'].append({254 'time': scheduled_time.strftime('%Y-%m-%d %H:%M:%S'),255 'message': message_text,256 'status': 'pending'257 })258 data_manager.save_data()259 260 await update.message.reply_text(f"✅ پیام برای زمان `{scheduled_time.strftime('%Y-%m-%d %H:%M')}` برنامهریزی شد.")261 262 except ValueError:263 await update.message.reply_text("⚠️ فرمت زمان نامعتبر است. لطفاً از فرمت YYYY-MM-DD HH:MM استفاده کنید.")264 265@admin_only266async def admin_list_scheduled_broadcasts(update: Update, context: ContextTypes.DEFAULT_TYPE):267 """نمایش لیست ارسالهای برنامهریزی شده."""268 if not data_manager.DATA['scheduled_broadcasts']:269 await update.message.reply_text("هیچ ارسال برنامهریزی شدهای وجود ندارد.")270 return271 272 broadcasts_text = "📅 **لیست ارسالهای برنامهریزی شده:**\n\n"273 for i, broadcast in enumerate(data_manager.DATA['scheduled_broadcasts'], 1):274 status_emoji = "✅" if broadcast['status'] == 'sent' else "⏳"275 broadcasts_text += f"{i}. {status_emoji} `{broadcast['time']}` - {broadcast['message'][:50]}...\n"276 277 await update.message.reply_text(broadcasts_text, parse_mode='Markdown')278 279@admin_only280async def admin_remove_scheduled_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):281 """حذف یک ارسال برنامهریزی شده."""282 if not context.args or not context.args[0].isdigit():283 await update.message.reply_text("⚠️ لطفاً شماره ارسال برنامهریزی شده را وارد کنید.\nمثال: `/remove_scheduled 1`")284 return285 286 index = int(context.args[0]) - 1287 288 if not data_manager.DATA['scheduled_broadcasts'] or not (0 <= index < len(data_manager.DATA['scheduled_broadcasts'])):289 await update.message.reply_text("⚠️ شماره ارسال برنامهریزی شده نامعتبر است.")290 return291 292 removed_broadcast = data_manager.DATA['scheduled_broadcasts'].pop(index)293 data_manager.save_data()294 295 await update.message.reply_text(f"✅ ارسال برنامهریزی شده برای زمان `{removed_broadcast['time']}` حذف شد.")296 297@admin_only298async def admin_ban(update: Update, context: ContextTypes.DEFAULT_TYPE):299 """یک کاربر را با آیدی عددی مسدود کرده و به او اطلاع میدهد."""300 if not context.args or not context.args[0].isdigit():301 await update.message.reply_text("⚠️ لطفاً آیدی عددی کاربر را وارد کنید.\nمثال: `/ban 123456789`")302 return303 304 user_id_to_ban = int(context.args[0])305 306 if user_id_to_ban in ADMIN_IDS:307 await update.message.reply_text("🛡️ شما نمیتوانید یک ادمین را مسدود کنید!")308 return309 310 if data_manager.is_user_banned(user_id_to_ban):311 await update.message.reply_text(f"کاربر `{user_id_to_ban}` از قبل مسدود شده است.")312 return313 314 data_manager.ban_user(user_id_to_ban)315 316 # ارسال پیام به کاربر مسدود شده317 try:318 await context.bot.send_message(319 chat_id=user_id_to_ban, 320 text="⛔️ شما توسط ادمین ربات مسدود شدید و دیگر نمیتوانید از خدمات ربات استفاده کنید."321 )322 except TelegramError as e:323 logger.warning(f"Could not send ban notification to user {user_id_to_ban}: {e}")324 325 await update.message.reply_text(f"✅ کاربر `{user_id_to_ban}` با موفقیت مسدود شد.", parse_mode='Markdown')326 327@admin_only328async def admin_unban(update: Update, context: ContextTypes.DEFAULT_TYPE):329 """مسدودیت یک کاربر را برمیدارد و به او اطلاع میدهد."""330 if not context.args or not context.args[0].isdigit():331 await update.message.reply_text("⚠️ لطفاً آیدی عددی کاربر را وارد کنید.\nمثال: `/unban 123456789`")332 return333 334 user_id_to_unban = int(context.args[0])335 336 if not data_manager.is_user_banned(user_id_to_unban):337 await update.message.reply_text(f"کاربر `{user_id_to_unban}` در لیست مسدود شدهها وجود ندارد.")338 return339 340 data_manager.unban_user(user_id_to_unban)341 342 # ارسال پیام به کاربر برای رفع مسدودیت343 try:344 await context.bot.send_message(345 chat_id=user_id_to_unban, 346 text="✅ مسدودیت شما توسط ادمین ربات برداشته شد. میتوانید دوباره از ربات استفاده کنید."347 )348 except TelegramError as e:349 logger.warning(f"Could not send unban notification to user {user_id_to_unban}: {e}")350 351 await update.message.reply_text(f"✅ مسدودیت کاربر `{user_id_to_unban}` با موفقیت برداشته شد.", parse_mode='Markdown')352 353@admin_only354async def admin_direct_message(update: Update, context: ContextTypes.DEFAULT_TYPE):355 """ارسال پیام مستقیم به یک کاربر خاص."""356 if len(context.args) < 2:357 await update.message.reply_text("⚠️ فرمت صحیح: `/direct_message [آیدی] [پیام]`")358 return359 360 user_id_str = context.args[0]361 if not user_id_str.isdigit():362 await update.message.reply_text("⚠️ لطفاً یک آیدی عددی معتبر وارد کنید.")363 return364 365 message_text = " ".join(context.args[1:])366 user_id = int(user_id_str)367 368 try:369 await context.bot.send_message(chat_id=user_id, text=message_text)370 await update.message.reply_text(f"✅ پیام با موفقیت به کاربر `{user_id}` ارسال شد.", parse_mode='Markdown')371 except TelegramError as e:372 await update.message.reply_text(f"❌ خطا در ارسال پیام: {e}")373 374@admin_only375async def admin_userinfo(update: Update, context: ContextTypes.DEFAULT_TYPE):376 """اطلاعات یک کاربر خاص را نمایش میدهد."""377 if not context.args or not context.args[0].isdigit():378 await update.message.reply_text("⚠️ لطفاً آیدی عددی کاربر را وارد کنید.\nمثال: `/user_info 123456789`")379 return380 381 user_id = int(context.args[0])382 user_info = data_manager.DATA['users'].get(str(user_id))383 384 if not user_info:385 await update.message.reply_text(f"کاربری با آیدی `{user_id}` در دیتابیس یافت نشد.")386 return387 388 is_banned = "بله" if data_manager.is_user_banned(user_id) else "خیر"389 390 if 'first_seen' in user_info and 'last_seen' in user_info:391 try:392 first_date = datetime.strptime(user_info['first_seen'], '%Y-%m-%d %H:%M:%S')393 last_date = datetime.strptime(user_info['last_seen'], '%Y-%m-%d %H:%M:%S')394 days_active = max(1, (last_date - first_date).days)395 avg_messages = user_info.get('message_count', 0) / days_active396 except:397 avg_messages = user_info.get('message_count', 0)398 else:399 avg_messages = user_info.get('message_count', 0)400 401 # اطلاعات context402 context_messages = len(user_info.get('context', []))403 context_tokens = data_manager.get_context_token_count(user_id)404 405 # اطلاعات ریپلایها406 reply_count = 0407 if 'context' in user_info:408 reply_count = sum(1 for msg in user_info['context'] if msg.get('has_reply', False))409 410 text = (411 f"ℹ️ **اطلاعات کاربر**\n\n"412 f"🆔 **آیدی:** `{user_id}`\n"413 f"👤 **نام:** {user_info.get('first_name', 'N/A')}\n"414 f"🔷 **نام کاربری:** @{user_info.get('username', 'N/A')}\n"415 f"📊 **تعداد پیامها:** `{user_info.get('message_count', 0)}`\n"416 f"📈 **میانگین پیام در روز:** `{avg_messages:.2f}`\n"417 f"📎 **تعداد ریپلایها:** `{reply_count}`\n"418 f"📅 **اولین پیام:** {user_info.get('first_seen', 'N/A')}\n"419 f"🕒 **آخرین فعالیت:** {user_info.get('last_seen', 'N/A')}\n"420 f"💭 **پیامهای context:** `{context_messages}`\n"421 f"🔢 **توکنهای context:** `{context_tokens}`\n"422 f"🚫 **وضعیت مسدودیت:** {is_banned}"423 )424 await update.message.reply_text(text, parse_mode='Markdown')425 426@admin_only427async def admin_logs(update: Update, context: ContextTypes.DEFAULT_TYPE):428 """آخرین خطوط لاگ ربات را ارسال میکند."""429 try:430 with open(data_manager.LOG_FILE, "r", encoding="utf-8") as f:431 lines = f.readlines()432 last_lines = lines[-30:]433 log_text = "".join(last_lines)434 if not log_text:435 await update.message.reply_text("فایل لاگ خالی است.")436 return437 438 if len(log_text) > 4096:439 for i in range(0, len(log_text), 4096):440 await update.message.reply_text(f"```{log_text[i:i+4096]}```", parse_mode='Markdown')441 else:442 await update.message.reply_text(f"```{log_text}```", parse_mode='Markdown')443 444 except FileNotFoundError:445 await update.message.reply_text("فایل لاگ یافت نشد.")446 except Exception as e:447 await update.message.reply_text(f"خطایی در خواندن لاگ رخ داد: {e}")448 449@admin_only450async def admin_logs_file(update: Update, context: ContextTypes.DEFAULT_TYPE):451 """فایل کامل لاگ ربات را ارسال میکند."""452 try:453 await update.message.reply_document(454 document=open(data_manager.LOG_FILE, 'rb'),455 caption="📂 فایل کامل لاگهای ربات"456 )457 except FileNotFoundError:458 await update.message.reply_text("فایل لاگ یافت نشد.")459 except Exception as e:460 await update.message.reply_text(f"خطایی در ارسال فایل لاگ رخ داد: {e}")461 462@admin_only463async def admin_users_list(update: Update, context: ContextTypes.DEFAULT_TYPE):464 """نمایش لیست کامل کاربران با صفحهبندی."""465 users = data_manager.DATA['users']466 467 page = 1468 if context.args and context.args[0].isdigit():469 page = int(context.args[0])470 if page < 1: page = 1471 472 users_per_page = 20473 total_users = len(users)474 total_pages = (total_users + users_per_page - 1) // users_per_page475 476 if page > total_pages: page = total_pages477 478 start_idx = (page - 1) * users_per_page479 end_idx = min(start_idx + users_per_page, total_users)480 481 sorted_users = sorted(users.items(), key=lambda item: item[1].get('last_seen', ''), reverse=True)482 483 users_text = f"👥 **لیست کاربران (صفحه {page}/{total_pages})**\n\n"484 485 for i, (user_id, user_info) in enumerate(sorted_users[start_idx:end_idx], start=start_idx + 1):486 is_banned = "🚫" if int(user_id) in data_manager.DATA['banned_users'] else "✅"487 username = user_info.get('username', 'N/A')488 first_name = user_info.get('first_name', 'N/A')489 last_seen = user_info.get('last_seen', 'N/A')490 message_count = user_info.get('message_count', 0)491 context_count = len(user_info.get('context', []))492 493 # تعداد ریپلایها494 reply_count = 0495 if 'context' in user_info:496 reply_count = sum(1 for msg in user_info['context'] if msg.get('has_reply', False))497 498 users_text += f"{i}. {is_banned} `{user_id}` - {first_name} (@{username})\n"499 users_text += f" 📝 پیامها: `{message_count}` | 💭 context: `{context_count}` | 📎 ریپلایها: `{reply_count}`\n"500 users_text += f" ⏰ آخرین فعالیت: `{last_seen}`\n\n"501 502 keyboard = []503 if page > 1: keyboard.append([InlineKeyboardButton("⬅️ صفحه قبل", callback_data=f"users_list:{page-1}")])504 if page < total_pages: keyboard.append([InlineKeyboardButton("➡️ صفحه بعد", callback_data=f"users_list:{page+1}")])505 506 reply_markup = InlineKeyboardMarkup(keyboard) if keyboard else None507 await update.message.reply_text(users_text, parse_mode='Markdown', reply_markup=reply_markup)508 509@admin_only510async def admin_user_search(update: Update, context: ContextTypes.DEFAULT_TYPE):511 """جستجوی کاربر بر اساس نام یا نام کاربری."""512 if not context.args:513 await update.message.reply_text("⚠️ لطفاً نام یا نام کاربری برای جستجو وارد کنید.\nمثال: `/user_search علی`")514 return515 516 search_term = " ".join(context.args).lower()517 users = data_manager.DATA['users']518 519 matching_users = []520 for user_id, user_info in users.items():521 first_name = (user_info.get('first_name') or '').lower()522 username = (user_info.get('username') or '').lower()523 524 if search_term in first_name or search_term in username:525 is_banned = "🚫" if int(user_id) in data_manager.DATA['banned_users'] else "✅"526 matching_users.append((user_id, user_info, is_banned))527 528 if not matching_users:529 await update.message.reply_text(f"هیچ کاربری با نام «{search_term}» یافت نشد.")530 return531 532 results_text = f"🔍 **نتایج جستجو برای «{search_term}»**\n\n"533 534 for user_id, user_info, is_banned in matching_users:535 username_display = user_info.get('username', 'N/A')536 first_name_display = user_info.get('first_name', 'N/A')537 last_seen = user_info.get('last_seen', 'N/A')538 message_count = user_info.get('message_count', 0)539 context_count = len(user_info.get('context', []))540 541 # تعداد ریپلایها542 reply_count = 0543 if 'context' in user_info:544 reply_count = sum(1 for msg in user_info['context'] if msg.get('has_reply', False))545 546 results_text += f"{is_banned} `{user_id}` - {first_name_display} (@{username_display})\n"547 results_text += f" 📝 پیامها: `{message_count}` | 💭 context: `{context_count}` | 📎 ریپلایها: `{reply_count}`\n"548 results_text += f" ⏰ آخرین فعالیت: `{last_seen}`\n\n"549 550 await update.message.reply_text(results_text, parse_mode='Markdown')551 552@admin_only553async def admin_backup(update: Update, context: ContextTypes.DEFAULT_TYPE):554 """ایجاد نسخه پشتیبان از دادههای ربات."""555 try:556 timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')557 backup_file = f"bot_backup_{timestamp}.json"558 559 data_to_backup = data_manager.DATA.copy()560 data_to_backup['banned_users'] = list(data_manager.DATA['banned_users'])561 562 with open(backup_file, 'w', encoding='utf-8') as f:563 json.dump(data_to_backup, f, indent=4, ensure_ascii=False)564 565 await update.message.reply_document(566 document=open(backup_file, 'rb'),567 caption=f"✅ نسخه پشتیبان با موفقیت ایجاد شد: {backup_file}"568 )569 570 logger.info(f"Backup created: {backup_file}")571 os.remove(backup_file)572 except Exception as e:573 await update.message.reply_text(f"❌ خطا در ایجاد نسخه پشتیبان: {e}")574 logger.error(f"Error creating backup: {e}")575 576@admin_only577async def admin_export_csv(update: Update, context: ContextTypes.DEFAULT_TYPE):578 """ایجاد و ارسال فایل CSV از اطلاعات کاربران."""579 users = data_manager.DATA['users']580 581 df_data = []582 for user_id, user_info in users.items():583 is_banned = "بله" if int(user_id) in data_manager.DATA['banned_users'] else "خیر"584 context_count = len(user_info.get('context', []))585 context_tokens = data_manager.get_context_token_count(int(user_id))586 587 # تعداد ریپلایها588 reply_count = 0589 if 'context' in user_info:590 reply_count = sum(1 for msg in user_info['context'] if msg.get('has_reply', False))591 592 df_data.append({593 'User ID': user_id,594 'First Name': user_info.get('first_name', 'N/A'),595 'Username': user_info.get('username', 'N/A'),596 'Message Count': user_info.get('message_count', 0),597 'Context Messages': context_count,598 'Context Tokens': context_tokens,599 'Reply Count': reply_count,600 'First Seen': user_info.get('first_seen', 'N/A'),601 'Last Seen': user_info.get('last_seen', 'N/A'),602 'Banned': is_banned603 })604 605 df = pd.DataFrame(df_data)606 607 with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False, encoding='utf-8') as f:608 df.to_csv(f.name, index=False)609 temp_file_path = f.name610 611 await update.message.reply_document(612 document=open(temp_file_path, 'rb'),613 caption="📊 فایل CSV اطلاعات کاربران"614 )615 616 os.unlink(temp_file_path)617 618@admin_only619async def admin_maintenance(update: Update, context: ContextTypes.DEFAULT_TYPE):620 """حالت نگهداری ربات را فعال یا غیرفعال کرده و به کاربران اطلاع میدهد."""621 if not context.args or context.args[0].lower() not in ['on', 'off']:622 await update.message.reply_text("⚠️ فرمت صحیح: `/maintenance on` یا `/maintenance off`")623 return624 625 status = context.args[0].lower()626 627 if status == 'on':628 if data_manager.DATA.get('maintenance_mode', False):629 await update.message.reply_text("🔧 ربات از قبل در حالت نگهداری قرار دارد.")630 return631 632 data_manager.DATA['maintenance_mode'] = True633 data_manager.save_data()634 635 await update.message.reply_text("✅ حالت نگهداری ربات فعال شد. در حال اطلاعرسانی به کاربران...")636 637 user_ids = list(data_manager.DATA['users'].keys())638 for user_id_str in user_ids:639 try:640 if int(user_id_str) not in ADMIN_IDS:641 await context.bot.send_message(642 chat_id=int(user_id_str), 643 text="🔧 ربات در حال حاضر در حالت بهروزرسانی و نگهداری قرار دارد. لطفاً چند لحظه دیگر صبر کنید. از صبر شما سپاسگزاریم!"644 )645 await asyncio.sleep(0.05)646 except TelegramError:647 continue648 649 elif status == 'off':650 if not data_manager.DATA.get('maintenance_mode', False):651 await update.message.reply_text("✅ ربات از قبل در حالت عادی قرار دارد.")652 return653 654 data_manager.DATA['maintenance_mode'] = False655 data_manager.save_data()656 657 await update.message.reply_text("✅ حالت نگهداری ربات غیرفعال شد. در حال اطلاعرسانی به کاربران...")658 659 user_ids = list(data_manager.DATA['users'].keys())660 for user_id_str in user_ids:661 try:662 if int(user_id_str) not in ADMIN_IDS:663 await context.bot.send_message(664 chat_id=int(user_id_str), 665 text="✅ بهروزرسانی ربات به پایان رسید. از صبر شما سپاسگزاریم! میتوانید دوباره از ربات استفاده کنید."666 )667 await asyncio.sleep(0.05)668 except TelegramError:669 continue670 671@admin_only672async def admin_set_welcome_message(update: Update, context: ContextTypes.DEFAULT_TYPE):673 """تنظیم پیام خوشامدگویی جدید."""674 if not context.args:675 await update.message.reply_text("⚠️ لطفاً پیام خوشامدگویی جدید را وارد کنید.\n"676 "مثال: `/set_welcome سلام {user_mention}! به ربات خوش آمدید.`")677 return678 679 new_message = " ".join(context.args)680 data_manager.DATA['welcome_message'] = new_message681 data_manager.save_data()682 683 await update.message.reply_text("✅ پیام خوشامدگویی با موفقیت بهروزرسانی شد.")684 685@admin_only686async def admin_set_goodbye_message(update: Update, context: ContextTypes.DEFAULT_TYPE):687 """تنظیم پیام خداحافظی جدید."""688 if not context.args:689 await update.message.reply_text("⚠️ لطفاً پیام خداحافظی جدید را وارد کنید.\n"690 "مثال: `/set_goodbye {user_mention}، خداحافظ!`")691 return692 693 new_message = " ".join(context.args)694 data_manager.DATA['goodbye_message'] = new_message695 data_manager.save_data()696 697 await update.message.reply_text("✅ پیام خداحافظی با موفقیت بهروزرسانی شد.")698 699@admin_only700async def admin_activity_heatmap(update: Update, context: ContextTypes.DEFAULT_TYPE):701 """ایجاد و ارسال نمودار فعالیت کاربران."""702 users = data_manager.DATA['users']703 activity_hours = [0] * 24704 705 for user_info in users.values():706 if 'last_seen' in user_info:707 try:708 last_seen = datetime.strptime(user_info['last_seen'], '%Y-%m-%d %H:%M:%S')709 activity_hours[last_seen.hour] += 1710 except ValueError:711 continue712 713 plt.figure(figsize=(12, 6))714 plt.bar(range(24), activity_hours, color='skyblue')715 plt.title('نمودار فعالیت کاربران بر اساس ساعت')716 plt.xlabel('ساعت')717 plt.ylabel('تعداد کاربران فعال')718 plt.xticks(range(24))719 plt.grid(axis='y', alpha=0.3)720 721 with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as f:722 plt.savefig(f.name, bbox_inches='tight')723 temp_file_path = f.name724 725 plt.close()726 727 await update.message.reply_photo(728 photo=open(temp_file_path, 'rb'),729 caption="📊 نمودار فعالیت کاربران بر اساس ساعت"730 )731 732 os.unlink(temp_file_path)733 734@admin_only735async def admin_response_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):736 """نمایش آمار زمان پاسخگویی ربات."""737 stats = data_manager.DATA['stats']738 await update.message.reply_text(739 "📈 **آمار زمان پاسخگویی ربات**\n\n"740 f"🟢 میانگین زمان پاسخگویی: `{stats.get('avg_response_time', 0):.2f}` ثانیه\n"741 f"🔴 بیشترین زمان پاسخگویی: `{stats.get('max_response_time', 0):.2f}` ثانیه\n"742 f"🟢 کمترین زمان پاسخگویی: `{stats.get('min_response_time', 0):.2f}` ثانیه\n"743 f"📊 کل پاسخهای ثبت شده: `{stats.get('total_responses', 0)}`"744 )745 746@admin_only747async def admin_add_blocked_word(update: Update, context: ContextTypes.DEFAULT_TYPE):748 """افزودن کلمه یا عبارت به لیست کلمات مسدود شده."""749 if not context.args:750 await update.message.reply_text("⚠️ لطفاً کلمه یا عبارت مورد نظر را وارد کنید.\n"751 "مثال: `/add_blocked_word کلمه_نامناسب`")752 return753 754 word = " ".join(context.args).lower()755 756 if word in data_manager.DATA['blocked_words']:757 await update.message.reply_text(f"⚠️ کلمه «{word}» از قبل در لیست کلمات مسدود شده وجود دارد.")758 return759 760 data_manager.DATA['blocked_words'].append(word)761 data_manager.save_data()762 763 await update.message.reply_text(f"✅ کلمه «{word}» به لیست کلمات مسدود شده اضافه شد.")764 765@admin_only766async def admin_remove_blocked_word(update: Update, context: ContextTypes.DEFAULT_TYPE):767 """حذف کلمه یا عبارت از لیست کلمات مسدود شده."""768 if not context.args:769 await update.message.reply_text("⚠️ لطفاً کلمه یا عبارت مورد نظر را وارد کنید.\n"770 "مثال: `/remove_blocked_word کلمه_نامناسب`")771 return772 773 word = " ".join(context.args).lower()774 775 if word not in data_manager.DATA['blocked_words']:776 await update.message.reply_text(f"⚠️ کلمه «{word}» در لیست کلمات مسدود شده وجود ندارد.")777 return778 779 data_manager.DATA['blocked_words'].remove(word)780 data_manager.save_data()781 782 await update.message.reply_text(f"✅ کلمه «{word}» از لیست کلمات مسدود شده حذف شد.")783 784@admin_only785async def admin_list_blocked_words(update: Update, context: ContextTypes.DEFAULT_TYPE):786 """نمایش لیست کلمات مسدود شده."""787 if not data_manager.DATA['blocked_words']:788 await update.message.reply_text("هیچ کلمه مسدود شدهای در لیست وجود ندارد.")789 return790 791 words_list = "\n".join([f"• {word}" for word in data_manager.DATA['blocked_words']])792 await update.message.reply_text(f"🚫 **لیست کلمات مسدود شده:**\n\n{words_list}")793 794@admin_only795async def admin_system_info(update: Update, context: ContextTypes.DEFAULT_TYPE):796 """نمایش اطلاعات سیستم و منابع."""797 bot_start_time_str = data_manager.DATA.get('bot_start_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))798 try:799 bot_start_time = datetime.strptime(bot_start_time_str, '%Y-%m-%d %H:%M:%S')800 uptime = datetime.now() - bot_start_time801 except:802 uptime = "نامشخص"803 804 total_context_messages = sum(len(user.get('context', [])) for user in data_manager.DATA['users'].values())805 users_with_context = sum(1 for user in data_manager.DATA['users'].values() if user.get('context'))806 807 # تعداد کل ریپلایها808 total_replies = 0809 for user in data_manager.DATA['users'].values():810 if 'context' in user:811 total_replies += sum(1 for msg in user['context'] if msg.get('has_reply', False))812 813 system_info = (814 f"💻 **اطلاعات سیستم:**\n\n"815 f"🖥️ سیستمعامل: {platform.system()} {platform.release()}\n"816 f"🐍 نسخه پایتون: {platform.python_version()}\n"817 f"💾 حافظه RAM استفاده شده: {psutil.virtual_memory().percent}%\n"818 f"💾 حافظه RAM آزاد: {psutil.virtual_memory().available / (1024**3):.2f} GB\n"819 f"💾 فضای دیسک استفاده شده: {psutil.disk_usage('/').percent}%\n"820 f"💾 فضای دیسک آزاد: {psutil.disk_usage('/').free / (1024**3):.2f} GB\n"821 f"⏱️ زمان اجرای ربات: {uptime}\n"822 f"💭 کاربران با context: {users_with_context}\n"823 f"💬 کل پیامهای context: {total_context_messages}\n"824 f"📎 کل ریپلایهای ثبت شده: {total_replies}"825 )826 827 await update.message.reply_text(system_info, parse_mode='Markdown')828 829@admin_only830async def admin_reset_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):831 """ریست کردن آمار ربات."""832 if not context.args:833 await update.message.reply_text("⚠️ لطفاً نوع آماری که میخواهید ریست کنید را مشخص کنید.\n"834 "مثال: `/reset_stats messages` یا `/reset_stats all`")835 return836 837 stat_type = context.args[0].lower()838 839 if stat_type == "messages":840 data_manager.DATA['stats']['total_messages'] = 0841 for user_id in data_manager.DATA['users']:842 data_manager.DATA['users'][user_id]['message_count'] = 0843 await update.message.reply_text("✅ آمار پیامها با موفقیت ریست شد.")844 845 elif stat_type == "all":846 data_manager.DATA['stats'] = {847 'total_messages': 0,848 'total_users': len(data_manager.DATA['users']),849 'total_groups': len(data_manager.DATA['groups']),850 'avg_response_time': 0,851 'max_response_time': 0,852 'min_response_time': 0,853 'total_responses': 0854 }855 for user_id in data_manager.DATA['users']:856 data_manager.DATA['users'][user_id]['message_count'] = 0857 await update.message.reply_text("✅ تمام آمارها با موفقیت ریست شد.")858 859 else:860 await update.message.reply_text("⚠️ نوع آمار نامعتبر است. گزینههای موجود: messages, all")861 return862 863 data_manager.save_data()864 865# --- دستورات مدیریت context ---866@admin_only867async def admin_clear_context(update: Update, context: ContextTypes.DEFAULT_TYPE):868 """پاک کردن context یک کاربر"""869 if not context.args or not context.args[0].isdigit():870 await update.message.reply_text("⚠️ لطفاً آیدی کاربر را وارد کنید.\nمثال: `/clear_context 123456789`")871 return872 873 user_id = int(context.args[0])874 data_manager.clear_user_context(user_id)875 876 await update.message.reply_text(f"✅ context کاربر `{user_id}` با موفقیت پاک شد.")877 878@admin_only879async def admin_view_context(update: Update, context: ContextTypes.DEFAULT_TYPE):880 """مشاهده context یک کاربر"""881 if not context.args or not context.args[0].isdigit():882 await update.message.reply_text("⚠️ لطفاً آیدی کاربر را وارد کنید.\nمثال: `/view_context 123456789`")883 return884 885 user_id = int(context.args[0])886 user_context = data_manager.get_user_context(user_id)887 888 if not user_context:889 await update.message.reply_text(f"کاربر `{user_id}` context ندارد.")890 return891 892 context_text = f"📋 **Context کاربر `{user_id}`**\n\n"893 total_tokens = 0894 reply_count = 0895 896 for i, msg in enumerate(user_context, 1):897 role_emoji = "👤" if msg['role'] == 'user' else "🤖"898 tokens = data_manager.count_tokens(msg['content'])899 total_tokens += tokens900 901 # بررسی ریپلای902 has_reply = msg.get('has_reply', False)903 if has_reply:904 reply_count += 1905 reply_emoji = "📎"906 else:907 reply_emoji = ""908 909 content_preview = msg['content']910 if len(content_preview) > 100:911 content_preview = content_preview[:100] + "..."912 913 context_text += f"{i}. {role_emoji} {reply_emoji} **{msg['role']}** ({tokens} توکن)\n"914 context_text += f" ⏰ {msg.get('timestamp', 'N/A')}\n"915 916 if has_reply:917 context_text += f" 📎 ریپلای به: {msg.get('reply_to_user_name', 'Unknown')}\n"918 919 context_text += f" 📝 {content_preview}\n\n"920 921 context_text += f"📊 **مجموع:** {len(user_context)} پیام، {total_tokens} توکن، {reply_count} ریپلای"922 923 await update.message.reply_text(context_text, parse_mode='Markdown')924 925@admin_only926async def admin_view_replies(update: Update, context: ContextTypes.DEFAULT_TYPE):927 """مشاهده ریپلایهای یک کاربر یا گروه"""928 if len(context.args) < 2:929 await update.message.reply_text(930 "⚠️ فرمت صحیح: `/view_replies [user|group] [آیدی]`\n"931 "مثال: `/view_replies user 123456789`\n"932 "مثال: `/view_replies group -1001234567890`"933 )934 return935 936 entity_type = context.args[0].lower()937 entity_id = context.args[1]938 939 if entity_type == 'user':940 try:941 user_id = int(entity_id)942 user_context = data_manager.get_user_context(user_id)943 if not user_context:944 await update.message.reply_text(f"کاربر `{entity_id}` context ندارد.")945 return946 947 replies = [msg for msg in user_context if msg.get('has_reply', False)]948 949 if not replies:950 await update.message.reply_text(f"کاربر `{entity_id}` هیچ ریپلایای ثبت نکرده است.")951 return952 953 text = f"📋 **ریپلایهای کاربر `{entity_id}`**\n\n"954 for i, msg in enumerate(replies, 1):955 text += f"{i}. **زمان:** {msg.get('timestamp', 'N/A')}\n"956 text += f" **ریپلای به:** {msg.get('reply_to_user_name', 'Unknown')}\n"957 if msg.get('is_reply_to_bot', False):958 text += f" **نوع:** ریپلای به ربات 🤖\n"959 else:960 text += f" **نوع:** ریپلای به کاربر\n"961 text += f" **متن ریپلای شده:** {msg.get('reply_to_content', '')}\n"962 text += f" **پاسخ کاربر:** {msg.get('content', '')[:100]}...\n\n"963 964 text += f"📊 **مجموع:** {len(replies)} ریپلای"965 966 await update.message.reply_text(text, parse_mode='Markdown')967 except ValueError:968 await update.message.reply_text("⚠️ آیدی کاربر باید عددی باشد.")969 970 elif entity_type == 'group':971 try:972 chat_id = int(entity_id)973 group_context = data_manager.get_group_context(chat_id)974 if not group_context:975 await update.message.reply_text(f"گروه `{entity_id}` context ندارد.")976 return977 978 replies = [msg for msg in group_context if msg.get('has_reply', False)]979 980 if not replies:981 await update.message.reply_text(f"گروه `{entity_id}` هیچ ریپلایای ثبت نکرده است.")982 return983 984 text = f"📋 **ریپلایهای گروه `{entity_id}`**\n\n"985 for i, msg in enumerate(replies, 1):986 user_name = msg.get('user_name', 'Unknown')987 text += f"{i}. **کاربر:** {user_name}\n"988 text += f" **زمان:** {msg.get('timestamp', 'N/A')}\n"989 text += f" **ریپلای به:** {msg.get('reply_to_user_name', 'Unknown')}\n"990 if msg.get('is_reply_to_bot', False):991 text += f" **نوع:** ریپلای به ربات 🤖\n"992 else:993 text += f" **نوع:** ریپلای به کاربر\n"994 text += f" **متن ریپلای شده:** {msg.get('reply_to_content', '')}\n"995 text += f" **پاسخ کاربر:** {msg.get('content', '')[:100]}...\n\n"996 997 text += f"📊 **مجموع:** {len(replies)} ریپلای"998 999 await update.message.reply_text(text, parse_mode='Markdown')1000 except ValueError:1001 await update.message.reply_text("⚠️ آیدی گروه باید عددی باشد.")1002 1003 else:1004 await update.message.reply_text("⚠️ نوع نامعتبر. فقط 'user' یا 'group' مجاز است.")1005 1006# --- دستورات جدید برای مدیریت گروهها ---1007@admin_only1008async def admin_set_context_mode(update: Update, context: ContextTypes.DEFAULT_TYPE):1009 """تنظیم حالت context ربات"""1010 if not context.args or context.args[0].lower() not in ['separate', 'group_shared', 'hybrid']:1011 await update.message.reply_text(1012 "⚠️ فرمت صحیح: `/set_context_mode [separate|group_shared|hybrid]`\n\n"1013 "• **separate**: هر کاربر context جداگانه دارد (8192 توکن)\n"1014 "• **group_shared**: همه کاربران در یک گروه context مشترک دارند (16384 توکن)\n"1015 "• **hybrid**: ترکیبی از context شخصی و گروهی\n\n"1016 "💡 **توجه:** حالت group_shared حافظه بیشتری برای گروهها فراهم میکند."1017 )1018 return1019 1020 mode = context.args[0].lower()1021 if data_manager.set_context_mode(mode):1022 await update.message.reply_text(f"✅ حالت context به `{mode}` تغییر یافت.")1023 else:1024 await update.message.reply_text("❌ خطا در تغییر حالت context.")1025 1026@admin_only1027async def admin_group_info(update: Update, context: ContextTypes.DEFAULT_TYPE):1028 """نمایش اطلاعات یک گروه"""1029 if not context.args or not context.args[0].lstrip('-').isdigit():1030 await update.message.reply_text("⚠️ لطفاً آیدی عددی گروه را وارد کنید.\nمثال: `/group_info -1001234567890`")1031 return1032 1033 chat_id = int(context.args[0])1034 group_info = data_manager.DATA['groups'].get(str(chat_id))1035 1036 if not group_info:1037 await update.message.reply_text(f"گروهی با آیدی `{chat_id}` در دیتابیس یافت نشد.")1038 return1039 1040 # تبدیل set اعضا به لیست برای نمایش1041 members = list(group_info.get('members', set()))1042 members_count = len(members)1043 1044 # اطلاعات context گروه1045 context_messages = len(group_info.get('context', []))1046 total_tokens = sum(data_manager.count_tokens(msg['content']) for msg in group_info.get('context', []))1047 1048 # تعداد ریپلایها در گروه1049 reply_count = 01050 if 'context' in group_info:1051 reply_count = sum(1 for msg in group_info['context'] if msg.get('has_reply', False))1052 1053 text = (1054 f"📊 **اطلاعات گروه**\n\n"1055 f"🆔 **آیدی:** `{chat_id}`\n"1056 f"🏷️ **عنوان:** {group_info.get('title', 'N/A')}\n"1057 f"📝 **تعداد پیامها:** `{group_info.get('message_count', 0)}`\n"1058 f"👥 **تعداد اعضا:** `{members_count}`\n"1059 f"💭 **پیامهای context:** `{context_messages}`\n"1060 f"📎 **تعداد ریپلایها:** `{reply_count}`\n"1061 f"🔢 **توکنهای context:** `{total_tokens}`\n"1062 f"📅 **اولین فعالیت:** {group_info.get('first_seen', 'N/A')}\n"1063 f"🕒 **آخرین فعالیت:** {group_info.get('last_seen', 'N/A')}"1064 )1065 1066 await update.message.reply_text(text, parse_mode='Markdown')1067 1068@admin_only1069async def admin_clear_group_context(update: Update, context: ContextTypes.DEFAULT_TYPE):1070 """پاک کردن context یک گروه"""1071 if not context.args or not context.args[0].lstrip('-').isdigit():1072 await update.message.reply_text("⚠️ لطفاً آیدی گروه را وارد کنید.\nمثال: `/clear_group_context -1001234567890`")1073 return1074 1075 chat_id = int(context.args[0])1076 data_manager.clear_group_context(chat_id)1077 1078 await update.message.reply_text(f"✅ context گروه `{chat_id}` با موفقیت پاک شد.")1079 1080@admin_only1081async def admin_memory_status(update: Update, context: ContextTypes.DEFAULT_TYPE):1082 """نمایش وضعیت حافظه و context گروهها"""1083 groups = data_manager.DATA['groups']1084 1085 if not groups:1086 await update.message.reply_text("هیچ گروهی در دیتابیس وجود ندارد.")1087 return1088 1089 # محاسبه آمار1090 total_groups = len(groups)1091 groups_with_context = sum(1 for g in groups.values() if g.get('context'))1092 total_context_messages = sum(len(g.get('context', [])) for g in groups.values())1093 total_context_tokens = 01094 total_replies = 01095 1096 for group_id, group_info in groups.items():1097 if 'context' in group_info:1098 total_context_tokens += sum(data_manager.count_tokens(msg['content']) for msg in group_info['context'])1099 total_replies += sum(1 for msg in group_info['context'] if msg.get('has_reply', False))1100 1101 # لیست گروههایی که بیشترین استفاده از حافظه را دارند1102 groups_by_tokens = []1103 for group_id, group_info in groups.items():1104 if 'context' in group_info:1105 tokens = sum(data_manager.count_tokens(msg['content']) for msg in group_info['context'])1106 messages = len(group_info['context'])1107 replies = sum(1 for msg in group_info['context'] if msg.get('has_reply', False))1108 groups_by_tokens.append((group_id, tokens, messages, replies))1109 1110 # مرتبسازی بر اساس تعداد توکن1111 groups_by_tokens.sort(key=lambda x: x[1], reverse=True)1112 1113 status_text = (1114 f"💾 **وضعیت حافظه گروهها**\n\n"1115 f"📊 **آمار کلی:**\n"1116 f"• تعداد کل گروهها: `{total_groups}`\n"1117 f"• گروههای دارای context: `{groups_with_context}`\n"1118 f"• کل پیامهای context: `{total_context_messages}`\n"1119 f"• کل ریپلایها: `{total_replies}`\n"1120 f"• کل توکنهای استفاده شده: `{total_context_tokens}`\n"1121 f"• میانگین توکن per گروه: `{total_context_tokens/max(1, groups_with_context):.0f}`\n\n"1122 f"🏆 **گروههای با بیشترین استفاده از حافظه:**\n"1123 )1124 1125 for i, (group_id, tokens, messages, replies) in enumerate(groups_by_tokens[:10], 1):1126 usage_percent = (tokens / 16384) * 1001127 status_text += f"{i}. گروه `{group_id}`: {messages} پیام، {replies} ریپلای، {tokens} توکن ({usage_percent:.1f}%)\n"1128 1129 await update.message.reply_text(status_text, parse_mode='Markdown')1130 1131# --- هندلر برای دکمههای صفحهبندی ---1132async def users_list_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):1133 """پردازش دکمههای صفحهبندی لیست کاربران."""1134 query = update.callback_query1135 await query.answer()1136 1137 if query.data.startswith("users_list:"):1138 page = int(query.data.split(":")[1])1139 context.args = [str(page)]1140 await admin_users_list(update, context)1141 1142# --- تابع برای پردازش ارسالهای برنامهریزی شده ---1143async def process_scheduled_broadcasts(context: ContextTypes.DEFAULT_TYPE):1144 """پردازش ارسالهای برنامهریزی شده و ارسال پیامها در زمان مقرر."""1145 now = datetime.now()1146 broadcasts_to_send_indices = []1147 1148 for i, broadcast in enumerate(data_manager.DATA['scheduled_broadcasts']):1149 if broadcast['status'] == 'pending':1150 broadcast_time = datetime.strptime(broadcast['time'], '%Y-%m-%d %H:%M:%S')1151 if broadcast_time <= now:1152 broadcasts_to_send_indices.append(i)1153 1154 if not broadcasts_to_send_indices:1155 return1156 1157 user_ids = list(data_manager.DATA['users'].keys())1158 1159 for index in broadcasts_to_send_indices:1160 broadcast = data_manager.DATA['scheduled_broadcasts'][index]1161 message_text = broadcast['message']1162 total_sent, total_failed = 0, 01163 1164 for user_id_str in user_ids:1165 try:1166 await context.bot.send_message(chat_id=int(user_id_str), text=message_text)1167 total_sent += 11168 await asyncio.sleep(0.05)1169 except TelegramError as e:1170 logger.warning(f"Failed to send scheduled broadcast to {user_id_str}: {e}")1171 total_failed += 11172 1173 # بهروزرسانی وضعیت ارسال1174 data_manager.DATA['scheduled_broadcasts'][index]['status'] = 'sent'1175 data_manager.DATA['scheduled_broadcasts'][index]['sent_time'] = now.strftime('%Y-%m-%d %H:%M:%S')1176 data_manager.DATA['scheduled_broadcasts'][index]['sent_count'] = total_sent1177 data_manager.DATA['scheduled_broadcasts'][index]['failed_count'] = total_failed1178 1179 logger.info(f"Scheduled broadcast sent: {total_sent} successful, {total_failed} failed")1180 1181 data_manager.save_data()1182 1183# --- تابع راهاندازی هندلرها ---1184def setup_admin_handlers(application):1185 """هندلرهای پنل ادمین را به اپلیکیشن اضافه میکند."""1186 # هندلرهای اصلی1187 application.add_handler(CommandHandler("commands", admin_commands))1188 application.add_handler(CommandHandler("stats", admin_stats))1189 application.add_handler(CommandHandler("broadcast", admin_broadcast))1190 application.add_handler(CommandHandler("targeted_broadcast", admin_targeted_broadcast))1191 application.add_handler(CommandHandler("schedule_broadcast", admin_schedule_broadcast))1192 application.add_handler(CommandHandler("list_scheduled", admin_list_scheduled_broadcasts))1193 application.add_handler(CommandHandler("remove_scheduled", admin_remove_scheduled_broadcast))1194 application.add_handler(CommandHandler("ban", admin_ban))1195 application.add_handler(CommandHandler("unban", admin_unban))1196 application.add_handler(CommandHandler("direct_message", admin_direct_message))1197 application.add_handler(CommandHandler("user_info", admin_userinfo))1198 application.add_handler(CommandHandler("logs", admin_logs))1199 application.add_handler(CommandHandler("logs_file", admin_logs_file))1200 application.add_handler(CommandHandler("users_list", admin_users_list))