CoolFace
Datasetpublic

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)

sourceHugging Faceapache-2.0updated 4mo agoView on Hugging Face
3likes1.6kdownloads
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 14# --- کتابخانه‌های جدید برای ویژگی‌های اضافه شده ---15import matplotlib16matplotlib.use('Agg') # تنظیم برای استفاده در محیط بدون رابط کاربری گرافیکی17import matplotlib.pyplot as plt18import pandas as pd19import tempfile20import psutil21import platform22 23# --- تنظیمات ---24ADMIN_IDS = list(map(int, os.environ.get("ADMIN_IDS", "").split(','))) if os.environ.get("ADMIN_IDS") else []25 26# وارد کردن مدیر داده‌ها27import data_manager28 29logger = logging.getLogger(__name__)30 31# --- دکوراتور برای دسترسی ادمین ---32 33def admin_only(func):34    """این دکوراتور تضمین می‌کند که فقط ادمین‌ها بتوانند دستور را اجرا کنند."""35    async def wrapped(update: Update, context: ContextTypes.DEFAULT_TYPE, *args, **kwargs):36        if update.effective_user.id not in ADMIN_IDS:37            await update.message.reply_text("⛔️ شما دسترسی لازم برای اجرای این دستور را ندارید.")38            return39        return await func(update, context, *args, **kwargs)40    return wrapped41 42# --- هندلرهای دستورات ادمین ---43 44@admin_only45async def admin_commands(update: Update, context: ContextTypes.DEFAULT_TYPE):46    """نمایش تمام دستورات موجود ادمین."""47    commands_text = (48        "📋 **دستورات ادمین ربات:**\n\n"49        "📊 `/stats` - نمایش آمار ربات\n"50        "📢 `/broadcast [پیام]` - ارسال پیام به تمام کاربران\n"51        "🎯 `/targeted_broadcast [معیار] [مقدار] [پیام]` - ارسال پیام هدفمند\n"52        "📅 `/schedule_broadcast [YYYY-MM-DD] [HH:MM] [پیام]` - ارسال برنامه‌ریزی شده\n"53        "📋 `/list_scheduled` - نمایش لیست ارسال‌های برنامه‌ریزی شده\n"54        "🗑️ `/remove_scheduled [شماره]` - حذف ارسال برنامه‌ریزی شده\n"55        "🚫 `/ban [آیدی]` - مسدود کردن کاربر\n"56        "✅ `/unban [آیدی]` - رفع مسدودیت کاربر\n"57        "💌 `/direct_message [آیدی] [پیام]` - ارسال پیام مستقیم به کاربر\n"58        "ℹ️ `/user_info [آیدی]` - نمایش اطلاعات کاربر\n"59        "📝 `/logs` - نمایش آخرین لاگ‌ها\n"60        "📂 `/logs_file` - دانلود فایل کامل لاگ‌ها\n"61        "👥 `/users_list [صفحه]` - نمایش لیست کاربران\n"62        "🔍 `/user_search [نام]` - جستجوی کاربر بر اساس نام\n"63        "💾 `/backup` - ایجاد نسخه پشتیبان از داده‌ها\n"64        "📊 `/export_csv` - دانلود اطلاعات کاربران در فایل CSV\n"65        "🔧 `/maintenance [on/off]` - فعال/غیرفعال کردن حالت نگهداری\n"66        "👋 `/set_welcome [پیام]` - تنظیم پیام خوشامدگویی\n"67        "👋 `/set_goodbye [پیام]` - تنظیم پیام خداحافظی\n"68        "📈 `/activity_heatmap` - دریافت نمودار فعالیت کاربران\n"69        "⏱️ `/response_stats` - نمایش آمار زمان پاسخگویی\n"70        "🚫 `/add_blocked_word [کلمه]` - افزودن کلمه مسدود\n"71        "✅ `/remove_blocked_word [کلمه]` - حذف کلمه مسدود\n"72        "📜 `/list_blocked_words` - نمایش لیست کلمات مسدود\n"73        "💻 `/system_info` - نمایش اطلاعات سیستم\n"74        "🔄 `/reset_stats [messages/all]` - ریست کردن آمار\n"75        "🗑️ `/clear_context [آیدی]` - پاک کردن context کاربر\n"76        "📋 `/view_context [آیدی]` - مشاهده context کاربر\n"77        "📋 `/commands` - نمایش این لیست دستورات"78    )79    await update.message.reply_text(commands_text, parse_mode='Markdown')80 81@admin_only82async def admin_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):83    """آمار ربات را نمایش می‌دهد."""84    total_users = len(data_manager.DATA['users'])85    total_messages = data_manager.DATA['stats']['total_messages']86    banned_count = len(data_manager.DATA['banned_users'])87    88    now = datetime.now()89    active_24h = sum(1 for user in data_manager.DATA['users'].values() 90                    if 'last_seen' in user and 91                    datetime.strptime(user['last_seen'], '%Y-%m-%d %H:%M:%S') > now - timedelta(hours=24))92    93    active_7d = sum(1 for user in data_manager.DATA['users'].values() 94                   if 'last_seen' in user and 95                   datetime.strptime(user['last_seen'], '%Y-%m-%d %H:%M:%S') > now - timedelta(days=7))96 97    active_users = sorted(98        data_manager.DATA['users'].items(),99        key=lambda item: item[1].get('last_seen', ''),100        reverse=True101    )[:5]102 103    active_users_text = "\n".join(104        [f"• {user_id}: {info.get('first_name', 'N/A')} (آخرین فعالیت: {info.get('last_seen', 'N/A')})"105         for user_id, info in active_users]106    )107 108    # آمار context109    users_with_context = sum(1 for user in data_manager.DATA['users'].values() 110                           if user.get('context') and len(user['context']) > 0)111    total_context_messages = sum(len(user.get('context', [])) for user in data_manager.DATA['users'].values())112 113    text = (114        f"📊 **آمار ربات**\n\n"115        f"👥 **تعداد کل کاربران:** `{total_users}`\n"116        f"📝 **تعداد کل پیام‌ها:** `{total_messages}`\n"117        f"🚫 **کاربران مسدود شده:** `{banned_count}`\n"118        f"🟢 **کاربران فعال 24 ساعت گذشته:** `{active_24h}`\n"119        f"🟢 **کاربران فعال 7 روز گذشته:** `{active_7d}`\n"120        f"💭 **کاربران با context فعال:** `{users_with_context}`\n"121        f"💬 **کل پیام‌های context:** `{total_context_messages}`\n\n"122        f"**۵ کاربر اخیر فعال:**\n{active_users_text}"123    )124    await update.message.reply_text(text, parse_mode='Markdown')125 126@admin_only127async def admin_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):128    """یک پیام را به تمام کاربران ارسال می‌کند."""129    if not context.args:130        await update.message.reply_text("⚠️ لطفاً پیامی برای ارسال بنویسید.\nمثال: `/broadcast سلام به همه!`")131        return132 133    message_text = " ".join(context.args)134    user_ids = list(data_manager.DATA['users'].keys())135    total_sent = 0136    total_failed = 0137 138    await update.message.reply_text(f"📣 در حال ارسال پیام به `{len(user_ids)}` کاربر...")139 140    for user_id_str in user_ids:141        try:142            await context.bot.send_message(chat_id=int(user_id_str), text=message_text)143            total_sent += 1144            await asyncio.sleep(0.05)145        except TelegramError as e:146            logger.warning(f"Failed to send broadcast to {user_id_str}: {e}")147            total_failed += 1148 149    result_text = (150        f"✅ **ارسال همگانی تمام شد**\n\n"151        f"✅ موفق: `{total_sent}`\n"152        f"❌ ناموفق: `{total_failed}`"153    )154    await update.message.reply_text(result_text, parse_mode='Markdown')155 156@admin_only157async def admin_targeted_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):158    """ارسال پیام به گروه خاصی از کاربران بر اساس معیارهای مشخص."""159    if len(context.args) < 3:160        await update.message.reply_text("⚠️ فرمت صحیح: `/targeted_broadcast [معیار] [مقدار] [پیام]`\n"161                                       "معیارهای موجود: `active_days`, `message_count`, `banned`")162        return163    164    criteria = context.args[0].lower()165    value = context.args[1]166    message_text = " ".join(context.args[2:])167    168    target_users = []169    170    if criteria == "active_days":171        try:172            days = int(value)173            target_users = data_manager.get_active_users(days)174        except ValueError:175            await update.message.reply_text("⚠️ مقدار روز باید یک عدد صحیح باشد.")176            return177    178    elif criteria == "message_count":179        try:180            min_count = int(value)181            target_users = data_manager.get_users_by_message_count(min_count)182        except ValueError:183            await update.message.reply_text("⚠️ تعداد پیام باید یک عدد صحیح باشد.")184            return185    186    elif criteria == "banned":187        if value.lower() == "true":188            target_users = list(data_manager.DATA['banned_users'])189        elif value.lower() == "false":190            for user_id in data_manager.DATA['users']:191                if int(user_id) not in data_manager.DATA['banned_users']:192                    target_users.append(int(user_id))193        else:194            await update.message.reply_text("⚠️ مقدار برای معیار banned باید true یا false باشد.")195            return196    197    else:198        await update.message.reply_text("⚠️ معیار نامعتبر است. معیارهای موجود: active_days, message_count, banned")199        return200    201    if not target_users:202        await update.message.reply_text("هیچ کاربری با معیارهای مشخص شده یافت نشد.")203        return204    205    await update.message.reply_text(f"📣 در حال ارسال پیام به `{len(target_users)}` کاربر...")206    207    total_sent, total_failed = 0, 0208    for user_id in target_users:209        try:210            await context.bot.send_message(chat_id=user_id, text=message_text)211            total_sent += 1212            await asyncio.sleep(0.05)213        except TelegramError as e:214            logger.warning(f"Failed to send targeted broadcast to {user_id}: {e}")215            total_failed += 1216    217    result_text = f"✅ **ارسال هدفمند تمام شد**\n\n✅ موفق: `{total_sent}`\n❌ ناموفق: `{total_failed}`"218    await update.message.reply_text(result_text, parse_mode='Markdown')219 220@admin_only221async def admin_schedule_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):222    """تنظیم ارسال برنامه‌ریزی شده پیام به همه کاربران."""223    if len(context.args) < 3:224        await update.message.reply_text("⚠️ فرمت صحیح: `/schedule_broadcast [YYYY-MM-DD] [HH:MM] [پیام]`")225        return226    227    try:228        date_str, time_str = context.args[0], context.args[1]229        message_text = " ".join(context.args[2:])230        231        scheduled_time = datetime.strptime(f"{date_str} {time_str}", '%Y-%m-%d %H:%M')232        233        if scheduled_time <= datetime.now():234            await update.message.reply_text("⚠️ زمان برنامه‌ریزی شده باید در آینده باشد.")235            return236        237        data_manager.DATA['scheduled_broadcasts'].append({238            'time': scheduled_time.strftime('%Y-%m-%d %H:%M:%S'),239            'message': message_text,240            'status': 'pending'241        })242        data_manager.save_data()243        244        await update.message.reply_text(f"✅ پیام برای زمان `{scheduled_time.strftime('%Y-%m-%d %H:%M')}` برنامه‌ریزی شد.")245        246    except ValueError:247        await update.message.reply_text("⚠️ فرمت زمان نامعتبر است. لطفاً از فرمت YYYY-MM-DD HH:MM استفاده کنید.")248 249@admin_only250async def admin_list_scheduled_broadcasts(update: Update, context: ContextTypes.DEFAULT_TYPE):251    """نمایش لیست ارسال‌های برنامه‌ریزی شده."""252    if not data_manager.DATA['scheduled_broadcasts']:253        await update.message.reply_text("هیچ ارسال برنامه‌ریزی شده‌ای وجود ندارد.")254        return255    256    broadcasts_text = "📅 **لیست ارسال‌های برنامه‌ریزی شده:**\n\n"257    for i, broadcast in enumerate(data_manager.DATA['scheduled_broadcasts'], 1):258        status_emoji = "✅" if broadcast['status'] == 'sent' else "⏳"259        broadcasts_text += f"{i}. {status_emoji} `{broadcast['time']}` - {broadcast['message'][:50]}...\n"260    261    await update.message.reply_text(broadcasts_text, parse_mode='Markdown')262 263@admin_only264async def admin_remove_scheduled_broadcast(update: Update, context: ContextTypes.DEFAULT_TYPE):265    """حذف یک ارسال برنامه‌ریزی شده."""266    if not context.args or not context.args[0].isdigit():267        await update.message.reply_text("⚠️ لطفاً شماره ارسال برنامه‌ریزی شده را وارد کنید.\nمثال: `/remove_scheduled 1`")268        return269    270    index = int(context.args[0]) - 1271    272    if not data_manager.DATA['scheduled_broadcasts'] or not (0 <= index < len(data_manager.DATA['scheduled_broadcasts'])):273        await update.message.reply_text("⚠️ شماره ارسال برنامه‌ریزی شده نامعتبر است.")274        return275    276    removed_broadcast = data_manager.DATA['scheduled_broadcasts'].pop(index)277    data_manager.save_data()278    279    await update.message.reply_text(f"✅ ارسال برنامه‌ریزی شده برای زمان `{removed_broadcast['time']}` حذف شد.")280 281@admin_only282async def admin_ban(update: Update, context: ContextTypes.DEFAULT_TYPE):283    """یک کاربر را با آیدی عددی مسدود کرده و به او اطلاع می‌دهد."""284    if not context.args or not context.args[0].isdigit():285        await update.message.reply_text("⚠️ لطفاً آیدی عددی کاربر را وارد کنید.\nمثال: `/ban 123456789`")286        return287 288    user_id_to_ban = int(context.args[0])289 290    if user_id_to_ban in ADMIN_IDS:291        await update.message.reply_text("🛡️ شما نمی‌توانید یک ادمین را مسدود کنید!")292        return293 294    if data_manager.is_user_banned(user_id_to_ban):295        await update.message.reply_text(f"کاربر `{user_id_to_ban}` از قبل مسدود شده است.")296        return297 298    data_manager.ban_user(user_id_to_ban)299    300    # ارسال پیام به کاربر مسدود شده301    try:302        await context.bot.send_message(303            chat_id=user_id_to_ban, 304            text="⛔️ شما توسط ادمین ربات مسدود شدید و دیگر نمی‌توانید از خدمات ربات استفاده کنید."305        )306    except TelegramError as e:307        logger.warning(f"Could not send ban notification to user {user_id_to_ban}: {e}")308 309    await update.message.reply_text(f"✅ کاربر `{user_id_to_ban}` با موفقیت مسدود شد.", parse_mode='Markdown')310 311@admin_only312async def admin_unban(update: Update, context: ContextTypes.DEFAULT_TYPE):313    """مسدودیت یک کاربر را برمی‌دارد و به او اطلاع می‌دهد."""314    if not context.args or not context.args[0].isdigit():315        await update.message.reply_text("⚠️ لطفاً آیدی عددی کاربر را وارد کنید.\nمثال: `/unban 123456789`")316        return317 318    user_id_to_unban = int(context.args[0])319 320    if not data_manager.is_user_banned(user_id_to_unban):321        await update.message.reply_text(f"کاربر `{user_id_to_unban}` در لیست مسدود شده‌ها وجود ندارد.")322        return323 324    data_manager.unban_user(user_id_to_unban)325 326    # ارسال پیام به کاربر برای رفع مسدودیت327    try:328        await context.bot.send_message(329            chat_id=user_id_to_unban, 330            text="✅ مسدودیت شما توسط ادمین ربات برداشته شد. می‌توانید دوباره از ربات استفاده کنید."331        )332    except TelegramError as e:333        logger.warning(f"Could not send unban notification to user {user_id_to_unban}: {e}")334 335    await update.message.reply_text(f"✅ مسدودیت کاربر `{user_id_to_unban}` با موفقیت برداشته شد.", parse_mode='Markdown')336 337@admin_only338async def admin_direct_message(update: Update, context: ContextTypes.DEFAULT_TYPE):339    """ارسال پیام مستقیم به یک کاربر خاص."""340    if len(context.args) < 2:341        await update.message.reply_text("⚠️ فرمت صحیح: `/direct_message [آیدی] [پیام]`")342        return343    344    user_id_str = context.args[0]345    if not user_id_str.isdigit():346        await update.message.reply_text("⚠️ لطفاً یک آیدی عددی معتبر وارد کنید.")347        return348    349    message_text = " ".join(context.args[1:])350    user_id = int(user_id_str)351    352    try:353        await context.bot.send_message(chat_id=user_id, text=message_text)354        await update.message.reply_text(f"✅ پیام با موفقیت به کاربر `{user_id}` ارسال شد.", parse_mode='Markdown')355    except TelegramError as e:356        await update.message.reply_text(f"❌ خطا در ارسال پیام: {e}")357 358@admin_only359async def admin_userinfo(update: Update, context: ContextTypes.DEFAULT_TYPE):360    """اطلاعات یک کاربر خاص را نمایش می‌دهد."""361    if not context.args or not context.args[0].isdigit():362        await update.message.reply_text("⚠️ لطفاً آیدی عددی کاربر را وارد کنید.\nمثال: `/user_info 123456789`")363        return364 365    user_id = int(context.args[0])366    user_info = data_manager.DATA['users'].get(str(user_id))367 368    if not user_info:369        await update.message.reply_text(f"کاربری با آیدی `{user_id}` در دیتابیس یافت نشد.")370        return371 372    is_banned = "بله" if data_manager.is_user_banned(user_id) else "خیر"373    374    if 'first_seen' in user_info and 'last_seen' in user_info:375        first_date = datetime.strptime(user_info['first_seen'], '%Y-%m-%d %H:%M:%S')376        last_date = datetime.strptime(user_info['last_seen'], '%Y-%m-%d %H:%M:%S')377        days_active = max(1, (last_date - first_date).days)378        avg_messages = user_info.get('message_count', 0) / days_active379    else:380        avg_messages = user_info.get('message_count', 0)381    382    # اطلاعات context383    context_messages = len(user_info.get('context', []))384    context_tokens = data_manager.get_context_token_count(user_id)385    386    text = (387        f"ℹ️ **اطلاعات کاربر**\n\n"388        f"🆔 **آیدی:** `{user_id}`\n"389        f"👤 **نام:** {user_info.get('first_name', 'N/A')}\n"390        f"🔷 **نام کاربری:** @{user_info.get('username', 'N/A')}\n"391        f"📊 **تعداد پیام‌ها:** `{user_info.get('message_count', 0)}`\n"392        f"📈 **میانگین پیام در روز:** `{avg_messages:.2f}`\n"393        f"📅 **اولین پیام:** {user_info.get('first_seen', 'N/A')}\n"394        f"🕒 **آخرین فعالیت:** {user_info.get('last_seen', 'N/A')}\n"395        f"💭 **پیام‌های context:** `{context_messages}`\n"396        f"🔢 **توکن‌های context:** `{context_tokens}`\n"397        f"🚫 **وضعیت مسدودیت:** {is_banned}"398    )399    await update.message.reply_text(text, parse_mode='Markdown')400 401@admin_only402async def admin_logs(update: Update, context: ContextTypes.DEFAULT_TYPE):403    """آخرین خطوط لاگ ربات را ارسال می‌کند."""404    try:405        with open(data_manager.LOG_FILE, "r", encoding="utf-8") as f:406            lines = f.readlines()407            last_lines = lines[-30:]408            log_text = "".join(last_lines)409            if not log_text:410                await update.message.reply_text("فایل لاگ خالی است.")411                return412            413            if len(log_text) > 4096:414                for i in range(0, len(log_text), 4096):415                    await update.message.reply_text(f"```{log_text[i:i+4096]}```", parse_mode='Markdown')416            else:417                await update.message.reply_text(f"```{log_text}```", parse_mode='Markdown')418 419    except FileNotFoundError:420        await update.message.reply_text("فایل لاگ یافت نشد.")421    except Exception as e:422        await update.message.reply_text(f"خطایی در خواندن لاگ رخ داد: {e}")423 424@admin_only425async def admin_logs_file(update: Update, context: ContextTypes.DEFAULT_TYPE):426    """فایل کامل لاگ ربات را ارسال می‌کند."""427    try:428        await update.message.reply_document(429            document=open(data_manager.LOG_FILE, 'rb'),430            caption="📂 فایل کامل لاگ‌های ربات"431        )432    except FileNotFoundError:433        await update.message.reply_text("فایل لاگ یافت نشد.")434    except Exception as e:435        await update.message.reply_text(f"خطایی در ارسال فایل لاگ رخ داد: {e}")436 437@admin_only438async def admin_users_list(update: Update, context: ContextTypes.DEFAULT_TYPE):439    """نمایش لیست کامل کاربران با صفحه‌بندی."""440    users = data_manager.DATA['users']441    442    page = 1443    if context.args and context.args[0].isdigit():444        page = int(context.args[0])445        if page < 1: page = 1446    447    users_per_page = 20448    total_users = len(users)449    total_pages = (total_users + users_per_page - 1) // users_per_page450    451    if page > total_pages: page = total_pages452    453    start_idx = (page - 1) * users_per_page454    end_idx = min(start_idx + users_per_page, total_users)455    456    sorted_users = sorted(users.items(), key=lambda item: item[1].get('last_seen', ''), reverse=True)457    458    users_text = f"👥 **لیست کاربران (صفحه {page}/{total_pages})**\n\n"459    460    for i, (user_id, user_info) in enumerate(sorted_users[start_idx:end_idx], start=start_idx + 1):461        is_banned = "🚫" if int(user_id) in data_manager.DATA['banned_users'] else "✅"462        username = user_info.get('username', 'N/A')463        first_name = user_info.get('first_name', 'N/A')464        last_seen = user_info.get('last_seen', 'N/A')465        message_count = user_info.get('message_count', 0)466        context_count = len(user_info.get('context', []))467        468        users_text += f"{i}. {is_banned} `{user_id}` - {first_name} (@{username})\n"469        users_text += f"   📝 پیام‌ها: `{message_count}` | 💭 context: `{context_count}`\n"470        users_text += f"   ⏰ آخرین فعالیت: `{last_seen}`\n\n"471    472    keyboard = []473    if page > 1: keyboard.append([InlineKeyboardButton("⬅️ صفحه قبل", callback_data=f"users_list:{page-1}")])474    if page < total_pages: keyboard.append([InlineKeyboardButton("➡️ صفحه بعد", callback_data=f"users_list:{page+1}")])475    476    reply_markup = InlineKeyboardMarkup(keyboard) if keyboard else None477    await update.message.reply_text(users_text, parse_mode='Markdown', reply_markup=reply_markup)478 479@admin_only480async def admin_user_search(update: Update, context: ContextTypes.DEFAULT_TYPE):481    """جستجوی کاربر بر اساس نام یا نام کاربری."""482    if not context.args:483        await update.message.reply_text("⚠️ لطفاً نام یا نام کاربری برای جستجو وارد کنید.\nمثال: `/user_search علی`")484        return485    486    search_term = " ".join(context.args).lower()487    users = data_manager.DATA['users']488    489    matching_users = []490    for user_id, user_info in users.items():491        # استفاده از (value or '') برای جلوگیری از خطا در صورت وجود None492        first_name = (user_info.get('first_name') or '').lower()493        username = (user_info.get('username') or '').lower()494        495        if search_term in first_name or search_term in username:496            is_banned = "🚫" if int(user_id) in data_manager.DATA['banned_users'] else "✅"497            matching_users.append((user_id, user_info, is_banned))498    499    if not matching_users:500        await update.message.reply_text(f"هیچ کاربری با نام «{search_term}» یافت نشد.")501        return502    503    results_text = f"🔍 **نتایج جستجو برای «{search_term}»**\n\n"504    505    for user_id, user_info, is_banned in matching_users:506        username_display = user_info.get('username', 'N/A')507        first_name_display = user_info.get('first_name', 'N/A')508        last_seen = user_info.get('last_seen', 'N/A')509        message_count = user_info.get('message_count', 0)510        context_count = len(user_info.get('context', []))511        512        results_text += f"{is_banned} `{user_id}` - {first_name_display} (@{username_display})\n"513        results_text += f"   📝 پیام‌ها: `{message_count}` | 💭 context: `{context_count}`\n"514        results_text += f"   ⏰ آخرین فعالیت: `{last_seen}`\n\n"515    516    await update.message.reply_text(results_text, parse_mode='Markdown')517 518@admin_only519async def admin_backup(update: Update, context: ContextTypes.DEFAULT_TYPE):520    """ایجاد نسخه پشتیبان از داده‌های ربات."""521    try:522        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')523        backup_file = f"bot_backup_{timestamp}.json"524        525        data_to_backup = data_manager.DATA.copy()526        data_to_backup['banned_users'] = list(data_manager.DATA['banned_users'])527        528        with open(backup_file, 'w', encoding='utf-8') as f:529            json.dump(data_to_backup, f, indent=4, ensure_ascii=False)530        531        await update.message.reply_document(532            document=open(backup_file, 'rb'),533            caption=f"✅ نسخه پشتیبان با موفقیت ایجاد شد: {backup_file}"534        )535        536        logger.info(f"Backup created: {backup_file}")537        os.remove(backup_file) # حذف فایل پس از ارسال538    except Exception as e:539        await update.message.reply_text(f"❌ خطا در ایجاد نسخه پشتیبان: {e}")540        logger.error(f"Error creating backup: {e}")541 542@admin_only543async def admin_export_csv(update: Update, context: ContextTypes.DEFAULT_TYPE):544    """ایجاد و ارسال فایل CSV از اطلاعات کاربران."""545    users = data_manager.DATA['users']546    547    df_data = []548    for user_id, user_info in users.items():549        is_banned = "بله" if int(user_id) in data_manager.DATA['banned_users'] else "خیر"550        context_count = len(user_info.get('context', []))551        context_tokens = data_manager.get_context_token_count(int(user_id))552        553        df_data.append({554            'User ID': user_id,555            'First Name': user_info.get('first_name', 'N/A'),556            'Username': user_info.get('username', 'N/A'),557            'Message Count': user_info.get('message_count', 0),558            'Context Messages': context_count,559            'Context Tokens': context_tokens,560            'First Seen': user_info.get('first_seen', 'N/A'),561            'Last Seen': user_info.get('last_seen', 'N/A'),562            'Banned': is_banned563        })564    565    df = pd.DataFrame(df_data)566    567    with tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False, encoding='utf-8') as f:568        df.to_csv(f.name, index=False)569        temp_file_path = f.name570    571    await update.message.reply_document(572        document=open(temp_file_path, 'rb'),573        caption="📊 فایل CSV اطلاعات کاربران"574    )575    576    os.unlink(temp_file_path)577 578@admin_only579async def admin_maintenance(update: Update, context: ContextTypes.DEFAULT_TYPE):580    """حالت نگهداری ربات را فعال یا غیرفعال کرده و به کاربران اطلاع می‌دهد."""581    if not context.args or context.args[0].lower() not in ['on', 'off']:582        await update.message.reply_text("⚠️ فرمت صحیح: `/maintenance on` یا `/maintenance off`")583        return584 585    status = context.args[0].lower()586    587    if status == 'on':588        if data_manager.DATA.get('maintenance_mode', False):589            await update.message.reply_text("🔧 ربات از قبل در حالت نگهداری قرار دارد.")590            return591            592        data_manager.DATA['maintenance_mode'] = True593        data_manager.save_data()594        595        await update.message.reply_text("✅ حالت نگهداری ربات فعال شد. در حال اطلاع‌رسانی به کاربران...")596        597        user_ids = list(data_manager.DATA['users'].keys())598        for user_id_str in user_ids:599            try:600                # به ادمین‌ها پیام ارسال نشود601                if int(user_id_str) not in ADMIN_IDS:602                    await context.bot.send_message(603                        chat_id=int(user_id_str), 604                        text="🔧 ربات در حال حاضر در حالت به‌روزرسانی و نگهداری قرار دارد. لطفاً چند لحظه دیگر صبر کنید. از صبر شما سپاسگزاریم!"605                    )606                    await asyncio.sleep(0.05) # جلوگیری از محدودیت تلگرام607            except TelegramError:608                continue # نادیده گرفتن کاربرانی که ربات را مسدود کرده‌اند609 610    elif status == 'off':611        if not data_manager.DATA.get('maintenance_mode', False):612            await update.message.reply_text("✅ ربات از قبل در حالت عادی قرار دارد.")613            return614 615        data_manager.DATA['maintenance_mode'] = False616        data_manager.save_data()617 618        await update.message.reply_text("✅ حالت نگهداری ربات غیرفعال شد. در حال اطلاع‌رسانی به کاربران...")619 620        user_ids = list(data_manager.DATA['users'].keys())621        for user_id_str in user_ids:622            try:623                if int(user_id_str) not in ADMIN_IDS:624                    await context.bot.send_message(625                        chat_id=int(user_id_str), 626                        text="✅ به‌روزرسانی ربات به پایان رسید. از صبر شما سپاسگزاریم! می‌توانید دوباره از ربات استفاده کنید."627                    )628                    await asyncio.sleep(0.05)629            except TelegramError:630                continue631 632@admin_only633async def admin_set_welcome_message(update: Update, context: ContextTypes.DEFAULT_TYPE):634    """تنظیم پیام خوشامدگویی جدید."""635    if not context.args:636        await update.message.reply_text("⚠️ لطفاً پیام خوشامدگویی جدید را وارد کنید.\n"637                                       "مثال: `/set_welcome سلام {user_mention}! به ربات خوش آمدید.`")638        return639    640    new_message = " ".join(context.args)641    data_manager.DATA['welcome_message'] = new_message642    data_manager.save_data()643    644    await update.message.reply_text("✅ پیام خوشامدگویی با موفقیت به‌روزرسانی شد.")645 646@admin_only647async def admin_set_goodbye_message(update: Update, context: ContextTypes.DEFAULT_TYPE):648    """تنظیم پیام خداحافظی جدید."""649    if not context.args:650        await update.message.reply_text("⚠️ لطفاً پیام خداحافظی جدید را وارد کنید.\n"651                                       "مثال: `/set_goodbye {user_mention}، خداحافظ!`")652        return653    654    new_message = " ".join(context.args)655    data_manager.DATA['goodbye_message'] = new_message656    data_manager.save_data()657    658    await update.message.reply_text("✅ پیام خداحافظی با موفقیت به‌روزرسانی شد.")659 660@admin_only661async def admin_activity_heatmap(update: Update, context: ContextTypes.DEFAULT_TYPE):662    """ایجاد و ارسال نمودار فعالیت کاربران."""663    users = data_manager.DATA['users']664    activity_hours = [0] * 24665    666    for user_info in users.values():667        if 'last_seen' in user_info:668            try:669                last_seen = datetime.strptime(user_info['last_seen'], '%Y-%m-%d %H:%M:%S')670                activity_hours[last_seen.hour] += 1671            except ValueError:672                continue673    674    plt.figure(figsize=(12, 6))675    plt.bar(range(24), activity_hours, color='skyblue')676    plt.title('نمودار فعالیت کاربران بر اساس ساعت')677    plt.xlabel('ساعت')678    plt.ylabel('تعداد کاربران فعال')679    plt.xticks(range(24))680    plt.grid(axis='y', alpha=0.3)681    682    with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as f:683        plt.savefig(f.name, bbox_inches='tight')684        temp_file_path = f.name685    686    plt.close()687    688    await update.message.reply_photo(689        photo=open(temp_file_path, 'rb'),690        caption="📊 نمودار فعالیت کاربران بر اساس ساعت"691    )692    693    os.unlink(temp_file_path)694 695@admin_only696async def admin_response_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):697    """نمایش آمار زمان پاسخگویی ربات."""698    stats = data_manager.DATA['stats']699    await update.message.reply_text(700        "📈 **آمار زمان پاسخگویی ربات**\n\n"701        f"🟢 میانگین زمان پاسخگویی: `{stats.get('avg_response_time', 0):.2f}` ثانیه\n"702        f"🔴 بیشترین زمان پاسخگویی: `{stats.get('max_response_time', 0):.2f}` ثانیه\n"703        f"🟢 کمترین زمان پاسخگویی: `{stats.get('min_response_time', 0):.2f}` ثانیه\n"704        f"📊 کل پاسخ‌های ثبت شده: `{stats.get('total_responses', 0)}`"705    )706 707@admin_only708async def admin_add_blocked_word(update: Update, context: ContextTypes.DEFAULT_TYPE):709    """افزودن کلمه یا عبارت به لیست کلمات مسدود شده."""710    if not context.args:711        await update.message.reply_text("⚠️ لطفاً کلمه یا عبارت مورد نظر را وارد کنید.\n"712                                       "مثال: `/add_blocked_word کلمه_نامناسب`")713        return714    715    word = " ".join(context.args).lower()716    717    if word in data_manager.DATA['blocked_words']:718        await update.message.reply_text(f"⚠️ کلمه «{word}» از قبل در لیست کلمات مسدود شده وجود دارد.")719        return720    721    data_manager.DATA['blocked_words'].append(word)722    data_manager.save_data()723    724    await update.message.reply_text(f"✅ کلمه «{word}» به لیست کلمات مسدود شده اضافه شد.")725 726@admin_only727async def admin_remove_blocked_word(update: Update, context: ContextTypes.DEFAULT_TYPE):728    """حذف کلمه یا عبارت از لیست کلمات مسدود شده."""729    if not context.args:730        await update.message.reply_text("⚠️ لطفاً کلمه یا عبارت مورد نظر را وارد کنید.\n"731                                       "مثال: `/remove_blocked_word کلمه_نامناسب`")732        return733    734    word = " ".join(context.args).lower()735    736    if word not in data_manager.DATA['blocked_words']:737        await update.message.reply_text(f"⚠️ کلمه «{word}» در لیست کلمات مسدود شده وجود ندارد.")738        return739    740    data_manager.DATA['blocked_words'].remove(word)741    data_manager.save_data()742    743    await update.message.reply_text(f"✅ کلمه «{word}» از لیست کلمات مسدود شده حذف شد.")744 745@admin_only746async def admin_list_blocked_words(update: Update, context: ContextTypes.DEFAULT_TYPE):747    """نمایش لیست کلمات مسدود شده."""748    if not data_manager.DATA['blocked_words']:749        await update.message.reply_text("هیچ کلمه مسدود شده‌ای در لیست وجود ندارد.")750        return751    752    words_list = "\n".join([f"• {word}" for word in data_manager.DATA['blocked_words']])753    await update.message.reply_text(f"🚫 **لیست کلمات مسدود شده:**\n\n{words_list}")754 755@admin_only756async def admin_system_info(update: Update, context: ContextTypes.DEFAULT_TYPE):757    """نمایش اطلاعات سیستم و منابع."""758    bot_start_time_str = data_manager.DATA.get('bot_start_time', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))759    bot_start_time = datetime.strptime(bot_start_time_str, '%Y-%m-%d %H:%M:%S')760    uptime = datetime.now() - bot_start_time761    762    # محاسبه آمار context763    total_context_messages = sum(len(user.get('context', [])) for user in data_manager.DATA['users'].values())764    users_with_context = sum(1 for user in data_manager.DATA['users'].values() if user.get('context'))765    766    system_info = (767        f"💻 **اطلاعات سیستم:**\n\n"768        f"🖥️ سیستم‌عامل: {platform.system()} {platform.release()}\n"769        f"🐍 نسخه پایتون: {platform.python_version()}\n"770        f"💾 حافظه RAM استفاده شده: {psutil.virtual_memory().percent}%\n"771        f"💾 حافظه RAM آزاد: {psutil.virtual_memory().available / (1024**3):.2f} GB\n"772        f"💾 فضای دیسک استفاده شده: {psutil.disk_usage('/').percent}%\n"773        f"💾 فضای دیسک آزاد: {psutil.disk_usage('/').free / (1024**3):.2f} GB\n"774        f"⏱️ زمان اجرای ربات: {uptime}\n"775        f"💭 کاربران با context: {users_with_context}\n"776        f"💬 کل پیام‌های context: {total_context_messages}"777    )778    779    await update.message.reply_text(system_info, parse_mode='Markdown')780 781@admin_only782async def admin_reset_stats(update: Update, context: ContextTypes.DEFAULT_TYPE):783    """ریست کردن آمار ربات."""784    if not context.args:785        await update.message.reply_text("⚠️ لطفاً نوع آماری که می‌خواهید ریست کنید را مشخص کنید.\n"786                                       "مثال: `/reset_stats messages` یا `/reset_stats all`")787        return788    789    stat_type = context.args[0].lower()790    791    if stat_type == "messages":792        data_manager.DATA['stats']['total_messages'] = 0793        for user_id in data_manager.DATA['users']:794            data_manager.DATA['users'][user_id]['message_count'] = 0795        await update.message.reply_text("✅ آمار پیام‌ها با موفقیت ریست شد.")796    797    elif stat_type == "all":798        data_manager.DATA['stats'] = {799            'total_messages': 0,800            'total_users': len(data_manager.DATA['users']),801            'avg_response_time': 0,802            'max_response_time': 0,803            'min_response_time': 0,804            'total_responses': 0805        }806        for user_id in data_manager.DATA['users']:807            data_manager.DATA['users'][user_id]['message_count'] = 0808        await update.message.reply_text("✅ تمام آمارها با موفقیت ریست شد.")809    810    else:811        await update.message.reply_text("⚠️ نوع آمار نامعتبر است. گزینه‌های موجود: messages, all")812        return813    814    data_manager.save_data()815 816# --- دستورات جدید برای مدیریت context ---817 818@admin_only819async def admin_clear_context(update: Update, context: ContextTypes.DEFAULT_TYPE):820    """پاک کردن context یک کاربر"""821    if not context.args or not context.args[0].isdigit():822        await update.message.reply_text("⚠️ لطفاً آیدی کاربر را وارد کنید.\nمثال: `/clear_context 123456789`")823        return824    825    user_id = int(context.args[0])826    data_manager.clear_user_context(user_id)827    828    await update.message.reply_text(f"✅ context کاربر `{user_id}` با موفقیت پاک شد.")829 830@admin_only831async def admin_view_context(update: Update, context: ContextTypes.DEFAULT_TYPE):832    """مشاهده context یک کاربر"""833    if not context.args or not context.args[0].isdigit():834        await update.message.reply_text("⚠️ لطفاً آیدی کاربر را وارد کنید.\nمثال: `/view_context 123456789`")835        return836    837    user_id = int(context.args[0])838    user_context = data_manager.get_user_context(user_id)839    840    if not user_context:841        await update.message.reply_text(f"کاربر `{user_id}` context ندارد.")842        return843    844    context_text = f"📋 **Context کاربر `{user_id}`**\n\n"845    total_tokens = 0846    847    for i, msg in enumerate(user_context, 1):848        role_emoji = "👤" if msg['role'] == 'user' else "🤖"849        tokens = data_manager.count_tokens(msg['content'])850        total_tokens += tokens851        852        # کوتاه کردن متن طولانی853        content_preview = msg['content']854        if len(content_preview) > 100:855            content_preview = content_preview[:100] + "..."856        857        context_text += f"{i}. {role_emoji} **{msg['role']}** ({tokens} توکن)\n"858        context_text += f"   ⏰ {msg.get('timestamp', 'N/A')}\n"859        context_text += f"   📝 {content_preview}\n\n"860    861    context_text += f"📊 **مجموع:** {len(user_context)} پیام، {total_tokens} توکن"862    863    await update.message.reply_text(context_text, parse_mode='Markdown')864 865# --- هندلر برای دکمه‌های صفحه‌بندی ---866async def users_list_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):867    """پردازش دکمه‌های صفحه‌بندی لیست کاربران."""868    query = update.callback_query869    await query.answer()870    871    if query.data.startswith("users_list:"):872        page = int(query.data.split(":")[1])873        context.args = [str(page)]874        await admin_users_list(update, context)875 876# --- تابع برای پردازش ارسال‌های برنامه‌ریزی شده ---877async def process_scheduled_broadcasts(context: ContextTypes.DEFAULT_TYPE):878    """پردازش ارسال‌های برنامه‌ریزی شده و ارسال پیام‌ها در زمان مقرر."""879    now = datetime.now()880    broadcasts_to_send_indices = []881    882    for i, broadcast in enumerate(data_manager.DATA['scheduled_broadcasts']):883        if broadcast['status'] == 'pending':884            broadcast_time = datetime.strptime(broadcast['time'], '%Y-%m-%d %H:%M:%S')885            if broadcast_time <= now:886                broadcasts_to_send_indices.append(i)887 888    if not broadcasts_to_send_indices:889        return890    891    user_ids = list(data_manager.DATA['users'].keys())892    893    for index in broadcasts_to_send_indices:894        broadcast = data_manager.DATA['scheduled_broadcasts'][index]895        message_text = broadcast['message']896        total_sent, total_failed = 0, 0897        898        for user_id_str in user_ids:899            try:900                await context.bot.send_message(chat_id=int(user_id_str), text=message_text)901                total_sent += 1902                await asyncio.sleep(0.05)903            except TelegramError as e:904                logger.warning(f"Failed to send scheduled broadcast to {user_id_str}: {e}")905                total_failed += 1906        907        # به‌روزرسانی وضعیت ارسال908        data_manager.DATA['scheduled_broadcasts'][index]['status'] = 'sent'909        data_manager.DATA['scheduled_broadcasts'][index]['sent_time'] = now.strftime('%Y-%m-%d %H:%M:%S')910        data_manager.DATA['scheduled_broadcasts'][index]['sent_count'] = total_sent911        data_manager.DATA['scheduled_broadcasts'][index]['failed_count'] = total_failed912        913        logger.info(f"Scheduled broadcast sent: {total_sent} successful, {total_failed} failed")914    915    data_manager.save_data()916 917# --- تابع راه‌اندازی هندلرها ---918def setup_admin_handlers(application):919    """هندلرهای پنل ادمین را به اپلیکیشن اضافه می‌کند."""920    # هندلرهای اصلی921    application.add_handler(CommandHandler("commands", admin_commands))922    application.add_handler(CommandHandler("stats", admin_stats))923    application.add_handler(CommandHandler("broadcast", admin_broadcast))924    application.add_handler(CommandHandler("ban", admin_ban))925    application.add_handler(CommandHandler("unban", admin_unban))926    application.add_handler(CommandHandler("user_info", admin_userinfo))927    application.add_handler(CommandHandler("logs", admin_logs))928    application.add_handler(CommandHandler("logs_file", admin_logs_file))929    application.add_handler(CommandHandler("users_list", admin_users_list))930    application.add_handler(CommandHandler("user_search", admin_user_search))931    application.add_handler(CommandHandler("backup", admin_backup))932    933    # هندلرهای جدید934    application.add_handler(CommandHandler("targeted_broadcast", admin_targeted_broadcast))935    application.add_handler(CommandHandler("schedule_broadcast", admin_schedule_broadcast))936    application.add_handler(CommandHandler("list_scheduled", admin_list_scheduled_broadcasts))937    application.add_handler(CommandHandler("remove_scheduled", admin_remove_scheduled_broadcast))938    application.add_handler(CommandHandler("direct_message", admin_direct_message))939    application.add_handler(CommandHandler("export_csv", admin_export_csv))940    application.add_handler(CommandHandler("maintenance", admin_maintenance))941    application.add_handler(CommandHandler("set_welcome", admin_set_welcome_message))942    application.add_handler(CommandHandler("set_goodbye", admin_set_goodbye_message))943    application.add_handler(CommandHandler("activity_heatmap", admin_activity_heatmap))944    application.add_handler(CommandHandler("response_stats", admin_response_stats))945    application.add_handler(CommandHandler("add_blocked_word", admin_add_blocked_word))946    application.add_handler(CommandHandler("remove_blocked_word", admin_remove_blocked_word))947    application.add_handler(CommandHandler("list_blocked_words", admin_list_blocked_words))948    application.add_handler(CommandHandler("system_info", admin_system_info))949    application.add_handler(CommandHandler("reset_stats", admin_reset_stats))950    951    # هندلرهای مدیریت context952    application.add_handler(CommandHandler("clear_context", admin_clear_context))953    application.add_handler(CommandHandler("view_context", admin_view_context))954    955    # هندلر برای دکمه‌های صفحه‌بندی956    application.add_handler(CallbackQueryHandler(users_list_callback, pattern="^users_list:"))957    958    # شروع وظیفه دوره‌ای برای بررسی ارسال‌های برنامه‌ریزی شده959    application.job_queue.run_repeating(process_scheduled_broadcasts, interval=60, first=0)960    961    logger.info("Admin panel handlers have been set up.")