xdragxt commited on
Commit
7214b78
Β·
verified Β·
1 Parent(s): fd6063f

Update jarvis.py

Browse files
Files changed (1) hide show
  1. jarvis.py +290 -251
jarvis.py CHANGED
@@ -7,14 +7,15 @@ 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
- OWNER_ID = int(os.environ.get("OWNER_ID", "7361622601")) # Owner user ID
 
18
  if not BOT_TOKEN:
19
  raise RuntimeError("BOT_TOKEN environment variable not set!")
20
  if not GEMINI_API_KEY:
@@ -28,19 +29,25 @@ os.makedirs("modules", exist_ok=True)
28
 
29
  # === MODULE LOADER ===
30
  def load_modules(folder="modules"):
 
31
  for file in os.listdir(folder):
32
  if file.endswith(".py"):
33
- path = os.path.join(folder, file)
34
- name = file[:-3]
35
- spec = importlib.util.spec_from_file_location(name, path)
36
- mod = importlib.util.module_from_spec(spec)
37
- spec.loader.exec_module(mod)
38
-
39
- load_modules()
 
 
 
 
 
40
 
41
  # === HELPERS ===
42
  def extract_module_name(code: str) -> str:
43
- match = re.search(r"def\\s+([a-zA-Z_][a-zA-Z0-9_]*)", code)
44
  return match.group(1).lower() if match else f"mod_{os.urandom(2).hex()}"
45
 
46
  def extract_commands(code: str) -> list:
@@ -48,86 +55,161 @@ def extract_commands(code: str) -> list:
48
 
49
  def determine_intent(text: str) -> str:
50
  lowered = text.lower()
51
- if any(x in lowered for x in ["create", "make", "build"]):
52
  return "CREATE"
53
- elif any(x in lowered for x in ["edit", "modify"]):
54
  return "EDIT"
55
  elif "recode" in lowered:
56
  return "RECODE"
57
  else:
58
- return "UNSURE"
59
 
60
  def clean_code_blocks(code: str) -> str:
61
- if code.startswith("```python"):
62
- code = code[9:]
63
- if code.startswith("```"):
64
- code = code[3:]
65
- if code.endswith("```"):
66
- code = code[:-3]
67
  return code.strip()
68
 
69
  def extract_module_name_from_description(description: str) -> str:
70
- # Improved module name extraction - focus on key nouns and actions
71
- import re
72
-
73
- # Common words to remove
74
  stopwords = {
75
  'jarvis', 'make', 'create', 'build', 'generate', 'a', 'an', 'the', 'please', 'module',
76
  'for', 'me', 'to', 'with', 'add', 'new', 'of', 'system', 'bot', 'command', 'that', 'and',
77
  'in', 'on', 'by', 'as', 'is', 'it', 'my', 'this', 'do', 'can', 'you', 'i', 'want', 'need',
78
  'from', 'like', 'using', 'feature', 'function', 'implement', 'write', 'code', 'file',
79
- 'python', 'telegram', 'pyrogram', 'handler', 'example', 'mod', 'mod_', 'particular', 'user'
80
  }
81
 
82
- # Clean the description
83
  desc = re.sub(r'[^a-zA-Z0-9_\s]', ' ', description.lower())
84
- words = desc.split()
85
-
86
- # Filter out stopwords and short words
87
- filtered_words = []
88
- for word in words:
89
- if word not in stopwords and len(word) > 2:
90
- filtered_words.append(word)
91
 
92
- # If we have good words, use them
93
- if filtered_words:
94
- # Take up to 3 most relevant words
95
- name_words = filtered_words[:3]
96
- name = '_'.join(name_words)
97
  else:
98
- # Fallback: extract any meaningful word
99
- meaningful_words = [w for w in words if len(w) > 3 and w not in stopwords]
100
- if meaningful_words:
101
- name = meaningful_words[0]
102
- else:
103
- # Last resort: use first few characters
104
- clean_desc = re.sub(r'[^a-zA-Z0-9]', '', description.lower())
105
- name = clean_desc[:10] if clean_desc else f"mod_{os.urandom(2).hex()}"
106
 
107
- # Clean up the name
108
- name = re.sub(r'_+', '_', name).strip('_')
109
- name = name.lower()
 
 
 
110
 
111
- # Ensure it's not empty
112
- if not name:
113
- name = f"mod_{os.urandom(2).hex()}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- return name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
  async def restart_bot(chat_id):
118
- await bot.send_message(chat_id, "♻️ Restarting to apply new module...")
 
 
119
  await bot.stop()
120
  os.execl(sys.executable, sys.executable, *sys.argv)
121
- os._exit(0) # Ensure process exits if execl fails
122
 
123
- # === WORD TRIGGER ===
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  @bot.on_message(filters.private & filters.text)
125
  async def jarvis_trigger(client, message):
