Pull to refresh

Реализация приложения для отслеживания самочувствия (Telegram bot)

Level of difficultyMedium
Reading time14 min
Views3K

Рад представить вам свой первый проект, как мне думается, достаточно интересная работа, если рассматривать её как первый pet project.

Введение

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

Целью работы является разработка приложения, которая помогает следить за самочувствием и отслеживать взаимосвязь с погодой». Для решения данной цели были поставлены следующие задачи: научиться создавать файл .csv формата, отправлять пользователю файл .csv формата, записывать информацию в созданный файл, с помощью языка python определять температуру воздуха и атмосферное давление. Также в списке задач было обязательное использование двух видов кнопок, при создании бота, callback-кнопки и кнопки в так называемом «Основное меню», которое находится в нижней части экрана на постоянной основе. Далее в списке задач было сначала приобретения навыка создания графиков, потом создания графиков на основе данных файла формата .csv, а потом было необходимо выбрать тип графика, который будет максимально просто для анализа пользователем.

В первом разделе был произведен анализ предметной области и выдвинуты основные требования к программе. Во втором разделе была описана непосредственно разработанная программа. В третьем разделе приведены скриншоты результатов.

1.  Постановка задачи

1.1. Описание предметной области

Телеграм-бот. Данный бот был создан, для того, чтобы пользователи могли следить за своим самочувствием сразу в нескольких удобных для них форматах, ведь для кого-то просто таблица с данными может быть гораздо удобней и информативней, чем построенные графики. Также Телеграм-бот поможет в целом следить за здоровьем абсолютно всем группам лиц, которым это необходимо или просто интересно, также можно следить за своим состоянием после тренировок, если Вы спортсмен. С точки зрения непосредственно работы с данным ботом, то пользователь может с ним общаться исключительно нажатием кнопок, но при большом желании может писать и сам, если пользователю что-то не понятно, то он может это всегда прочитать в инструкции.

В ходе выполнения курсовой работы я создал Телеграм-бота. Данный бот занимается тем, что принимает данные о самочувствии пользователя, хранит их в отдельном файле и когда пользователь хочет узнать отчет о своем самочувствии за последнее время, он может запросить у бота эти данные, бот ему отправит файл формата .csv в котором будут находиться данные о состоянии пользователя, за каждый из дней, в которые пользователь отправлял боту необходимую информацию, а также два графика зависимости самочувствия бота от температуры и от атмосферного давления. Сам бот очень прост в использовании, к нему прилагается очень подробная инструкция и пользоваться ботом можно исключительно нажатием кнопок, которые все подписаны. Также при использовании бота, пользователь может сделать таблицу с данными пустой и начать заполнять её заново. Данный бот очень поможет метеозависимым людям, таким как я, например, пока я создавал данного бота и тестировал его на выведение ошибок, с помощью графиков я понял, что мое самочувствие очень сильно снижается при резкой смене атмосферного давления. Все обычные пользователи могут также в результате работы с ботом выяснить, от каких изменений погоды им становится лучше или хуже и благодаря этому смогут более четко планировать, когда им лучше поехать отдыхать или наоборот получше поработать, когда им лучше подольше поспать, чтобы быть более бодрыми. Город в моем боте зафиксирован и это Санкт-Петербург.

1.2. Выбор методов, которыми можно решить задачу

Данную задачу было решено выполнять, исходя из того, чтобы пользователю было как можно удобней для него и при этом он примерно понял, как работает построение графиков для него. Исходя из этого был выбран следующий алгоритм, сделал несколько основных кнопок, который можно нажать в любой момент, чтобы выполнить ту или иную задачу, но также были созданы инлайн кнопки, которые появляются непосредственно в переписке и только в случае того, если пользователь выполняет какое-то определенное действие, это сделано для того, чтобы после выполнения этого самого действия, инлайн кнопки пропадали и больше не путали пользователя. Если обратится непосредственно к заполнению файла, то тут было сделано просто несколько функций, связанных с погодой, которые автоматически по месту положения человека определяют температуру местности, в которой он находится и атмосферное давление (на основании которых в последствии и строит графики) и, если пользователь захочет посмотреть не графики, а конкретно свое состояние по всем пунктам за определенную дату, он сможет это легко сделать, просто открыв файл формата .csv. Был выбран именно файл именно формата .csv потому что его можно открыть на любом устройстве, либо в самом формате .csv, либо в формате .xlsx, если пользователю это будет удобнее.

1.3. Выбор средств разработки

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

1.4. Требование к разрабатываемую боту

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

