Справочник электронной базы в формате телеграм бота

Формат интерфейса между справочными данными и пользователем в виде телеграм бота кажется очень привлекательным в современном мире. Допустим вы хотите обеспечить своих сотрудников справочными данными, которые будут всегда под рукой. При этом хорошо бы предусмотреть возможность добавления данных в зависимости от потребностей сотрудников. Как это сделать?

Именно такую задачу предлагаю сегодня рассмотреть.

Стандартно поставим Python и PyCharm. С использованием BotFather создадим бот и получим токен. Для обеспечения защиты токена я храню его в отдельной файле secrets.py и импортирую.

from secrets import secrets 

token = secrets.get('BOT_API_TOKEN')
bot = telebot.TeleBot(token)

Создадим справочник (файл Dictionary.py), данные из которого будем по запросу выдавать пользователям. Я, для примера, сделал справочник по микросхемам памяти. Данные представляют собой набор данных: маркировка, аннотация, название файла с даташитом.

spisok=[["w25q128jv", "Последовательная Flash память на 128 Мбит с интерфейсом SPI.",  "1.pdf"],
        ["w25q128fv", "Последовательная Flash память на 128 Мбит с интерфейсом SPI.",  "2.pdf"],
        ["w25q128jw", "Последовательная Flash память на 128 Мбит с интерфейсом SPI.", "3.pdf"],
        ["w25q128bv", "Последовательная Flash память на 128 Мбит с интерфейсом SPI.", "4.pdf"],
        ["w25q128fw", "Последовательная Flash память на 128 Мбит с интерфейсом SPI.", "5.pdf"],
        ["w25q16jv",  "Последовательная Flash память на 16 Мбит с интерфейсом SPI.",  "6.pdf"],
        ["w25q32bv", "Последовательная Flash память на 32 Мбит с интерфейсом SPI.", "7.pdf"],
        ["w25q32fv", "Последовательная Flash память на 32 Мбит с интерфейсом SPI.", "8.pdf"],
        ["w25q32jv", "Последовательная Flash память на 32 Мбит с интерфейсом SPI.", "9.pdf"],
        ["w25q40ew", "Последовательная Flash память на 4 Мбит с интерфейсом SPI.", "10.pdf"],
        ["w25q64jv", "Последовательная Flash память на 64 Мбит с интерфейсом SPI.", "11.pdf"],
        ["w25x20cl", "Последовательная Flash память на 2 Мбит с интерфейсом SPI.", "12.pdf"],
        ["w9812g6kh", "Микросхема памяти SDRAM, 128 Мбит.", "14.pdf"],
        ["w25q64bv", "Последовательная Flash память на 64 Мбит с интерфейсом SPI.", "15.pdf"],
        ["w9825g6kh", "Микросхема памяти SDRAM, 256 Мбит.", "16.pdf"],
        ["w25q256jv", "Последовательная Flash память на 256 Мбит с интерфейсом SPI.", "17.pdf"],
        ["w25q80d", "Последовательная Flash память на 8 Мбит с интерфейсом SPI.", "18.pdf"],
        ["w25x40cl", "Последовательная Flash память на 4 Мбит с интерфейсом SPI.", "19.pdf"],
        ["w27c512", "Микросхема памяти EEPROM на 512 кбит.", "20.pdf"],
        ["w9864g6kh", "Микросхема памяти SDRAM, 64 Мбит.", "21.pdf"],
        ["w25q80ew", "Последовательная Flash память на 8 Мбит с интерфейсом SPI.", "22.pdf"],
        ["w25n01gv", "Последовательная Flash память на 1 Гбит с интерфейсом SPI.", "23.pdf"],
        ["w25q16jw", "Последовательная Flash память на 16 Мбит с интерфейсом SPI.", "24.pdf"],
        ["w25q20ew", "Последовательная Flash память на 2 Мбит с интерфейсом SPI.", "25.pdf"],
        ["w25q64fv", "Последовательная Flash память на 64 Мбит с интерфейсом SPI.", "26.pdf"],
        ["w25q80bv", "Последовательная Flash память на 8 Мбит с интерфейсом SPI.", "27.pdf"],
        ["w978h6kb", "Микросхема памяти SDRAM, 256 Мбит.", "28.pdf"],
        ["w978h2kb", "Микросхема памяти SDRAM, 256 Мбит.", "28.pdf"],
        ["w25q20cl", "Последовательная Flash память на 2 Мбит с интерфейсом SPI.", "29.pdf"],
        ["w25q40cl", "Последовательная Flash память на 4 Мбит с интерфейсом SPI.", "30.pdf"]]