126
  # Owner-only access control
127
- print(f"DEBUG: User ID: {message.from_user.id}, Expected: {OWNER_ID}")
128
- print(f"DEBUG: User: {message.from_user.first_name} {message.from_user.last_name}")
129
  if message.from_user.id != OWNER_ID:
130
- print(f"DEBUG: Access denied for user {message.from_user.id}")
131
  return await message.reply("❌ Access denied. Only the owner can use this bot.")
132
 
133
  text = message.text.strip()
@@ -136,125 +218,84 @@ async def jarvis_trigger(client, message):
136
 
137
  description = text[6:].strip()
138
  if not description:
139
- return await message.reply("πŸ€– Hello, what would you like me to do?")
140
 
141
  intent = determine_intent(description)
142
- progress_msg = await message.reply(f"πŸ€– Acknowledged.\n🧠 Determining intent...\nπŸ“˜ Intent: {intent}\nπŸ“ Task: `{description}`", parse_mode=ParseMode.MARKDOWN)
 
 
 
 
 
 
143
 
144
- # --- NEW: Handle EDIT intent for existing files ---
145
  if intent == "EDIT":
146
- # Try to extract filename and edit instruction
147
- match = re.match(r"edit\s+([\w/\\.]+)\s+(.*)", description, re.IGNORECASE)
148
- if match:
149
- file_path = match.group(1)
150
- edit_instruction = match.group(2)
151
  if not os.path.exists(file_path):
152
- await progress_msg.edit(f"❌ File `{file_path}` not found.")
153
- return
154
- with open(file_path, "r", encoding="utf-8") as f:
155
- current_content = f.read()
156
- edit_prompt = (
157
- f"You are an expert Python developer. Here is the current content of `{file_path}`:\n"
158
- f"""\n{current_content}\n"""
159
- f"Please edit this file to: {edit_instruction}.\n"
160
- f"Output ONLY the new Python code, no explanations or markdown."
161
- )
162
  try:
163
- response = model.generate_content(edit_prompt)
 
 
 
 
 
 
164
  new_code = clean_code_blocks(response.text.strip())
165
- if not new_code or "def " not in new_code:
166
- await progress_msg.edit(f"❌ Edit failed: No valid code returned.")
167
- return
 
 
168
  with open(file_path, "w", encoding="utf-8") as f:
169
  f.write(new_code)
170
- # Try to reload the module if it's in modules/
171
- if file_path.startswith("modules/") and file_path.endswith(".py"):
172
- mod_name = os.path.basename(file_path)[:-3]
173
- try:
174
- spec = importlib.util.spec_from_file_location(mod_name, file_path)
175
- mod = importlib.util.module_from_spec(spec)
176
- mod.bot = bot
177
- spec.loader.exec_module(mod)
178
- except Exception as test_error:
179
- await progress_msg.edit(f"⚠️ Edit applied, but module reload failed: {test_error}")
180
- return
181
- await progress_msg.edit(f"βœ… Edit applied to `{file_path}`. Restarting bot...")
182
  await asyncio.sleep(2)
183
  asyncio.create_task(restart_bot(message.chat.id))
184
  return
 
185
  except Exception as e:
186
- await progress_msg.edit(f"❌ Edit failed: `{str(e)[:100]}...`")
187
- return
188
  else:
189
- await progress_msg.edit("❗ Could not parse edit command. Use: 'edit <file> <instruction>'")
190
- return
191
- # --- END NEW ---
192
 
 
193
  success = False
194
- code = ""
195
  last_error = None
196
- for attempt in range(1, 6):
197
- await progress_msg.edit(f"`Attempt {attempt}/5:` Thinking and generating code...\n- Executing prerequisite shell commands...")
198
-
199
  try:
200
- prompt = (
201
- f"Write a full Pyrogram Telegram bot module that implements:\n"
202
- f"{description}.\n\n"
203
- f"IMPORTANT RULES:\n"
204
- f"1. Use 'bot' variable (not 'Client') - it will be injected\n"
205
- f"2. Include commands using @bot.on_message(filters.command(...))\n"
206
- 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"
207
- f"4. Don't create a new Client instance\n"
208
- f"5. Make functions async when using bot methods\n"
209
- f"6. ONLY create the specific commands requested - do NOT add standard commands like /start, /help, /about unless explicitly asked for\n"
210
- f"7. If the user asks for '/bash', only create the /bash command, not additional commands\n\n"
211
- f"Output ONLY Python code, no explanations or markdown."
212
  )
213
- if attempt > 1 and last_error is not None:
214
- prompt += f"\n\nNote: Previous attempt failed with error: {str(last_error)}. Fix that issue this time."
215
-
216
- response = model.generate_content(prompt)
217
  code = clean_code_blocks(response.text.strip())
