ChaterJee 0.1.8__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,8 @@ import pickle
7
7
  import html
8
8
  import traceback
9
9
  import logging, json
10
- from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, ReplyKeyboardMarkup, KeyboardButton
11
- from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, ConversationHandler, filters, PollAnswerHandler, PollHandler
10
+ from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton, WebAppInfo, ReplyKeyboardMarkup, KeyboardButton, ReplyKeyboardRemove
11
+ from telegram.ext import Updater, ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, ConversationHandler, filters, PollAnswerHandler, PollHandler
12
12
  from telegram.constants import ParseMode
13
13
  import os.path
14
14
  import threading
@@ -19,11 +19,14 @@ start_txt = \
19
19
  """
20
20
  I am ChaterJee, a Research assistant Bot developed by Pallab Dutta in 2025.
21
21
 
22
- ChaterJee helps you to:
23
- - Receive research updates
24
- - Start new computational experiments
22
+ *TEXT*
23
+ acts as a bash command and runs on host terminal.
25
24
 
26
- even when you are at a remote location.
25
+ *COMMANDS*
26
+ /start : returns this text.
27
+ /jobs : shows your jobs
28
+ /clear : clears chat history
29
+ /edit file.json : let you edit the file.json
27
30
 
28
31
  """
29
32
 
@@ -40,8 +43,10 @@ class ChatLogs:
40
43
  self.jobs = {}
41
44
 
42
45
  def cmdTRIGGER(self, read_timeout=7, get_updates_read_timeout=42):
46
+ #que = asyncio.Queue()
43
47
  application = ApplicationBuilder().token(self.TOKEN).read_timeout(read_timeout)\
44
48
  .get_updates_read_timeout(get_updates_read_timeout).build()
49
+ #updater = Updater(application.bot, update_queue=que)
45
50
 
46
51
  start_handler = CommandHandler('start', self.start)
47
52
  application.add_handler(start_handler)
@@ -49,195 +54,56 @@ class ChatLogs:
49
54
  fEdit_handler = CommandHandler('edit', self.EditorBabu)
50
55
  application.add_handler(fEdit_handler)
51
56
 
52
- cmd_handler = CommandHandler('sh', self.commands)
53
- application.add_handler(cmd_handler)
57
+ #cmd_handler = CommandHandler('sh', self.commands)
58
+ #application.add_handler(cmd_handler)
54
59
 
55
- #jobs_handler = CommandHandler('jobs', self.ShowJobs)
56
- #application.add_handler(jobs_handler)
60
+ cancel_handler = CommandHandler('cancel', self.cancel)
61
+ application.add_handler(cancel_handler)
57
62
 
58
63
  jobs_handler = ConversationHandler(\
59
- entry_points=[CommandHandler("jobs", self.ShowJobs)],\
64
+ entry_points=[CommandHandler("jobs", self.ShowJobs), CommandHandler("clear", self.ask2clear)],\
60
65
  states={
61
- 0: [MessageHandler(filters.Regex(f"^({'|'.join(list(self.jobs.keys()))})$"), self.StatJobs)],
66
+ 0: [MessageHandler(filters.Regex("^(JOB)"), self.StatJobs)],
67
+ 1: [MessageHandler(filters.Regex("^(Yes|No)$"), self.ClearChat)],
62
68
  },
63
69
  fallbacks=[CommandHandler("cancel", self.cancel)],
64
70
  )
65
-
66
71
  application.add_handler(jobs_handler)
67
- #add_handler = CommandHandler('add', addDICT)
68
- #application.add_handler(add_handler)
69
- #run_handler = CommandHandler('run', runCMD)
70
- #application.add_handler(run_handler)
71
- #com_handler = CommandHandler('com', comCMD)
72
- #application.add_handler(com_handler)
73
- #exit_handler = CommandHandler('exit', exitCMD)
74
- #application.add_handler(exit_handle)
75
- #clear_handler = CommandHandler('clear', clsCMD)
76
- #application.add_handler(clear_handler)
77
- #jedit_handler = CommandHandler('edit', editJSON) # JSON file editor
78
- #application.add_handler(jedit_handler)
79
72
 