Импортируем данный список в проект.

from Dictionary import spisok

Теперь можно приступить к разработке алгоритма работы справочной системы. Код обработки введенной строки представлен ниже.

@bot.message_handler(content_types=['text'])
def get_text_messages(message):
    global file_name
    global stroka3
    chec = 0
    stroka1 = message.text.lower()
    if message.text == "/start":
        bot.send_message(message.from_user.id, "Справочник по электронике. Введите маркировку.")
    else:
        for i in range(len(spisok)):
            #все в нижний регистр
            stroka = spisok[i][0].lower()
            fin_stroka = []
            if stroka.find(stroka1) >= 0 or stroka1.find(stroka) >= 0:
                chec += 1 # увеличиваем счетчик на 1
                file_name = spisok[i][2]
                fin_stroka.append("___"+spisok[i][0]+"___")
                fin_stroka.append(spisok[i][1])
                bot.send_message(message.chat.id, '\n'.join(fin_stroka))
        if chec == 1 :
            keyboard = types.InlineKeyboardMarkup()
            key_yes = types.InlineKeyboardButton(text='Да', callback_data='yes')
            keyboard.add(key_yes)
            key_no = types.InlineKeyboardButton(text='Нет', callback_data='no')
            keyboard.add(key_no)
            question = 'Загрузить даташит?'
            bot.send_message(message.from_user.id, text=question, reply_markup=keyboard)
        elif chec == 0:
            f = open('zayavka.txt', 'a')
            if stroka3 != stroka1:
                stroka3 = stroka1
                f.write(stroka1 + '\n')
                bot.send_message(message.from_user.id, "Данная позиция отсутствует в справочнике. Заявка на ее добавление принята.")

В ответ на стартовое сообщение пользователю выдается приглашение к вводу маркировки (строки 7,9).

В строках 10–19 осуществляется поиск введенной пользователем маркировки в импортированном списке. При этом очень важный момент заключается в том, что поиск осуществляется путем поиска введенной строки в строке из списка и наоборот (строка 14). Это позволяет найти микросхему при введении части маркировки, а также при введении избыточной для поиска маркировки (т.к. даташит рассматривает несколько вариантов по корпусам, то написанная на корпусе маркировка будет более полной).

Все найденные совпадения в виде отдельных сообщений выводятся пользователю. На основе данной информации пользователь может скорректировать свой запрос для получения конкретного даташита. В случае обнаружения одного совпадения предлагается скачать даташит (строки 20–27). Для определения необходимости скачивания пользователю выводятся кнопки «да» и «нет»

Обработка нажатий на данные кнопки в виде кода описана ниже.

@bot.callback_query_handler(func=lambda call: True)
def callback_worker(call):
    global file_name
    if call.data == "yes": #call.data это callback_data, которую мы указали при объявлении кнопки
        file = open("./Baza/"+file_name, "rb")
        bot.send_document(call.message.chat.id, file)
        bot.send_message(call.message.chat.id, "Справочник по электронике. Введите маркировку.")
    elif call.data == "no":
        bot.send_message(call.message.chat.id, "Справочник по электронике. Введите маркировку.")

Если пользователь выбирает кнопку «да», то осуществляется выгрузка даташита из каталога Baza (строки 4–7).

При начале эксплуатации данной системы пользователи будут часто сталкиваться с отсутствием данных в нашей справочной системы. Для решения данной проблемы предусмотрено сохранение запроса пользователя в случае отсутствия в базе (файл zayavka.txt).

    f = open('zayavka.txt', 'a')
            if stroka3 != stroka1:
                stroka3 = stroka1
                f.write(stroka1 + '\n')
                bot.send_message(message.from_user.id, "Данная позиция отсутствует в справочнике. Заявка на ее добавление принята.")

