xdragxt commited on
Commit
e730fea
Β·
verified Β·
1 Parent(s): 7205096

Update jarvis.py

Browse files
Files changed (1) hide show
  1. jarvis.py +135 -57
jarvis.py CHANGED
@@ -6,9 +6,12 @@ import importlib.util
6
  from pyrogram import Client, filters
7
  from pyrogram.enums import ParseMode
8
  import google.generativeai as genai
 
9
 
10
- API_ID = os.environ.get("API_ID")
11
- API_HASH = os.environ.get("API_HASH")
 
 
12
  BOT_TOKEN = os.environ.get("BOT_TOKEN")
13
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
14
  if not BOT_TOKEN:
@@ -16,11 +19,13 @@ if not BOT_TOKEN:
16
  if not GEMINI_API_KEY:
17
  raise RuntimeError("GEMINI_API_KEY environment variable not set!")
18
 
 
19
  genai.configure(api_key=GEMINI_API_KEY)
20
  model = genai.GenerativeModel("gemini-2.5-flash")
21
  bot = Client("JarvisBot", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)
22
  os.makedirs("modules", exist_ok=True)
23
 
 
24
  def load_modules(folder="modules"):
25
  for file in os.listdir(folder):
26
  if file.endswith(".py"):
@@ -32,6 +37,7 @@ def load_modules(folder="modules"):
32
 
33
  load_modules()
34
 
 
35
  def extract_module_name(code: str) -> str:
36
  match = re.search(r"def\\s+([a-zA-Z_][a-zA-Z0-9_]*)", code)
37
  return match.group(1).lower() if match else f"mod_{os.urandom(2).hex()}"
@@ -60,46 +66,65 @@ def clean_code_blocks(code: str) -> str:
60
  return code.strip()
61
 
62
  def extract_module_name_from_description(description: str) -> str:
 
63
  import re
 
 
64
  stopwords = {
65
- 'jarvis', 'make', 'create', 'build', 'generate', 'a', 'an', 'the', 'please', 'module',
66
- 'for', 'me', 'to', 'with', 'add', 'new', 'of', 'system', 'bot', 'command', 'that', 'and',
67
- 'in', 'on', 'by', 'as', 'is', 'it', 'my', 'this', 'do', 'can', 'you', 'i', 'want', 'need',
68
- 'from', 'like', 'using', 'feature', 'function', 'implement', 'write', 'code', 'file',
69
  'python', 'telegram', 'pyrogram', 'handler', 'example', 'mod', 'mod_', 'particular', 'user'
70
  }
 
 
71
  desc = re.sub(r'[^a-zA-Z0-9_\s]', ' ', description.lower())
72
  words = desc.split()
 
 
73
  filtered_words = []
74
  for word in words:
75
  if word not in stopwords and len(word) > 2:
76
  filtered_words.append(word)
 
 
77
  if filtered_words:
 
78
  name_words = filtered_words[:3]
79
  name = '_'.join(name_words)
80
  else:
 
81
  meaningful_words = [w for w in words if len(w) > 3 and w not in stopwords]
82
  if meaningful_words:
83
  name = meaningful_words[0]
84
  else:
 
85
  clean_desc = re.sub(r'[^a-zA-Z0-9]', '', description.lower())
86
  name = clean_desc[:10] if clean_desc else f"mod_{os.urandom(2).hex()}"
 
 
87
  name = re.sub(r'_+', '_', name).strip('_')
88
  name = name.lower()
 
 
89
  if not name:
90
  name = f"mod_{os.urandom(2).hex()}"
 
91
  return name
92
 
93
  async def restart_bot(chat_id):
94
- await bot.send_message(chat_id, "Restarting to apply new module...")
95
  await bot.stop()
96
  os.execl(sys.executable, sys.executable, *sys.argv)
97
- os._exit(0)
98
 
 
99
  @bot.on_message(filters.private & filters.text)
100
  async def jarvis_trigger(client, message):
 
101
  if message.from_user.id != 7361622601:
102
- return await message.reply("Access denied. Only the owner can use this bot.")
103
 