218
-
219
- # === AUTO-FIX COMMON LLM MISTAKES ===
220
- code = code.replace('asyncio.PIPE', 'subprocess.PIPE')
221
- # Add more auto-fixes as needed
222
-
223
- # === REMOVE UNWANTED STANDARD COMMANDS ===
224
- # Only keep commands that were explicitly requested
225
- import re
226
- requested_commands = []
227
- # Extract commands mentioned in the description
228
- cmd_matches = re.findall(r'/(\w+)', description.lower())
229
- if cmd_matches:
230
- requested_commands = [f'/{cmd}' for cmd in cmd_matches]
231
 
232
- # If specific commands were requested, remove unwanted standard commands
233
- if requested_commands:
234
- unwanted_commands = ['/start', '/help', '/about', '/info']
235
- for unwanted in unwanted_commands:
236
- if unwanted not in requested_commands:
237
- # Remove the entire function/handler for unwanted commands
238
- pattern = rf'@bot\.on_message\(filters\.command\(["\']{unwanted[1:]}["\']\)\).*?(?=@bot\.on_message|$)'
239
- code = re.sub(pattern, '', code, flags=re.DOTALL)
240
-
241
- # === LINTER/STATIC CHECKER ===
242
- with open('tmp_lint_module.py', 'w', encoding='utf-8') as tmpf:
243
- tmpf.write(code)
244
- lint_proc = subprocess.run(['pyflakes', 'tmp_lint_module.py'], capture_output=True, text=True)
245
- if lint_proc.returncode != 0 or lint_proc.stdout.strip() or lint_proc.stderr.strip():
246
- lint_output = (lint_proc.stdout + '\n' + lint_proc.stderr).strip()
247
- await progress_msg.edit(f"❌ Linter/static check failed!\n\n```\n{lint_output}\n```")
248
- os.remove('tmp_lint_module.py')
249
- continue
250
- os.remove('tmp_lint_module.py')
251
-
252
- if "def " not in code or "@bot" not in code:
253
- await progress_msg.edit(f"❌ Attempt {attempt}: Invalid function or handler.")
254
  continue
255
-
256
- # --- NEW: Use file path from description if present ---
257
- import re
 
 
 
258
  file_path_match = re.search(r"(modules/[\w\-]+\.py)", description)
259
  if file_path_match:
260
  mod_path = file_path_match.group(1)
@@ -262,145 +303,143 @@ async def jarvis_trigger(client, message):
262
  else:
263
  mod_name = extract_module_name_from_description(description)
264
  mod_path = f"modules/{mod_name}.py"
265
- # If file exists, use edit flow instead of creating a new file
266
- if os.path.exists(mod_path):
267
- with open(mod_path, "r", encoding="utf-8") as f:
268
- current_content = f.read()
269
- edit_prompt = (
270
- f"You are an expert Python developer. Here is the current content of `{mod_path}`:\n"
271
- f"""\n{current_content}\n"""
272
- f"Please update this file to: {description}.\n"
273
- f"Output ONLY the new Python code, no explanations or markdown."
274
- )
275
- response = model.generate_content(edit_prompt)
276
- code = clean_code_blocks(response.text.strip())
277
- # --- END NEW ---
278
-
279
  with open(mod_path, "w", encoding="utf-8") as f:
280
  f.write(code)
281
-
282
- await progress_msg.edit(f"`Attempt {attempt}/5: Thinking and generating code...\n- Executing prerequisite shell commands...\n- Testing generated code...")
283
-
 
 
 
 
 
 
 
284
  try:
285
  spec = importlib.util.spec_from_file_location(mod_name, mod_path)
286
  mod = importlib.util.module_from_spec(spec)
287
  mod.bot = bot
288
  spec.loader.exec_module(mod)
289
  except Exception as test_error:
290
- raise RuntimeError(f"Testing error: {test_error}")
291
-
292
- 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...")
293
-
294
- # === NEW: Show module details before restart ===
295
- try:
296
- commands = extract_commands(code)
297
- commands_str = ', '.join(f'/{cmd}' for cmd in commands) if commands else 'No commands found.'
298
- except Exception as cmd_error:
299
- commands_str = f'Error extracting commands: {cmd_error}'
300
 
 
301
  try:
302
- explain_prompt = (
303
- f"Explain in 2-3 sentences what this Pyrogram Telegram bot module does, given the following code and the user's request.\n"
304
- f"User request: {description}\n"
305
- f"Module code:\n{code}\n"
306
- f"Be concise and clear."
307
- )
308
- explain_response = model.generate_content(explain_prompt)
 
 
 
 
 
309
  explanation = explain_response.text.strip()
310
- except Exception as exp_explain:
311
- explanation = f"Could not generate explanation: {exp_explain}"
312
-
313
- try:
314
- details_msg = (
315
- f"βœ… Module created successfully!\n\n"
316
- f"**Commands:** {commands_str}\n\n"
317
- f"**What it does:**\n{explanation}\n\n"
318
- f"♻️ Restarting bot to load the new module..."
319
  )
