import os import re import asyncio import sys import importlib.util from pyrogram import Client, filters from pyrogram.enums import ParseMode import google.generativeai as genai API_ID = os.environ.get("API_ID") API_HASH = os.environ.get("API_HASH") BOT_TOKEN = os.environ.get("BOT_TOKEN") GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY") if not BOT_TOKEN: raise RuntimeError("BOT_TOKEN environment variable not set!") if not GEMINI_API_KEY: raise RuntimeError("GEMINI_API_KEY environment variable not set!") genai.configure(api_key=GEMINI_API_KEY) model = genai.GenerativeModel("gemini-2.5-flash") bot = Client("JarvisBot", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN) os.makedirs("modules", exist_ok=True) def load_modules(folder="modules"): for file in os.listdir(folder): if file.endswith(".py"): path = os.path.join(folder, file) name = file[:-3] spec = importlib.util.spec_from_file_location(name, path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) load_modules() def extract_module_name(code: str) -> str: match = re.search(r"def\\s+([a-zA-Z_][a-zA-Z0-9_]*)", code) return match.group(1).lower() if match else f"mod_{os.urandom(2).hex()}" def extract_commands(code: str) -> list: return re.findall(r'filters\.command\(["\'](\w+)["\']', code) def determine_intent(text: str) -> str: lowered = text.lower() if any(x in lowered for x in ["create", "make", "build"]): return "CREATE" elif any(x in lowered for x in ["edit", "modify"]): return "EDIT" elif "recode" in lowered: return "RECODE" else: return "UNSURE" def clean_code_blocks(code: str) -> str: if code.startswith("```python"): code = code[9:] if code.startswith("```"): code = code[3:] if code.endswith("```"): code = code[:-3] return code.strip() def extract_module_name_from_description(description: str) -> str: import re stopwords = { 'jarvis', 'make', 'create', 'build', 'generate', 'a', 'an', 'the', 'please', 'module', 'for', 'me', 'to', 'with', 'add', 'new', 'of', 'system', 'bot', 'command', 'that', 'and', 'in', 'on', 'by', 'as', 'is', 'it', 'my', 'this', 'do', 'can', 'you', 'i', 'want', 'need', 'from', 'like', 'using', 'feature', 'function', 'implement', 'write', 'code', 'file', 'python', 'telegram', 'pyrogram', 'handler', 'example', 'mod', 'mod_', 'particular', 'user' } desc = re.sub(r'[^a-zA-Z0-9_\s]', ' ', description.lower()) words = desc.split() filtered_words = [] for word in words: if word not in stopwords and len(word) > 2: filtered_words.append(word) if filtered_words: name_words = filtered_words[:3] name = '_'.join(name_words) else: meaningful_words = [w for w in words if len(w) > 3 and w not in stopwords] if meaningful_words: name = meaningful_words[0] else: clean_desc = re.sub(r'[^a-zA-Z0-9]', '', description.lower()) name = clean_desc[:10] if clean_desc else f"mod_{os.urandom(2).hex()}" name = re.sub(r'_+', '_', name).strip('_') name = name.lower() if not name: name = f"mod_{os.urandom(2).hex()}" return name async def restart_bot(chat_id): await bot.send_message(chat_id, "Restarting to apply new module...") await bot.stop() os.execl(sys.executable, sys.executable, *sys.argv) os._exit(0) @bot.on_message(filters.private & filters.text) async def jarvis_trigger(client, message): if message.from_user.id != 7361622601: return await message.reply("Access denied. Only the owner can use this bot.") text = message.text.strip() if not text.lower().startswith("jarvis"): return description = text[6:].strip() if not description: return await message.reply("Hello, what would you like me to do?") intent = determine_intent(description) progress_msg = await message.reply(f"Acknowledged.\nDetermining intent...\nIntent: {intent}\nTask: `{description}`", parse_mode=ParseMode.MARKDOWN) if intent == "EDIT": match = re.match(r"edit\s+([\w/\\.]+)\s+(.*)", description, re.IGNORECASE) if match: file_path = match.group(1) edit_instruction = match.group(2) if not os.path.exists(file_path): await progress_msg.edit(f"File `{file_path}` not found.") return with open(file_path, "r", encoding="utf-8") as f: current_content = f.read() edit_prompt = ( f"You are an expert Python developer. Here is the current content of `{file_path}`:\n" f"{current_content}\n" f"Please edit this file to: {edit_instruction}.\n" f"Output ONLY the new Python code, no explanations or markdown." ) try: response = model.generate_content(edit_prompt) new_code = clean_code_blocks(response.text.strip()) if not new_code or "def " not in new_code: await progress_msg.edit(f"Edit failed: No valid code returned.") return with open(file_path, "w", encoding="utf-8") as f: f.write(new_code) if file_path.startswith("modules/") and file_path.endswith(".py"): mod_name = os.path.basename(file_path)[:-3] try: spec = importlib.util.spec_from_file_location(mod_name, file_path) mod = importlib.util.module_from_spec(spec) mod.bot = bot spec.loader.exec_module(mod) except Exception as test_error: await progress_msg.edit(f"Edit applied, but module reload failed: {test_error}") return await progress_msg.edit(f"Edit applied to `{file_path}`. Restarting bot...") await asyncio.sleep(2) asyncio.create_task(restart_bot(message.chat.id)) return except Exception as e: await progress_msg.edit(f"Edit failed: `{str(e)[:100]}...`") return else: await progress_msg.edit("Could not parse edit command. Use: 'edit '") return success = False code = "" last_error = None for attempt in range(1, 6): await progress_msg.edit(f"Attempt {attempt}/5: Thinking and generating code...\n- Executing prerequisite shell commands...") try: prompt = ( f"Write a full Pyrogram Telegram bot module that implements:\n" f"{description}.\n\n" f"IMPORTANT RULES:\n" f"1. Use 'bot' variable (not 'Client') - it will be injected\n" f"2. Include commands using @bot.on_message(filters.command(...))\n" f"3. Import only what you need from pyrogram\n and use 'from ..t1 import bot'\n 'try: from ..t1 import bot except (ImportError, ValueError): \n from __main__ import bot' \n" f"4. Don't create a new Client instance\n" f"5. Make functions async when using bot methods\n\n" f"Output ONLY Python code, no explanations or markdown." ) if attempt > 1 and last_error is not None: prompt += f"\n\nNote: Previous attempt failed with error: {str(last_error)}. Fix that issue this time." response = model.generate_content(prompt) code = clean_code_blocks(response.text.strip()) if "def " not in code or "@bot" not in code: await progress_msg.edit(f"Attempt {attempt}: Invalid function or handler.") continue import re file_path_match = re.search(r"(modules/[\w\-]+\.py)", description) if file_path_match: mod_path = file_path_match.group(1) mod_name = os.path.basename(mod_path)[:-3] else: mod_name = extract_module_name_from_description(description) mod_path = f"modules/{mod_name}.py" if os.path.exists(mod_path): with open(mod_path, "r", encoding="utf-8") as f: current_content = f.read() edit_prompt = ( f"You are an expert Python developer. Here is the current content of `{mod_path}`:\n" f"{current_content}\n" f"Please update this file to: {description}.\n" f"Output ONLY the new Python code, no explanations or markdown." ) response = model.generate_content(edit_prompt) code = clean_code_blocks(response.text.strip()) with open(mod_path, "w", encoding="utf-8") as f: f.write(code) await progress_msg.edit(f"Attempt {attempt}/5: Thinking and generating code...\n- Executing prerequisite shell commands...\n- Testing generated code...") try: spec = importlib.util.spec_from_file_location(mod_name, mod_path) mod = importlib.util.module_from_spec(spec) mod.bot = bot spec.loader.exec_module(mod) except Exception as test_error: raise RuntimeError(f"Testing error: {test_error}") commands = extract_commands(code) commands_str = ', '.join(f'/{cmd}' for cmd in commands) if commands else 'No commands found.' try: explain_prompt = ( f"Explain in 2-3 sentences what this Pyrogram Telegram bot module does, given the following code and the user's request.\n" f"User request: {description}\n" f"Module code:\n{code}\n" f"Be concise and clear." ) explain_response = model.generate_content(explain_prompt) explanation = explain_response.text.strip() except Exception as exp_explain: explanation = f"Could not generate explanation: {exp_explain}" await progress_msg.edit( f"Module created successfully!\n\n" f"Commands: {commands_str}\n\n" f"What it does:\n{explanation}\n\n" f"Restarting bot to load the new module...", parse_mode=ParseMode.MARKDOWN ) await asyncio.sleep(2) asyncio.create_task(restart_bot(message.chat.id)) success = True break except Exception as e: last_error = e try: await progress_msg.edit(f"Attempt {attempt} Error: {str(e)[:100]}...") except: await message.reply(f"Attempt {attempt} failed. Check logs.") if not success: await progress_msg.edit("All 5 attempts failed. Please try again with a simpler instruction.") @bot.on_message(filters.command("modules") & filters.private) async def list_modules(client, message): if message.from_user.id != 7361622601: return await message.reply("Access denied. Only the owner can use this bot.") modules = [f for f in os.listdir("modules") if f.endswith(".py")] if modules: module_list = "\n".join([f"• {m[:-3]}" for m in modules]) await message.reply(f"Loaded Modules:\n{module_list}", parse_mode=ParseMode.MARKDOWN) else: await message.reply("No modules found.", parse_mode=ParseMode.MARKDOWN) @bot.on_message(filters.command("delete") & filters.private) async def delete_module(client, message): if message.from_user.id != 7361622601: return await message.reply("Access denied. Only the owner can use this bot.") if len(message.command) < 2: return await message.reply("Specify module name.\n\nExample: /delete calculator", parse_mode=ParseMode.MARKDOWN) mod_name = message.command[1].lower() mod_path = f"modules/{mod_name}.py" if os.path.exists(mod_path): os.remove(mod_path) await message.reply(f"Deleted {mod_name}.py\nRestart required to take effect.", parse_mode=ParseMode.MARKDOWN) else: await message.reply(f"Module {mod_name}.py not found.", parse_mode=ParseMode.MARKDOWN) @bot.on_message(filters.regex(r"(?i)what( can)? i do\??") & filters.private) async def what_to_do(_, message): if message.from_user.id != 7361622601: return await message.reply("Access denied. Only the owner can use this bot.") await message.reply( "Jarvis Assistant\n\n" "I can generate custom bot modules for you!\n\n" "Commands:\n" "jarvis make a calculator - Natural language trigger\n" "/modules - List all modules\n" "/delete - Delete a module\n\n" "Examples:\n" "jarvis build a reminder system\n" "jarvis create a dice game\n" "jarvis weather checker", parse_mode=ParseMode.MARKDOWN ) print("Starting Jarvis Bot...") load_modules() print("Bot is ready!") bot.run()