Бот-диетолог под слив на нутру своими руками: часть 2
Traffic Cardinal Traffic Cardinal  написал 31.08.2022

Бот-диетолог под слив на нутру своими руками: часть 2

Traffic Cardinal Traffic Cardinal  написал 31.08.2022
16 мин
0
3234
Содержание
В прошлой части мы научились создавать бота-диетолога, способного рассчитывать калорийность рациона и необходимое количество нутриентов, исходя из биологических особенностей организма, образа жизни и целей пользователя.

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

*Спойлер: ближе к концу статьи будет ссылка на файл с исходным кодом бота.

Что уже умеет бот и что мы добавим

В актуальной версии бот имеет следующий функционал:
  1. Запрашивает согласие на отказ от претензий (все же бот — не врач).
  2. Анализирует указанные пользователем биологические данные.
  3. Сопоставляет их с образом жизни и целью пользователя.
  4. Сохраняет всю эту информацию в базе данных.
  5. Выводит рекомендованную калорийность и количество нутриентов в граммах.
Текущая версия функциональности бота
Текущая версия функциональности бота

Мы же добавим к нему следующие фишки:
  1. Расчет количества грамм разных типов пищи (несколько вариантов по 4 блюда).
  2. Возможность самостоятельно добавлять продукты в меню (для владельца бота).
  3. Вывод вариантов питания пользователю.
  4. Вывод нутра-офферов.

Алгоритм составления плана питания

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

  • Есть 4 разных типов продуктов — злаки/мучное, овощи/фрукты, мясо/рыба и молочка/яйца (некоторые типы продуктов совмещены, т. к. они близки по содержанию нутриентов, а нагружать сервер отдельным типом продуктов нет смысла).
  • Каждый тип продуктов (точнее, каждое отдельно взятое блюдо) имеет разные показатели калорийности и содержания нутриентов (см. таблицу с примером ниже).
  • Все эти продукты записаны в отдельных файлах — по 4 блюда разного типа (чтобы питание было сбалансированным).
  • Бот рассчитывает нужное количество грамм каждого блюда из 4 так, чтобы пропорция сошлась с ранее рассчитанной калорийностью и количеством нутриентов, с допустимым отклонением +/- 10% (есть грамм в грамм с расчетными цифрами все равно не получится, так как в реальности даже 2 разных кусочка мяса одного и того же веса будут иметь разную пищевую ценность).
  • Если пользователя устраивает предложенное ему блюдо — ок. Если не устраивает, он может выбрать другое. В конце статьи будут варианты меню по 4 продукта, но вы всегда можете увеличить их количество без внесения изменений в код бота (достаточно будет положить текстовые файлы в папку на сервере).
Примерно так это будет видеть пользователь
Примерно так это будет видеть пользователь

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

Повторимся — очень важно не «накосячить» при создании текстовиков с меню. Впрочем, если накосячите, не страшно. Вы всегда можете просто удалить файлы с ними с сервера и перезапустить бота :)

Улучшаем бота-диетолога

Подробнее о том, как добавить Telegram бота на сервер, мы писали в прошлой статье. Подразумевается, что читатель уже умеет это. Если нет — ознакомьтесь с прошлым материалом. Сейчас же достаточно сделать следующее:

  1. Открыть файл bot.py на сервере.
  2. Удалить исходный код из прошлой части (мы специально заменим код целиком, чтобы точно не возникло каких-либо ошибок).
  3. Добавить новый вариант кода:
import telebot
import time
import os
import random
from telebot import types
from random import randint
bot = telebot.TeleBot('ТОКЕН СЮДА')