104
  text = message.text.strip()
105
  if not text.lower().startswith("jarvis"):
@@ -107,24 +132,26 @@ async def jarvis_trigger(client, message):
107
 
108
  description = text[6:].strip()
109
  if not description:
110
- return await message.reply("Hello, what would you like me to do?")
111
 
112
  intent = determine_intent(description)
113
- progress_msg = await message.reply(f"Acknowledged.\nDetermining intent...\nIntent: {intent}\nTask: `{description}`", parse_mode=ParseMode.MARKDOWN)
114
 
 
115
  if intent == "EDIT":
 
116
  match = re.match(r"edit\s+([\w/\\.]+)\s+(.*)", description, re.IGNORECASE)
117
  if match:
118
  file_path = match.group(1)
119
  edit_instruction = match.group(2)
120
  if not os.path.exists(file_path):
121
- await progress_msg.edit(f"File `{file_path}` not found.")
122
  return
123
  with open(file_path, "r", encoding="utf-8") as f:
124
  current_content = f.read()
125
  edit_prompt = (
126
  f"You are an expert Python developer. Here is the current content of `{file_path}`:\n"
127
- f"{current_content}\n"
128
  f"Please edit this file to: {edit_instruction}.\n"
129
  f"Output ONLY the new Python code, no explanations or markdown."
130
  )
@@ -132,10 +159,11 @@ async def jarvis_trigger(client, message):
132
  response = model.generate_content(edit_prompt)
133
  new_code = clean_code_blocks(response.text.strip())
134
  if not new_code or "def " not in new_code:
135
- await progress_msg.edit(f"Edit failed: No valid code returned.")
136
  return
137
  with open(file_path, "w", encoding="utf-8") as f:
138
  f.write(new_code)
 
139
  if file_path.startswith("modules/") and file_path.endswith(".py"):
140
  mod_name = os.path.basename(file_path)[:-3]
141
  try:
@@ -144,24 +172,25 @@ async def jarvis_trigger(client, message):
144
  mod.bot = bot
145
  spec.loader.exec_module(mod)
146
  except Exception as test_error:
147
- await progress_msg.edit(f"Edit applied, but module reload failed: {test_error}")
148
  return
149
- await progress_msg.edit(f"Edit applied to `{file_path}`. Restarting bot...")
150
  await asyncio.sleep(2)
151
  asyncio.create_task(restart_bot(message.chat.id))
152
  return
153
  except Exception as e:
154
- await progress_msg.edit(f"Edit failed: `{str(e)[:100]}...`")
155
  return
156
  else:
157
- await progress_msg.edit("Could not parse edit command. Use: 'edit <file> <instruction>'")
158
  return
 
159
 
160
  success = False
161
  code = ""
162
  last_error = None
163
  for attempt in range(1, 6):
164
- await progress_msg.edit(f"Attempt {attempt}/5: Thinking and generating code...\n- Executing prerequisite shell commands...")
165
 
166
  try:
167
  prompt = (
@@ -181,10 +210,28 @@ async def jarvis_trigger(client, message):
181
  response = model.generate_content(prompt)
182
  code = clean_code_blocks(response.text.strip())
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  if "def " not in code or "@bot" not in code:
185
- await progress_msg.edit(f"Attempt {attempt}: Invalid function or handler.")
186
  continue
187
 
 
188
  import re
189
  file_path_match = re.search(r"(modules/[\w\-]+\.py)", description)
190
  if file_path_match:
@@ -193,23 +240,24 @@ async def jarvis_trigger(client, message):
193
  else:
194
  mod_name = extract_module_name_from_description(description)
195
  mod_path = f"modules/{mod_name}.py"
196
-
197
  if os.path.exists(mod_path):
198
  with open(mod_path, "r", encoding="utf-8") as f:
199
  current_content = f.read()
200
  edit_prompt = (
201
  f"You are an expert Python developer. Here is the current content of `{mod_path}`:\n"
202
- f"{current_content}\n"
203
  f"Please update this file to: {description}.\n"
204
  f"Output ONLY the new Python code, no explanations or markdown."
205
  )
206
  response = model.generate_content(edit_prompt)
207
  code = clean_code_blocks(response.text.strip())
 
208
 
209
  with open(mod_path, "w", encoding="utf-8") as f:
210
  f.write(code)
211
 
212
- await progress_msg.edit(f"Attempt {attempt}/5: Thinking and generating code...\n- Executing prerequisite shell commands...\n- Testing generated code...")
213
 
214
  try:
215
  spec = importlib.util.spec_from_file_location(mod_name, mod_path)
@@ -219,9 +267,15 @@ async def jarvis_trigger(client, message):
219
  except Exception as test_error:
220
  raise RuntimeError(f"Testing error: {test_error}")
221
 
222
- commands = extract_commands(code)
223
- commands_str = ', '.join(f'/{cmd}' for cmd in commands) if commands else 'No commands found.'
224
 
 
 
 
 
 
 
 
225
  try:
226
  explain_prompt = (
227
  f"Explain in 2-3 sentences what this Pyrogram Telegram bot module does, given the following code and the user's request.\n"
@@ -233,15 +287,19 @@ async def jarvis_trigger(client, message):
233
  explanation = explain_response.text.strip()
234
  except Exception as exp_explain:
235
  explanation = f"Could not generate explanation: {exp_explain}"
236
-
237
- await progress_msg.edit(
238
- f"Module created successfully!\n\n"
239
- f"Commands: {commands_str}\n\n"
240
- f"What it does:\n{explanation}\n\n"
241
- f"Restarting bot to load the new module...",
242
- parse_mode=ParseMode.MARKDOWN
243
- )
244
-
 
 
 
 
245
  await asyncio.sleep(2)
246
  asyncio.create_task(restart_bot(message.chat.id))
247
  success = True
@@ -249,58 +307,78 @@ async def jarvis_trigger(client, message):
249
 
250
  except Exception as e:
251
  last_error = e
 
 
 
252
  try:
253
- await progress_msg.edit(f"Attempt {attempt} Error: {str(e)[:100]}...")
254
- except:
255
- await message.reply(f"Attempt {attempt} failed. Check logs.")
 
 
 
 
 
256
 
257
  if not success:
258
- await progress_msg.edit("All 5 attempts failed. Please try again with a simpler instruction.")
259
 
 
260
  @bot.on_message(filters.command("modules") & filters.private)
261
  async def list_modules(client, message):
 
262
  if message.from_user.id != 7361622601:
263
- return await message.reply("Access denied. Only the owner can use this bot.")
 
264
  modules = [f for f in os.listdir("modules") if f.endswith(".py")]
265
  if modules:
266
  module_list = "\n".join([f"β€’ {m[:-3]}" for m in modules])
267
- await message.reply(f"Loaded Modules:\n{module_list}", parse_mode=ParseMode.MARKDOWN)
268
  else:
269
- await message.reply("No modules found.", parse_mode=ParseMode.MARKDOWN)
270
 
 
271
  @bot.on_message(filters.command("delete") & filters.private)
272
  async def delete_module(client, message):
 
273
  if message.from_user.id != 7361622601:
274
- return await message.reply("Access denied. Only the owner can use this bot.")
 
275
  if len(message.command) < 2:
276
- return await message.reply("Specify module name.\n\nExample: /delete calculator", parse_mode=ParseMode.MARKDOWN)
 
277
  mod_name = message.command[1].lower()
278
  mod_path = f"modules/{mod_name}.py"
 
279
  if os.path.exists(mod_path):
280
  os.remove(mod_path)
281
- await message.reply(f"Deleted {mod_name}.py\nRestart required to take effect.", parse_mode=ParseMode.MARKDOWN)
282
  else:
283
- await message.reply(f"Module {mod_name}.py not found.", parse_mode=ParseMode.MARKDOWN)
284
 
 
285
  @bot.on_message(filters.regex(r"(?i)what( can)? i do\??") & filters.private)
286
  async def what_to_do(_, message):
 
287
  if message.from_user.id != 7361622601:
288
- return await message.reply("Access denied. Only the owner can use this bot.")
 
289
  await message.reply(
290
- "Jarvis Assistant\n\n"
291
  "I can generate custom bot modules for you!\n\n"
292
- "Commands:\n"
293
- "jarvis make a calculator - Natural language trigger\n"
294
- "/modules - List all modules\n"
295
- "/delete <name> - Delete a module\n\n"
296
- "Examples:\n"
297
- "jarvis build a reminder system\n"
298
- "jarvis create a dice game\n"
299
- "jarvis weather checker",
300
  parse_mode=ParseMode.MARKDOWN
301
  )
302
 
303
- print("Starting Jarvis Bot...")
 
304
  load_modules()
305
- print("Bot is ready!")
306
  bot.run()
 
6
  from pyrogram import Client, filters
7
  from pyrogram.enums import ParseMode
8
  import google.generativeai as genai
9
+ import subprocess
10
 
11
+ # check line 93 .. accordingly
12
+ # === CONFIG ===
13
+ API_ID = os.environ.get("API_ID") # Replace with your API ID
14
+ API_HASH = os.environ.get("API_HASH") # Replace with your API HASH
15
  BOT_TOKEN = os.environ.get("BOT_TOKEN")
16
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
17
  if not BOT_TOKEN:
 
19
  if not GEMINI_API_KEY:
20
  raise RuntimeError("GEMINI_API_KEY environment variable not set!")
21
 
22
+ # === SETUP ===
23
  genai.configure(api_key=GEMINI_API_KEY)
24
  model = genai.GenerativeModel("gemini-2.5-flash")
25
  bot = Client("JarvisBot", api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN)
26
  os.makedirs("modules", exist_ok=True)
27
 
28
+ # === MODULE LOADER ===
29
  def load_modules(folder="modules"):
30
  for file in os.listdir(folder):
31
  if file.endswith(".py"):
 
37
 
38
  load_modules()
39
 
40
+ # === HELPERS ===
41
  def extract_module_name(code: str) -> str:
42
  match = re.search(r"def\\s+([a-zA-Z_][a-zA-Z0-9_]*)", code)
43
  return match.group(1).lower() if match else f"mod_{os.urandom(2).hex()}"
 
66
  return code.strip()
67
 
68
  def extract_module_name_from_description(description: str) -> str:
69
+ # Improved module name extraction - focus on key nouns and actions
70
  import re
71
+
72
+ # Common words to remove
73
  stopwords = {
74
+ 'jarvis', 'make', 'create', 'build', 'generate', 'a', 'an', 'the', 'please', 'module',
75
+ 'for', 'me', 'to', 'with', 'add', 'new', 'of', 'system', 'bot', 'command', 'that', 'and',
76
+ 'in', 'on', 'by', 'as', 'is', 'it', 'my', 'this', 'do', 'can', 'you', 'i', 'want', 'need',
77
+ 'from', 'like', 'using', 'feature', 'function', 'implement', 'write', 'code', 'file',
78
  'python', 'telegram', 'pyrogram', 'handler', 'example', 'mod', 'mod_', 'particular', 'user'
79
  }
80
+
81
+ # Clean the description
82
  desc = re.sub(r'[^a-zA-Z0-9_\s]', ' ', description.lower())
83
  words = desc.split()
84
+
85
+ # Filter out stopwords and short words
86
  filtered_words = []
87
  for word in words:
88
  if word not in stopwords and len(word) > 2:
89
  filtered_words.append(word)
90
+
91
+ # If we have good words, use them
92
  if filtered_words:
93
+ # Take up to 3 most relevant words
94
  name_words = filtered_words[:3]
95
  name = '_'.join(name_words)
96
  else:
97
+ # Fallback: extract any meaningful word
98
  meaningful_words = [w for w in words if len(w) > 3 and w not in stopwords]
99
  if meaningful_words:
100
  name = meaningful_words[0]
101
  else:
102
+ # Last resort: use first few characters
103
  clean_desc = re.sub(r'[^a-zA-Z0-9]', '', description.lower())
104
  name = clean_desc[:10] if clean_desc else f"mod_{os.urandom(2).hex()}"
105
+
106
+ # Clean up the name
107
  name = re.sub(r'_+', '_', name).strip('_')
108
  name = name.lower()
109
+
110
+ # Ensure it's not empty
111
  if not name:
112
  name = f"mod_{os.urandom(2).hex()}"
113
+
114
  return name
115
 
116
  async def restart_bot(chat_id):
117
+ await bot.send_message(chat_id, "♻️ Restarting to apply new module...")
118
  await bot.stop()
119
  os.execl(sys.executable, sys.executable, *sys.argv)
120
+ os._exit(0) # Ensure process exits if execl fails
121
 
122
+ # === WORD TRIGGER ===
123
  @bot.on_message(filters.private & filters.text)
124
  async def jarvis_trigger(client, message):
125
+ # Owner-only access control
126
  if message.from_user.id != 7361622601:
127
+ return await message.reply("❌ Access denied. Only the owner can use this bot.")
128
 
129
  text = message.text.strip()
130
  if not text.lower().startswith("jarvis"):
 
132
 
133
  description = text[6:].strip()
134
  if not description:
135
+ return await message.reply("πŸ€– Hello, what would you like me to do?")
136
 
137
  intent = determine_intent(description)
138
+ progress_msg = await message.reply(f"πŸ€– Acknowledged.\n🧠 Determining intent...\nπŸ“˜ Intent: {intent}\nπŸ“ Task: `{description}`", parse_mode=ParseMode.MARKDOWN)
139
 
140
+ # --- NEW: Handle EDIT intent for existing files ---
141
  if intent == "EDIT":
142
+ # Try to extract filename and edit instruction
143
  match = re.match(r"edit\s+([\w/\\.]+)\s+(.*)", description, re.IGNORECASE)
144
  if match:
145
  file_path = match.group(1)
146
  edit_instruction = match.group(2)
147
  if not os.path.exists(file_path):
148
+ await progress_msg.edit(f"❌ File `{file_path}` not found.")
149
  return
150
  with open(file_path, "r", encoding="utf-8") as f:
151
  current_content = f.read()
152
  edit_prompt = (
153
  f"You are an expert Python developer. Here is the current content of `{file_path}`:\n"
154
+ f"""\n{current_content}\n"""
155
  f"Please edit this file to: {edit_instruction}.\n"
156
  f"Output ONLY the new Python code, no explanations or markdown."
157
  )
 
159
  response = model.generate_content(edit_prompt)
160
  new_code = clean_code_blocks(response.text.strip())
161
  if not new_code or "def " not in new_code:
162
+ await progress_msg.edit(f"❌ Edit failed: No valid code returned.")
163
  return
164
  with open(file_path, "w", encoding="utf-8") as f:
165
  f.write(new_code)
166
+ # Try to reload the module if it's in modules/
167
  if file_path.startswith("modules/") and file_path.endswith(".py"):
168
  mod_name = os.path.basename(file_path)[:-3]
169
  try:
 
172
  mod.bot = bot
173
  spec.loader.exec_module(mod)
174
  except Exception as test_error:
175
+ await progress_msg.edit(f"⚠️ Edit applied, but module reload failed: {test_error}")
176
  return
177
+ await progress_msg.edit(f"βœ… Edit applied to `{file_path}`. Restarting bot...")
178
  await asyncio.sleep(2)
179
  asyncio.create_task(restart_bot(message.chat.id))
180
  return
181
  except Exception as e:
182
+ await progress_msg.edit(f"❌ Edit failed: `{str(e)[:100]}...`")
183
  return
184
  else:
185
+ await progress_msg.edit("❗ Could not parse edit command. Use: 'edit <file> <instruction>'")
186
  return
187
+ # --- END NEW ---
188
 
189
  success = False
190
  code = ""
191
  last_error = None
192
  for attempt in range(1, 6):
193
+ await progress_msg.edit(f"`Attempt {attempt}/5:` Thinking and generating code...\n- Executing prerequisite shell commands...")
194
 
195
  try:
196
  prompt = (
 
210
  response = model.generate_content(prompt)
211
  code = clean_code_blocks(response.text.strip())
212
 
213
+ # === AUTO-FIX COMMON LLM MISTAKES ===
214
+ code = code.replace('asyncio.PIPE', 'subprocess.PIPE')
215
+ # Add more auto-fixes as needed
216
+
217
+ # === LINTER/STATIC CHECKER ===
218
+ with open('tmp_lint_module.py', 'w', encoding='utf-8') as tmpf:
219
+ tmpf.write(code)
220
+ lint_proc = subprocess.run(['pyflakes', 'tmp_lint_module.py'], capture_output=True, text=True)
221
+ if lint_proc.returncode != 0 or lint_proc.stdout.strip() or lint_proc.stderr.strip():
222
+ lint_output = (lint_proc.stdout + '\n' + lint_proc.stderr).strip()
223
+ await progress_msg.edit(f"❌ Linter/static check failed!\n\n```
224
+ {lint_output}
225
+ ```")
226
+ os.remove('tmp_lint_module.py')
227
+ continue
228
+ os.remove('tmp_lint_module.py')
229
+
230
  if "def " not in code or "@bot" not in code:
231
+ await progress_msg.edit(f"❌ Attempt {attempt}: Invalid function or handler.")
232
  continue
233
 
234
+ # --- NEW: Use file path from description if present ---
235
  import re
236
  file_path_match = re.search(r"(modules/[\w\-]+\.py)", description)
237
  if file_path_match:
 
240
  else:
241
  mod_name = extract_module_name_from_description(description)
242
  mod_path = f"modules/{mod_name}.py"
243
+ # If file exists, use edit flow instead of creating a new file
244
  if os.path.exists(mod_path):
245
  with open(mod_path, "r", encoding="utf-8") as f:
246
  current_content = f.read()
247
  edit_prompt = (
248
  f"You are an expert Python developer. Here is the current content of `{mod_path}`:\n"
249
+ f"""\n{current_content}\n"""
250
  f"Please update this file to: {description}.\n"
251
  f"Output ONLY the new Python code, no explanations or markdown."
252
  )
253
  response = model.generate_content(edit_prompt)
254
  code = clean_code_blocks(response.text.strip())
255
+ # --- END NEW ---
256
 
257
  with open(mod_path, "w", encoding="utf-8") as f:
258
  f.write(code)
259
 
260
+ await progress_msg.edit(f"`Attempt {attempt}/5: Thinking and generating code...\n- Executing prerequisite shell commands...\n- Testing generated code...")
261
 
262
  try:
263
  spec = importlib.util.spec_from_file_location(mod_name, mod_path)
 
267
  except Exception as test_error:
268
  raise RuntimeError(f"Testing error: {test_error}")
269
 
270
+ 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...")
 
271
 
272
+ # === NEW: Show module details before restart ===
273
+ try:
274
+ commands = extract_commands(code)
275
+ commands_str = ', '.join(f'/{cmd}' for cmd in commands) if commands else 'No commands found.'
276
+ except Exception as cmd_error:
277
+ commands_str = f'Error extracting commands: {cmd_error}'
278
+
279
  try:
280
  explain_prompt = (
281
  f"Explain in 2-3 sentences what this Pyrogram Telegram bot module does, given the following code and the user's request.\n"
 
287
  explanation = explain_response.text.strip()
288
  except Exception as exp_explain:
289
  explanation = f"Could not generate explanation: {exp_explain}"
290
+
291
+ try:
292
+ details_msg = (
293
+ f"βœ… Module created successfully!\n\n"
294
+ f"**Commands:** {commands_str}\n\n"
295
+ f"**What it does:**\n{explanation}\n\n"
296
+ f"♻️ Restarting bot to load the new module..."
297
+ )
298
+ await progress_msg.edit(details_msg, parse_mode=ParseMode.MARKDOWN)
299
+ except Exception as msg_error:
300
+ # Fallback message if formatting fails
301
+ await progress_msg.edit(f"βœ… Module created successfully! Commands: {commands_str}\n\nWhat it does: {explanation}\n\n♻️ Restarting bot...")
302
+ # === END NEW ===
303
  await asyncio.sleep(2)
304
  asyncio.create_task(restart_bot(message.chat.id))
305
  success = True
 
307
 
308
  except Exception as e:
309
  last_error = e
310
+ error_msg = f"❌ Attempt {attempt} Error: {str(e)}"
311
+ print(f"DEBUG: Module generation error on attempt {attempt}: {e}")
312
+ print(f"DEBUG: Error type: {type(e).__name__}")
313
  try:
314
+ await progress_msg.edit(error_msg[:100] + "..." if len(error_msg) > 100 else error_msg)
315
+ except Exception as edit_error:
316
+ print(f"DEBUG: Failed to edit progress message: {edit_error}")
317
+ # Try to send a new message if editing fails
318
+ try:
319
+ await message.reply(f"❌ Attempt {attempt} failed. Check logs for details.")
320
+ except:
321
+ pass
322
 
323
  if not success:
324
+ await progress_msg.edit("❌ All 5 attempts failed. Please try again with a simpler instruction.")
325
 
326
+ # === /modules ===
327
  @bot.on_message(filters.command("modules") & filters.private)
328
  async def list_modules(client, message):
329
+ # Owner-only access control
330
  if message.from_user.id != 7361622601:
331
+ return await message.reply("❌ Access denied. Only the owner can use this bot.")
332
+
333
  modules = [f for f in os.listdir("modules") if f.endswith(".py")]
334
  if modules:
335
  module_list = "\n".join([f"β€’ {m[:-3]}" for m in modules])
336
+ await message.reply(f" Loaded Modules: \n{module_list}", parse_mode=ParseMode.MARKDOWN)
337
  else:
338
+ await message.reply(" No modules found.", parse_mode=ParseMode.MARKDOWN)
339
 
340
+ # === /delete ===
341
  @bot.on_message(filters.command("delete") & filters.private)
342
  async def delete_module(client, message):
343
+ # Owner-only access control
344
  if message.from_user.id != 7361622601:
345
+ return await message.reply("❌ Access denied. Only the owner can use this bot.")
346
+
347
  if len(message.command) < 2:
348
+ return await message.reply("❗ Specify module name.\n\nExample: `/delete calculator`", parse_mode=ParseMode.MARKDOWN)
349
+
350
  mod_name = message.command[1].lower()
351
  mod_path = f"modules/{mod_name}.py"
352
+
353
  if os.path.exists(mod_path):
354
  os.remove(mod_path)
355
+ await message.reply(f"πŸ—‘ Deleted `{mod_name}.py`\n♻️ Restart required to take effect.", parse_mode=ParseMode.MARKDOWN)
356
  else:
357
+ await message.reply(f"❌ Module `{mod_name}.py` not found.", parse_mode=ParseMode.MARKDOWN)
358
 
359
+ # === /what to do ===
360
  @bot.on_message(filters.regex(r"(?i)what( can)? i do\??") & filters.private)
361
  async def what_to_do(_, message):
362
+ # Owner-only access control
363
  if message.from_user.id != 7361622601:
364
+ return await message.reply("❌ Access denied. Only the owner can use this bot.")
365
+
366
  await message.reply(
367
+ "**🧠 Jarvis Assistant**\n\n"
368
  "I can generate custom bot modules for you!\n\n"
369
+ "**Commands:**\n"
370
+ "`jarvis make a calculator` - Natural language trigger\n"
371
+ "`/modules` - List all modules\n"
372
+ "`/delete <name>` - Delete a module\n\n"
373
+ "**Examples:**\n"
374
+ "`jarvis build a reminder system`\n"
375
+ "`jarvis create a dice game`\n"
376
+ "`jarvis weather checker`\n",
377
  parse_mode=ParseMode.MARKDOWN
378
  )
379
 
380
+ # === START ===
381
+ print("πŸš€ Starting Jarvis Bot...")
382
  load_modules()
383
+ print("βœ… Bot is ready!")
384
  bot.run()