320
- await progress_msg.edit(details_msg, parse_mode=ParseMode.MARKDOWN)
321
- except Exception as msg_error:
322
- # Fallback message if formatting fails
323
- await progress_msg.edit(f"βœ… Module created successfully! Commands: {commands_str}\n\nWhat it does: {explanation}\n\n♻️ Restarting bot...")
324
- # === END NEW ===
 
 
 
 
 
325
  await asyncio.sleep(2)
326
  asyncio.create_task(restart_bot(message.chat.id))
327
  success = True
328
  break
329
-
330
  except Exception as e:
331
- last_error = e
332
- error_msg = f"❌ Attempt {attempt} Error: {str(e)}"
333
- print(f"DEBUG: Module generation error on attempt {attempt}: {e}")
334
- print(f"DEBUG: Error type: {type(e).__name__}")
335
- try:
336
- await progress_msg.edit(error_msg[:100] + "..." if len(error_msg) > 100 else error_msg)
337
- except Exception as edit_error:
338
- print(f"DEBUG: Failed to edit progress message: {edit_error}")
339
- # Try to send a new message if editing fails
340
- try:
341
- await message.reply(f"❌ Attempt {attempt} failed. Check logs for details.")
342
- except:
343
- pass
344
-
345
  if not success:
346
- await progress_msg.edit("❌ All 5 attempts failed. Please try again with a simpler instruction.")
347
-
348
- # === /modules ===
 
 
 
 
 
349
  @bot.on_message(filters.command("modules") & filters.private)
350
  async def list_modules(client, message):
351
- # Owner-only access control
352
  if message.from_user.id != OWNER_ID:
353
- return await message.reply("❌ Access denied. Only the owner can use this bot.")
354
 
355
  modules = [f for f in os.listdir("modules") if f.endswith(".py")]
356
  if modules:
357
- module_list = "\n".join([f"β€’ {m[:-3]}" for m in modules])
358
- await message.reply(f" Loaded Modules: \n{module_list}", parse_mode=ParseMode.MARKDOWN)
359
  else:
360
- await message.reply(" No modules found.", parse_mode=ParseMode.MARKDOWN)
361
 
362
- # === /delete ===
363
  @bot.on_message(filters.command("delete") & filters.private)
364
  async def delete_module(client, message):
365
- # Owner-only access control
366
  if message.from_user.id != OWNER_ID:
367
- return await message.reply("❌ Access denied. Only the owner can use this bot.")
368
 
369
  if len(message.command) < 2:
370
- return await message.reply("❗ Specify module name.\n\nExample: `/delete calculator`", parse_mode=ParseMode.MARKDOWN)
371
 
372
  mod_name = message.command[1].lower()
373
  mod_path = f"modules/{mod_name}.py"
374
 
375
  if os.path.exists(mod_path):
376
  os.remove(mod_path)
377
- await message.reply(f"πŸ—‘ Deleted `{mod_name}.py`\n♻️ Restart required to take effect.", parse_mode=ParseMode.MARKDOWN)
378
  else:
379
  await message.reply(f"❌ Module `{mod_name}.py` not found.", parse_mode=ParseMode.MARKDOWN)
380
 
381
- # === /what to do ===
382
- @bot.on_message(filters.regex(r"(?i)what( can)? i do\??") & filters.private)
383
- async def what_to_do(_, message):
384
- # Owner-only access control
385
  if message.from_user.id != OWNER_ID:
386
- return await message.reply("❌ Access denied. Only the owner can use this bot.")
387
 
388
  await message.reply(
389
- "**🧠 Jarvis Assistant**\n\n"
390
- "I can generate custom bot modules for you!\n\n"
 
 
 
391
  "**Commands:**\n"
392
- "`jarvis make a calculator` - Natural language trigger\n"
393
- "`/modules` - List all modules\n"
394
- "`/delete <name>` - Delete a module\n\n"
395
  "**Examples:**\n"
396
- "`jarvis build a reminder system`\n"
397
- "`jarvis create a dice game`\n"
398
- "`jarvis weather checker`\n",
399
  parse_mode=ParseMode.MARKDOWN
400
  )
401
 
402
- # === START ===
403
- print("πŸš€ Starting Jarvis Bot...")
404
- load_modules()
405
- print("βœ… Bot is ready!")
406
- bot.run()
 
 
7
  from pyrogram.enums import ParseMode
8
  import google.generativeai as genai
9
  import subprocess
10
+ import traceback
11
 
 
12
  # === CONFIG ===
13
+ API_ID = os.environ.get("API_ID")
14
+ API_HASH = os.environ.get("API_HASH")
15
  BOT_TOKEN = os.environ.get("BOT_TOKEN")