@bot.message_handler(commands=['start'])
def start(message):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Принять")
btn2 = types.KeyboardButton("Отказаться")
markup.add(btn1, btn2)
policy = open('policy.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+policy, reply_markup=markup, parse_mode="Markdown")
user_id = str(message.from_user.id)
t=0
file = open('log.txt')
for num_line, line in enumerate(file):
if user_id in line:
t=1
my_file = open('users/'+user_id+'.txt', 'w')
my_file.write("0" + '\n')
my_file.close()
break
file.close()
if(t == 0):
file = open('log.txt', 'a')
file.write(user_id + '\n')
file.close()
my_file = open('users/'+user_id+'.txt', 'w')
my_file.write("0" + '\n')
my_file.close()
@bot.message_handler(content_types=['text'])
def func(message):
time.sleep(3)
user_id = str(message.from_user.id)
my_file = open('users/'+user_id+'.txt', 'r')
num_lines = sum(1 for line in my_file)
print(num_lines)
my_file.close()
text=message.text
if(message.text == "Изменить профиль"):
my_file = open('users/'+user_id+'.txt', 'w')
my_file.write("0" + '\n')
my_file.close()
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Принять")
btn2 = types.KeyboardButton("Отказаться")
markup.add(btn1, btn2)
policy = open('policy.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+policy, reply_markup=markup, parse_mode="Markdown")
if(message.text == "Отказаться"):
my_file = open('users/'+user_id+'.txt', 'w')
my_file.write("0" + '\n')
my_file.close()
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Принять")
btn2 = types.KeyboardButton("Отказаться")
markup.add(btn1, btn2)
policy = open('policy.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+policy, reply_markup=markup, parse_mode="Markdown")
if(num_lines == 1 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Мужской")
btn2 = types.KeyboardButton("Женский")
markup.add(btn1, btn2)
bot.send_message(message.chat.id, text="Выберите ваш пол", reply_markup=markup)
if(num_lines == 2 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
markup = types.ReplyKeyboardRemove()
bot.send_message(message.chat.id, text="Выберите ваш возраст (только цифру)", reply_markup=markup)
if(num_lines == 3 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
bot.send_message(message.chat.id, text="Выберите ваш рост в сантиметрах (только цифру)")
if(num_lines == 4 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
bot.send_message(message.chat.id, text="Выберите ваш вес в киллограмах (только цифру)")
if(num_lines == 5 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Малоактивный")
btn2 = types.KeyboardButton("Среднеактивный")
btn3 = types.KeyboardButton("Активный")
btn4 = types.KeyboardButton("Очень активный")
btn5 = types.KeyboardButton("Ежедневные тренировки")
btn6 = types.KeyboardButton("До двух тренировок в день")
btn7 = types.KeyboardButton("Очень активные и тяжелые физические нагрузки ежедневно")
markup.add(btn1, btn2, btn3, btn4, btn5, btn6, btn7)
bot.send_message(message.chat.id, text="Укажите ваш образ жизни", reply_markup=markup)
if(num_lines == 6 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Экстримальное похудение")
btn2 = types.KeyboardButton("Безопасное похудение")
btn3 = types.KeyboardButton("Поддержание веса")
btn4 = types.KeyboardButton("Набор мышечной массы")
btn5 = types.KeyboardButton("Сушка ")
markup.add(btn1, btn2, btn3, btn4, btn5)
bot.send_message(message.chat.id, text="Выберите цель диеты", reply_markup=markup)
if(num_lines == 7 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Расчитать каллорийность и норму БЖУ")
markup.add(btn1)
bot.send_message(message.chat.id, text="Погнали?", reply_markup=markup)
if(num_lines == 8 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
f = open('users/'+user_id+'.txt', 'r')
fd = f.readlines()
if("Мужской" in fd[2]):
pol=5
elif("Женский" in fd[2]):
pol=-161
if("Малоактивный" in fd[6]):
fizo=1.2
elif("Среднеактивный" in fd[6]):
fizo=1.37
elif("Активный" in fd[6]):
fizo=1.45
elif("Очень активный" in fd[6]):
fizo=1.55
elif("Ежедневные тренировки" in fd[6]):
fizo=1.65
elif("До двух тренировок в день" in fd[6]):
fizo=1.725
elif("Очень активные и тяжелые физические нагрузки ежедневно" in fd[6]):
fizo=1.9
vozrast=int(fd[3])
rost=int(fd[4])
ves=int(fd[5])
summ=int(((9.99*ves+6.25*rost-4.92*vozrast+pol)*fizo))
if("Экстримальное похудение" in fd[7]):
probel=0.35
projir=0.35
prougl=0.3
ksum=0.7
elif("Безопасное похудение" in fd[7]):
probel=0.3
projir=0.3
prougl=0.4
ksum=0.8
elif("Поддержание веса" in fd[7]):
probel=0.25
projir=0.25
prougl=0.5
ksum=1
elif("Набор мышечной массы" in fd[7]):
probel=0.3
projir=0.25
prougl=0.5
ksum=1.2
elif("Сушка" in fd[7]):
probel=0.35
projir=0.25
prougl=0.40
ksum=1.1
summa=int(summ*ksum)
bel=int((probel*summa)/4)
jir=int((projir*summa)/9)
ugl=int((prougl*summa)/4)
my_file = open('users/'+user_id+'.txt', 'a')
my_file.write(str(summa) + '\n')
my_file.write(str(bel) + '\n')
my_file.write(str(jir) + '\n')
my_file.write(str(ugl) + '\n')
my_file.close()
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
btn1 = types.KeyboardButton("Выбрать диету")
btn2 = types.KeyboardButton("Изменить профиль")
markup.add(btn1, btn2)
bot.send_message(message.chat.id, text="Ваша дневная норма:\n"+str(summa)+" ккал.\n"+str(bel)+" грамм белка.\n"+str(jir)+" грамм жиров.\n"+str(ugl)+" грамм углеводов.", reply_markup=markup)
my_file.close()
if(num_lines > 0 and num_lines <= 9 and message.text != "Изменить профиль" and message.text != "Выбрать диету" and message.text != "Отказаться"):
my_file = open('users/'+user_id+'.txt', 'a')
my_file.write(text + '\n')
my_file.close()
if(num_lines == 13 and message.text == "Выбрать диету"):
markup = types.ReplyKeyboardMarkup(resize_keyboard=True)
f = open('users/'+user_id+'.txt', 'r')
fd = f.readlines()
etalon = [int(fd[8]), int(fd[9]), int(fd[10]), int(fd[11])]
prop=[0.3,0.4,0.3]
DIRI=['zavtrak', 'obed', 'ujin']
priem=['Завтрак:', 'Обед:', 'Ужин:']
for g in range(3):
etalon = [float(fd[8])*float(prop[g]), float(fd[9])*float(prop[g]), float(fd[10])*float(prop[g]), float(fd[11])*float(prop[g])]
DIR = DIRI[g]
ed=open(os.path.join(DIR, random.choice(os.listdir(DIR))), 'rt')
eda = []
i = 0
for line in ed:
lines = line.split(', ')
lst = []
for ln in lines:
ln = ln.rstrip()
if ln != '':
num = ln
lst = lst + [num]
eda = eda + [lst]
ed.close()
size=len(eda)
bludo_koef=[(1) for i in range(size)]
bludo=[([i],eda[i][0],eda[i][1]*bludo_koef[i],eda[i][2]*bludo_koef[i],eda[i][3]*bludo_koef[i],eda[i][4]*bludo_koef[i]) for i in range(size)]
for i in range(size):
summ=[0,0,0,0]
for i in range(2,6):
n=float(0)
for j in range(1,size):
n=float(n)+float(bludo[j][i])
summ[i-2]=n
test=[0,0,0,0]
for i in range(4):
test[i]=abs(100-(etalon[i]/summ[i])*100)
max_number = max(test)
num=test.index(max_number)
max_number = max_number+100
test1=round(etalon[num]/summ[num],2)
bludo_koef=[(test1) for i in range(size)]
bludo=[([i],eda[i][0],float(eda[i][1])*bludo_koef[i],float(eda[i][2])*bludo_koef[i],float(eda[i][3])*bludo_koef[i],float(eda[i][4])*bludo_koef[i]) for i in range(1,size)]
for i in range(2,6):
n=0
for j in range(4):
n=n+bludo[j][i]
summ[i-2]=n
test=[0,0,0,0]
for i in range(4):
test[i]=100-(etalon[i]/summ[i])*100
max_number = max(test)
num=test.index(max_number)
while summ[num] > etalon[num]*0.9 or summ[num] < etalon[num]*1.1:
if summ[num] < etalon[num]*1.1 and summ[num] > etalon[num]*0.9:
break
for i in range(size):
if (i==1):
bludo_koef[i]=bludo_koef[i]-0.02
if summ[num] < etalon[num]*1.1 and summ[num] > etalon[num]*0.9:
break
else:
bludo_koef[i]=bludo_koef[i]
bludo=[([i],eda[i][0],float(eda[i][1])*bludo_koef[i],float(eda[i][2])*bludo_koef[i],float(eda[i][3])*bludo_koef[i],float(eda[i][4])*bludo_koef[i]) for i in range(1,size)]
for i in range(2,6):
n=0
for j in range(4):
n=n+bludo[j][i]
summ[i-2]=n
text_menu=0
text_menu=[]
text_menu=[priem[g]+'\n']
for i in range(size-1):
text_menu.append(str(bludo[i][1])+": "+str(round(bludo_koef[i+1]*100))+"грамм")
time.sleep(5)
bot.send_message(message.chat.id, text=str('\n'.join(text_menu)), reply_markup=markup)
num_lines=None
e=randint(0, 100)
if (e>70 and "Экстримальное похудение" in fd[7]) or (e>70 and "Безопасное похудение" in fd[7]):
offer = open('offers/offer1.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+offer, reply_markup=markup, parse_mode="Markdown")
elif (e>70 and "Набор мышечной массы" in fd[7]):
offer = open('offers/offer2.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+offer, reply_markup=markup, parse_mode="Markdown")
elif (e>70 and "Сушка" in fd[7]):
offer = open('offers/offer3.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+offer, reply_markup=markup, parse_mode="Markdown")
elif (e>70 and "Поддержание веса" in fd[7]):
offer = open('offers/offer4.txt', 'r').read()
bot.send_message(message.chat.id, text="Привет, {0.first_name}! \n".format(message.from_user)+offer, reply_markup=markup, parse_mode="Markdown")
bot.polling(none_stop=True)

  1. Создать папки zavtrak, obed, ujin.
  2. Открыть блокнот, прописать в нем следующую структуру:
  • Продукт, Ка, Б, Ж, У
  • Блюдо1, 100, 1.1, 0.1, 7
  • Блюдо2, 200, 2.2, 3.5, 0.7
  • Блюдо3, 300, 18, 0.6, 1.5
  • Блюдо4, 400, 7.9, 1, 51.9
(ЭТО ЛИШЬ ПРИМЕР СТРУКТУРЫ! Разумеется, прописывать нужно реальные блюда/продукты и их пищевую ценность).

Примерно так будут выглядеть файлы с пищевой ценностью разных комбинаций блюд
Примерно так будут выглядеть файлы с пищевой ценностью разных комбинаций блюд

  1. Сохранить файл под любым именем.
  2. Загрузить его в папку zavtrak, obed или ujin (хотя бы 1 файл должен быть в каждой папке).
  3. Добавить нужно количество вариантов меню, повторяя шаги 5-7 (имена файлов должны быть разные).
  4. Создать папку offers.
  5. Открыть блокнот, прописать в нем текст оффера.
  6. Сохранить файлы под именами offer1, offer2, offer3 и offer4.
  7. Загрузить их в папку offers.
  8. Запустить бота нажатием RUN.
  9. Проверить результат.
Готово!

Результат работы — разные варианты меню
Результат работы — разные варианты меню

Результат работы — пример возможного вывода оффера по нутре
Результат работы — пример возможного вывода оффера по нутре

Подводя итоги

Теперь бот-диетолог, который мы создали в первой части гайда, стал универсальнее и с большим шансом сможет вовлечь аудиторию в воронку продаж. Надеемся, предложенный нами инструмент окажется полезен вам при заливе трафа.
ТОП партнерских программ
Год основания: 2014
Leadbit Nutra - опытная партнерская программа с 900+ офферов на ТОПовые ГЕО. Для вебмастеров представлены COD и Trials&SS офферы на любой вкус.

Ключевые особенности:
- эксклюзивные рекламодатели
- огромный выбор офферов по всему миру
- индивидуальные условия для партнеров
- дружелюбные персональные менеджеры
- программа лояльности с ценными призами
  • Вертикали: 1
  • Офферы: 76
  • Минимум: 50 $
Год основания: 2016
Официальная партнерская программа букмекерской конторы MostBet. Программа запущена в 2016 году. За это время несколько тысяч партнеров привели в Mostbet более 15 000 000 игроков со всего мира. Партнерка специализируется на онлайн-казино и беттинге, а выплаты происходят по моделям CPA и RevShare. У продукта Mostbet есть ряд важных преимуществ, которые неизменно привлекают азартных игроков и позволяют достигать высоких Retention Rate и LTV. Например, на сайте можно найти около 1300 слотов и прочих продуктов казино.

Преимущества:
- Досрочные выплаты по запросу;
- Экспертная поддержка менеджеров,
- Высокая конверсия и LTV;
- Уникальные промо-материалы и прелендинги;
- собственный трекер приложения;
- Демо-счет для игроков на любую сумму;
- Персональный промокод для привлечения игроков.
- Минимальная выплата: 50 $
- Периодичность выплат: по запросу
- Реферальная система: 0%
  • Вертикали: 1
  • Офферы: 8
  • Минимум: 50 $
Год основания: 2013
Shakes.pro — крупная партнерская сеть с 2013 года, отбирает самые выгодные nutra-офферы по всему миру (включая in-house). Является частью крупного холдинга. Забудь о бесконечном поиске офферов! Здесь тебе предлагают только то, что уже приносит реальные деньги на все страны.

Основные преимущества

Гарантированный и высокий апрув. Команда сама решит все вопросы с рекламодателями и поделится качественными промо с локализацией.
3 программы лояльности, с которыми ты будешь получать ценные призы за каждый лид.
Ежеквартальные подборки офферов с подробной аналитикой, которые успешнее других по доходам.
  • Вертикали: 1
  • Офферы: 23
  • Минимум: 3000 ₽
Год основания: 2014
Не нашли подходящий оффер? Не беда, подключим под вас

Работать можно со многими источниками трафика. Поможем со всем необходимым для работы. Наша главная цель - обеспечение комфортных и качественных условий работы как для вебмастеров, так и для рекламодателей.

Ключевые особенности:
• Family партнерка. Решим любые боли наших вебмастеров
• Индивидуальные условия работы по любым офферам. Наличие капов
• Выплаты по запросу, без выходных и праздников
• Собственный store с шикарными призами
• Выдаем прилы под iOS/android, готовые крео под залив, аудитории таргетинга
• Максимально подробная статистика, обновляемая в режиме Real-Time
• Саппорт, личный менеджер 24/7
  • Вертикали: 2
  • Офферы: 649
  • Минимум: 50 $
LGaming — это партнерская сеть в вертикали беттинг и гемблинг с более чем 1000 активными офферами от 200 рекламодателей. В партнерке доступен инхаус-продукт BetAndreas. Сеть LGaming создана командой, за плечами которой несколько лет опыта в гемблинг-вертикали CPA-сети Leadbit. Партнерская сеть предлагает проверенные креативы с высоким конвертом и рекомендации по проливу от отдела баинга. Также у компании есть собственный бренд и партнерский сервис по выдаче виртуальных карт.
  • Вертикали: 1
  • Офферы: 1000+
  • Минимум: 100 $
Комментарии
0
Написать комментарий

Здравствуйте! У вас включен блокировщик рекламы, часть сайта не будет работать!