def render_for_groupchat(sender, reply_to, text): ttr = 0 error = False try: t1 = time.time() png = conv.convertExpressionToPng(text, sender, str(uuid.uuid4())) ttr = time.time()-t1 upload = vk_api.upload.VkUpload(vk_session) photo = upload.photo_messages(png)[0] photo_send_kwargs = {'peer_id':reply_to, 'attachment':f'photo{photo["owner_id"]}_{photo["id"]}', 'random_id':0} opt_man = data_managers.UserOptsManager(api) cic = opt_man.get_code_in_caption(sender) tic = opt_man.get_time_in_caption(sender) if cic and tic: photo_send_kwargs.update({'message': f'{utils.get_at_spec(sender)}: {text} (rendered in {ttr} seconds)'}) elif tic: photo_send_kwargs.update({'message': f'{utils.get_at_spec(sender)}: rendered in {ttr} seconds'}) elif cic: photo_send_kwargs.update({'message': f'{utils.get_at_spec(sender)}: {text}'}) else: photo_send_kwargs.update({'message': f'{utils.get_at_spec(sender)}'}) api.messages.send(**photo_send_kwargs) opt_man.set_last_render_time(sender, time.time()) except ValueError as e: api.messages.send(peer_id=reply_to, message=f'{utils.get_at_spec(sender)}: LaTeX error:\n'+e.args[0], random_id=0) error = True except: api.messages.send(peer_id=reply_to, message='{utils.get_at_spec(sender)}: ERROR, see '+ERROR(traceback.format_exc(), sender, text), random_id=0) error = True finally: stats.record_render(sender, ttr, error) stats.delete_older_than()
def set_caption_time(val, user_id=None): if val not in list('01'): return 'Please provide a (0 for no) or (1 for yes) as parameter.' opt_man = data_managers.UserOptsManager(vkapi) opt_man.set_time_in_caption(user_id, val == '1') return 'The next renders made for you will ' + ( 'not ' if val == '0' else "") + 'have the render time as part of the image caption.'
def set_dpi(val, user_id=None): rlstore = data_managers.DisabledRateLimitStore(vkapi) max_dpi = 1200 if not rlstore[user_id] else 10000 try: val = int(val) if val not in range(20, max_dpi): raise ValueError except ValueError: return f'Please provide an integer in the range (20, {max_dpi}). The default value is 300.' opt_man = data_managers.UserOptsManager(vkapi) opt_man.set_dpi(user_id, val) return f'Your DPI has been updated to {val}'
def slash_help(*args, user_id=None): opt_man = data_managers.UserOptsManager(vkapi) cic = opt_man.get_code_in_caption(user_id) tic = opt_man.get_time_in_caption(user_id) dpi = opt_man.get_dpi(user_id) output = f'''Command list, values in <brackets> are required parameters, in [brackets] are optional: /help -- this help Preamble commands: /reset-preamble -- restore your custom preamble to the default -- use this if you get render errors on valid code /show-preamble -- show your custom preamble /add-preamble <line> -- add a line to the end of your custom preamble /delete-preamble <line-index> -- remove a line by its index from your custom preamble Settings commands (current settings are in <brackets>): /set-caption-code <{1 if cic else 0}> -- do you want to have LaTeX code in the message caption? /set-render-time <{1 if tic else 0}> -- do you want render time in the message caption? /set-dpi <{dpi}> -- set image resolution, higher is better ''' is_manager = data_managers.ManagerStore(vkapi) if is_manager[user_id]: output += f''' As a manager, you also have these commands: /ratelimit <@-user> -- enable rate-limiting for this user /unratelimit <@-user> -- disable rate-limiting for this user /getratelimit <@-user> -- check the state of rate-limiting for this user /top-by-time [how-many]-- get top users by time taken to render /top-by-renders [how-many] -- get top users by render requests /top-by-errors [how-many] -- get top users by errors during rendering /error-out -- intentionally cause an exception to test the error reporting feature ''' if user_id == OWNER_ID: output += f''' As the bot owner, you also have these commands: /promote <@-user> -- make user a manager /demote <@-user> -- stop user being a manager /get-promoted <@-user> -- check whether this user is a manager /delete-error <uuid> -- delete an error report by its uuid /delete-all-errors -- delete all error reports /show-errors [how-many] -- show a list of error reports ''' return output
def render_for_user(sender, text): error = False ttr = 0 try: t1 = time.time() png, pdf = conv.convertExpressionToPng(text, sender, str(uuid.uuid4()), returnPdf=True) ttr = time.time()-t1 upload = vk_api.upload.VkUpload(vk_session) photo = upload.photo_messages(png)[0] photo_send_kwargs = {'peer_id':sender, 'attachment':f'photo{photo["owner_id"]}_{photo["id"]}', 'random_id':0, 'message':''} opt_man = data_managers.UserOptsManager(api) cic = opt_man.get_code_in_caption(sender) tic = opt_man.get_time_in_caption(sender) if cic: photo_send_kwargs.update({'message': text}) if tic: if photo_send_kwargs['message']: photo_send_kwargs['message'] += f' (rendered in {ttr} seconds)' else: photo_send_kwargs['message'] = f'Rendered in {ttr} seconds' doc_send_kwargs = {'peer_id': sender, 'attachment': upload_doc(pdf, sender, upload), 'message': photo_send_kwargs['message'], 'random_id': 0} api.messages.send(**photo_send_kwargs) api.messages.send(**doc_send_kwargs) opt_man.set_last_render_time(sender, time.time()) except ValueError as e: api.messages.send(peer_id=sender, message='LaTeX error:\n'+e.args[0], random_id=0) error = True except: api.messages.send(peer_id=sender, message='ERROR: see '+ERROR(traceback.format_exc(), sender, text), random_id=0) error = True finally: stats.record_render(sender, ttr, error) stats.delete_older_than()
def recv_message(data): if data.get('secret') != VK_SECRET: ERROR('Request with improper secret field received!!\n\nData:\n' + str(data) + '\n\nRequest parameters:\n' + str(request)) return 'plz no hack me :(', 403 message = data['object']['message'] sender = message['from_id'] reply_to = message['peer_id'] def reply(t): vkapi.messages.send(peer_id=reply_to, message=(f'{utils.get_at_spec(sender)}: ' if sender != reply_to else '') + t, random_id=0) if 'payload' in message: payload = json.loads(bytes(message['payload'], 'utf-8')) if 'command' in payload: if payload['command'] == 'start': reply( 'Welcome to InLaTeX! To begin, type a LaTeX expression to render it, or type "/help" for a command list.' ) return if 'action' in message: if 'type' in message['action']: if message['action']['type'] == 'chat_invite_user': reply( 'This is the InLaTeX bot. To use, please @-mention me and write an expression to render (like this: "@inlatexbot $E=mc^2$").\nFor more features, enter a private chat with me and type "/help".' ) return try: text = message['text'] if not text: raise KeyError except KeyError: reply('Your message did not contain text, but it is required.') return grp_ref = re.search('\\[.*\\|.*\\] ', text) if grp_ref != None: text = text[(grp_ref.span()[1]):] if text.startswith('/'): command = text[1:].split() if command[0] in slash_commands: fun = slash_commands[command[0]] try: answer = fun(*(command[1:]), user_id=sender) if answer: reply(answer) except TypeError: reply( 'Wrong number of arguments for command, for command list type "/help".' + traceback.format_exc()) except: reply('ERROR: see ' + ERROR(traceback.format_exc(), reply_to, text)) else: reply(f'Unknown command "{command[0]}", for list type "/help".') return rlstore = data_managers.DisabledRateLimitStore(vkapi) if not rlstore[sender]: RATE_LIM_INTERVAL = 30 opt_man = data_managers.UserOptsManager(vkapi) if time.time() - opt_man.get_last_render_time( sender) < RATE_LIM_INTERVAL: # unregistered rate-limiting reply( f'It\'s been only {time.time() - opt_man.get_last_render_time(sender)}, please wait at least {RATE_LIM_INTERVAL} seconds before requesting next render' ) return workers = cel.control.inspect(timeout=0.75).ping() if workers is None: reply('''ERROR: No Celery workers responded to ping! This is a serious problem! The bot is currently unable to render images. A report has been sent to the bot's admin.''') ERROR('Celery ping failed', sender, text) return latex_celery_tasks.ERROR = ERROR if sender == reply_to: latex_celery_tasks.render_for_user.apply_async((sender, text)) else: latex_celery_tasks.render_for_groupchat.apply_async( (sender, reply_to, text))