16
  GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
17
+ OWNER_ID = int(os.environ.get("OWNER_ID", "7361622601"))
18
+
19
  if not BOT_TOKEN:
20
  raise RuntimeError("BOT_TOKEN environment variable not set!")
21
  if not GEMINI_API_KEY:
 
29
 
30
  # === MODULE LOADER ===
31
  def load_modules(folder="modules"):
32
+ loaded_count = 0
33
  for file in os.listdir(folder):
34
  if file.endswith(".py"):
35
+ try:
36
+ path = os.path.join(folder, file)
37
+ name = file[:-3]
38
+ spec = importlib.util.spec_from_file_location(name, path)
39
+ mod = importlib.util.module_from_spec(spec)
40
+ mod.bot = bot # Inject bot instance
41
+ spec.loader.exec_module(mod)
42
+ loaded_count += 1
43
+ print(f"βœ… Loaded module: {name}")
44
+ except Exception as e:
45
+ print(f"❌ Failed to load {file}: {e}")
46
+ print(f"πŸ“¦ Loaded {loaded_count} modules")
47
 
48
  # === HELPERS ===
49
  def extract_module_name(code: str) -> str:
50
+ match = re.search(r"def\s+([a-zA-Z_][a-zA-Z0-9_]*)", code)
51
  return match.group(1).lower() if match else f"mod_{os.urandom(2).hex()}"
52
 
53
  def extract_commands(code: str) -> list:
 
55
 
56
  def determine_intent(text: str) -> str:
57
  lowered = text.lower()
58
+ if any(x in lowered for x in ["create", "make", "build", "generate", "add"]):
59
  return "CREATE"
60
+ elif any(x in lowered for x in ["edit", "modify", "update", "change"]):
61
  return "EDIT"
62
  elif "recode" in lowered:
63
  return "RECODE"
64
  else:
65
+ return "CREATE" # Default to CREATE instead of UNSURE
66
 
67
  def clean_code_blocks(code: str) -> str:
68
+ # Remove markdown code blocks
69
+ code = re.sub(r'^```python\n?', '', code, flags=re.MULTILINE)
70
+ code = re.sub(r'^```\n?', '', code, flags=re.MULTILINE)
71
+ code = re.sub(r'\n?```$', '', code, flags=re.MULTILINE)
 
 
72
  return code.strip()
73
 
74
  def extract_module_name_from_description(description: str) -> str:
75
+ """Enhanced module name extraction"""
 
 
 
76
  stopwords = {
77
  'jarvis', 'make', 'create', 'build', 'generate', 'a', 'an', 'the', 'please', 'module',
78
  'for', 'me', 'to', 'with', 'add', 'new', 'of', 'system', 'bot', 'command', 'that', 'and',
79
  'in', 'on', 'by', 'as', 'is', 'it', 'my', 'this', 'do', 'can', 'you', 'i', 'want', 'need',
80
  'from', 'like', 'using', 'feature', 'function', 'implement', 'write', 'code', 'file',
81
+ 'python', 'telegram', 'pyrogram', 'handler', 'example', 'mod', 'particular', 'user'
82
  }
83
 
84
+ # Extract meaningful words
85
  desc = re.sub(r'[^a-zA-Z0-9_\s]', ' ', description.lower())
86
+ words = [w for w in desc.split() if w not in stopwords and len(w) > 2]
 
 
 
 
 
 
87
 
88
+ if words:
89
+ name = '_'.join(words[:2]) # Take first 2 meaningful words
 
 
 
90
  else:
91
+ # Fallback to extracting from original description
92
+ clean_desc = re.sub(r'[^a-zA-Z0-9]', '', description.lower())
93
+ name = clean_desc[:10] if clean_desc else f"mod_{os.urandom(2).hex()}"
 
 
 
 
 
94
 
95
+ # Clean and validate
96
+ name = re.sub(r'_+', '_', name).strip('_').lower()
97
+ return name if name else f"mod_{os.urandom(2).hex()}"
98
+
99
+ def get_improved_prompt(description: str, attempt: int = 1, last_error: str = None) -> str:
100
+ """Generate improved prompts for better code generation"""
101
 