Полный текст основного файла представлен ниже

import telebot  # Импортируем telebot
from secrets import secrets  # Словарь с токеном из файла secrets.py
from Dictionary import spisok  # Импортируем словарь для Списка продуктов
from telebot import types  # для указания типов


# передаём значение переменной с кодом экземпляру бота
token = secrets.get('BOT_API_TOKEN')
bot = telebot.TeleBot(token)
global stroka3
stroka3 = ""

@bot.callback_query_handler(func=lambda call: True)
def callback_worker(call):
    global file_name
    if call.data == "yes": #call.data это callback_data, которую мы указали при объявлении кнопки
        file = open("./Baza/"+file_name, "rb")
        bot.send_document(call.message.chat.id, file)
        bot.send_message(call.message.chat.id, "Справочник по электронике. Введите маркировку.")
    elif call.data == "no":
        bot.send_message(call.message.chat.id, "Справочник по электронике. Введите маркировку.")

@bot.message_handler(content_types=['text'])
def get_text_messages(message):
    global file_name
    global stroka3
    chec = 0
    stroka1 = message.text.lower()
    if message.text == "/start":
        bot.send_message(message.from_user.id, "Справочник по электронике. Введите маркировку.")
    else:
        for i in range(len(spisok)):
            #все в нижний регистр
            stroka = spisok[i][0].lower()
            fin_stroka = []
            if stroka.find(stroka1) >= 0 or stroka1.find(stroka) >= 0:
                chec += 1 # увеличиваем счетчик на 1
                file_name = spisok[i][2]
                fin_stroka.append("___"+spisok[i][0]+"___")
                fin_stroka.append(spisok[i][1])
                bot.send_message(message.chat.id, '\n'.join(fin_stroka))
                #print(stroka.find(stroka1))
                #print(stroka1.find(stroka))
        if chec == 1 :
            keyboard = types.InlineKeyboardMarkup()
            key_yes = types.InlineKeyboardButton(text='Да', callback_data='yes')
            keyboard.add(key_yes)
            key_no = types.InlineKeyboardButton(text='Нет', callback_data='no')
            keyboard.add(key_no)
            question = 'Загрузить даташит?'
            bot.send_message(message.from_user.id, text=question, reply_markup=keyboard)
        elif chec == 0:
            f = open('zayavka.txt', 'a')
            if stroka3 != stroka1:
                stroka3 = stroka1
                f.write(stroka1 + '\n')
                bot.send_message(message.from_user.id, "Данная позиция отсутствует в справочнике. Заявка на ее добавление принята.")

# бесконечное выполнение кода
while True:
    try:
      bot.polling(none_stop=True, interval=0)
    except:
      continue

В строках 60–64 предусмотрено постоянное выполнение кода с учетом исключения ошибок.

Протестируем наш бот. После старта бот предлагает ввести маркировку. Введем запрос »128». Бот выдает все микросхемы в маркировке которых есть »128» и аннотацию по ним.

25df9ad8cbfbc4f60bde6de473e3a544.jpg

Мы видим, что в базе есть микросхема w25q128bv. Скорректируем наш запрос «w25q128bv».

f16cb2568f1f317f2b0359c021f1e1e8.jpg

Соглашаемся со скачиванием даташита.

afe26e82f75eea2e0b4408b864a94d9d.jpg

Попробуем ввести отсутствующую маркировку. Например «qwert123».

0ded03c28b6d3aece74185e871ab913a.jpg

В файл zayavka.txt добавлена строка с отсутствующей маркировкой. Это позволяет администратору справочника при обновлении базы добавить в базу нужные элементы.

7865e45bbb8e80cd599678b01a923378.jpg

В статье рассмотрен вариант формирования справочной системы с использованием телеграм бота. Удобство данного подхода заключается в доступности актуальной информации с использованием мессенджера, который установлен почти на всех мобильных гаджетах.

© Habrahabr.ru