80
73
  application.add_handler(MessageHandler(filters.StatusUpdate.WEB_APP_DATA, self.web_app_data))
81
- #application.add_handler(MessageHandler(filters.TEXT, self.commands))
74
+ application.add_handler(MessageHandler(filters.TEXT & ~(filters.COMMAND | filters.Regex("^(JOB:|Yes$|No$)")), self.commands))
82
75
 
83
- application.run_polling()
76
+ #await application.shutdown()
77
+ #await application.initialize()
84
78
 
85
- def strSMS(self, update, context):
86
- self.smsID.append(update.message.message_id)
87
- self.txt=update.message.text
88
- cmd = self.txt.split(' ')[0]
89
- args = self.txt.split(' ')[1:]
90
- if cmd == '/add':
91
- self.addDICT(args)
92
- elif cmd == '/run':
93
- self.cmdRUN(args)
94
- elif cmd == '/com':
95
- self.cmdCOM(args)
96
- elif cmd == '/exit':
97
- self.EXIT()
98
- elif cmd == '/clear':
99
- self.cls()
100
- elif cmd[0] == '/':
101
- self.txt = 'command not found !'
102
- self.sendUPDATE()
103
- else:
104
- self.txt = "Sorry I can only read '/commands', not 'texts'."
105
- self.sendUPDATE()
79
+ #updater = Updater(application.bot, update_queue=que)
80
+ #await updater.initialize()
81
+ #await updater.start_polling()
82
+ application.run_polling()
106
83
 