102
+ base_prompt = f"""You are an expert Python developer creating a Pyrogram Telegram bot module.
103
+
104
+ TASK: Create a module that implements: {description}
105
+
106
+ CRITICAL REQUIREMENTS:
107
+ 1. Use the existing 'bot' variable - DO NOT create a new Client instance
108
+ 2. Import bot using this exact pattern:
109
+ ```python
110
+ try:
111
+ from __main__ import bot
112
+ except ImportError:
113
+ from ..main import bot
114
+ ```
115
+ 3. Import only necessary Pyrogram components:
116
+ ```python
117
+ from pyrogram import filters
118
+ from pyrogram.enums import ParseMode
119
+ ```
120
+ 4. Use proper async/await for all bot operations
121
+ 5. Handle errors gracefully with try/except blocks
122
+ 6. Include proper message validation and user feedback
123
+
124
+ HANDLER PATTERN:
125
+ ```python
126
+ @bot.on_message(filters.command("commandname") & filters.private)
127
+ async def function_name(client, message):
128
+ try:
129
+ # Your code here
130
+ await message.reply("Response")
131
+ except Exception as e:
132
+ await message.reply(f"❌ Error: {{str(e)}}")
133
+ ```
134
+
135
+ SPECIFIC GUIDELINES:
136
+ - Only create commands explicitly mentioned in the request
137
+ - Use descriptive function names
138
+ - Include input validation
139
+ - Provide helpful error messages
140
+ - Use markdown formatting for responses when appropriate
141
+ - Handle edge cases (empty inputs, invalid data, etc.)
142
+
143
+ CODE STRUCTURE:
144
+ - Start with imports
145
+ - Define helper functions if needed
146
+ - Create command handlers
147
+ - No main execution code (no if __name__ == "__main__")
148
+
149
+ OUTPUT: Provide ONLY the Python code, no explanations or markdown formatting."""
150
+
151
+ if attempt > 1 and last_error:
152
+ base_prompt += f"\n\nPREVIOUS ERROR TO FIX: {last_error}\n"
153
+ base_prompt += "Make sure to address this specific error in your implementation."
154
 
155
+ return base_prompt
156
+
157
+ def get_edit_prompt(file_path: str, current_content: str, edit_instruction: str) -> str:
158
+ """Generate prompt for editing existing modules"""
159
+ return f"""You are an expert Python developer. Edit the following Pyrogram bot module.
160
+
161
+ CURRENT FILE: {file_path}
162
+ CURRENT CONTENT:
163
+ ```python
164
+ {current_content}
165
+ ```
166
+
167
+ EDIT INSTRUCTION: {edit_instruction}
168
+
169
+ REQUIREMENTS:
170
+ 1. Maintain the existing import structure
171
+ 2. Keep the bot variable usage consistent
172
+ 3. Preserve working functionality while making requested changes
173
+ 4. Follow the same coding patterns as the existing code
174
+ 5. Add proper error handling for new features
175
+
176
+ OUTPUT: Provide ONLY the complete updated Python code, no explanations."""
177
 
178
  async def restart_bot(chat_id):
179
+ """Restart the bot to load new modules"""
180
+ await bot.send_message(chat_id, "♻️ Restarting to apply changes...")
181
+ await asyncio.sleep(1)
182
  await bot.stop()
183
  os.execl(sys.executable, sys.executable, *sys.argv)
 
184
 
185
+ def validate_generated_code(code: str) -> tuple[bool, str]:
186
+ """Validate generated code before saving"""
187
+ if not code.strip():
188
+ return False, "Empty code generated"
189
+
190
+ if "def " not in code:
191
+ return False, "No function definitions found"
192
+
193
+ if "@bot.on_message" not in code:
194
+ return False, "No message handlers found"
195
+
196
+ if "import" not in code:
197
+ return False, "No imports found"
198
+
199
+ # Check for common issues
200
+ if "Client(" in code:
201
+ return False, "Code creates new Client instance (should use existing bot)"
202
+
203
+ if "__main__" in code and "if __name__" in code:
204
+ return False, "Code contains main execution block (not allowed in modules)"
205
+
206
+ return True, "Code validation passed"
207
+
208
+ # === MAIN HANDLER ===
209
  @bot.on_message(filters.private & filters.text)
210
  async def jarvis_trigger(client, message):
211
  # Owner-only access control
 
 
212
  if message.from_user.id != OWNER_ID:
 
213
  return await message.reply("❌ Access denied. Only the owner can use this bot.")
214
 
215
  text = message.text.strip()
 
218
 
219
  description = text[6:].strip()
220
  if not description:
221
+ return await message.reply("πŸ€– Hello! What would you like me to create?")
222
 
223
  intent = determine_intent(description)
224
+ progress_msg = await message.reply(
225
+ f"πŸ€– **Jarvis Assistant**\n"
226
+ f"πŸ“ Task: `{description}`\n"
227
+ f"🧠 Intent: {intent}\n"
228
+ f"⏳ Processing...",
229
+ parse_mode=ParseMode.MARKDOWN
230
+ )
231
 
232
+ # Handle EDIT intent
233
  if intent == "EDIT":
234
+ edit_match = re.match(r"edit\s+([\w/\\.]+)\s+(.*)", description, re.IGNORECASE)
235
+ if edit_match:
236
+ file_path = edit_match.group(1)
237
+ edit_instruction = edit_match.group(2)
238
+
239
  if not os.path.exists(file_path):
