def _send_answer_for_voice_input(bot: TeleBot, message: Message, telegram_token: str, yandex_key: str, botan_key: str) -> None: """Finding out answer for voice input. First of all - convert voice to text via yandex service, then searching correct answer. """ file_info = bot.get_file(message.voice.file_id) file = requests.get('https://api.telegram.org/file/bot{0}/{1}'.format(telegram_token, file_info.file_path)) try: # обращение к нашему новому модулю text: str = speech_to_text(file_in_bytes=file.content, key=yandex_key) is_answer = _send_text_answer(bot, text, message.chat.id) if not botan_track(botan_key, message.chat.id, message, 'Обработка голоса', text=text): logging.error('botan problem') except SpeechException: # Обработка случая, когда распознавание не удалось bot.send_message(message.chat.id, 'Не удалось распознать Ваш акцент') if not botan_track(botan_key, message.chat.id, message, 'Обработка голоса', 'Не распознано', text=""): logging.error('botan problem') else: if not is_answer: # Бизнес-логика bot.send_message(message.chat.id, 'Вы сказали: "{}"\nЯ не знаю, как на это реагировать :-('.format(text)) if not botan_track(botan_key, message.chat.id, message, 'Обработка голоса', 'Нет ответа', text=text): logging.error('botan problem')
def _form_max_size_archive(bot: TeleBot, max_size=40) -> str: MAXIMUM_FILE_SIZE = 5 * 1024**2 max_size *= 1024**2 cv_users = User.objects.filter(cv_file_id__ne=None) cv_users_size = cv_users.count() index = 0 archive_index = 0 is_continue = True while index < cv_users_size: current_size = 0 archive_index += 1 # make temp directory with tempfile.TemporaryDirectory(prefix="ejf_bot_") as temp_dir_path: while index < cv_users_size: if current_size + MAXIMUM_FILE_SIZE >= max_size: break # get current user cv_user = cv_users[index] # get file from telegram servers file_info = bot.get_file(file_id=cv_user.cv_file_id) file_name = cv_user.cv_file_name file_size = file_info.file_size downloaded_file = bot.download_file(file_info.file_path) # save file to temp directory temp_file_path = os.path.join(temp_dir_path, file_name) if os.path.exists(temp_file_path): file_name = f"{file_name.split('.')[0]}{index}.pdf" temp_file_path = os.path.join(temp_dir_path, file_name) with open(temp_file_path, "wb") as new_file: new_file.write(downloaded_file) # count overall size current_size += file_size # go to next user index += 1 # make archive archive_path = shutil.make_archive(f"CV_database_{archive_index}", "zip", temp_dir_path) yield archive_path
class ColorCodeBot: def __init__(self, api_key: str, lang: Mapping[str, str], theme_image_ids: tuple[str], keyboards: Mapping[str, InlineKeyboardMarkup], guesslang_syntaxes: Mapping[str, str], *args: Any, admin_chat_id: Optional[str] = None, db_path: str = str( local.path(__file__).up() / 'user_themes.sqlite'), **kwargs: Any): self.lang = lang self.theme_image_ids = theme_image_ids self.kb = keyboards self.guesslang_syntaxes = guesslang_syntaxes self.admin_chat_id = admin_chat_id self.db_path = db_path self.user_themes = KeyValue(key_field=IntegerField(primary_key=True), value_field=CharField(), database=APSWDatabase(db_path)) self.log = mk_logger() self.bot = TeleBot(api_key, *args, **kwargs) self.register_handlers() self.guesser = Guess() def register_handlers(self): self.welcome = self.bot.message_handler(commands=['start', 'help'])( self.welcome) self.browse_themes = self.bot.message_handler( commands=['theme', 'themes'])(self.browse_themes) self.mk_theme_previews = self.bot.message_handler( commands=['previews'])(self.mk_theme_previews) self.intake_snippet = self.bot.message_handler( func=lambda m: m.content_type == 'text')(self.intake_snippet) self.recv_photo = self.bot.message_handler(content_types=['photo'])( self.recv_photo) self.restore_kb = self.bot.callback_query_handler( lambda q: yload(q.data)['action'] == 'restore')(self.restore_kb) self.set_snippet_filetype = self.bot.callback_query_handler( lambda q: yload(q.data)['action'] == 'set ext')( self.set_snippet_filetype) self.set_theme = self.bot.callback_query_handler( lambda q: yload(q.data)['action'] == 'set theme')(self.set_theme) self.send_photo_elsewhere = self.bot.inline_handler( lambda q: q.query.startswith("img "))(self.send_photo_elsewhere) self.switch_from_inline = self.bot.inline_handler(lambda q: True)( self.switch_from_inline) @retry def switch_from_inline(self, inline_query: InlineQuery): self.log.msg("receiving inline query", user_id=inline_query.from_user.id, user_first_name=inline_query.from_user.first_name, query=inline_query.query) self.bot.answer_inline_query( inline_query.id, [], switch_pm_text=self.lang['switch to direct'], switch_pm_parameter='x') @retry def welcome(self, message: Message): self.log.msg("introducing myself", user_id=message.from_user.id, user_first_name=message.from_user.first_name, chat_id=message.chat.id) self.bot.reply_to( message, self.lang['welcome'], reply_markup=ForceReply( input_field_placeholder=self.lang['input field placeholder'])) @retry def mk_theme_previews(self, message: Message): if not self.admin_chat_id or str( message.chat.id) != self.admin_chat_id: self.log.msg("naughty preview attempt", user_id=message.from_user.id, user_first_name=message.from_user.first_name, chat_id=message.chat.id, admin_chat_id=self.admin_chat_id) return sample_code = dedent(""" # palinDay :: Int -> [ISO Date] def palinDay(y): '''A possibly empty list containing the palindromic date for the given year, if such a date exists. ''' s = str(y) r = s[::-1] iso = '-'.join([s, r[0:2], r[2:]]) try: datetime.strptime(iso, '%Y-%m-%d') return [iso] except ValueError: return [] """) for button in chain.from_iterable(self.kb['theme'].keyboard): theme = button.text html = mk_html(f"# {theme}{sample_code}", 'py', theme) with local.tempdir() as folder: png_path = mk_png(html, folder=folder) send_image(bot=self.bot, chat_id=message.chat.id, png_path=png_path, reply_msg_id=message.message_id) @retry def browse_themes(self, message: Message): self.log.msg("browsing themes", user_id=message.from_user.id, user_first_name=message.from_user.first_name, chat_id=message.chat.id) albums = [ self.theme_image_ids[i:i + 10] for i in range(0, len(self.theme_image_ids), 10) ] for album in albums: self.bot.send_media_group(message.chat.id, map(InputMediaPhoto, album), reply_to_message_id=message.message_id) self.bot.reply_to(message, self.lang['select theme'], reply_markup=self.kb['theme']) @retry def set_theme(self, cb_query: CallbackQuery): data = yload(cb_query.data) user = cb_query.message.reply_to_message.from_user self.log.msg("setting theme", user_id=user.id, user_first_name=user.first_name, theme=data['theme'], chat_id=cb_query.message.chat.id) self.bot.edit_message_reply_markup(cb_query.message.chat.id, cb_query.message.message_id, reply_markup=minikb('theme')) self.user_themes[user.id] = data['theme'] self.bot.answer_callback_query( cb_query.id, text=self.lang['acknowledge theme'].format(data['theme'])) if self.admin_chat_id: with open(self.db_path, 'rb') as doc: self.bot.send_document(self.admin_chat_id, doc) def guess_ext(self, code: str, probability_min: float = .12) -> Optional[str]: syntax, probability = self.guesser.probabilities(code)[0] ext = self.guesslang_syntaxes.get(syntax) self.log.msg("guessed syntax", probability_min=probability_min, probability=probability, syntax=syntax, ext=ext) if probability >= probability_min: return ext for start, ext in { '{': 'json', '---\n': 'yaml', '[[': 'toml', '[': 'ini', '<?php': 'php', '<': 'xml', '-- ': 'lua' }.items(): if code.startswith(start): return ext @retry def intake_snippet(self, message: Message): self.log.msg("receiving code", user_id=message.from_user.id, user_first_name=message.from_user.first_name, chat_id=message.chat.id) ext = self.guess_ext(message.text) if ext: kb_msg = self.bot.reply_to( message, f"{self.lang['query ext']}\n\n{self.lang['guessed syntax'].format(ext)}", reply_markup=minikb('syntax', self.lang['syntax picker']), parse_mode='Markdown', disable_web_page_preview=True) self.set_snippet_filetype(cb_query=None, query_message=kb_msg, ext=ext) else: self.bot.reply_to(message, self.lang['query ext'], reply_markup=self.kb['syntax'], parse_mode='Markdown', disable_web_page_preview=True) @retry def send_photo_elsewhere(self, inline_query: InlineQuery): file_id = inline_query.query.split('img ', 1)[-1] self.log.msg("creating inline query result", file_id=file_id, file_info=self.bot.get_file(file_id)) self.bot.answer_inline_query(inline_query.id, [ InlineQueryResultCachedPhoto( id=str(uuid4()), photo_file_id=file_id, title="Send Image") ], is_personal=True) @retry def restore_kb(self, cb_query: CallbackQuery): data = yload(cb_query.data) self.bot.edit_message_reply_markup( cb_query.message.chat.id, cb_query.message.message_id, reply_markup=self.kb[data['kb_name']]) self.bot.answer_callback_query(cb_query.id) @retry def set_snippet_filetype(self, cb_query: Optional[CallbackQuery] = None, query_message: Optional[Message] = None, ext: Optional[str] = None): if cb_query: query_message = cb_query.message ext = yload(cb_query.data)['ext'] elif not (query_message and ext): raise Exception( "Either cb_query or both query_message and ext are required") self.log.msg("colorizing code", user_id=query_message.reply_to_message.from_user.id, user_first_name=query_message.reply_to_message.from_user. first_name, syntax=ext, chat_id=query_message.chat.id) if cb_query: self.bot.edit_message_reply_markup(query_message.chat.id, query_message.message_id, reply_markup=minikb( 'syntax', self.lang['syntax picker'])) snippet = query_message.reply_to_message theme = self.user_themes.get(snippet.from_user.id, 'base16/gruvbox-dark-hard') html = mk_html(snippet.text, ext, theme) send_html(bot=self.bot, chat_id=snippet.chat.id, html=html, reply_msg_id=snippet.message_id) with local.tempdir() as folder: png_path = mk_png(html, folder=folder) did_send = False if len(snippet.text.splitlines()) <= 30: try: photo_msg = send_image(bot=self.bot, chat_id=snippet.chat.id, png_path=png_path, reply_msg_id=snippet.message_id) except ApiException as e: self.log.error("failed to send compressed image", exc_info=e, chat_id=snippet.chat.id) else: did_send = True kb_to_chat = InlineKeyboardMarkup() kb_to_chat.add( InlineKeyboardButton( self.lang['send to chat'], switch_inline_query= f"img {photo_msg.photo[-1].file_id}")) self.bot.edit_message_reply_markup(photo_msg.chat.id, photo_msg.message_id, reply_markup=kb_to_chat) if not did_send: send_image(bot=self.bot, chat_id=snippet.chat.id, png_path=png_path, reply_msg_id=snippet.message_id, compress=False) if cb_query: self.bot.answer_callback_query(cb_query.id) def recv_photo(self, message: Message): self.log.msg('received photo', file_id=message.photo[0].file_id, user_id=message.from_user.id, user_first_name=message.from_user.first_name, chat_id=message.chat.id)
class TelegramBot: def __init__(self): try: self._user_bot = TeleBot(Settings.UserBot.token) self._admin_bot = TeleBot(Settings.AdminBot.token) self._log = Logger(self._admin_bot, self._user_bot, Settings.logger_name, Settings.AdminBot.id, Settings.path_to_logs) self._statuses = Status(self._log) self._processing = Processing(self._log) self._networks = Networks(self._log, Settings.Networks.path_to_models) self._deepdream = DeepDream(self._log, self._user_bot, self._admin_bot, Settings.Photo.path, self._send_mail) self._colorize = Colorize(self._log, self._user_bot, self._admin_bot, Settings.Photo.path, self._send_mail) self._init_handlers() self._log.admin_info("Bot is running!!") self._log.info("Bot is running!!") self.start() except SystemExit: pass except BaseException as e: self._processing.stop_all() self._log.fatal("Bot is not running!!", e=e.args) def start(self): self._user_bot.polling(none_stop=True, interval=1) # local functions def _random_string(self, n): a = string.ascii_letters + string.digits return ''.join([random.choice(a) for i in range(n)]) # web functions def _send_mail(self, mess, first_photo, second_photo, msg): try: file_path_one = Settings.Photo.path + first_photo file_path_two = Settings.Photo.path + second_photo msg_root = MIMEMultipart('related') msg_root[ 'Subject'] = mess.from_user.first_name + " " + mess.from_user.last_name msg_root['From'] = Settings.Mail.username msg_root['To'] = Settings.Mail.username msg_root.preamble = 'This is a multi-part message in MIME format.' msg_alternative = MIMEMultipart('alternative') msg_root.attach(msg_alternative) msg_text = MIMEText( '<i>' + msg + '</i><br><img src="cid:image1"><img src="cid:image2"><br>', 'html') msg_alternative.attach(msg_text) fp = open(file_path_one, 'rb') msg_image_one = MIMEImage(fp.read()) fp.close() msg_image_one.add_header('Content-ID', '<image1>') msg_root.attach(msg_image_one) fp = open(file_path_two, 'rb') msg_image_two = MIMEImage(fp.read()) fp.close() msg_image_two.add_header('Content-ID', '<image2>') msg_root.attach(msg_image_two) smtp = smtplib.SMTP('smtp.mail.ru:587') smtp.ehlo() smtp.starttls() smtp.login(Settings.Mail.username, Settings.Mail.password) smtp.sendmail(Settings.Mail.username, Settings.Mail.username, msg_root.as_string()) smtp.quit() except BaseException as e: self._log.warning("Mail sending error [" + mess.from_user.id + "]") def _download_photo(self, message): try: photo_name = self._random_string(8) photo_id = message.photo[-1].file_id photo_image = self._user_bot.download_file( self._user_bot.get_file(photo_id).file_path) with open(Settings.Photo.path + photo_name + ".jpg", 'wb') as imgfile: imgfile.write(photo_image) return photo_name except BaseException as e: self._log.error( "Can`t download photo [" + message.from_user.id + "]", message.from_user.id, e.args) # handlers def _text_mess(self, message): self._user_bot.send_message(message.from_user.id, message.text) def _photo_mess(self, message): try: if self._statuses[message.from_user.id].get_status() == 0: self._user_bot.send_message(message.from_user.id, "I don't know what to do 😕") else: photo_name = self._download_photo(message) if self._statuses[message.from_user.id].get_status() == 32: self._colorize_function(message, photo_name) elif self._statuses[message.from_user.id].get_status() == 23: self._deepdream_function(message, photo_name) except BaseException as e: self._log.error("Something went wrong with photo", message.from_user.id, e.args) # handlers commands def _deepdream_command(self, message): try: keyboard = types.InlineKeyboardMarkup() for net in self._networks.get_parameterized_keys(): callback_button = types.InlineKeyboardButton( text=net, callback_data="deepdream_net_" + net) keyboard.add(callback_button) self._user_bot.send_message(message.chat.id, "Please, choose a neural network", reply_markup=keyboard) self._statuses[message.chat.id].set_status(21) except BaseException as e: self._log.error("DeepDream command error ", message.from_user.id, e.args) def _colorize_command(self, message): try: keyboard = types.InlineKeyboardMarkup() for net in self._networks.get_standart_keys(): callback_button = types.InlineKeyboardButton( text=net, callback_data="colorize_net_" + net) keyboard.add(callback_button) self._user_bot.send_message(message.chat.id, "Please, choose a neural network", reply_markup=keyboard) self._statuses[message.chat.id].set_status(31) except BaseException as e: self._log.error("Colorize command error ", message.from_user.id, e.args) def _stop_command(self): self._processing.stop_all() self._log.warning("Bot is stopped!") self._log.admin_info("Bot is stopped!") #self._user_bot.stop_polling() def _stop_process_command(self, i): self._processing.stop_process(i) def _stop_all_command(self): self._processing.stop_all() # callbacks def _deepdream_callback(self, call): try: if call.data[:14] == "deepdream_net_": if self._statuses[call.message.chat.id].get_status() == 21: self._statuses[call.message.chat.id].set_net( call.data[14:]) self._user_bot.edit_message_text( chat_id=call.message.chat.id, message_id=call.message.message_id, text=call.data[14:]) layers = self._networks.get_parameterized_net( self._statuses[ call.message.chat.id].get_net()).get_layers() keyboard = types.InlineKeyboardMarkup() for layer in layers: self._log.debug(layer) callback_button = types.InlineKeyboardButton( text=layer, callback_data="deepdream_layer_" + layer) keyboard.add(callback_button) self._user_bot.send_message(call.message.chat.id, "Please, choose layer level", reply_markup=keyboard) self._statuses[call.message.chat.id].set_status(22) elif call.data[:16] == "deepdream_layer_": if self._statuses[call.message.chat.id].get_status() == 22: self._statuses[call.message.chat.id].set_layer( str(call.data[16:]).replace(".", "/")) self._user_bot.edit_message_text( chat_id=call.message.chat.id, message_id=call.message.message_id, text=call.data[16:]) self._user_bot.send_message(call.message.chat.id, "Send your photo, please") self._statuses[call.message.chat.id].set_status(23) except BaseException as e: self._log.error("Something went wrong with callback", call.message.from_user.id, e.args) def _colorize_callback(self, call): try: if call.data[:13] == "colorize_net_": if self._statuses[call.message.chat.id].get_status() == 31: self._statuses[call.message.chat.id].set_net( call.data[13:]) self._user_bot.edit_message_text( chat_id=call.message.chat.id, message_id=call.message.message_id, text=call.data[13:]) self._user_bot.send_message(call.message.chat.id, "Send your photo, please") self._statuses[call.message.chat.id].set_status(32) except BaseException as e: self._log.error("Something went wrong with callback", call.message.from_user.id, e.args) # functional def _deepdream_function(self, message, photo_name): try: args = (message, photo_name + ".jpg", self._networks.get_parameterized_net(self._statuses[ message.from_user.id].get_net()).get_model(), self._statuses[message.from_user.id].get_layer()) self._processing.new_process(self._deepdream.start_deep_dream, args, "DeepDream", message.from_user.id) self._user_bot.send_message(message.from_user.id, "I'm working on it") self._statuses[message.from_user.id].set_status(0) except BaseException as e: self._log.error("Something went wrong with deepdream starting", message.from_user.id, e.args) def _colorize_function(self, message, photo_name): try: args = (message, photo_name + ".jpg", self._networks.get_standart_net(self._statuses[ message.from_user.id].get_net()).get_model()) self._processing.new_process(self._colorize.start_colorize, args, "Colorize", message.from_user.id) self._user_bot.send_message(message.from_user.id, "I'm working on it") self._statuses[message.from_user.id].set_status(0) except BaseException as e: self._log.error("Something went wrong with colorize starting", message.from_user.id, e.args) def _weather_function(self, message): pass # init handlers def _init_handlers(self): # admin @self._user_bot.message_handler(commands=['stopbot']) def handle_command(message): if message.from_user.id == Settings.AdminBot.id: self._stop_command() @self._user_bot.message_handler(commands=['allprocessesstop']) def handle_command(message): if message.from_user.id == Settings.AdminBot.id: self._stop_all_command() @self._user_bot.message_handler(commands=['processstop']) def handle_command(message): if message.from_user.id == Settings.AdminBot.id: self._stop_process_command(int(message.text.split()[1])) # user @self._user_bot.message_handler(commands=['weather']) def handle_command(message): self._weather_function(message) @self._user_bot.message_handler(commands=['colorize']) def handle_command(message): self._colorize_command(message) @self._user_bot.message_handler(commands=['deepdream']) def handle_command(message): self._deepdream_command(message) @self._user_bot.message_handler(content_types=['text']) def handle_text(message): self._text_mess(message) @self._user_bot.message_handler(content_types=['photo']) def handle_photo(message): self._photo_mess(message) @self._user_bot.callback_query_handler(func=lambda call: True) def callback_inline(call): if call.data[:9] == "deepdream": self._deepdream_callback(call) elif call.data[:8] == "colorize": self._colorize_callback(call)