CoolFace
Apppublic

Engineersatya/EmpireBot

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
bot.py2298 linesDownload Raw Back to root
1import time, random, gspread, asyncio, os, sys, re2import datetime as dt3from datetime import datetime, timedelta4import pytz5from oauth2client.service_account import ServiceAccountCredentials6from telegram import Update, Poll, InlineKeyboardButton, InlineKeyboardMarkup, WebAppInfo7from telegram.ext import ApplicationBuilder, CommandHandler, ContextTypes, MessageHandler, filters, PollAnswerHandler8import logging9 10# ๐Ÿ‘‡ เคฏเฅ‡ 2 เคฒเคพเค‡เคจเฅ‡เค‚ เคœเฅ‹เฅœเคจเคพ เคฌเคนเฅเคค เฅ›เคฐเฅ‚เคฐเฅ€ เคนเฅˆ ๐Ÿ‘‡11from flask import Flask12from threading import Thread13 14logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')15 16# --- CONFIGURATION ---17BOT_TOKEN = '5180085614:AAGSm3d5x16neC4QTs2k3In6CLt1Nmck6mM'18MY_ADMIN_ID = 882736738 # ๐Ÿ‘ˆ YAHAN APNI NUMERIC ID DAALIYE19BRANDING = "\n\n๐Ÿ“’Eอ†nอ†gอ†iอ†nอ†eอ†eอ†rอ†sอ†aอ†tอ†yอ†aอ†๐Ÿ“’"20DEFAULT_LIMIT = 5021NEG_MARK = 0.2522 23# ๐Ÿ‘‘ GROUP CONFIGURATION (FREE VS PAID)24PUBLIC_GROUP = '@engineersatya'25PAID_GROUP = -100229556149026PAID_UP_GROUP = -100388905402527PAID_3RD_GROUP = -100246523119728 29GROUP_CONFIG = {30    PUBLIC_GROUP: '15Q0ST9CcvDbWZdBobGDDSAJAq80K4XiQhFxn4R8e_Dk',31    PAID_GROUP: '1Jc79jX4X5AV8-JMlUqRaDAe6g2ix1DReOJn8gj3h0Mk',32    PAID_UP_GROUP: "1NnoJS9Rx4Usn68vDer83fXUo6qLipchFlMEwg3AsDbg"33}34 35# ====================================================================36# ๐Ÿง  NAYA JADOO: AI SUBJECT AUTO-TAGGER (Keywords Dictionary)37# ====================================================================38SUBJECT_KEYWORDS = {39    "1. Building Materials & Construction (BMC)": ["Cement", "Concrete", "Brick", "Timber", "Aggregate", "Mortar", "Curing", "Workability", "Stone", "Granite", "Modulus of Elasticity", "RPC", "Phase-change material", "Paraffin wax", "FRP", "Vicat", "Setting time", "Frog", "Brinell", "Modular brick", "Marble", "Mohs", "Seasoning", "English bond", "Xylem", "Phloem", "Cambium", "Soundness", "ALAG", "Pozzolana", "Sulfate attack", "Water absorption", "Ballast", "Paint vehicle", "Annual rings", "Sound absorbent", "Cork", "Efflorescence", "Honeycombing", "Retarder", "Pointing", "Flexible thermal insulation", "Mineral wool", "Perpend", "Cement plaster", "Flaky", "Elongated aggregates", "Single scaffolding", "Monolithic floor", "Ashlar masonry", "ASCU treatment", "Jhama bricks"],40    "2. Soil Mechanics & Foundation Engineering": ["Void ratio", "Porosity", "Permeability", "Shear strength parameters", "Consolidation", "Primary creep", "Secondary creep", "Compaction", "Tensiometer", "Lime stabilization", "Terzaghi", "Uniformity coefficient", "IS Soil classification", "MDD", "OMC", "Bulking", "Se=wG", "Plastic limit", "Critical hydraulic gradient", "Angle of internal friction", "Bearing capacity", "Settlement in sand", "Aeolian soil", "Quicksand", "Piping", "Pycnometer", "Ultimate bearing capacity", "FOS", "Pore water pressure", "Effective stress", "Boreholes", "Slope stability", "Sudden drawdown", "Active earth pressure", "Pseudo-static method", "Vane shear test", "Sounding", "Raft footing", "Batter piles", "Negative skin friction", "Layered soil", "Dupuit's theory", "UU test", "B parameter", "Laplace", "Anisotropic", "Flow net", "Shape factor"],41    "3. Fluid Mechanics (FM) & Hydraulics": ["Viscosity", "Bernoulli", "Reynolds", "Mach", "Weir", "Flume", "Specific energy", "Open channel", "Continuity", "Conservation of mass", "Venturimeter", "Flow rate", "Piezometer", "Gauge pressure", "GVF", "Froude", "Water hammer", "EGL", "Hydraulic jump", "Pelton wheel", "Jet velocity", "Cavitation", "NPSH", "Hydrostatic pressure", "Fully developed flow", "Laminar", "Wetted perimeter", "Hydraulic radius", "Total acceleration", "Boundary layer", "separation point", "Buoyant force", "Turbulent flow", "Eddies", "Newtonian fluid", "du/dy", "Unit discharge", "Unit head", "HGL", "Reciprocating pump", "Piston acceleration", "Jet propulsion", "Kinematic viscosity", "Stokes", "Manning's formula"],42    "4. Environmental Engineering": ["BOD", "Aquatic life", "COD", "Water treatment", "Sewage", "Filtration", "Chlorination", "Ozone", "Sludge", "THMs", "Smog", "Fracking", "Alum", "Industrial effluents", "Chemical precipitation", "EIA", "Air Sparging", "Venturi Scrubber", "SCR", "Geologic sequestration", "Potable water", "pH", "TDS", "Pathogens", "Design period", "Carbon monoxide", "BOD test", "Permanent hardness", "Sullage", "Aerobic bacteria", "Freeman formula", "Soak pit", "Arsenic", "Grit chamber", "Trickling filter", "Skimming", "Primary pollutant", "Nitrate", "Landfill gas", "Sludge drying beds", "Constructed wetlands", "Pyrolysis", "FGD", "Leachate", "Factories Act 1948", "Activated carbon", "Adsorption", "Bar screen"],43    "5. Surveying": ["Theodolite", "Leveling", "Contouring", "Traverse", "Tachometry", "Stadia hairs", "EDM", "Total station", "Compass", "Metric chain", "Offset", "Plane table", "Direct plotting", "Pull correction", "HI", "Magnetic Declination", "Base line", "Cross-section", "RF", "Dip", "WCB to QB", "Prismatic compass", "Additive", "Multiplying constants", "1ยฐ Curve radius", "Latitude", "Face left", "Face right", "Trapezoidal volume", "Benchmark", "Level surface", "Backsighting", "Ranging", "Isogonic lines", "Working from whole to part", "Local attraction", "Reciprocal levelling", "Radiometric resolution", "Curvature correction", "Simpson's rule", "Optical square", "Overhanging cliff", "Tubular compass", "Stadia measurements", "Long chord", "PC to PT", "Surveyor's compass", "Cushing's level", "Transit axis", "Horizontal"],44    "6. Highway / Transportation Engineering": ["Sight distance", "Super elevation", "Camber", "Pavement", "Traffic", "Bitumen", "Tar", "Railway", "Parabolic camber", "Long rails", "Fishplate", "SSD", "Mean headway", "Ruling gradient", "Carriageway", "Brake reaction time", "Impact value", "CBR", "Viscosity", "Jayakar Committee", "Runway length", "Fatigue cracking", "Circular curve", "Greenshields", "Marshall Stability", "Ogee spillway", "PHF", "Vertical curve", "Spiral transition", "Max vehicle width", "2.44m", "OSD", "Highway drainage", "Westergaard assumption", "Vertical subgrade reaction", "Summit curve", "Off-tracking", "PIEV", "Asphalt mixes", "Cold", "Warm", "Hot", "Porous"],45    "7. Strength of Materials (SOM) / Mechanics of Structures": ["Stress", "Strain", "Bending moment", "Shear force", "Deflection", "Hooke's law", "Poisson's ratio", "Ductility", "Mild steel", "Strain energy", "P2L3/96EI", "Stiffness matrix", "Flexural rigidity", "Secant formula", "Eccentric loading", "Section modulus", "Volumetric strain", "Bulk Modulus", "Creep", "Propped cantilever", "Moment-area method", "Plastic moment capacity", "Plastic modulus", "Mohr's circle", "Max shear", "Flexibility method", "Buckling", "Fatigue", "Hoop stress", "Sphere PR/2t", "Shear stress distribution", "Zero at fibers", "Static indeterminacy", "m+r-3j", "Influence Line Diagram", "ILD", "Strain rosette", "Conjugate beam", "Zero force members"],46    "8. RCC (Reinforced Cement Concrete) / Prestressed Concrete": ["Limit state", "WSD", "Reinforcement", "Prestress", "Post-tensioning", "Stirrups", "Development length", "Inversely proportional to bond", "Modulus of Rupture", "Flexural test", "Exposure class", "Limiting moment", "Minimum tension steel", "Prevent buckling", "Static modulus", "Diagonal tension", "Side face reinforcement", "Retaining wall", "Seawater", "M30", "Ductile detailing", "Seismic Zone V", "Strong column-weak beam", "Torsional effect", "Shear wall", "Jacketing", "Retrofitting", "Floating columns", "Warping", "Dowel bars", "Under-reinforced", "Neutral axis 0.48d", "Fe415", "Pedestal", "L-beam", "Effective width", "Primary torsion", "Secondary torsion", "Modular ratio", "Es/Ec", "Chemical anchoring", "Epoxy"],47    "9. Steel Structures": ["Rivet", "Weld", "Bolt", "Tension member", "Compression member", "Plate girder", "Roof truss", "Plastic analysis", "Yield stress", "Block shear", "Slenderness ratio", "Pitch of rivets", "Fillet weld", "Gusset plate", "Load transfer", "Residual stresses", "Welding"],48    "10. Irrigation & Hydrology": ["Precipitation", "Runoff", "Hydrograph", "Duty", "Delta", "Crop period", "Spillway", "Canal", "Double-mass", "Sodic soil", "Drip", "Transpiration", "Unit Hydrograph", "Base flow", "Phi-index", "Mass curve", "Hydrologic cycle", "P=E+R", "Hyetograph", "Under-sluices", "Aqueduct", "Useful storage", "Water depth", "CCA", "Alluvial", "Non-alluvial channel", "Kor watering"],49    "11. Estimating, Costing & Valuation": ["Estimate", "BOQ", "Tender", "Contract", "Valuation", "Depreciation", "Salvage value", "Residual", "Rate analysis", "Centreline", "Carpet area", "Built-up area", "Super built-up area", "Loading", "Half brick wall", "Cement bag volume", "Dry volume", "Side slopes", "Pre-tender", "Revised estimate", "Plinth area", "Sunk cost", "Quantity surveying", "Capitalized value", "Net income", "YP"],50    "12. CPM / PERT (Construction Management)": ["Float", "Slack", "Critical path", "Event", "Activity", "Dummy", "Crashing", "PERT", "Te calculation", "Tail event", "Head event", "Objectives", "scope", "Scaffolding", "Total float", "Gantt chart", "Staircase", "3-12 steps", "Isometric projection", "0.816 scale factor", "View", "Controlling function", "WBS"]51}52# ====================================================================53 54# Google Sheets Setup55scope = ["https://spreadsheets.google.com/feeds", "https://www.googleapis.com/auth/drive"]56creds = ServiceAccountCredentials.from_json_keyfile_name("creds.json", scope)57client = gspread.authorize(creds)58 59# ๐ŸŒŸ HAR GROUP KI ALAG RAM60QUIZ_STATE = {}61POLL_DATA = {}62 63def get_state(chat_id):64    if chat_id not in QUIZ_STATE:65        QUIZ_STATE[chat_id] = {'running': False, 'pending_results': [], 'pending_num_results': [], 'latest_paper': [], 'q_current': 0, 'q_total': 0, 'practice_finished_early': False}66    return QUIZ_STATE[chat_id]67 68def get_current_group(update: Update):69    chat_id_num = update.effective_chat.id70    chat_username = f"@{update.effective_chat.username}" if update.effective_chat.username else None71    if chat_id_num in GROUP_CONFIG: return chat_id_num72    if chat_username in GROUP_CONFIG: return chat_username73    return None74 75async def is_admin(update: Update, chat_id):76    if update.effective_user.id == MY_ADMIN_ID:77        return True78    try:79        user = await update.get_bot().get_chat_member(chat_id, update.effective_user.id)80        return user.status in ['creator', 'administrator'] or update.effective_user.username == "engineersatyaquiz"81    except:82        return False83 84async def is_paid_member(update: Update, context: ContextTypes.DEFAULT_TYPE):85    user_id = str(update.effective_user.id).strip()86    try:87        sheet = client.open_by_key(GROUP_CONFIG[PAID_GROUP])88        vip_sheet = sheet.worksheet("VIP_Members")89        data = vip_sheet.get_all_values()[1:]90        for row in data:91            if len(row) >= 6 and str(row[0]).strip() == user_id:92                status = str(row[5]).strip().lower()93                if status in ['active', 'free', 'permanent']:94                    return True95        return False96    except Exception as e:97        print(f"VIP Sheet Check Error: {e}")98        return False99 100# --- 0. BOT START COMMAND ---101async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE):102    if update.effective_chat.type == 'private':103        welcome_text = (104            "๐ŸŽ‰ <b>Welcome to EngineerSatya Official Bot!</b> ๐ŸŽ‰\n\n"105            "๐ŸŽฏ <b>Join our Daily practice sessions using /practice</b>\n\n"106            "๐Ÿ’ก <b>Important Note:</b>\n"107            "โœ… If you are already a <b>VIP Paid Member</b>, this premium practice feature is completely <b>FREE</b> for you! Just type /practice to start.\n"108            "โŒ If you are <b>NOT</b> a paid member, you need to join our VIP Paid Group first to unlock these exclusive quizzes.\n\n"109            "๐Ÿ’ผ <b>Want to unlock premium questions and join the Paid Group?</b>\n"110            "Send a personal message to @Engineersatyaquiz ๐Ÿ“ฉ"111        )112        await update.message.reply_text(welcome_text, parse_mode='HTML')113 114# --- 1. RESULT SAVING ---115async def receive_quiz_answer(update: Update, context: ContextTypes.DEFAULT_TYPE):116    answer = update.poll_answer117    poll_info = POLL_DATA.get(answer.poll_id)118    if poll_info:119        chat_id = poll_info['chat_id']120        correct_id = poll_info['correct_id']121        is_num = poll_info.get('is_num', False)122        poll_date = poll_info.get('poll_date')123        user_name = f"{answer.user.first_name} {answer.user.last_name or ''}".strip()124        status = "Correct" if answer.option_ids[0] == correct_id else "Wrong"125        IST = pytz.timezone('Asia/Kolkata')126        now = datetime.now(IST)127        if is_num:128            if poll_date == now.date() and now.hour < 22:129                get_state(chat_id)['pending_num_results'].append([now.strftime("%d-%m-%Y %H:%M:%S"), answer.poll_id, user_name, status])130        else:131            get_state(chat_id)['pending_results'].append([str(time.ctime()), answer.poll_id, user_name, status])132 133# --- 2. ZIDDI LEADERBOARD ---134async def post_leaderboard(context: ContextTypes.DEFAULT_TYPE, chat_id):135    state = get_state(chat_id)136    max_retries = 5 137    for attempt in range(max_retries):138        try:139            sheet = client.open_by_key(GROUP_CONFIG[chat_id])140            res_sheet = sheet.worksheet("Results")141            if state['pending_results']:142                res_sheet.append_rows(state['pending_results'])143                state['pending_results'].clear()144            data = res_sheet.get_all_values()[1:]145            if not data:146                await context.bot.send_message(chat_id=chat_id, text="๐Ÿง <b>Arey! Scoreboard khali hai. Pahale Quiz to chalao!!!</b>", parse_mode='HTML')147                return148            stats = {}149            for row in data:150                if len(row) > 3:151                    name, status = row[2], row[3].strip()152                    if name not in stats: stats[name] = {"correct": 0, "wrong": 0}153                    if status == "Correct": stats[name]["correct"] += 1154                    else: stats[name]["wrong"] += 1155            leaderboard_data = sorted([{"name": n, "net": (s["correct"] * 1) - (s["wrong"] * NEG_MARK), "total": s["correct"] + s["wrong"], "c": s["correct"], "w": s["wrong"]} for n, s in stats.items()], key=lambda x: x['net'], reverse=True)156            total_students = len(leaderboard_data)157            chunk_size = 20158            for chunk_start in range(0, total_students, chunk_size):159                chunk_end = min(chunk_start + chunk_size, total_students)160                chunk_data = leaderboard_data[chunk_start:chunk_end]161                if chunk_start == 0:162                    msg = f"๐Ÿ† <b>ENGINEERSATYA OFFICIAL RANKING</b> ๐Ÿ†\n๐Ÿ‘ฅ <b>Total Participants: {total_students}</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"163                else:164                    msg = f"๐Ÿ“Š <b>RANKING CONTINUED ({chunk_start + 1} to {chunk_end})</b> ๐Ÿ“Š\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"165                for idx, p in enumerate(chunk_data):166                    real_rank = chunk_start + idx + 1167                    rank_emoji = "๐Ÿฅ‡" if real_rank == 1 else "๐Ÿฅˆ" if real_rank == 2 else "๐Ÿฅ‰" if real_rank == 3 else "๐ŸŽ—"168                    safe_name = str(p['name']).replace('<', 'ใ€').replace('>', 'ใ€‘').replace('&', 'and')169                    msg += f"{rank_emoji} <b>{safe_name}</b> (Rank {real_rank}/{total_students})\nโ”œ Total Attempt: {p['total']}\nโ”œ Correct: {p['c']} (x1)\nโ”œ Wrong: {p['w']} | Neg: -{p['w']*NEG_MARK:.2f}\nโ”” <b>NET SCORE: {p['net']:.2f} Marks</b>\n\n"170                if chunk_end == total_students:171                    msg += "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ”ฅ <b>Consistency is the key to success! Analyze your mistakes and keep practicing to secure your selection!</b> ๐Ÿ˜Ž"172                await context.bot.send_message(chat_id=chat_id, text=msg, parse_mode='HTML')173                await asyncio.sleep(1)174            return175        except Exception as e:176            if attempt < max_retries - 1:177                await asyncio.sleep(10)178            else:179                try:180                    await context.bot.send_message(chat_id=chat_id, text=f"โš ๏ธ <b>Leaderboard Error:</b> Server baar-baar fail ho raha hai. Thodi der baad `/Result_satya` command chala kar result nikal lijiye.", parse_mode='HTML')181                except: pass182 183# --- 3. AUTO WELCOME & PAID PROMO ---184async def welcome_new_member(update: Update, context: ContextTypes.DEFAULT_TYPE):185    chat_id = get_current_group(update)186    if not chat_id: return187    for member in update.message.new_chat_members:188        is_paid = chat_id == PAID_GROUP189        if is_paid:190            welcome_text = (191                f"๐ŸŽ‰ <b>Welcome to the VIP Engineersatya Squad, {member.first_name}!</b> ๐Ÿ‘ทโ€โ™‚๏ธ๐Ÿ—๏ธ\n\n"192                "You have officially unlocked the most premium practice platform for AE/JE Exams! Here is what you get as a VIP member:\n\n"193                "๐ŸŽฏ <b>VIP EXCLUSIVE FEATURES:</b>\n"194                "โž– <b>Strict Negative Marking</b> to build exam-like accuracy.\n"195                "โฑ๏ธ <b>Variable Dynamic Timers</b> (More time for numericals, less for one-liners).\n"196                "๐Ÿ“š <b>Subject-Wise Quizzes</b> to target your weak areas.\n"197                "๐Ÿ”ฅ <b>Daily Top 20 Numericals</b> (Attempt anytime before 10:00 PM for the leaderboard).\n"198                "๐Ÿ“ <b>Updated Question Bank:</b> Access to all recent exam papers and questions up to 2026.\n"199                "๐Ÿค– <b>24/7 Personal Access:</b> Any quiz conducted in the group goes straight to the Official Bot for you to practice privately anytime!\n"200                "๐Ÿ“„ <b>On-Demand PDF Tests:</b> Send any previous year paper PDF to @engineersatyaquiz, and we will convert it into a live bot quiz for you!\n\n"201                "๐Ÿ’ก <b>HOW TO PRACTICE PRIVATELY?</b>\n"202                "Go to our official bot DM and type:\n"203                "๐Ÿ‘‰ <b>/satya_quiz_sets</b> (To see and attempt all previous VIP quizzes)\n\n"204                "<i>Let the real preparation begin. Your gateway to selection starts here!</i> ๐Ÿš€๐Ÿ†"205            )206        else:207            welcome_text = (208                f"๐ŸŽ‰ Welcome to <b>Engineersatya Quiz Group</b>, {member.first_name}! ๐Ÿ‘ทโ€โ™‚๏ธ๐Ÿ—๏ธ\n\n"209                "๐Ÿ“ <b>Group Rules:</b>\n1. No Spamming or Personal Chats. ๐Ÿšซ\n2. Focus on your AE/JE Exams. ๐ŸŽฏ\n3. Respect all members and admins. ๐Ÿค\n\n"210                "๐Ÿ’ก <b>Want to boost your preparation?</b>\n"211                "You are warmly invited to join our <b>VIP Paid Group</b> to take your preparation to the next level (It's completely optional! ๐Ÿ˜Š). Here is what you get:\n"212                "โœ… <b>Strict Negative Marking</b> to build exam-like accuracy.\n"213                "โœ… Daily Top 20 Numericals & Subject-wise Quizzes.\n"214                "โœ… <b>Updated Question Bank</b> covering all recent exams up to 2026.\n"215                "โœ… <b>Private Access:</b> Practice all previous quizzes anytime via Bot.\n\n"216                "๐Ÿ“ฉ <i>To join the VIP Squad, please send a direct message to: @Engineersatyaquiz</i>\n\n"217                "<b>Your Gateway to Selection starts here!</b> ๐Ÿš€๐Ÿ†"218            )219        await update.message.reply_text(welcome_text, parse_mode='HTML')220 221# ๐ŸŒŸ 1. ADVANCE MEMORY WALA LIVE QUIZ LOOP 222async def run_quiz_loop(chat_id, context, final_list, set_name=""):223    state = get_state(chat_id)224    for i, item in enumerate(final_list):225        if not state['running']: break226        state['q_current'] += 1227        row = item['data']228        current_tab = item.get('tab', 'Satya_quiz')229        msg_kwargs = {'chat_id': chat_id}230        if chat_id == PAID_UP_GROUP:231            if current_tab == "UpGk":232                msg_kwargs['message_thread_id'] = 4   233            elif current_tab == "Computer":234                msg_kwargs['message_thread_id'] = 10  235            if i == 0 and current_tab == "UpGk":236                await context.bot.send_message(text="๐Ÿ“ข <b>[UP GK SECTION]</b>\nShuru ho rahe hain UP GK ke 20 shandaar sawal! ๐Ÿ”ฅ", parse_mode='HTML', **msg_kwargs)237                await asyncio.sleep(2)238            elif i > 0 and current_tab == "Computer" and final_list[i-1].get('tab', '') != "Computer":239                await context.bot.send_message(text="๐Ÿ’ป <b>[COMPUTER SECTION]</b>\nAb baari hai Computer ke sawalon ki! Taiyar ho jao! ๐Ÿš€", parse_mode='HTML', **msg_kwargs)240                await asyncio.sleep(2)241        try:242            raw_q = f"Q. {state['q_current']}/{state['q_total']} {row[0]}"243            max_q_len = 300 - len(BRANDING) - 5244            if len(raw_q) > max_q_len:245                full_msg = f"๐Ÿ“ <b>Q. {state['q_current']}/{state['q_total']} (Full Question):</b>\n{row[0]}"246                await context.bot.send_message(text=full_msg, parse_mode='HTML', **msg_kwargs)247                await asyncio.sleep(1)248                raw_q = f"Q. {state['q_current']}/{state['q_total']} Please read the full question sent above and answer below. ๐Ÿ‘‡"249            q_text = raw_q + BRANDING250            251            # --- ๐Ÿ›ก๏ธ SMART DYNAMIC OPTIONS HANDLER ---252            raw_opts = [str(row[1]).strip(), str(row[2]).strip(), str(row[3]).strip(), str(row[4]).strip()]253            safe_options = [opt[:97] + "..." if len(opt) > 100 else opt for opt in raw_opts if opt != ""]254            if len(safe_options) < 2:255                safe_options.extend(["Option A (Empty)", "Option B (Empty)"][:2 - len(safe_options)])256            try:257                c_id = int(row[5])258                if c_id >= len(safe_options) or c_id < 0: c_id = 0259            except:260                c_id = 0261            # -----------------------------------------262            263            exp_text = str(row[6]) if len(row) > 6 and row[6] else "๐Ÿ“’Eอ†nอ†gอ†iอ†nอ†eอ†eอ†rอ†sอ†aอ†tอ†yอ†aอ†๐Ÿ“’"264            if len(exp_text) > 200: exp_text = exp_text[:197] + "..."265            timer = int(row[7]) if len(row) > 7 and str(row[7]).isdigit() else 30266            image_url = str(row[8]).strip() if len(row) > 8 else ""267            if image_url.startswith("http"):268                try:269                    await context.bot.send_photo(photo=image_url, **msg_kwargs)270                    await asyncio.sleep(1)271                except: pass272            message = await context.bot.send_poll(273                question=q_text, options=safe_options, type=Poll.QUIZ,274                correct_option_id=c_id, explanation=exp_text,275                open_period=timer, is_anonymous=False, **msg_kwargs276            )277            POLL_DATA[message.poll.id] = {'chat_id': chat_id, 'correct_id': c_id}278            await asyncio.sleep(timer + 5)279        except Exception as e:280            try: await context.bot.send_message(chat_id=chat_id, text=f"โš ๏ธ <b>Network issue </b> Q.{i+1} skip ho gaya. Agla sawal aa raha hai...", parse_mode='HTML')281            except Exception: pass282            await asyncio.sleep(5)283            continue284    if state['running']:285        state['running'] = False286        await context.bot.send_message(chat_id=chat_id, text="๐Ÿ <b>Quiz Completed!</b> Calculating results... ๐Ÿฅ‡๐Ÿฅณ", parse_mode='HTML')287        await post_leaderboard(context, chat_id)288 289# --- 4. START GROUP QUIZ ---290async def start_quiz(update: Update, context: ContextTypes.DEFAULT_TYPE):291    await handle_quiz_start(update, context, is_resume=False)292 293# --- 4B. RESUME QUIZ COMMAND ---294async def resume_quiz(update: Update, context: ContextTypes.DEFAULT_TYPE):295    await handle_quiz_start(update, context, is_resume=True)296 297# ๐ŸŒŸ 2. START QUIZ HANDLER298async def handle_quiz_start(update: Update, context: ContextTypes.DEFAULT_TYPE, is_resume):299    chat_id = get_current_group(update)300    if not chat_id:301        await update.message.reply_text("โŒ Ye group bot ke config mein added nahi hai!")302        return303    if not await is_admin(update, update.effective_chat.id):304        await update.message.reply_text("๐Ÿšซ <b>Sabar Karo!</b> Admin is the captain . ๐Ÿ˜Ž๐Ÿ”ฅ", parse_mode='HTML')305        return306    state = get_state(chat_id)307    if state['running']:308        await update.message.reply_text("โš ๏ธ <b>Quiz already chal raha hai! Thora wait kro ya pahle Stop kro</b>", parse_mode='HTML')309        return310    sheet = client.open_by_key(GROUP_CONFIG[chat_id])311    if not is_resume:312        try:313            res_sheet = sheet.worksheet("Results")314            res_sheet.clear()315            res_sheet.append_row(["Time", "Poll ID", "Name", "Status"])316        except Exception as e: pass317        state['pending_results'].clear()318    else:319        await update.message.reply_text("๐Ÿ”„ <b>RESUME MODE ON!</b> Purane marks safe hain, yahin se aage shuru kar rahe hain...", parse_mode='HTML')320    state['running'] = True321    limit = DEFAULT_LIMIT322    tab_name = "Satya_quiz"323    set_name = ""324    if context.args:325        if context.args[0].isdigit():326            limit = int(context.args[0])327            if len(context.args) > 1:328                set_name = context.args[1]329                if len(context.args) > 2:330                    tab_name = " ".join(context.args[2:])331        else:332            set_name = context.args[0]333            if len(context.args) > 1:334                tab_name = " ".join(context.args[1:])335    # ================= UP SPECIAL LOGIC =================336    if chat_id == PAID_UP_GROUP:337        await update.message.reply_text(f"๐Ÿงน <b>UP GK aur Computer ka Special Data nikal raha hoon... (Set: {set_name if set_name else 'None'})</b> โš”๏ธ", parse_mode='HTML')338        try:339            upgk_sheet = sheet.worksheet("UpGk")340            comp_sheet = sheet.worksheet("Computer")341        except Exception:342            await update.message.reply_text("โš ๏ธ <b>Error:</b> Sheet mein 'UpGk' ya 'Computer' tab nahi mila! Spelling check karein.", parse_mode='HTML')343            state['running'] = False344            return345        upgk_data = upgk_sheet.get_all_values()346        upgk_pool = [{'row_num': idx, 'data': row, 'tab': 'UpGk'} for idx, row in enumerate(upgk_data, start=1) if idx > 1 and (row[11].strip() if len(row) > 11 else "") != "Sent"]347        random.shuffle(upgk_pool)348        final_list = upgk_pool[:20]349        comp_data = comp_sheet.get_all_values()350        comp_pool = [{'row_num': idx, 'data': row, 'tab': 'Computer'} for idx, row in enumerate(comp_data, start=1) if idx > 1 and (row[11].strip() if len(row) > 11 else "") != "Sent"]351        random.shuffle(comp_pool)352        final_list.extend(comp_pool[:15])353        if not final_list:354            await update.message.reply_text("โš ๏ธ In dono tabs mein naye sawal bache hi nahi hain!")355            state['running'] = False356            return357        if not is_resume: state['q_current'] = 0; state['q_total'] = len(final_list)358        else: state['q_total'] = state['q_current'] + len(final_list)359        360        # ๐Ÿ’ฅ JADOO: BULK UPDATE ADVANCE MEIN (WITH AI TAGGER) ๐Ÿ’ฅ361        if final_list:362            try:363                IST = pytz.timezone('Asia/Kolkata')364                today_str = datetime.now(IST).strftime("%d-%m-%Y")365                updates_by_tab = {}366                for item in final_list:367                    tab = item.get('tab', 'Satya_quiz')368                    row_num = item['row_num']369                    row_data = item['data']370                    if tab not in updates_by_tab: updates_by_tab[tab] = []371 372                    # --- ๐Ÿง  AI SUBJECT DETECTOR ---373                    existing_sub = str(row_data[9]).strip() if len(row_data) > 9 else ""374                    if not existing_sub and tab not in ["UpGk", "Computer"]:375                        full_text = f"{row_data[0]} {row_data[1]} {row_data[2]} {row_data[3]} {row_data[4]} {row_data[6] if len(row_data)>6 else ''}".lower()376                        best_sub = "13. Civil Engg"377                        max_matches = 0378                        for sub_name, keywords in SUBJECT_KEYWORDS.items():379                            matches = sum(1 for kw in keywords if kw.lower() in full_text)380                            if matches > max_matches:381                                max_matches = matches382                                best_sub = sub_name383                        updates_by_tab[tab].append({'range': f'J{row_num}', 'values': [[best_sub]]})384                    # -------------------------------385 386                    if set_name: updates_by_tab[tab].append({'range': f'L{row_num}:O{row_num}', 'values': [["Sent", today_str, set_name, today_str]]})387                    else: updates_by_tab[tab].append({'range': f'L{row_num}:M{row_num}', 'values': [["Sent", today_str]]})388                for tab, updates in updates_by_tab.items():389                    ws = sheet.worksheet(tab)390                    ws.batch_update(updates)391            except Exception as e: print(f"Advance Batch Update Error: {e}")392 393        await update.message.reply_text(f"๐Ÿš€ <b>BOOM! [UP SPECIAL QUIZ] is LIVE!</b>\nTarget: <b>{state['q_total']}</b> Questions. ๐Ÿ’ช๐Ÿ†", parse_mode='HTML')394        asyncio.create_task(run_quiz_loop(chat_id, context, final_list, set_name))395        try:396            if not is_resume and set_name:397                log_sheet = sheet.worksheet("Command_Log")398                IST = pytz.timezone('Asia/Kolkata')399                time_str = datetime.now(IST).strftime("%d-%m-%Y %H:%M:%S")400                clean_set = set_name.lower().replace(' ', '')401                log_sheet.append_row([time_str, f"/practice_up_{clean_set}", len(final_list), set_name, "UP Special"])402        except Exception as e: pass403        return404 405    # ================= GENERAL QUIZ LOGIC =================406    await update.message.reply_text(f"๐Ÿงน <b>'{tab_name}' wali sheet se data nikal raha hoon... (Set: {set_name if set_name else 'None'})</b> โš”๏ธ", parse_mode='HTML')407    try: quiz_sheet = sheet.worksheet(tab_name)408    except Exception:409        await update.message.reply_text(f"โš ๏ธ <b>Oops!</b> `{tab_name}` naam ka koi Panna (Tab) nahi mila.", parse_mode='HTML')410        state['running'] = False411        return412    data = quiz_sheet.get_all_values()413    quiz_pool = []414    for idx, row in enumerate(data, start=1):415        if idx == 1: continue416        if (row[11].strip() if len(row) > 11 else "") != "Sent":417            quiz_pool.append({'row_num': idx, 'data': row, 'tab': tab_name})418    if not quiz_pool:419        state['running'] = False420        await update.message.reply_text(f"โš ๏ธ <b>Arre!</b> '{tab_name}' wali sheet mein naye sawal bache hi nahi hain!", parse_mode='HTML')421        return422    random.shuffle(quiz_pool)423    final_list = quiz_pool[:limit]424    if chat_id == PAID_GROUP: state['latest_paper'] = [item['data'] for item in final_list]425    if not is_resume: state['q_current'] = 0; state['q_total'] = len(final_list)426    else: state['q_total'] = state['q_current'] + len(final_list)427    428    # ๐Ÿ’ฅ JADOO: BULK UPDATE ADVANCE MEIN (WITH AI TAGGER) ๐Ÿ’ฅ429    if final_list:430        try:431            IST = pytz.timezone('Asia/Kolkata')432            today_str = datetime.now(IST).strftime("%d-%m-%Y")433            updates_by_tab = {}434            for item in final_list:435                tab = item.get('tab', 'Satya_quiz')436                row_num = item['row_num']437                row_data = item['data']438                if tab not in updates_by_tab: updates_by_tab[tab] = []439 440                # --- ๐Ÿง  AI SUBJECT DETECTOR ---441                existing_sub = str(row_data[9]).strip() if len(row_data) > 9 else ""442                if not existing_sub and tab not in ["UpGk", "Computer"]:443                    full_text = f"{row_data[0]} {row_data[1]} {row_data[2]} {row_data[3]} {row_data[4]} {row_data[6] if len(row_data)>6 else ''}".lower()444                    best_sub = "13. Civil Engg"445                    max_matches = 0446                    for sub_name, keywords in SUBJECT_KEYWORDS.items():447                        matches = sum(1 for kw in keywords if kw.lower() in full_text)448                        if matches > max_matches:449                            max_matches = matches450                            best_sub = sub_name451                    updates_by_tab[tab].append({'range': f'J{row_num}', 'values': [[best_sub]]})452                # -------------------------------453 454                if set_name: updates_by_tab[tab].append({'range': f'L{row_num}:O{row_num}', 'values': [["Sent", today_str, set_name, today_str]]})455                else: updates_by_tab[tab].append({'range': f'L{row_num}:M{row_num}', 'values': [["Sent", today_str]]})456            for tab, updates in updates_by_tab.items():457                ws = sheet.worksheet(tab)458                ws.batch_update(updates)459        except Exception as e: print(f"Advance Batch Update Error: {e}")460 461    await update.message.reply_text(f"๐Ÿš€ <b>BOOM! [{tab_name.upper()}] Quiz battle is LIVE!</b>\nTarget: <b>{state['q_total']}</b> Questions. ๐Ÿ’ช๐Ÿ†", parse_mode='HTML')462    asyncio.create_task(run_quiz_loop(chat_id, context, final_list, set_name))463    try:464        if not is_resume and set_name:465            log_sheet = sheet.worksheet("Command_Log")466            IST = pytz.timezone('Asia/Kolkata')467            time_str = datetime.now(IST).strftime("%d-%m-%Y %H:%M:%S")468            clean_set = set_name.lower() if set_name else 'general'469            log_sheet.append_row([time_str, f"/practice_{clean_set}_{limit}_{tab_name}", limit, set_name, tab_name])470    except Exception as e: pass471 472# --- 5. EMERGENCY STOP COMMAND ---473async def stop_quiz(update: Update, context: ContextTypes.DEFAULT_TYPE):474    chat_id = get_current_group(update)475    if not chat_id: return476    if not await is_admin(update, update.effective_chat.id):477        await update.message.reply_text("๐Ÿšซ <b>Sabar Karo!</b> Sirf admin roksakta hai.", parse_mode='HTML')478        return479    state = get_state(chat_id)480    if state['running']:481        state['running'] = False482        await update.message.reply_text("๐Ÿ›‘ <b>Emergency Brake Applied!</b> ๐Ÿšจ\nAakhri sawal khatam hote hi Leaderboard aa jayega!", parse_mode='HTML')483    else:484        await update.message.reply_text("โ„น๏ธ <b>Relax!</b> Quiz pehle se hi ruki hui hai. ๐Ÿ˜ด", parse_mode='HTML')485 486# --- 6. MANUAL RESULT COMMAND ---487async def manual_result(update: Update, context: ContextTypes.DEFAULT_TYPE):488    chat_id = get_current_group(update)489    if not chat_id: return490    if not await is_admin(update, update.effective_chat.id):491        await update.message.reply_text("๐Ÿšซ <b>Sabar Karo!</b> Admin is the captain . ๐Ÿ˜Ž๐Ÿ”ฅ", parse_mode='HTML')492        return493    await update.message.reply_text("๐Ÿ“Š <b>Generating the Leaderboard... Please wait a moment!</b> โณ", parse_mode='HTML')494    await post_leaderboard(context, chat_id)495 496# ๐ŸŒŸ NAYA FEATURE: Background Task Function for VIP Practice497async def run_practice_loop(chat_id, context, final_list, test_name, user_id, user_name):498    state = get_state(chat_id)499    state['pending_results'].clear()500    total_seconds = len(final_list) * 35501    minutes = total_seconds // 60502    seconds = total_seconds % 60503    time_text = f"{minutes} min {seconds} sec" if minutes > 0 else f"{seconds} seconds"504    for i, row in enumerate(final_list):505        try:506            raw_q = f"Q. {i+1}/{len(final_list)} {row[0]}"507            max_q_len = 300 - len(BRANDING) - 5508            if len(raw_q) > max_q_len:509                full_msg = f"๐Ÿ“ <b>Q. {i+1}/{len(final_list)} (Full Question):</b>\n{row[0]}"510                await context.bot.send_message(chat_id=chat_id, text=full_msg, parse_mode='HTML', protect_content=True)511                await asyncio.sleep(1)512                raw_q = f"Q. {i+1}/{len(final_list)} Please read the full question sent above and answer below. ๐Ÿ‘‡"513            q_text = raw_q + BRANDING514            515            # --- ๐Ÿ›ก๏ธ SMART DYNAMIC OPTIONS HANDLER ---516            raw_opts = [str(row[1]).strip(), str(row[2]).strip(), str(row[3]).strip(), str(row[4]).strip()]517            safe_options = [opt[:97] + "..." if len(opt) > 100 else opt for opt in raw_opts if opt != ""]518            if len(safe_options) < 2:519                safe_options.extend(["Option A (Empty)", "Option B (Empty)"][:2 - len(safe_options)])520            try:521                c_id = int(row[5])522                if c_id >= len(safe_options) or c_id < 0: c_id = 0523            except:524                c_id = 0525            # -----------------------------------------526            527            exp_text = str(row[6]) if len(row) > 6 and row[6] else "Keep practicing! ๐Ÿ“š"528            if len(exp_text) > 200: exp_text = exp_text[:197] + "..."529            calc_button = InlineKeyboardMarkup([530                [InlineKeyboardButton(text="๐Ÿ”ข Scientific Calculator", web_app=WebAppInfo(url="https://www.desmos.com/scientific"))]531            ])532            image_url = str(row[8]).strip() if len(row) > 8 else ""533            if image_url.startswith("http"):534                try:535                    await context.bot.send_photo(chat_id=chat_id, photo=image_url)536                    await asyncio.sleep(1)537                except Exception as e: pass538            message = await context.bot.send_poll(539                chat_id=chat_id,540                question=q_text,541                options=safe_options,542                type=Poll.QUIZ,543                correct_option_id=c_id,544                explanation=exp_text,545                is_anonymous=False,546                reply_markup=calc_button,547                protect_content=True548            )549            POLL_DATA[message.poll.id] = {'chat_id': chat_id, 'correct_id': c_id}550            await asyncio.sleep(1)551        except: continue552 553    await context.bot.send_message(554        chat_id=chat_id,555        text=f"๐Ÿ <b>VIP Paper bhej diya gaya hai!</b>\n\nโฑ๏ธ Aapke paas test attempt karne ke liye total <b>{time_text}</b> hain.\n\nโšก <b>JALDI RESULT CHAHIYE?</b>\nAgar aapne paper poora kar liya aur time se pehle result dekhna chahte hain, toh yahan click karein ๐Ÿ‘‰ /finish",556        parse_mode='HTML',557        protect_content=True558    )559    560    state['practice_finished_early'] = False561    for _ in range(total_seconds):562        if state.get('practice_finished_early'):563            break564        await asyncio.sleep(1)565 566    user_results = state['pending_results']567    if not user_results:568        await context.bot.send_message(chat_id=chat_id, text="โš ๏ธ <b>Time Up!</b> Lekin aapne ek bhi question attempt nahi kiya. Agli baar dhyan se time par test dein!", parse_mode='HTML', protect_content=True)569        return570        571    correct = 0572    wrong = 0573    subject_mistakes = {} 574 575    for i, res in enumerate(user_results):576        status = res[3]577        if status == "Correct": 578            correct += 1579        else: 580            wrong += 1581            try:582                if len(final_list[i]['data']) > 9:583                    sub = final_list[i]['data'][9].strip()584                    if not sub: sub = "Mixed/Unknown"585                else:586                    sub = "Mixed/Unknown"587            except:588                sub = "Mixed/Unknown"589                590            if sub in subject_mistakes:591                subject_mistakes[sub] += 1592            else:593                subject_mistakes[sub] = 1594 595    net_score = (correct * 1) - (wrong * NEG_MARK)596    total_attempt = correct + wrong597    accuracy = (correct / total_attempt * 100) if total_attempt > 0 else 0598    599    if accuracy >= 80: remark = "๐ŸŒŸ BEST (Top Ranker Level!)"600    elif accuracy >= 70: remark = "๐Ÿ‘ BETTER (Strong Chances!)"601    elif accuracy >= 60: remark = "๐Ÿ™‚ GOOD (Keep Practicing!)"602    else: remark = "โš ๏ธ NEEDS IMPROVEMENT (Clear Your Concepts!)"603    604    scorecard = (605        "โฑ๏ธ <b>TIME UP!</b> โฑ๏ธ\n\n"606        "๐Ÿ“Š <b>AAPKA PERSONAL SCORECARD</b> ๐Ÿ“Š\n"607        "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"608        f"๐Ÿ“ Total Questions: {len(final_list)}\n"609        f"๐ŸŽฏ Total Attempted: {total_attempt}\n"610        f"โœ… Correct Answers: {correct} (x1 Mark)\n"611        f"โŒ Wrong Answers: {wrong}\n"612        f"โš ๏ธ Negative Marks: -{wrong * NEG_MARK:.2f}\n"613        "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"614        f"๐Ÿ† <b>NET SCORE: {net_score:.2f} Marks</b>\n"615        f"๐Ÿงฎ <b>Accuracy: {accuracy:.2f}%</b>\n"616        f"๐Ÿ’ก <b>Remark: {remark}</b>\n\n"617    )618    619    if wrong > 0:620        scorecard += "๐Ÿ” <b>Satya Sir's AI Analysis:</b>\n"621        for sub, count in subject_mistakes.items():622            if sub != "Mixed/Unknown":623                scorecard += f"โš ๏ธ Aapke <b>{sub}</b> ke <b>{count}</b> sawal galat hue hain.\n"624        scorecard += "\n๐Ÿ’ก <i>Advice: In subjects ko wapas revise karne ki sakht zaroorat hai!</i>\n\n"625        626    scorecard += "Success demands sacrifice! ๐Ÿ”ฅ Keep practicing, stay away from distractions, and focus purely on your goals! ๐ŸŽฏ"627    628    await context.bot.send_message(chat_id=chat_id, text=scorecard, parse_mode='HTML', protect_content=True)629    state['pending_results'].clear()630    try:631        IST = pytz.timezone('Asia/Kolkata')632        time_str = datetime.now(IST).strftime("%d-%m-%Y %H:%M:%S")633        neg_marks_str = f"{wrong * NEG_MARK:.2f}"634        net_score_str = f"{net_score:.2f}"635        accuracy_str = f"{accuracy:.2f}%"636        sheet = client.open_by_key(GROUP_CONFIG[PAID_GROUP])637        prac_sheet = sheet.worksheet("Practiceresult")638        prac_sheet.append_row([time_str, user_id, user_name, total_attempt, correct, wrong, neg_marks_str, net_score_str, test_name, accuracy_str, remark])639    except Exception as e:640        print(f"Practice Result Save Error: {e}")641 642# --- 7A. SECURE VIP PRACTICE MODE ---643async def practice_quiz(update: Update, context: ContextTypes.DEFAULT_TYPE):644    chat_id = update.effective_chat.id645    if update.effective_chat.type != 'private': return646    if not await is_paid_member(update, context):647        denied_msg = (648            "๐Ÿšซ <b>Access Denied!</b>\n\n"649            "๐Ÿ‡ฌ๐Ÿ‡ง You are not a VIP member yet! Please become a VIP member first by messaging in the Paid Group to unlock practice tests.\n\n"650            "๐Ÿ‡ฎ๐Ÿ‡ณ เคชเคนเคฒเฅ‡ เค†เคช เคชเฅ‡เคก เค—เฅเคฐเฅเคช (Paid Group) เคฎเฅ‡เค‚ เคฎเฅˆเคธเฅ‡เคœ เค•เคฐเค•เฅ‡ VIP เคฎเฅ‡เค‚เคฌเคฐ เคฌเคจ เคœเคพเค“, เค‰เคธเค•เฅ‡ เคฌเคพเคฆ เคนเฅ€ เค†เคช เคฏเคนเคพเค เคชเฅเคฐเฅˆเค•เฅเคŸเคฟเคธ เค•เคฐ เคชเคพเค“เค—เฅ‡!"651        )652        await context.bot.send_message(chat_id=chat_id, text=denied_msg, parse_mode='HTML')653        return654    text = update.message.text655    limit = DEFAULT_LIMIT656    tab_name = "Satya_quiz"657    req_set = ""658    if text.startswith('/practice_'):659        parts = text.split('_', 3)660        if len(parts) >= 4:661            req_set = parts[1].lower()662            if req_set == 'general': req_set = ""663            try: limit = int(parts[2])664            except: limit = DEFAULT_LIMIT665            tab_name = parts[3]666    else:667        words = text.split()668        command = words[0].lower()669        if "set" in command and command != "/practice":670            req_set = command.replace("/practice", "")671            args = words[1:]672        else:673            args = words[1:]674            if args and args[0].lower().startswith("set"):675                req_set = args[0]676                args = args[1:]677        if args:678            if args[0].isdigit():679                limit = int(args[0])680                if len(args) > 1: tab_name = " ".join(args[1:])681            else:682                tab_name = " ".join(args)683    set_msg = f" (Filtering for {req_set.upper()})" if req_set else " (Today's General Test)"684    await context.bot.send_message(chat_id=chat_id, text=f"๐Ÿ” VIP Sheet ke `{tab_name}` se sawal dhoondh raha hoon...{set_msg}")685    try:686        paid_sheet = client.open_by_key(GROUP_CONFIG[PAID_GROUP])687        quiz_sheet = paid_sheet.worksheet(tab_name)688        data = quiz_sheet.get_all_values()[1:]689        sent_questions = []690        IST = pytz.timezone('Asia/Kolkata')691        today_str = datetime.now(IST).strftime("%d-%m-%Y")692        for row in data:693            is_sent = str(row[11]).strip() if len(row) > 11 else ""694            row_date = str(row[12]).strip() if len(row) > 12 else ""695            row_set = str(row[13]).strip() if len(row) > 13 else ""696            if is_sent == "Sent":697                if req_set:698                    if req_set == "all": sent_questions.append(row)699                    elif row_set.lower() == req_set.lower(): sent_questions.append(row)700                else:701                    if row_date == today_str: sent_questions.append(row)702        if not sent_questions:703            if req_set:704                await context.bot.send_message(chat_id=chat_id, text=f"โš ๏ธ `{tab_name}` mein `{req_set}` ka koi test nahi mila!")705            else:706                await context.bot.send_message(chat_id=chat_id, text=f"โš ๏ธ Aaj `{tab_name}` mein koi naya general test nahi chalaya gaya hai!")707            return708        final_list = sent_questions[-limit:]709        await context.bot.send_message(chat_id=chat_id, text=f"๐Ÿ‘‘ <b>Premium Practice Mode ON! [{tab_name.upper()}]</b>\nYe raha aapka VIP Paper ({len(final_list)} questions). Aaram se solve karo! ๐Ÿ’ช", parse_mode='HTML')710        user_id = str(update.effective_user.id)711        user_name = update.effective_user.first_name712        test_name = f"{tab_name} {req_set}".strip() if req_set else f"{tab_name} General"713        asyncio.create_task(run_practice_loop(chat_id, context, final_list, test_name, user_id, user_name))714    except Exception as e:715        await context.bot.send_message(chat_id=chat_id, text=f"โš ๏ธ <b>System Error!</b> `{str(e)[:150]}`", parse_mode='HTML')716 717# --- 7B. UP SPECIAL PRACTICE ---718async def practice_up_quiz(update: Update, context: ContextTypes.DEFAULT_TYPE):719    chat_id = update.effective_chat.id720    if update.effective_chat.type != 'private':721        await context.bot.send_message(chat_id=chat_id, text="โš ๏ธ Practice akele mein hoti hai. DM karo! ๐Ÿคซ")722        return723    if not await is_paid_member(update, context):724        denied_msg = "๐Ÿšซ <b>Access Denied!</b>\n๐Ÿ‡ฌ๐Ÿ‡ง You are not a VIP member yet!"725        await context.bot.send_message(chat_id=chat_id, text=denied_msg, parse_mode='HTML')726        return727    text = update.message.text728    req_set = text.replace('/practice_up_', '').strip().lower() if text.startswith('/practice_up_') else ""729    set_msg = f" (Filtering for SET: {req_set.upper()})" if req_set else " (Today's Test)"730    await context.bot.send_message(chat_id=chat_id, text=f"๐Ÿ“‚ <b>UP GK & Computer Tabs</b> khol raha hoon...{set_msg}", parse_mode='HTML')731    try:732        up_sheet = client.open_by_key(GROUP_CONFIG[PAID_UP_GROUP])733        try:734            upgk_sheet = up_sheet.worksheet("UpGk")735            comp_sheet = up_sheet.worksheet("Computer")736        except Exception:737            await context.bot.send_message(chat_id=chat_id, text="โš ๏ธ <b>Oops!</b> UP sheet mein 'UpGk' ya 'Computer' tab nahi mila.", parse_mode='HTML')738            return739        IST = pytz.timezone('Asia/Kolkata')740        today_str = datetime.now(IST).strftime("%d-%m-%Y")741        upgk_data = upgk_sheet.get_all_values()[1:]742        comp_data = comp_sheet.get_all_values()[1:]743        if req_set:744            upgk_sent = [row for row in upgk_data if (str(row[11]).strip() if len(row) > 11 else "") == "Sent" and (str(row[13]).strip().lower() if len(row) > 13 else "") == req_set]745            comp_sent = [row for row in comp_data if (str(row[11]).strip() if len(row) > 11 else "") == "Sent" and (str(row[13]).strip().lower() if len(row) > 13 else "") == req_set]746        else:747            upgk_sent = [row for row in upgk_data if (str(row[11]).strip() if len(row) > 11 else "") == "Sent" and (str(row[12]).strip() if len(row) > 12 else "") == today_str]748            comp_sent = [row for row in comp_data if (str(row[11]).strip() if len(row) > 11 else "") == "Sent" and (str(row[12]).strip() if len(row) > 12 else "") == today_str]749        upgk_final = upgk_sent[-20:] if len(upgk_sent) >= 20 else upgk_sent750        comp_final = comp_sent[-15:] if len(comp_sent) >= 15 else comp_sent751        final_list = upgk_final + comp_final752        if not final_list:753            await context.bot.send_message(chat_id=chat_id, text="โš ๏ธ Koi sawal nahi mila! Check kijiye Set Name sahi hai ya aaj koi test hua hai.")754            return755        await context.bot.send_message(chat_id=chat_id, text=f"๐ŸŽฏ <b>UP Special Practice Mode ON!</b>\nTotal <b>{len(final_list)}</b> Questions aa gaye! Phod do! ๐Ÿ’ช", parse_mode='HTML')756        user_id = str(update.effective_user.id)757        user_name = update.effective_user.first_name758        test_name = f"UP Special {req_set.upper()}" if req_set else "UP Special General"759        asyncio.create_task(run_practice_loop(chat_id, context, final_list, test_name, user_id, user_name))760    except Exception as e:761        await context.bot.send_message(chat_id=chat_id, text=f"โš ๏ธ <b>System Error!</b> `{str(e)[:150]}`", parse_mode='HTML')762 763# --- 8. RESTART BOT COMMAND ---764async def restart_bot(update: Update, context: ContextTypes.DEFAULT_TYPE):765    if not await is_admin(update, update.effective_chat.id):766        await update.message.reply_text("๐Ÿšซ Ruko jara....Sabar Karo! Admin is the captain  . ๐Ÿ˜Ž๐Ÿ”ฅ")767        return768    await update.message.reply_text("โ™ป๏ธ <b>Bot Restart ho raha hai...</b>", parse_mode='HTML')769    os.execl(sys.executable, sys.executable, *sys.argv)770 771# --- 9. MANUAL RESET RESULT COMMAND ---772async def reset_result(update: Update, context: ContextTypes.DEFAULT_TYPE):773    chat_id = get_current_group(update)774    if not chat_id: return775    if not await is_admin(update, update.effective_chat.id):776        await update.message.reply_text("๐Ÿšซ <b>Sabar Karo!</b> Sirf Admin hi scoreboard saaf kar sakta hai. ๐Ÿ˜Ž๐Ÿ”ฅ", parse_mode='HTML')777        return778    await update.message.reply_text("๐Ÿงน Scoreboard saaf kiya ja raha hai... Ek second rukiye! Clean India Green India!!!! โณ")779    try:780        state = get_state(chat_id)781        state['pending_results'].clear()782        sheet = client.open_by_key(GROUP_CONFIG[chat_id])783        res_sheet = sheet.worksheet("Results")784        res_sheet.clear()785        res_sheet.append_row(["Time", "Poll ID", "Name", "Status"])786        await update.message.reply_text("โœ… <b>Lo Bhai! Scoreboard ekdum naya aur khali ho gaya.</b> Ab naye test ki taiyari karo! ๐Ÿ†", parse_mode='HTML')787    except Exception as e:788        await update.message.reply_text(f"โš ๏ธ <b>Error:</b> Sheet saaf karne mein dikkat aayi: {str(e)[:100]}", parse_mode='HTML')789 790# ---10. VIP MANAGEMENT COMMAND ---791async def add_vip(update: Update, context: ContextTypes.DEFAULT_TYPE):792    if not await is_admin(update, update.effective_chat.id): return793    if not update.message.reply_to_message:794        await update.message.reply_text("โš ๏ธ Jis student ko VIP banana hai, uske message par reply karke command dein.")795        return796    reply_msg = update.message.reply_to_message797    if reply_msg.from_user.id == context.bot.id and "๐Ÿ†”" in reply_msg.text:798        match_id = re.search(r"๐Ÿ†”\s*(\d+)", reply_msg.text)799        match_name = re.search(r"๐Ÿ‘ค Name:\s*(.+)", reply_msg.text)800        user_id = match_id.group(1).strip() if match_id else None801        name = match_name.group(1).strip() if match_name else "Student"802        username = "No Username"803    else:804        user_id = str(reply_msg.from_user.id).strip()805        name = reply_msg.from_user.first_name806        username = f"@{reply_msg.from_user.username}" if reply_msg.from_user.username else "No Username"807    if not user_id:808        await update.message.reply_text("โŒ Error: Student ki ID nahi mil saki.")809        return810    args = context.args811    IST = pytz.timezone('Asia/Kolkata')812    join_date = datetime.now(IST)813    dur_str = "30"814    amount = "0"815    if len(args) == 2:816        dur_str = args[0]817        amount = args[1]818    elif len(args) == 3:819        try:820            join_date = datetime.strptime(args[0], "%d-%m-%Y")821            dur_str = args[1]822            amount = args[2]823        except:824            return await update.message.reply_text("โš ๏ธ Date format galat hai! DD-MM-YYYY use karein.")825    elif len(args) == 1:826        dur_str = args[0]827    else:828        return await update.message.reply_text("โš ๏ธ <b>Format:</b>\n`/addvip 30 100` (30 din, 100 Rs)\n`/addvip 15-03-2026 30 100` (Date, Din, Rs)", parse_mode='HTML')829    try:830        if dur_str.lower().endswith('m'): days = int(dur_str[:-1]) * 30831        else: days = int(dur_str)832    except: days = 30833    expiry_date = join_date + timedelta(days=days)834    join_str = join_date.strftime("%d-%m-%Y")835    expiry_str = expiry_date.strftime("%d-%m-%Y")836    await update.message.reply_text(f"โณ Processing... Payment: โ‚น{amount}")837    try:838        sheet = client.open_by_key(GROUP_CONFIG[PAID_GROUP])839        vip_sheet = sheet.worksheet("VIP_Members")840        existing_data = vip_sheet.get_all_values()841        row_found = False842        for i, row in enumerate(existing_data):843            if i == 0: continue844            if len(row) > 0 and str(row[0]).strip() == user_id:845                vip_sheet.update_cell(i + 1, 4, join_str)846                vip_sheet.update_cell(i + 1, 5, expiry_str)847                vip_sheet.update_cell(i + 1, 6, "Active")848                vip_sheet.update_cell(i + 1, 7, amount)849                row_found = True850                break851        if not row_found:852            vip_sheet.append_row([user_id, name, username, join_str, expiry_str, "Active", amount])853        success_msg = (854            f"โœ… <b>VIP ACCESS CONFIRMED!</b> ๐Ÿ‘‘\n\n"855            f"๐Ÿ‘ค <b>Name:</b> {name}\n"856            f"๐Ÿ’ฐ <b>Payment Received:</b> โ‚น{amount}\n"857            f"๐Ÿ“… <b>Valid Till:</b> {expiry_str}\n"858            f"๐ŸŸข <b>Status:</b> Active\n\n"859            f"Student ko VIP groups join karne ke liye /sendlinks bhej dein! ๐Ÿš€"860        )861        await update.message.reply_text(success_msg, parse_mode='HTML')862        try:863            if update.effective_chat.type == 'private':864                await context.bot.send_message(chat_id=user_id, text=success_msg, parse_mode='HTML')865                await update.message.reply_text("๐Ÿ”” <i>Student ko notification DM me bhej diya gaya hai!</i>", parse_mode='HTML')866        except: pass867    except Exception as e:868        await update.message.reply_text(f"โŒ Error: {str(e)[:100]}", parse_mode='HTML')869 870# --- 11. VIP Rozana Reminder & 5th Day Kick Engine ---871async def check_vip_expiry(context: ContextTypes.DEFAULT_TYPE):872    IST = pytz.timezone('Asia/Kolkata')873    today = datetime.now(IST).date()874    try:875        sheet = client.open_by_key(GROUP_CONFIG[PAID_GROUP])876        vip_sheet = sheet.worksheet("VIP_Members")877        rows = vip_sheet.get_all_values()878        879        for i, row in enumerate(rows):880            if i == 0: continue881            if len(row) < 6: continue882 883            user_id = row[0]884            name = row[1]885            expiry_str = row[4]886            status = row[5]887 888            # In logon ko touch nahi karna889            if status.lower() in ["removed", "free", "permanent"]:890                continue891 892            try:893                expiry_date = datetime.strptime(expiry_str, "%d-%m-%Y").date()894            except ValueError:895                continue896 897            # Check kitne din hue expire hue898            days_passed = (today - expiry_date).days899 900            # ๐ŸŸข CASE 1: Expire hone wala hai ya aaj expire hua (Reminders for 4 days)901            if 0 <= days_passed <= 3:902                warning_number = days_passed + 1  # 1st, 2nd, 3rd, 4th Warning903                days_left_to_kick = 5 - warning_number904                905                msg = (906                    f"โš ๏ธ <b>VIP Plan Expired! (Warning {warning_number}/5)</b>\n\n"907                    f"Hello {name}, aapka VIP plan <b>{expiry_str}</b> ko expire ho gaya hai.\n"908                    f"System aapko <b>{days_left_to_kick} din</b> baad auto-kick kar dega.\n\n"909                    f"๐Ÿ™ Kripya aaj hi payment karke renew kar lein taki aapki practice na ruke!\n"910                    f"๐Ÿ’ฐ UPI ID: <code>engineersatya@sbi</code>\n"911                    f"๐Ÿ“ฉ Screenshot Satya Sir ko bhej dein."912                )913                try:914                    await context.bot.send_message(chat_id=user_id, text=msg, parse_mode='HTML')915                except: pass916 917            # ๐Ÿ”ด CASE 2: Panchwa Din (Final Kick)918            elif days_passed >= 4:919                # Student ko final bye-bye message920                final_msg = (921                    f"๐Ÿšซ <b>Final Alert! Access Terminated</b>\n\n"922                    f"Alvida {name}! Aapne 5 din ke warning period mein plan renew nahi kiya.\n"923                    f"Aapko VIP groups se nikal diya gaya hai. Re-join karne ke liye Satya Sir se sampark karein."924                )925                try:926                    await context.bot.send_message(chat_id=user_id, text=final_msg, parse_mode='HTML')927                except: pass928 929                # Saare groups se kick karna930                private_groups = [PAID_GROUP, PAID_UP_GROUP, PAID_3RD_GROUP]931                for group_id in private_groups:932                    try:933                        await context.bot.ban_chat_member(chat_id=group_id, user_id=user_id)934                        await context.bot.unban_chat_member(chat_id=group_id, user_id=user_id)935                    except: pass936 937                # Sheet update karna938                vip_sheet.update_cell(i + 1, 6, "Removed")939                940                # Admin ko report dena941                try:942                    await context.bot.send_message(943                        chat_id=PAID_GROUP,944                        text=f"๐Ÿฅพ <b>Auto-Kick Done:</b> `{name}` ko plan expire hone ke 5 din baad nikal diya gaya hai.",945                        parse_mode='HTML'946                    )947                except: pass948                949    except Exception as e:950        print(f"VIP Check Error: {e}")951 952# ==========================================953# ๐Ÿš€ NEW FEATURE: WEEKLY NUMERICAL ENGINE954# ==========================================955async def auto_send_numericals(context: ContextTypes.DEFAULT_TYPE=None, update: Update=None):956    if update:957        chat_id = update.effective_chat.id958        if not await is_admin(update, chat_id):959            await update.message.reply_text("๐Ÿšซ Sirf admin numerical bhej sakta hai!")960            return961        bot_context = context962    else:963        chat_id = PAID_GROUP964        bot_context = context965 966    try:967        sheet = client.open_by_key(GROUP_CONFIG[chat_id])968        quiz_sheet = sheet.worksheet("Numerical_Satya")969        data = quiz_sheet.get_all_values()[1:]970        971        numerical_pool = []972        for idx, row in enumerate(data, start=2):973            num_sent = str(row[11]).strip() if len(row) > 11 else "" 974            if num_sent != "Sent" and row[0].strip() != "":975                numerical_pool.append({'row_num': idx, 'data': row})976 977        if not numerical_pool:978            msg = "โš ๏ธ <b>Admin Alert:</b> 'Numerical_Satya' tab mein naye sawal khatam ho gaye hain! Kripya sheet update karein."979            if update: await update.message.reply_text(msg, parse_mode='HTML')980            else: await bot_context.bot.send_message(chat_id=chat_id, text=msg, parse_mode='HTML')981            return982 983        random.shuffle(numerical_pool)984        final_list = numerical_pool[:20]985        total_nums = len(final_list)986 987        IST = pytz.timezone('Asia/Kolkata')988        today_str = datetime.now(IST).strftime("%A, %d %B %Y")989        today_date_only = datetime.now(IST).strftime("%d-%m-%Y")990 991        announcement = (992            f"๐ŸŒž GOOD MORNING ENGINEERS! ๐ŸŒž\n\n"993            f"๐Ÿ“… Date: {today_str}\n"994            f"๐Ÿ† TOP {total_nums} NUMERICALS OF THE DAY ๐Ÿ†\n\n"995            f"Aaj ke premium numericals bhej diye gaye hain. Pen-Copy uthaiye aur shuru ho jaiye! โœ๏ธ\n"996            f"โณ Attempt Window: Raat 10:00 PM tak\n"997            f"๐Ÿ† Final Rankings raat 10 baje publish ki jayengi! All the best! ๐ŸŽฏ๐Ÿš€"998        )999        1000        if update: await update.message.reply_text(announcement)1001        else: await bot_context.bot.send_message(chat_id=chat_id, text=announcement)1002        1003        await asyncio.sleep(5)1004 1005        for i, item in enumerate(final_list):1006            row_num = item['row_num']1007            row = item['data']1008            try:1009                raw_q = f"Q. {i+1}/{total_nums} {row[0]}"1010                max_q_len = 300 - len(BRANDING) - 51011                1012                if len(raw_q) > max_q_len:1013                    full_msg = f"๐Ÿ“ <b>Q. {i+1}/{total_nums} (Full Question):</b>\n{row[0]}"1014                    if update: await bot_context.bot.send_message(chat_id=chat_id, text=full_msg, parse_mode='HTML')1015                    else: await bot_context.bot.send_message(chat_id=chat_id, text=full_msg, parse_mode='HTML')1016                    await asyncio.sleep(1)1017                    raw_q = f"Q. {i+1}/{total_nums} Please read the full question sent above and answer below. ๐Ÿ‘‡"1018 1019                q_text = raw_q + BRANDING1020                1021                # --- ๐Ÿ›ก๏ธ SMART DYNAMIC OPTIONS HANDLER ---1022                raw_opts = [str(row[1]).strip(), str(row[2]).strip(), str(row[3]).strip(), str(row[4]).strip()]1023                safe_options = [opt[:97] + "..." if len(opt) > 100 else opt for opt in raw_opts if opt != ""]1024                if len(safe_options) < 2:1025                    safe_options.extend(["Option 1 (Empty)", "Option 2 (Empty)"][:2 - len(safe_options)])1026                try:1027                    c_id = int(row[5])1028                    if c_id >= len(safe_options) or c_id < 0: c_id = 01029                except:1030                    c_id = 01031                # -----------------------------------------1032                1033                exp_text = str(row[6]) if len(row) > 6 and row[6] else "๐Ÿ“’Eอ†nอ†gอ†iอ†nอ†eอ†eอ†rอ†sอ†aอ†tอ†yอ†aอ†๐Ÿ“’"1034                if len(exp_text) > 200: exp_text = exp_text[:197] + "..."1035                1036                image_url = str(row[8]).strip() if len(row) > 8 else ""1037                if image_url.startswith("http"):1038                    try:1039                        if update: await bot_context.bot.send_photo(chat_id=chat_id, photo=image_url)1040                        else: await bot_context.bot.send_photo(chat_id=chat_id, photo=image_url)1041                        await asyncio.sleep(1)1042                    except Exception as e: pass1043 1044                message = await bot_context.bot.send_poll(1045                    chat_id=chat_id, question=q_text, options=safe_options, type=Poll.QUIZ,1046                    correct_option_id=c_id, explanation=exp_text, is_anonymous=False,1047                )1048                1049                POLL_DATA[message.poll.id] = {'chat_id': chat_id, 'correct_id': c_id, 'is_num': True, 'poll_date': datetime.now(IST).date()}1050 1051                quiz_sheet.update_cell(row_num, 12, "Sent")      1052                quiz_sheet.update_cell(row_num, 13, today_date_only) 1053                1054                await asyncio.sleep(random.randint(5, 7))1055                1056            except Exception as e:1057                print(f"Numerical Send Error on Q{i+1}: {e}")1058                continue1059 1060        closing_msg = "โœ… <b>BOOM! Aaj ke saare Numericals upload ho gaye hain!</b> ๐Ÿš€\n\nPhod do Engineers! Raat 10 baje Topper list mein naam chahiye! ๐Ÿ†"1061        if update: await update.message.reply_text(closing_msg, parse_mode='HTML')1062        else: await bot_context.bot.send_message(chat_id=chat_id, text=closing_msg, parse_mode='HTML')1063 1064    except Exception as e:1065        print(f"Auto-Numerical Major Error: {e}")1066 1067# ๐ŸŒŸ NAYA FEATURE: DAILY TOP 10 NUMERICAL CHAMPIONS1068async def daily_num_result_trigger(context: ContextTypes.DEFAULT_TYPE):1069    chat_id = PAID_GROUP1070    try:1071        sheet = client.open_by_key(GROUP_CONFIG[chat_id])1072        res_sheet = sheet.worksheet("Numresult")1073        state = get_state(chat_id)1074        if state['pending_num_results']:1075            res_sheet.append_rows(state['pending_num_results'])1076            state['pending_num_results'].clear()1077 1078        data = res_sheet.get_all_values()[1:]1079        if not data: return1080 1081        stats = {}1082        for row in data:1083            if len(row) > 3:1084                name, status = row[2], row[3].strip()1085                if name not in stats: stats[name] = {"correct": 0, "wrong": 0}1086                if status == "Correct": stats[name]["correct"] += 11087                else: stats[name]["wrong"] += 11088 1089        leaderboard_data = sorted([{"name": n, "net": (s["correct"] * 1) - (s["wrong"] * NEG_MARK), "total": s["correct"] + s["wrong"], "c": s["correct"], "w": s["wrong"]} for n, s in stats.items()], key=lambda x: x['net'], reverse=True)1090        top_10 = leaderboard_data[:10]1091 1092        msg = f"๐Ÿ† <b>TODAY'S TOP 10 NUMERICAL CHAMPIONS</b> ๐Ÿ†\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n"1093        for idx, p in enumerate(top_10):1094            rank_emoji = "๐Ÿฅ‡" if idx == 0 else "๐Ÿฅˆ" if idx == 1 else "๐Ÿฅ‰" if idx == 2 else "๐ŸŽ—"1095            safe_name = str(p['name']).replace('<', 'ใ€').replace('>', 'ใ€‘').replace('&', 'and')1096            msg += f"{rank_emoji} <b>{safe_name}</b>\nโ”œ Attempt: {p['total']}\nโ”œ Correct: {p['c']}\nโ”œ Wrong: {p['w']}\nโ”” <b>SCORE: {p['net']:.2f} Marks</b>\n\n"1097 1098        msg += "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ”ฅ <b>Asli aur Final Result Sunday raat 10 baje aayega! Phodte raho!</b> ๐Ÿ˜Ž"1099        await context.bot.send_message(chat_id=chat_id, text=msg, parse_mode='HTML')1100    except Exception as e:1101        print(f"Daily Num Result Error: {e}")1102 1103# ๐ŸŒŸ SUNDAY FINAL RANKING ENGINE1104async def auto_post_weekly_numerical_result(context: ContextTypes.DEFAULT_TYPE=None, update: Update=None):1105    is_manual = False1106    if update:1107        chat_id = update.effective_chat.id1108        if not await is_admin(update, chat_id):1109            await update.message.reply_text("๐Ÿšซ Bhai bhai bhai ruko Sirf admin result nikal sakta hai!")1110            return1111        bot_context = context1112        is_manual = True1113    else:1114        chat_id = PAID_GROUP1115        bot_context = context1116 1117    try:1118        sheet = client.open_by_key(GROUP_CONFIG[chat_id])1119        res_sheet = sheet.worksheet("Numresult")1120 1121        state = get_state(chat_id)1122        if state['pending_num_results']:1123            res_sheet.append_rows(state['pending_num_results'])1124            state['pending_num_results'].clear()1125 1126        data = res_sheet.get_all_values()[1:]1127        if not data:1128            msg = "๐Ÿง <b>Abhi tak is hafte koi Numerical attempt nahi hua!</b>"1129            if update: await update.message.reply_text(msg, parse_mode='HTML')1130            else: await bot_context.bot.send_message(chat_id=chat_id, text=msg, parse_mode='HTML')1131            return1132 1133        stats = {}1134        for row in data:1135            if len(row) > 3:1136                name, status = row[2], row[3].strip()1137                if name not in stats: stats[name] = {"correct": 0, "wrong": 0}1138                if status == "Correct": stats[name]["correct"] += 11139                else: stats[name]["wrong"] += 11140 1141        leaderboard_data = sorted([{"name": n, "net": (s["correct"] * 1) - (s["wrong"] * NEG_MARK), "total": s["correct"] + s["wrong"], "c": s["correct"], "w": s["wrong"]} for n, s in stats.items()], key=lambda x: x['net'], reverse=True)1142        total_students = len(leaderboard_data)1143        chunk_size = 201144 1145        for chunk_start in range(0, total_students, chunk_size):1146            chunk_end = min(chunk_start + chunk_size, total_students)1147            chunk_data = leaderboard_data[chunk_start:chunk_end]1148 1149            if chunk_start == 0:1150                if is_manual:1151                    msg = f"๐Ÿ† <b>CURRENT NUMERICAL RANKING (MID-WEEK)</b> ๐Ÿ†\n๐Ÿ‘ฅ <b>Total Participants: {total_students}</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"1152                else:1153                    msg = f"๐Ÿ† <b>FINAL WEEKLY NUMERICAL RANKING</b> ๐Ÿ†\n๐Ÿ‘ฅ <b>Total Participants: {total_students}</b>\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"1154            else:1155                msg = f"๐Ÿ“Š <b>RANKING CONTINUED ({chunk_start + 1} to {chunk_end})</b> ๐Ÿ“Š\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n"1156 1157            for idx, p in enumerate(chunk_data):1158                real_rank = chunk_start + idx + 11159                rank_emoji = "๐Ÿฅ‡" if real_rank == 1 else "๐Ÿฅˆ" if real_rank == 2 else "๐Ÿฅ‰" if real_rank == 3 else "๐ŸŽ—"1160                safe_name = str(p['name']).replace('<', 'ใ€').replace('>', 'ใ€‘').replace('&', 'and')1161                msg += f"{rank_emoji} <b>{safe_name}</b> (Rank {real_rank}/{total_students})\nโ”œ Total Attempt: {p['total']}\nโ”œ Correct: {p['c']} (x1)\nโ”œ Wrong: {p['w']} | Neg: -{p['w']*NEG_MARK:.2f}\nโ”” <b>NET SCORE: {p['net']:.2f} Marks</b>\n\n"1162 1163            if chunk_end == total_students:1164                if is_manual: msg += "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ”ฅ <b>Padhai shuru karo! Asli result Sunday ko aayega!</b> ๐Ÿ˜Ž"1165                else: msg += "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n๐Ÿ”ฅ <b>Hafte ki mehnat yahan dikhti hai! Agle hafte fir se milte hain!</b> ๐Ÿ˜Ž"1166 1167            try:1168                if update and chunk_start == 0: await update.message.reply_text(msg, parse_mode='HTML')1169                else: await bot_context.bot.send_message(chat_id=chat_id, text=msg, parse_mode='HTML')1170                await asyncio.sleep(1)1171            except Exception as msg_e: pass1172 1173        if not is_manual:1174            res_sheet.clear()1175            res_sheet.append_row(["Time", "Poll ID", "Name", "Status"])1176            print("Sunday Automatic Sheet Cleared.")1177 1178    except Exception as e:1179        print(f"Weekly Numerical Result Error: {e}")1180 1181# ๐ŸŒŸ NAYA FEATURE: DAILY PAID GROUP ADVERTISEMENT IN PUBLIC GROUP1182async def daily_paid_promo(context: ContextTypes.DEFAULT_TYPE):1183    chat_id = PUBLIC_GROUP1184    promo_msg = (1185        "๐Ÿš€ <b>BOOST YOUR PREPARATION WITH VIP SQUAD!</b> ๐Ÿš€\n\n"1186        "Are you serious about your AE/JE Exams? Join the <b>Engineersatya VIP Paid Group</b> and practice like a topper! ๐Ÿ†\n\n"1187        "๐Ÿ’Ž <b>WHAT YOU GET IN VIP BATCH:</b>\n"1188        "โž– <b>Strict Negative Marking</b> to build exam-like accuracy.\n"1189        "โฑ๏ธ <b>Variable Dynamic Timers</b> (More time for numericals, less for one-liners).\n"1190        "๐Ÿ“š <b>Subject-Wise Quizzes</b> to target your weak areas.\n"1191        "๐Ÿ”ฅ <b>Daily Top 20 Numericals</b> (Attempt anytime before 10:00 PM for the leaderboard).\n"1192        "๐Ÿ“ <b>Latest 2026 Pattern Questions</b> strictly aligned with recent exams.\n"1193        "๐Ÿค– <b>Lifetime Personal Access:</b> Any quiz conducted in the group goes straight to the Official Bot for you to practice privately anytime!\n"1194        "๐Ÿ“„ <b>On-Demand PDF Tests:</b> Send any previous year paper PDF to @engineersatyaquiz, and we will convert it into a live bot quiz for you!\n\n"1195        "๐Ÿ’ก <i>Don't just study, practice smartly!</i>\n"1196        "๐Ÿ“ฉ <b>DM @Engineersatyaquiz now to join the VIP Squad!</b>"1197    )1198    try:1199        await context.bot.send_message(chat_id=chat_id, text=promo_msg, parse_mode='HTML')1200    except Exception as e: pass

Showing the first 1,200 of 2298 lines. Download the file for the rest.