class AssisBot: def __init__(self): config = ConfigObj(fileInit) self.Listen = False self.IA = AssisIA() self.apikey = config['bot']['apikey'] self.name = config['bot']['name'] self.adminChatId = config['bot']['adminChatId'] self.updatesDelay = float(config['bot']['delay']) self.Telegram = TelegramBot(self.apikey) self.Telegram.update_bot_info().wait() self.ListenerUsers = threading.Thread(target=self.listeningUser, daemon=True) def changeApiKey(self, apikey): self.Telegram = TelegramBot(apikey) self.Telegram.update_bot_info().wait() def startToListen(self): self.Listen = True if (not self.ListenerUsers.is_alive()): self.ListenerUsers.start() logging.info('Corriendo programa: ' + str(self.ListenerUsers.is_alive())) def stopToListen(self): if self.ListenerUsers.is_alive(): self.Listen = False logging.info('Deja de escuchar') else: logging.info("No hay programa que detener") def listeningUser(self): logging.info("Inicio subproceso de escucha") updates = self.Telegram.get_updates().wait() last_updateId = (updates[-1].update_id) if (len(updates) > 0) else 0 while True: try: updates = self.Telegram.get_updates(offset=last_updateId + 1, timeout=100).wait() logging.info("Updates: " + str(len(updates))) if len(updates) > 0: if self.Listen: #debería responder? (Es una bandera) res = self.IA.getResponse(updates[0]) if (res['Options'] == False): self.Telegram.send_message( updates[0].message.chat.id, res['Text']).wait() if (res['Image']): fp = open(res['ImagePath'], 'rb') file_info = InputFileInfo( 'NOCData.png', fp, 'image/png') chart = InputFile('photo', file_info) self.Telegram.send_photo( updates[0].message.chat.id, photo=chart).wait() if (res['Document']): doc = open(res['DocumentPath'], 'rb') file_info = InputFileInfo( 'Details.csv', doc, 'csv') document = InputFile('document', file_info) self.Telegram.send_document( updates[0].message.chat.id, document=document).wait() else: keyboard = res['Options'] reply_markup = ReplyKeyboardMarkup.create(keyboard) msg = 'Seleccione el grupo para ver los detalles' self.Telegram.send_message( updates[0].message.chat.id, msg, reply_markup=reply_markup).wait() dataLoadDelta = (datetime.now() - datetime.strptime( res['UpdateTime'], '%a %b %d %H:%M:%S %Y')) dataLoadTimeHours = dataLoadDelta.seconds / 3600 maxHours = 3 if (dataLoadTimeHours >= maxHours): msg = "Carga de Datos igual a " + str( dataLoadDelta ) + " horas. Revisar BD desactualizada" self.Telegram.send_message(self.adminChatId, msg).wait() msg = "Última actualización mayor a 02:30 horas. BD desactualizada, contactar a Administrador" self.Telegram.send_message( updates[0].message.chat.id, msg).wait() logging.info('Nuevo mensaje: ' + updates[0].message.text) last_updateId = updates[0].update_id except Exception as ex: template = "Un error del tipo {0} ha ocurrido, por favor contactar Administrador. Detalles:\n{1!r}" excepMsg = template.format(type(ex).__name__, ex.args) logging.error("Error generado en el Bot") logging.error(excepMsg) if ( type(ex).__name__ == "FileNotFoundError" ): #Error no se ha encontrado el archivo, contestar con el error self.Telegram.send_message(updates[0].message.chat.id, excepMsg).wait() self.Telegram.send_message(self.adminChatId, excepMsg).wait() last_updateId = updates[0].update_id time.sleep(10)
class CloudLog(object): """ Lets you duplicate console logs in a locally stored file, folder on Dropbox and receive updates in a Telegram chat. """ def __init__(self, root_path, dropbox_token=None, telegram_token=None, telegram_chat_id=None): """ Initialises a new logger instance. Parameters ---------- root_path : Local log root path. dropbox_token : Dropbox access token. telegram_token : Telegram Bot API access token. telegram_chat_id : Telegram chat ID. """ self.telegram_chat_id = int(telegram_chat_id) if telegram_chat_id is not None else None self.cloud_log_writer = dropbox.Dropbox(dropbox_token) if dropbox_token is not None else None self.notification_bot = TelegramBot(telegram_token) if telegram_token is not None else None self.log_file = time.strftime('%Y-%m-%d_%H-%M-%S') + '_log.txt' self.root = root_path os.makedirs(root_path, exist_ok=True) def __call__(self, string): """ Logs the value to console and appends the same string to the log file. Parameters ---------- string : string Value to be logged. """ print(string) with open(os.path.join(self.root, self.log_file), 'a') as file: file.write(string + '\n') def add_plot(self, notify=False, caption=None): """ Saves current `pyplot` plot as a .png, uploads it to Dropbox and optionally notifies via Telegram chat. Parameters ---------- notify : Flag indicating if we need to send a Telegram notification. caption : Optional plot caption. """ plot_file = time.strftime('%Y-%m-%d_%H-%M-%S') + '.png' plot_path = os.path.join(self.root, plot_file) pyplot.savefig(plot_path) self.cloud_upload_plot(plot_file) if notify: self.bot_send_plot(plot_file, caption) def sync(self, notify=False, message=None): """ Synchronises local log with Dropbox. Parameters ---------- notify : Flag indicating if we need to send a Telegram notification. message : Optional notification message. """ self.cloud_sync_log() if notify: self.bot_send_message(message) self.bot_send_log() # Dropbox routines def cloud_sync_log(self): """ Syncs local log with the one in Dropbox App's folder (e.g. overwrtites it). """ if self.cloud_log_writer is None: return with open(os.path.join(self.root, self.log_file), 'rb') as file: try: self.cloud_log_writer.files_upload( file.read(), '/' + self.log_file, mode=dropbox.files.WriteMode('overwrite', None) ) except Exception as e: self('Failed to sync log: ' + str(e)) pass def cloud_upload_plot(self, filename): """ Uploads plot to Dropbox app's folder. Parameters ---------- filename : Plot filename or relative path. """ if self.cloud_log_writer is None: return plot_path = os.path.join(self.root, filename) with open(plot_path, 'rb') as file: try: self.cloud_log_writer.files_upload( file.read(), '/' + filename, mode=dropbox.files.WriteMode('overwrite', None) ) except Exception as e: self('Failed to upload plot: ' + str(e)) pass # Telegram routines def bot_send_message(self, message, mode="Markdown"): """ Sends a text message to default Telegram chat. Parameters ---------- message : Message to send. mode : Message parsing mode. Defaults to `Markdown`. """ if self.notification_bot is None or self.telegram_chat_id is None: return try: self.notification_bot.send_message( self.telegram_chat_id, message, parse_mode=mode ).wait() except Exception as e: self('Failed to send notification: ' + str(e)) pass def bot_send_plot(self, filename, caption=None): """ Sends plot saved as `filename` to default Telegram chat with optional caption. Parameters ---------- filename : Plot filename or path relative to current directory. caption : Optional plot caption. """ if self.notification_bot is None or self.telegram_chat_id is None: return plot_path = os.path.join(self.root, filename) with open(plot_path, 'rb') as file: try: self.notification_bot.send_photo( self.telegram_chat_id, InputFile('photo', InputFileInfo(filename, file, 'image/png')), caption=caption, disable_notification=True ).wait() except Exception as e: self('Failed to send plot: ' + str(e)) pass def bot_send_log(self): """ Sends current log file to default Telegram chat. Does not notify the user about this message, send a separate message if you want the notification to hit user's device. """ if self.notification_bot is None or self.telegram_chat_id is None: return with open(os.path.join(self.root, self.log_file), 'rb') as file: try: self.notification_bot.send_document( self.telegram_chat_id, InputFile('document', InputFileInfo(self.log_file, file, 'text/plain')), disable_notification=True ).wait() except Exception as e: self('Failed to send log: ' + str(e)) pass