Skip to content

Instantly share code, notes, and snippets.

@a-sakharov
Created February 3, 2023 13:35
Show Gist options
  • Select an option

  • Save a-sakharov/b6bb36b791c698daffca5099c6d565d5 to your computer and use it in GitHub Desktop.

Select an option

Save a-sakharov/b6bb36b791c698daffca5099c6d565d5 to your computer and use it in GitHub Desktop.

Revisions

  1. @aleaksah aleaksah created this gist Feb 3, 2023.
    180 changes: 180 additions & 0 deletions telegram_pills_schedule_reminder.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,180 @@
    # -*- coding: utf-8 -*-
    import asyncio
    import datetime
    import sys

    from pyrogram import Client
    import random
    from num2words import *


    # Тут надо выставить параметры соответствующие своим (https://my.telegram.org/apps). Я свои на всякий случай заменю заглушками
    API_ID = 0
    API_HASH = "000000000000000000000000000000000"


    class PillsSchedule:
    name = "" # Название препарата. Гроприносин, например
    per_time_amount = 0 # Сколько пьется за раз. Например, 2
    per_day_times = 0 # Сколько раз в день пьется. Например, 1
    total_count = 0 # Сколько единиц всего надо принять. Не сколько раз, а сколько единиц
    already_consumed = 0 # Сколько уже принято в единицах. Опять же, в единицах, а не в разах
    per_day_first_offset = 0 # Задержка в минутах от полуночи до первой дозы
    per_day_subsequent_offset = 0 # Задержка в минутах перед последующими приемами относительно предыдущего приема
    days_period = 0 # сколько дней пропускается между приемами
    days_offset = 0 # Задержка в днях перед первых приемом
    course_started = None # datetime первого приема?

    def __init__(self, name, per_time_amount=1, per_day_times=1, total_count=1, already_consumed=0, per_day_first_offset=60*8, per_day_subsequent_offset=60*4, days_period=1, days_offset=0):
    self.name = name
    self.per_time_amount = per_time_amount
    self.per_day_times = per_day_times
    self.total_count = total_count
    self.already_consumed = already_consumed
    self.per_day_first_offset = per_day_first_offset
    self.per_day_subsequent_offset = per_day_subsequent_offset
    self.days_period = days_period
    self.days_offset = days_offset


    class OneTimePills:
    name = ""
    count = 0
    total_consumed = 0
    total_count = 0

    def __init__(self, name, count, total_consumed, total_count):
    self.name = name
    self.count = count
    self.total_consumed = total_consumed
    self.total_count = total_count


    def get_right_noun(count):
    if count == 1:
    return "штука"
    elif count >=2 and count <=4:
    return "штуки"
    else:
    return "штук"


    def datetime_to_day_start(date):
    return datetime.datetime.combine(date.date(), datetime.time(0))


    def pills_array_to_time_text(pills_array, start_of_admission=datetime.datetime.today()+datetime.timedelta(days=1)): # default start_of_admission is tomorrow
    # 1. строим массив со всеми приемами (название, количество и время)
    # 2. объединяем те приемы, что имеют одно время, и генерируем текст

    if start_of_admission.second != 0 or start_of_admission.microsecond != 0:
    start_of_admission -= datetime.timedelta(seconds=start_of_admission.second, microseconds=start_of_admission.microsecond)

    times = dict()

    for pill in pills_array:
    if pill.days_offset:
    time_offset = datetime_to_day_start(start_of_admission) + datetime.timedelta(days=pill.days_offset)
    else:
    time_offset = start_of_admission

    while pill.already_consumed < pill.total_count:
    for in_day_index in range(pill.per_day_times):
    consumption_time_in_day_offset = pill.per_day_first_offset + in_day_index * pill.per_day_subsequent_offset
    consumption_datetime = datetime_to_day_start(time_offset) + datetime.timedelta(minutes=consumption_time_in_day_offset)
    if time_offset <= consumption_datetime and pill.already_consumed < pill.total_count:
    pill.already_consumed += pill.per_time_amount
    if consumption_datetime not in times:
    times[consumption_datetime] = list()
    times[consumption_datetime].append(OneTimePills(pill.name, pill.per_time_amount, pill.already_consumed, pill.total_count))
    # print("💊 Consumed {0} pills of {1} at {2} ({3}/{4})".format(pill.per_time_amount, pill.name, consumption_datetime, pill.already_consumed, pill.total_count))
    if pill.days_period:
    time_offset = datetime_to_day_start(time_offset) + datetime.timedelta(days=pill.days_period)
    else:
    time_offset = datetime_to_day_start(time_offset) + datetime.timedelta(days=1)

    result = dict()
    lang_ru_n2w = lang_RU.Num2Word_RU()
    for time in times:
    if time.hour < 12:
    text = "Доброе утро!\n"
    elif time.hour > 19:
    text = ""
    else:
    text = "Привет\n"

    text += "Сейчас тебе нужно принять следующее:\n"

    for pill in times[time]:
    text += ("💊 {0}: {1} {2}. Это будет {3} из {4}, или {5:.1f}%\n".format(pill.name, lang_ru_n2w._int2word(pill.count, True), get_right_noun(pill.count), pill.total_consumed, pill.total_count, pill.total_consumed/pill.total_count*100.))

    # Возможные поздравления.
    # Первый элемент - вес, выше - больше вероятность что выпадет
    # Второй элемент - само поздравление
    # Можно менять и удалять как нравится
    trailing_text_setup = [
    [3, ""],
    [3, "Выздоравливай!"],
    [3, "Ты справишься!"],
    [3, "Скоро будешь здоровой!"],
    [2, "Хмели сумели и ты сможешь!"],
    [2, "Выпей таблетку, чтобы показать какая ты особенная"],
    [2, "Ради Барсика!"],
    [3, "За Маму"],
    [3, "За Папу"],
    [1, "За Юлю"],
    [1, "За Настю"],
    ]

    trailing_text_final = []
    for item in trailing_text_setup:
    trailing_text_final = [*trailing_text_final, *(item[0] * [item[1]])]

    random.shuffle(trailing_text_final)

    training_text = trailing_text_final[random.randint(0, len(trailing_text_final)-1)]

    text += training_text

    if time.hour > 19:
    if text[-1] != '\n':
    text += '\n'
    text += "Спокойной ночи!"

    result[time] = text
    return result


    async def create_notifications(to, messages):
    async with Client("my_account", API_ID, API_HASH) as app:
    for date in messages:
    if date >= datetime.datetime.now():
    pass
    await app.send_message(chat_id=to, text=messages[date], schedule_date=date)


    def print_messages(messages):
    for date in messages:
    print(date)
    print(messages[date])
    print()
    print()


    # Тут настраиваются таблетосы
    pills = [
    PillsSchedule("Гроприносин", per_time_amount=2, per_day_times=3, total_count=168, already_consumed=0, per_day_first_offset=60*8, per_day_subsequent_offset=60*6, days_period=0, days_offset=0),
    PillsSchedule("Юнидокс", per_time_amount=1, per_day_times=2, total_count=20, already_consumed=0, per_day_first_offset=60*8, per_day_subsequent_offset=60*12, days_period=0, days_offset=0),
    PillsSchedule("Флуконазол 150мг", per_time_amount=1, per_day_times=1, total_count=2, already_consumed=0, per_day_first_offset=60*8, per_day_subsequent_offset=0, days_period=5, days_offset=5),
    PillsSchedule("Метрамикон форте", per_time_amount=1, per_day_times=1, total_count=7, already_consumed=0, per_day_first_offset=60*20, per_day_subsequent_offset=0, days_period=0, days_offset=0),

    PillsSchedule("Джес Плюс", per_time_amount=1, per_day_times=1, total_count=56, already_consumed=0, per_day_first_offset=60*8, per_day_subsequent_offset=0, days_period=0, days_offset=14),
    ]

    time_text = pills_array_to_time_text(pills, start_of_admission=datetime.datetime(2023, 1, 20, 18, 0, 0))
    print_messages(time_text)

    # Отправка. Для теста отправляем сами себе, иначе надо изменить 'me' на имя пользователя
    asyncio.run(create_notifications(to="me", messages=time_text))

    print("Done!")