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 # check line 93 .. accordingly # === CONFIG === API_ID = os.environ.get("API_ID") # Replace with your API ID API_HASH = os.environ.get("API_HASH") # Replace with your 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!") # === SETUP === 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) # === MODULE LOADER === 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() # === HELPERS === 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: # Try to extract the last noun/phrase as the module name # Remove common verbs and stopwords 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_' # etc. ] # Remove punctuation desc = re.sub(r'[^a-zA-Z0-9_\s]', '', description.lower()) # Remove stopwords words = [w for w in desc.split() if w not in stopwords] if not words: return f"mod_{os.urandom(2).hex()}" # Join remaining words with underscores name = '_'.join(words) # Remove leading/trailing underscores and collapse multiple underscores name = re.sub(r'_+', '_', name).strip('_') # Fallback if name is empty if not name: return 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) # Ensure process exits if execl fails # === WORD TRIGGER === @bot.on_message(filters.private & filters.text) async def jarvis_trigger(client, message): 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.\n🧠 Determining intent...\nšŸ“˜ Intent: {intent}\nšŸ“ Task: `{description}`", parse_mode=ParseMode.MARKDOWN) # --- NEW: Handle EDIT intent for existing files --- if intent == "EDIT": # Try to extract filename and edit instruction 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"""\n{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) # Try to reload the module if it's in modules/ 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 # --- END NEW --- success = False code = "" 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: prompt += f"\n\nNote: Previous attempt failed with error: {str(e)}. 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 # --- NEW: Use file path from description if present --- 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 file exists, use edit flow instead of creating a new file 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"""\n{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()) # --- END NEW --- 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}") await progress_msg.edit(f"`Attempt {attempt}/5:` Thinking and generating code...\n- Executing prerequisite shell commands...\n- Testing generated code...\n- Tests passed. Writing files...\n- Files written. Initiating restart...") await asyncio.sleep(2) asyncio.create_task(restart_bot(message.chat.id)) success = True break except Exception as e: await progress_msg.edit(f"āŒ Attempt {attempt} Error: `{str(e)[:100]}...`") if not success: await progress_msg.edit("āŒ All 5 attempts failed. Please try again with a simpler instruction.") # === /modules === @bot.on_message(filters.command("modules") & filters.private) async def list_modules(client, message): 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) # === /delete === @bot.on_message(filters.command("delete") & filters.private) async def delete_module(client, message): 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`\nā™»ļø Restart required to take effect.", parse_mode=ParseMode.MARKDOWN) else: await message.reply(f"āŒ Module `{mod_name}.py` not found.", parse_mode=ParseMode.MARKDOWN) # === /what to do === @bot.on_message(filters.regex(r"(?i)what( can)? i do\??") & filters.private) async def what_to_do(_, message): 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`\n", parse_mode=ParseMode.MARKDOWN ) # === START === print("šŸš€ Starting Jarvis Bot...") load_modules() print("āœ… Bot is ready!") bot.run()