240
+ return await progress_msg.edit(f"❌ File `{file_path}` not found.")
241
+
 
 
 
 
 
 
 
 
242
  try:
243
+ with open(file_path, "r", encoding="utf-8") as f:
244
+ current_content = f.read()
245
+
246
+ edit_prompt = get_edit_prompt(file_path, current_content, edit_instruction)
247
+
248
+ await progress_msg.edit(f"πŸ”„ Editing {file_path}...")
249
+ response = await asyncio.to_thread(model.generate_content, edit_prompt)
250
  new_code = clean_code_blocks(response.text.strip())
251
+
252
+ is_valid, validation_msg = validate_generated_code(new_code)
253
+ if not is_valid:
254
+ return await progress_msg.edit(f"❌ Edit failed: {validation_msg}")
255
+
256
  with open(file_path, "w", encoding="utf-8") as f:
257
  f.write(new_code)
258
+
259
+ await progress_msg.edit(f"βœ… Successfully edited `{file_path}`\n♻️ Restarting bot...")
 
 
 
 
 
 
 
 
 
 
260
  await asyncio.sleep(2)
261
  asyncio.create_task(restart_bot(message.chat.id))
262
  return
263
+
264
  except Exception as e:
265
+ return await progress_msg.edit(f"❌ Edit failed: {str(e)}")
 
266
  else:
267
+ return await progress_msg.edit("❗ Format: `jarvis edit <file> <instruction>`")
 
 
268
 
269
+ # Handle CREATE intent
270
  success = False
 
271
  last_error = None
272
+
273
+ for attempt in range(1, 4): # Reduced to 3 attempts
 
274
  try:
275
+ await progress_msg.edit(
276
+ f"πŸ€– **Jarvis Assistant**\n"
277
+ f"πŸ“ Task: `{description}`\n"
278
+ f"🧠 Intent: {intent}\n"
279
+ f"πŸ”„ Attempt {attempt}/3: Generating code...",
280
+ parse_mode=ParseMode.MARKDOWN
 
 
 
 
 
 
281
  )
282
+
283
+ # Generate code
284
+ prompt = get_improved_prompt(description, attempt, last_error)
285
+ response = await asyncio.to_thread(model.generate_content, prompt)
286
  code = clean_code_blocks(response.text.strip())
 
 
 
 
 
 
 
 
 
 
 
 
 
287
 
288
+ # Validate generated code
289
+ is_valid, validation_msg = validate_generated_code(code)
290
+ if not is_valid:
291
+ last_error = validation_msg
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
  continue
293
+
294
+ # Auto-fix common issues
295
+ code = code.replace('asyncio.PIPE', 'subprocess.PIPE')
296
+ code = code.replace('asyncio.create_subprocess_shell', 'subprocess.run')
297
+
298
+ # Determine module name and path
299
  file_path_match = re.search(r"(modules/[\w\-]+\.py)", description)
300
  if file_path_match:
301
  mod_path = file_path_match.group(1)
 
303
  else:
304
  mod_name = extract_module_name_from_description(description)
305
  mod_path = f"modules/{mod_name}.py"
306
+
307
+ # Save the module
308
+ await progress_msg.edit(
309
+ f"πŸ€– **Jarvis Assistant**\n"
310
+ f"πŸ“ Task: `{description}`\n"
311
+ f"🧠 Intent: {intent}\n"
312
+ f"πŸ’Ύ Saving module: {mod_name}...",
313
+ parse_mode=ParseMode.MARKDOWN
314
+ )
315
+
 
 
 
 
316
  with open(mod_path, "w", encoding="utf-8") as f:
317
  f.write(code)
318
+
319
+ # Test the module
320
+ await progress_msg.edit(
321
+ f"πŸ€– **Jarvis Assistant**\n"
322
+ f"πŸ“ Task: `{description}`\n"
323
+ f"🧠 Intent: {intent}\n"
324
+ f"πŸ§ͺ Testing module...",
325
+ parse_mode=ParseMode.MARKDOWN
326
+ )
327
+
328
  try:
329
  spec = importlib.util.spec_from_file_location(mod_name, mod_path)
330
  mod = importlib.util.module_from_spec(spec)
331
  mod.bot = bot
332
  spec.loader.exec_module(mod)
333
  except Exception as test_error:
334
+ last_error = f"Module test failed: {str(test_error)}"
335
+ continue
 
 
 
 
 
 
 
 
336
 
337
+ # Success! Show details
338
  try:
339
+ commands = extract_commands(code)
340
+ commands_str = ', '.join(f'/{cmd}' for cmd in commands) if commands else 'No commands found'
341
+
342
+ # Generate explanation
343
+ explain_prompt = f"""Briefly explain what this Telegram bot module does based on the user's request and the code.
344
+
345
+ User request: {description}
346
+ Commands found: {commands_str}
347
+
348
+ Provide a concise 1-2 sentence explanation."""
349
+
350
+ explain_response = await asyncio.to_thread(model.generate_content, explain_prompt)
351
  explanation = explain_response.text.strip()
