Формат интерфейса между справочными данными и пользователем в виде телеграм бота кажется очень привлекательным в современном мире. Допустим вы хотите обеспечить своих сотрудников справочными данными, которые будут всегда под рукой. При этом хорошо бы предусмотреть возможность добавления данных в зависимости от потребностей сотрудников. Как это сделать?
Именно такую задачу предлагаю сегодня рассмотреть.
Стандартно поставим 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" и аннотацию по ним.
Мы видим, что в базе есть микросхема w25q128bv. Скорректируем наш запрос "w25q128bv".
Соглашаемся со скачиванием даташита.
Попробуем ввести отсутствующую маркировку. Например "qwert123".
В файл zayavka.txt добавлена строка с отсутствующей маркировкой. Это позволяет администратору справочника при обновлении базы добавить в базу нужные элементы.
В статье рассмотрен вариант формирования справочной системы с использованием телеграм бота. Удобство данного подхода заключается в доступности актуальной информации с использованием мессенджера, который установлен почти на всех мобильных гаджетах.
Комментарии (4)
kuzzdra
29.08.2024 22:06+2Справочник в виде программного кода на python? Ну, допустим. Как насчет загрузить туда несколько миллионов наименований? И поддерживать его в актуальном состоянии?
Dmitry740 Автор
29.08.2024 22:06В данной статье рассмотрен подход к реализации варианта организации получения справочной информации для Вашей команды. Элементная база выбрана как пример.
zorn-v100500
.env же для этого придумали. И например пакет dotenv.
Можно напрямую в ENV задавать значения (в контейнерах удобно), а можно в файлике хранить. Приоритет у реального ENV
Мне нравится подход как в symfony - в .env какие нибудь значения "по умолчанию" и файлик в репе (чтобы было видно какие вообще переменные доступны) и еще один .env.local который в .gitignore и где уже реальные прописываются. Приоритет (от меньшего к большему) .env -> .env.local -> реальный ENV