107
- def addDICT(self, context):
108
- try:
109
- key = context[0]
110
- eql = context[1]
111
- if ('$' in key) and (eql == '='):
112
- val = context[2]
113
- self.dict[key]=val
114
- self.txt = 'added to dictionary'
115
- elif ('$' in key) and (eql == '-1'):
116
- del self.dict[key]
117
- self.txt = 'removed from dictionary'
118
- else:
119
- self.txt = 'pass the command as:\n/add $key = val'
120
- except:
121
- self.txt = 'pass the command as:\n/add $key = val'
122
- self.sendUPDATE()
123
-
124
- def fmtDICT(self, context):
125
- key = []
126
- idx = []
127
- c = context
128
- for i in range(len(context)):
129
- w = context[i]
130
- if '$' in w:
131
- key.append(w)
132
- idx.append(i)
133
- for j in range(len(idx)):
134
- val = self.dict[key[j]]
135
- c[idx[j]] = val
136
- return c
137
-
138
- #async def cmdRUN(update: object, context: ContextTypes.DEFAULT_TYPE) -> None:
139
- def cmdRUN(self, context):
140
- context = self.fmtDICT(context)
141
- cmd0 = context[0]
142
- if cmd0=='cd':
143
- cmd1 = context[1]
144
- try:
145
- os.chdir(cmd1)
146
- self.txt=os.popen('pwd').read()
147
- except:
148
- self.txt='path not found'
149
- else:
150
- cmd=' '.join(context)
151
- try:
152
- self.txt=os.popen('%s'%(cmd)).read()
153
- except:
154
- self.txt='error !'
155
- self.sendUPDATE()
156
-
157
- def readout(self):
158
- time.sleep(1)
159
- fout=open('stdout.txt','r')
160
- ferr=open('stderr.txt','r')
161
- lout = fout.readlines()
162
- out = ' '.join(lout)
163
- lerr = ferr.readlines()
164
- err = ' '.join(lerr)
165
- #out = out.strip()
166
- #err = err.strip()
167
- if out == '' and err == '':
168
- self.txt = 'command executed !'
169
- elif out != '' and err == '':
170
- self.txt = 'out:\n%s\n'%(out)
171
- elif out == '' and err != '':
172
- self.txt = 'err:\n%s\n'%(err)
173
- else:
174
- self.txt = 'out:\n%s\nerr:\n%s\n'%(out,err)
175
- print(self.txt)
176
- fout.close()
177
- ferr.close()
178
- tout=open('stdout.txt','w')
179
- tout.close()
180
- terr=open('stderr.txt','w')
181
- terr.close()
182
-
183
- def cmdCOM(self, context):
184
- context = self.fmtDICT(context)
185
- if context[0]!='i' and context[0]!='kill':
186
- self.fout = open('stdout.txt','w')
187
- self.ferr = open('stderr.txt','w')
188
- self.p=Popen(context,stdin=PIPE,stdout=self.fout,stderr=self.ferr,universal_newlines=True,bufsize=0)
189
- self.fout.close()
190
- self.ferr.close()
191
- elif context[0]=='kill':
192
- self.txt = 'process terminated'
193
- self.p.terminate()
194
- else:
195
- comsg = ' '.join(context[1:])
196
- self.p.stdin.write(comsg+'\n')
197
- self.readout()
198
-
199
- #out,err = self.p.communicate()
200
- #out = ' '.join(self.p.stdout)
201
- #err = ' '.join(self.p.stderr)
202
- #self.txt = "out: \n%s\n\nerr: \n%s"%(out,err)
203
- self.sendUPDATE()
204
-
205
- def EXIT(self):
206
- os.chdir(self.path)
207
- self.txt = "Thanks! I am signing off."
208
- self.sendUPDATE()
209
- time.sleep(2)
210
- self.cls()
211
- threading.Thread(target=self.shutdown).start()
212
-
213
- def shutdown(self):
214
- self.updater.stop()
215
- self.updater.is_idle = False
216
-
217
- def cls(self):
218
- for i in self.smsID:
219
- self.BOT.delete_message(chat_id=self.CHATID, message_id=i)
220
- self.smsID = []
221
-
222
- def sendUPDATE(self):
223
- self.BOT.sendChatAction(chat_id=self.CHATID, action="typing")
224
- msg = self.BOT.sendMessage(chat_id=self.CHATID, text=self.txt)
225
- self.smsID.append(msg.message_id)
84
+ async def sendUpdate(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
85
+ if len(self.txt):
86
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
87
+ msg = await context.bot.send_message(chat_id=self.CHATID, text=self.txt, parse_mode='Markdown')
88
+ self.smsID.append(msg.message_id)
226
89
 
227
90
  async def start(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
228
- msg = await context.bot.send_message(chat_id=self.CHATID, text=start_txt)
229
- self.smsID.append(msg.message_id)
91
+ self.smsID.append(update.message.message_id)
92
+ self.txt = start_txt
93
+ await self.sendUpdate(update, context)
230
94
 
231
95
  def register_to_log(self, job_name: str, log_path: str):
232
96
  self.jobs[job_name] = log_path
233
97
 
234
- async def ShowJobs(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
98
+ async def ShowJobs(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
99
+ self.smsID.append(update.message.message_id)
235
100
  jobs_file = self.home / ".data" / "JOB_status.json"
236
101
  with open(jobs_file, 'r') as ffr:
237
102
  jobs = json.load(ffr)
238
103
  self.jobs = jobs
239
104
 
240
- reply_keyboard = [[f'{job}'] for job in list(jobs.keys())]
105
+ reply_keyboard = [[f'{job}'] for job in list(self.jobs.keys())]
106
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
241
107
  msg = await update.message.reply_text("Select a job to get updates on",\
242
108
  reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True, input_field_placeholder="Select the job."\
243
109
  ),\
@@ -246,6 +112,7 @@ class ChatLogs:
246
112
  return 0
247
113
 
248
114
  async def StatJobs(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
115
+ self.smsID.append(update.message.message_id)
249
116
  job_name = update.message.text
250
117
 
251
118
  jobs_file = self.home / ".data" / "JOB_status.json"
@@ -257,15 +124,23 @@ class ChatLogs:
257
124
  logFILE = jobs[job_name]['logFILE']
258
125
  logIMAGE = jobs[job_name]['logIMAGE']
259
126
 
260
- txt = self.get_last_line(logDIR / logFILE)
261
- print(txt)
127
+ self.txt = self.get_last_line(logDIR / logFILE)
262
128
 
263
- if txt is not None:
264
- msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
265
- self.smsID.append(msg.message_id)
129
+ if self.txt is None:
130
+ self.txt = 'No updates found'
131
+ #await self.sendUpdate(update, context)
132
+ #msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
133
+ #self.smsID.append(msg.message_id)
134
+
135
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
136
+ msg = await update.message.reply_text(
137
+ self.txt, reply_markup=ReplyKeyboardRemove()
138
+ )
139
+ self.smsID.append(msg.message_id)
266
140
 
267
141
  try:
268
142
  with open(logDIR / logIMAGE, 'rb') as ffrb:
143
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
269
144
  msg = await context.bot.send_photo(chat_id=self.CHATID, photo=ffrb)
270
145
  self.smsID.append(msg.message_id)
271
146
  except:
@@ -294,10 +169,16 @@ class ChatLogs:
294
169
  return last_line.strip()
295
170
 
296
171
  async def cancel(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
297
- pass
172
+ self.smsID.append(update.message.message_id)
173
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
174
+ msg = await update.message.reply_text(
175
+ "Keyboard is refreshed!", reply_markup=ReplyKeyboardRemove()
176
+ )
177
+ self.smsID.append(msg.message_id)
178
+ return ConversationHandler.END
298
179
 
299
180
  async def EditorBabu(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
300
- print('Opening Json file in edit mode')
181
+ self.smsID.append(update.message.message_id)
301
182
  if len(context.args) == 1:
302
183
  file_path = context.args[0]
303
184
  if os.path.exists(file_path):
@@ -306,6 +187,7 @@ class ChatLogs:
306
187
  encoded_params = urllib.parse.quote(json.dumps(JsonStr))
307
188
  file_name = file_path.split('/')[-1]
308
189
  extender = f"?variables={encoded_params}&fileNAME={file_name}"
190
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
309
191
  msg = await update.message.reply_text(
310
192
  "Editor-Babu is opening the Json file.",
311
193
  reply_markup=ReplyKeyboardMarkup.from_button(
@@ -316,13 +198,14 @@ class ChatLogs:
316
198
  ),
317
199
  )
318
200
  else:
319
- txt = f"File {file_path} not Found!"
320
- msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
201
+ self.txt = f"File {file_path} not Found!"
202
+ #msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
321
203
  else:
322
- txt = "Expected a JSON file as argument. Nothing provided."
323
- msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
204
+ self.txt = "Expected a JSON file as argument. Nothing provided."
205
+ #msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
324
206
 
325
- self.smsID.append(msg.message_id)
207
+ #self.smsID.append(msg.message_id)
208
+ await self.sendUpdate(update, context)
326
209
 
327
210
  async def web_app_data(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None :
328
211
  data = json.loads(update.effective_message.web_app_data.data)
@@ -337,39 +220,66 @@ class ChatLogs:
337
220
  JSdata = {**JSdata, **data}
338
221
  with open(fileNAME, 'w') as ffw:
339
222
  json.dump(JSdata, ffw, indent=4)
340
- txt = f"edits are saved to {fileNAME}"
223
+ self.txt = f"edits are saved to {fileNAME}"
341
224
  else:
342
- txt = f"No new changes! file kept unchanged."
225
+ self.txt = f"No new changes! file kept unchanged."
343
226
 
344
- msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
345
- self.smsID.append(msg.message_id)
227
+ #msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
228
+ #self.smsID.append(msg.message_id)
229
+ await self.sendUpdate(update, context)
346
230
 
347
231
  async def commands(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
348
232
  self.smsID.append(update.message.message_id)
349
- cmd2run = ' '.join(context.args) #update.message.text.strip()
233
+ #cmd2run = ' '.join(context.args) #update.message.text.strip()
234
+ cmd2run = update.message.text.strip()
350
235
  cmd0 = cmd2run.split(' ')[0]
351
- if cmd0=='cd':
236
+ if cmd0[0]=='/':
237
+ print('It came here')
238
+ pass
239
+ elif cmd0=='cd':
352
240
  cmd1 = cmd2run[3:]
353
241
  try:
354
242
  os.chdir(cmd1)
355
- txt=os.popen('pwd').read()
243
+ self.txt=os.popen('pwd').read()
356
244
  except:
357
- txt='path not found'
245
+ self.txt='path not found'
358
246
  elif cmd0=='clear':
359
- for i in self.smsID:
360
- await context.bot.delete_message(chat_id=self.CHATID, message_id=i)
361
- self.smsID = []
362
- txt=''
247
+ self.txt="This clears the terminal screen!\nTo clear telegram screen type /clear"
363
248
  else:
364
249
  print('command: ',cmd2run)
365
250
  cmd=cmd2run
366
251
  try:
367
- txt=os.popen('%s'%(cmd)).read()
252
+ self.txt=os.popen('%s'%(cmd)).read()
368
253
  except:
369
- txt='error !'
370
- if len(txt):
371
- msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
372
- self.smsID.append(msg.message_id)
254
+ self.txt='error !'
255
+ await self.sendUpdate(update, context)
256
+ #msg = await context.bot.send_message(chat_id=self.CHATID, text=txt)
257
+ #self.smsID.append(msg.message_id)
258
+
259
+ async def ClearChat(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
260
+ self.smsID.append(update.message.message_id)
261
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
262
+ msg = await update.message.reply_text(
263
+ "Full chat history will be cleared", reply_markup=ReplyKeyboardRemove()
264
+ )
265
+ self.smsID.append(msg.message_id)
266
+ for i in self.smsID:
267
+ await context.bot.delete_message(chat_id=self.CHATID, message_id=i)
268
+
269
+ self.smsID = []
270
+ return ConversationHandler.END
271
+
272
+ async def ask2clear(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> int:
273
+ self.smsID.append(update.message.message_id)
274
+ reply_keyboard = [['Yes','No']]
275
+ print(reply_keyboard)
276
+ await context.bot.sendChatAction(chat_id=self.CHATID, action="typing")
277
+ msg = await update.message.reply_text("Entire chat history in the current session will be cleared. Proceed?",\
278
+ reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True, input_field_placeholder="Select to proceed."\
279
+ ),\
280
+ )
281
+ self.smsID.append(msg.message_id)
282
+ return 1
373
283
 
374
284
 
375
285
  class NoteLogs:
@@ -396,7 +306,7 @@ class NoteLogs:
396
306
 
397
307
  logDIR = str(_logDIR)
398
308
 
399
- self.jobNAME = jobNAME
309
+ self.jobNAME = f"JOB: {jobNAME}"
400
310
  self.logDIR = logDIR
401
311
  self.logFILE = logFILE
402
312
  self.logIMAGE = logIMAGE
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ChaterJee
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: Communicate your project updates via Telegram Bot!
5
5
  Author: Pallab Dutta
6
6
  Author-email: pallab9997@gmail.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ChaterJee
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: Communicate your project updates via Telegram Bot!
5
5
  Author: Pallab Dutta
6
6
  Author-email: pallab9997@gmail.com
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name='ChaterJee',
5
- version='0.1.8',
5
+ version='0.2.0',
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  'python-telegram-bot==20.7',
File without changes
File without changes