352
+
353
+ await progress_msg.edit(
354
+ f"βœ… **Module Created Successfully!**\n\n"
355
+ f"πŸ“„ **File:** `{mod_path}`\n"
356
+ f"πŸ”§ **Commands:** {commands_str}\n"
357
+ f"πŸ“‹ **Description:** {explanation}\n\n"
358
+ f"♻️ Restarting bot to load the module...",
359
+ parse_mode=ParseMode.MARKDOWN
 
360
  )
361
+
362
+ except Exception:
363
+ await progress_msg.edit(
364
+ f"βœ… **Module Created Successfully!**\n\n"
365
+ f"πŸ“„ **File:** `{mod_path}`\n"
366
+ f"πŸ”§ **Commands:** {commands_str}\n\n"
367
+ f"♻️ Restarting bot to load the module...",
368
+ parse_mode=ParseMode.MARKDOWN
369
+ )
370
+
371
  await asyncio.sleep(2)
372
  asyncio.create_task(restart_bot(message.chat.id))
373
  success = True
374
  break
375
+
376
  except Exception as e:
377
+ last_error = str(e)
378
+ print(f"❌ Attempt {attempt} failed: {e}")
379
+ print(f"❌ Traceback: {traceback.format_exc()}")
380
+
 
 
 
 
 
 
 
 
 
 
381
  if not success:
382
+ await progress_msg.edit(
383
+ f"❌ **Failed to create module**\n\n"
384
+ f"All attempts failed. Last error:\n`{last_error}`\n\n"
385
+ f"Please try with a simpler request or check the logs.",
386
+ parse_mode=ParseMode.MARKDOWN
387
+ )
388
+
389
+ # === UTILITY COMMANDS ===
390
  @bot.on_message(filters.command("modules") & filters.private)
391
  async def list_modules(client, message):
 
392
  if message.from_user.id != OWNER_ID:
393
+ return await message.reply("❌ Access denied.")
394
 
395
  modules = [f for f in os.listdir("modules") if f.endswith(".py")]
396
  if modules:
397
+ module_list = "\n".join([f"β€’ `{m[:-3]}`" for m in modules])
398
+ await message.reply(f"πŸ“¦ **Loaded Modules:**\n{module_list}", parse_mode=ParseMode.MARKDOWN)
399
  else:
400
+ await message.reply("πŸ“¦ **No modules found.**", parse_mode=ParseMode.MARKDOWN)
401
 
 
402
  @bot.on_message(filters.command("delete") & filters.private)
403
  async def delete_module(client, message):
 
404
  if message.from_user.id != OWNER_ID:
405
+ return await message.reply("❌ Access denied.")
406
 
407
  if len(message.command) < 2:
408
+ return await message.reply("❗ **Usage:** `/delete <module_name>`", parse_mode=ParseMode.MARKDOWN)
409
 
410
  mod_name = message.command[1].lower()
411
  mod_path = f"modules/{mod_name}.py"
412
 
413
  if os.path.exists(mod_path):
414
  os.remove(mod_path)
415
+ await message.reply(f"πŸ—‘ **Deleted:** `{mod_name}.py`\n♻️ Restart required.", parse_mode=ParseMode.MARKDOWN)
416
  else:
417
  await message.reply(f"❌ Module `{mod_name}.py` not found.", parse_mode=ParseMode.MARKDOWN)
418
 
419
+ @bot.on_message(filters.regex(r"(?i)(what|help|commands)") & filters.private)
420
+ async def help_command(_, message):
 
 
421
  if message.from_user.id != OWNER_ID:
422
+ return await message.reply("❌ Access denied.")
423
 
424
  await message.reply(
425
+ "πŸ€– **Jarvis Assistant - Help**\n\n"
426
+ "**Natural Language:**\n"
427
+ "β€’ `jarvis create a calculator`\n"
428
+ "β€’ `jarvis make a weather bot`\n"
429
+ "β€’ `jarvis build a reminder system`\n\n"
430
  "**Commands:**\n"
431
+ "β€’ `/modules` - List all modules\n"
432
+ "β€’ `/delete <name>` - Delete a module\n\n"
 
433
  "**Examples:**\n"
434
+ "β€’ `jarvis create a /joke command`\n"
435
+ "β€’ `jarvis make a password generator`\n"
436
+ "β€’ `jarvis build a text to speech module`\n",
437
  parse_mode=ParseMode.MARKDOWN
438
  )
439
 
440
+ # === STARTUP ===
441
+ if __name__ == "__main__":
442
+ print("πŸš€ Starting Jarvis Bot...")
443
+ load_modules()
444
+ print("βœ… Bot is ready!")
445
+ bot.run()