2. Описание разработанной программы

2.1. Описание используемых библиотек

Больше всего в данной курсовой работе использовалась библиотека pandas. С помощью данной библиотеки был создан датафрейм, в который непосредственно записываются данные пользователя, приходят в правильный порядок, высчитывается правильное самочувствие и только потом, сохраняется все это в формат файла .csv. С помощью библиотеки matplotlib были созданы графики, а благодаря библиотеки aiogram.types были созданы инлайн-кнопки, без которых интерфейс кода был бы гораздо более унылым и сам бот был бы не удобен для пользования.

2.2 Описание созданных функций

Функция start_message, когда пользователь первый раз только знакомится с ботом и первый раз заходит с ним в переписку, он нажимает на кнопку start, после чего у него создается пустая таблица и главные кнопки, все это происходит с помощью данной функции. Листинг функции start_message:

@bot.message_handler(commands=['start'])
def start_message(message):
	keyboard = telebot.types.ReplyKeyboardMarkup(True)
	keyboard.row('Прислать мне отчет', 'Ввести данные')
	keyboard.row('Сделать таблицу пустой', 'Инструкция')
	fname=message.from_user.id
	idname = str(fname) + '.csv'
	newtable(idname)
	bot.send_message(message.chat.id, 'Ура!', reply_markup=keyboard)

Функция menu_new, может возникнуть в телеграмме такая ситуация в телеграмме, что пропадает основное (нижнее) меню, тогда пользователь может выбрать /menu и с помощью данной функции меню появится снова. Данный сценарий также прописан в инструкции к боту. Листинг функции menu_new:

@bot.message_handler(commands=['menu'])
def menu_new(message):
	keyboard = telebot.types.ReplyKeyboardMarkup(True)
	keyboard.row('Прислать мне отчет', 'Ввести данные')
	keyboard.row('Сделать таблицу пустой', 'Инструкция')
	bot.send_message(message.chat.id, 'Надеюсь появилось)', reply_markup=keyboard)

Функция any_msg, данная функция обрабатывает все сообщения, которые пользователь отправляет боту (в том числе и кнопки из основного меню). Листинг функции any_msg:

@bot.message_handler(content_types=["text"])
def any_msg(message):
	fname=message.from_user.id
	global idname
	idname = str(fname) + '.csv'
	idname_photo = str(fname) + '.png'
	global b
	if message.text == 'Привет':
		bot.send_message(message.from_user.id, "Привет, " + str(message.from_user.first_name))
	elif message.text == 'Спасибо':
		bot.send_message(message.from_user.id, "Пожалуйста))))")
	elif message.text == '/help':
		bot.send_message(message.from_user.id, 'Этот бот создан для того, чтобы отслеживать твое состояние в течении дня, месяца, года.😊')
		bot.send_message(message.from_user.id,'Пункт 1.❗️\nЕсли ты в основном меню выберешь кнопку "Прислать мне отчет", то бот отправит тебе таблицу в формате .csv, которую ты заполнял за время пользования ботом и графики зависимости твоего самочувствия от температуры и погоды.🚀')
		bot.send_message(message.from_user.id,'Пункт 2.❗️\nЕсли ты в основном меню выберешь кнопку "Ввести данные", то ты сможешь отправить боту данные о своем самочувствии.😜')
		bot.send_message(message.from_user.id,'Пункт 3.❗️\nЕсли ты в основном меню выберешь кнопку "Сделать таблицу пустой", то все данные из таблицы, которые ты вносил до этого, пропадут.😀')
		bot.send_message(message.from_user.id,'Пункт 4.❗️\nЕсли ты в основном меню выберешь пункт "Инструкция", то тебе придут эти же сообщения.😂')
		bot.send_message(message.from_user.id,'Пункт 5.❗️\nЕсли хочешь начать с нуля все, то выбери /start')
		bot.send_message(message.from_user.id,'Пункт 6.❗️\nЕсли вдруг у вас пропало основное меню нажмите /menu' )
	elif message.text == 'Инструкция':
		bot.send_message(message.from_user.id, 'Этот бот создан для того, чтобы отслеживать твое состояние в течении дня, месяца, года.😊')
		bot.send_message(message.from_user.id,'Пункт 1.❗️\nЕсли ты в основном меню выберешь кнопку "Прислать мне отчет", то бот отправит тебе таблицу в формате .csv, которую ты заполнял за время пользования ботом и графики зависимости твоего самочувствия от температуры и погоды.🚀')
		bot.send_message(message.from_user.id,'Пункт 2.❗️\nЕсли ты в основном меню выберешь кнопку "Ввести данные", то ты сможешь отправить боту данные о своем самочувствии.😜')
		bot.send_message(message.from_user.id,'Пункт 3.❗️\nЕсли ты в основном меню выберешь кнопку "Сделать таблицу пустой", то все данные из таблицы, которые ты вносил до этого, пропадут.😀')
		bot.send_message(message.from_user.id,'Пункт 4.❗️\nЕсли ты в основном меню выберешь пункт "Инструкция", то тебе придут эти же сообщения.😂')
		bot.send_message(message.from_user.id,'Пункт 5.❗️\nЕсли хочешь начать с нуля все, то выбери /start')
		bot.send_message(message.from_user.id,'Пункт 6.❗️\nЕсли вдруг у вас пропало основное меню нажмите /menu' )
	elif message.text == 'Ввести данные': 
		keyboard = create_number(message)
		bot.send_message(message.from_user.id, "Если у Вас возникают какие-то вопросы, отправьте боту команду /help",reply_markup=keyboard)
	elif message.text == 'Сделать таблицу пустой':
		newtable(idname)
		bot.send_message(message.from_user.id, "Таблица стала пустой!")
	elif message.text == 'Прислать мне отчет':
		bot.send_message(message.from_user.id,'Таблица в формате .csv:')
		f = open("C:\\telegrambot\\Fails\\" + idname, "rb")
		bot.send_document(message.chat.id, f)
		schedule(idname, idname_photo)
		bot.send_message(message.from_user.id,'Зависимость самочувствия от температуры:')
		bot.send_photo(message.from_user.id, photo=open('C:\\telegrambot\\Pictures_temp\\' + idname_photo, 'rb'))
		bot.send_message(message.from_user.id,'Зависимость самочувствия от атмосферного давления:')
		bot.send_photo(message.from_user.id, photo=open('C:\\telegrambot\\Pictures_Atm.davl\\' + idname_photo, 'rb'))
	else:
		bot.send_message(message.from_user.id, 'Что-то не понятное, если есть вопросы, выбери "Инструкция" в основном меню или выбери /help')
@bot.callback_query_handler(func=lambda call: Tru

Функция resh, с помощью данной функции информация, введенная пользователем, попадает в файл. Сначала проверяется размер файла .csv формата, чтобы в одну строку не попали данные за разные дни, затем данные заносятся в файл, а вместе с ними автоматически заносятся город, время, дата и определяются температура и давление. После этого идет подсчет данных о самочувствие, на основе введенных пользователем данных, ну а в конце вся эта информация записывается в файл csv. Формата. Листинг функции resh:

def resh(a, b, idname):
	global df
	try:
		df = pd.read_csv('C:\\telegrambot\\Fails\\' + idname)
	except:
		logging.error('файл не обнаружен')
	if len(df) == 0:
		i = 0
		p = datetime.date.today()
	else:
		i = len(df)-1
		p = df.loc[i, "Data"]#откуда он находит это значение, если изначально там пусто
	if str(p) != str(datetime.date.today()):
		p = datetime.date.today()
		i = i + 1
	df.loc[i, b] = float(a)
	df.loc[i, "Data"] = datetime.date.today()
	df.loc[i, "Time"] = datetime.datetime.today().strftime("%H:%M:%S")
	df.loc[i, "City"] = 'Saint Petersburg,rus'
	df.loc[i, "Atm.davl"] = pressure()
	df.loc[i, "Temperatyra"] = float(weather())
	print('Именно значения:', df.loc[i, "Golova"], df.loc[i, "Prodyktivnost"], df.loc[i, "Bodrost"])
	print('Именно типы:', type(df.loc[i, "Golova"]), type(df.loc[i, "Prodyktivnost"]), type(df.loc[i, "Bodrost"]))
	if test(i, "Golova") and not test(i, "Prodyktivnost") and  not test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = df.loc[i, "Golova"]
	if not test(i, "Golova") and test(i, "Prodyktivnost") and  not test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = df.loc[i, "Prodyktivnost"]
	if not test(i, "Golova") and not test(i, "Prodyktivnost") and  test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = df.loc[i, "Bodrost"]
	if test(i, "Golova") and test(i, "Prodyktivnost") and  not test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = round(((df.loc[i, "Golova"]) + (df.loc[i, "Prodyktivnost"])/2),1)
	if test(i, "Golova") and not test(i, "Prodyktivnost") and  test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = round(((df.loc[i, "Golova"] + df.loc[i, "Bodrost"])/2),1)
	if not test(i, "Golova") and test(i, "Prodyktivnost") and  test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = round(((df.loc[i, "Prodyktivnost"] + df.loc[i, "Bodrost"])/2),1)
	if test(i, "Golova") and test(i, "Prodyktivnost") and  test(i, "Bodrost"):
		df.loc[i, "Samochyvstvie"] = round((((df.loc[i, "Prodyktivnost"]) + (df.loc[i, "Golova"]) + (df.loc[i, "Bodrost"]))/3),1)
	df.to_csv('C:\\telegrambot\\Fails\\' + idname, index=False)

Функция weather, данная функция при помощи определенного API определяет количество градусов в городе Санкт-Петербург, сначала в Кельвинах, но потом переводит в градусы. Листинг функции weather:

def weather():
	owm = OWM(tokens.weather)
	mgr = owm.weather_manager()
	weather = mgr.weather_at_place('Saint Petersburg,rus').weather
	temp_dict_kelvin = weather.temperature()   
	w = ((temp_dict_kelvin['temp_min']+temp_dict_kelvin['temp_max'])/2)-273.15
	return int(w)

Функция pressure, данная функция при помощи определенного API определяет атмосферное давление в городе Санкт-Петербург. Листинг функции pressure:

def pressure():
	owm = OWM(tokens.weather)
	mgr = owm.weather_manager()
	pressure_dict = mgr.weather_at_place('Saint Petersburg,rus').weather.pressure  # 'weather', not 'observation'
	return int(pressure_dict['press']*100/133.3-13)

Функция newtable, данная функция создает новую таблицу в самом начале работы пользователя с ботом, либо когда этого захочет сам пользователь. Листинг функции newtable:

def newtable(idname):
	with open("C:\\telegrambot\\Fails\\" + idname,"w",newline="") as file_writer:
		fields=['Data', 'Time', 'City', 'Samochyvstvie','Golova','Bodrost','Prodyktivnost','Atm.davl','Temperatyra']
		writer=csv.DictWriter(file_writer,fieldnames=fields)
		writer.writeheader()

Функции create_batton и create_number занимаются тем, что создают необходимые инлайн-кнопки, которые потом с остальным кодом callback_data. Листинг функций create_batton:

def create_batton(message):
	keyboard = types.InlineKeyboardMarkup()
	keyboard.add(types.InlineKeyboardButton(text="Очень плохо", callback_data="test1"))
	keyboard.add(types.InlineKeyboardButton(text="Плохо", callback_data="test2"))
	keyboard.add(types.InlineKeyboardButton(text="Нормально", callback_data="test3"))
	keyboard.add(types.InlineKeyboardButton(text="Хорошо", callback_data="test4"))
	keyboard.add(types.InlineKeyboardButton(text="Отлично", callback_data="test5"))
	bot.send_message(message.from_user.id, "Выбирайте", reply_markup=keyboard)
def create_number(message):
	keyboard = types.InlineKeyboardMarkup()
	keyboard.add(types.InlineKeyboardButton(text="Состояние головы 🧠", callback_data="test7"))
	keyboard.add(types.InlineKeyboardButton(text="Состояние бодрости🦵", callback_data="test8"))
	keyboard.add(types.InlineKeyboardButton(text="Состояние продуктивности🖊️", callback_data="test9"))
	return keyboard

Функция i_can, которая как раз принимает callback_data из функций

create_batton и create_number и обрабатывает их необходимым образом и в зависимости от того, какую кнопку нажал пользователь, бот либо сохраняет данные, либо открывает новые инлайн-кнопки. Листинг функции i_can:

def i_can(call):
	if call.message:
		global b
		fname=call.from_user.id
		idname = str(fname) + '.csv'
		if call.data == "test7":
			b = "Golova"
			create_batton(call)
		if call.data == "test8":
			b = "Bodrost"
			create_batton(call)
		if call.data == "test9":
			b = "Prodyktivnost"
			create_batton(call)
		if call.data == "test1":
			a = 1
			resh(a, b, idname)
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Спасибо, принято!")
		elif call.data == "test2":
			a = 2
			resh(a, b, idname)
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Спасибо, принято!")
		elif call.data == "test3":
			a = 3
			resh(a, b, idname)
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Спасибо, принято!")
		elif call.data == "test4":
			a = 4
			resh(a, b, idname)
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Спасибо, принято!")
		elif call.data == "test5":
			a = 5
			resh(a, b, idname)
			bot.edit_message_text(chat_id=call.message.chat.id, message_id=call.message.message_id, text="Спасибо, принято!")

Функция schedule занимается непосредственно тем, что создает 2 графика на основе данных из файла. Листинг функции schedule:

def schedule(idname, idname_photo):
	data = pd.read_csv('C:\\telegrambot\\Fails\\' + idname,sep=r'\s*,\s*', header=0, encoding='utf8', engine='python')
	data = data.sort_values('Temperatyra',ascending=True)
	data.plot(kind='scatter', x = 'Temperatyra', y = 'Samochyvstvie')
	plt.xlabel('Температура')
	plt.ylabel('Самочувствие')
	plt.title('Зависимость самочувствия от температуры')
	plt.savefig('C:\\telegrambot\\Pictures_temp\\' + idname_photo)
	data = data.sort_values('Atm.davl',ascending=True)
	data.plot(kind='scatter', x = 'Atm.davl', y = 'Samochyvstvie')
	plt.xlabel('Атмосферное давление')
	plt.ylabel('Самочувствие')
	plt.title('Зависимость самочувствия от атмосферного давления')
	plt.savefig('C:\\telegrambot\\Pictures_Atm.davl\\' + idname_photo)

3. Тестирование программы

Бот был реализован для отслеживания зависимости своего самочувствия от погоды и атмосферного давления.

Ссылка на репозиторий с кодом

Заходя в переписку с ботом, на главном экране, пользователь видит 4 основные кнопки, каждую со своим уникальным функционалом, в соответствии с рисунком 1.

Рисунок 1 — Основные кнопки
Рисунок 1 — Основные кнопки

Если пользователь первый раз пользуется ботом, то он скорее всего нажмет на кнопку «Инструкция», чтобы узнать зачем нужен этот бот и какие кнопки в какой момент надо нажимать, чтобы добиться необходимого результата в соответствии с рисунком 2.

Рисунок 2 — Кнопка «Инструкция»
Рисунок 2 — Кнопка «Инструкция»

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

Рисунок 3 — Непонятное сообщение
Рисунок 3 — Непонятное сообщение

После того, как пользователь прочитал инструкцию и во всем разобрался, он пытается занести свои данные в таблицу, нажимая на кнопку «Ввести данные». Далее он видит перед собой несколько новых инлайн-кнопок с разными темами и ему необходимо нажать на ту кнопку, о состоянии чего он хочет занести данные в таблицу в соответствии с рисунком 4. После нажатия кнопки пользователь видит еще некоторое количество инлайн-кнопок и нажатием на одну из них определяет конкретное состояние той части тела, которое было выбрано предыдущей кнопкой, после выбора непосредственно состояния данные заносятся в файл в соответствии с рисунком 5. В самом файле формата .csv автоматически определяется время сообщения с датой, а также атмосферное давление и температура в Санкт-Петербурге в соответствии с рисунком 6.

Рисунок 4 — Выбор кнопки «Ввести данные»
Рисунок 4 — Выбор кнопки «Ввести данные»
Рисунок 5 — Непосредственная оценка состояния
Рисунок 5 — Непосредственная оценка состояния
Рисунок 6 — Файл формата .csv
Рисунок 6 — Файл формата .csv

Заполняя определенное время свои данные и общаясь с ботом, пользователь может узнать отчет по своему состоянию за данный период, для этого, следуя инструкции, ему необходимо нажат на кнопку «Прислать мне отчет», после чего ему придет файл формата .csv и два графика зависимости самочувствия от температуры и от атмосферного давления в соответствии с рисунком 7.

Рисунок 7 — Кнопка «Прислать мне отчет»
Рисунок 7 — Кнопка «Прислать мне отчет»

Также, в случае если, пользователь захочет начать бот заново, заполнять новую таблицу и забыть все старые данные, он должен нажать на кнопку «Сделать таблицу пустой» и тогда файл формата .csv станет пустым и его можно будет заполнять заново в соответствии с рисунком 8.

Рисунок 8 — Пустой файл формата .csv
Рисунок 8 — Пустой файл формата .csv

Заключение

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

Стоит отметить, что приложение может продуктивно использоваться на практике, так как пользователь может писать этому боту в любое время суток и независимо от того, где он находится, ведь для этого ему нужен будет только интернет и телефон.

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

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

Таким образом, основная цель работы была достигнута и все задачи успешно выполнены.

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

Tags:
Hubs:
Total votes 8: ↑3 and ↓50
Comments7

Articles