Симулятор инсулиновой помпы в формате телеграмм бота

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

Главная цель разработки — тренажер подборки настроек инсулинотерапии с обратной реакцией в виде значения глюкозы.

Для навигации в боте разработано меню, представленное ниже

Меню

Меню

Первой задачей является разработка генератора пациентов. Генерить эти данные с помощью генератора случайных чисел, идея конечно рабочая, но она отдаляет от реальности. Ведь в медицине давно сформированы соотношения всех взаимосвязанных параметров, которые характеризуют пациента: возраст, вес, суточная доза инсулина, УК (углеводный коэффициент), ФЧИ (фактор чувствительности к инсулину), БП (базальный профиль/ базальная скорость). Воспользуемся известными соотношениями и научим будущего бота генерить пациентов с «адекватными» параметрами. Ниже представлен код модуля формирования пациента.

 if call.data == "btn_new"  and chet == 0: # Обработка нажатия inline кнопки для вывода списка продуктов

        users[call.from_user.id]['uk_et'] = 0
        users[call.from_user.id]['phi_et'] = 0
        users[call.from_user.id]['bp_et'] = 0
        users[call.from_user.id]['uk'] = 0
        users[call.from_user.id]['phi'] = 0
        users[call.from_user.id]['bp'] = 0
        users[call.from_user.id]['mode'] = 0
        users[call.from_user.id]['chas'] = 0
        users[call.from_user.id]['summ_gluk'] = 5.5
        users[call.from_user.id]['N_gluk'] = 1
        users[call.from_user.id]['gluk_tek'] = 5.5
        users[call.from_user.id]['kol_xe'] = 0
        users[call.from_user.id]['about'] = " "
        users[call.from_user.id]['insulin'] = 0  # Сброс режима

        fin_stroka = []
        fin_stroka.append("Описание пациента:")
        temp_vozr = random.randint(1, 69)
        fin_stroka.append("1.Возраст пациента [лет]: " + str(temp_vozr))
        if temp_vozr == 1:
            temp_ves = 10 + random.randint(0, 2)
        elif temp_vozr == 2:
            temp_ves = 11 + random.randint(0, 3)
        elif temp_vozr == 3:
            temp_ves = 13 + random.randint(0, 2)
        elif temp_vozr == 4:
            temp_ves = 13 + random.randint(0, 5)
        elif temp_vozr == 5:
            temp_ves = 15 + random.randint(0, 7)
        elif temp_vozr == 6:
            temp_ves = 18 + random.randint(0, 4)
        elif temp_vozr == 7:
            temp_ves = 20 + random.randint(0, 8)
        elif temp_vozr == 8:
            temp_ves = 22 + random.randint(0, 9)
        elif temp_vozr == 9:
            temp_ves = 25 + random.randint(0, 10)
        elif temp_vozr == 10:
            temp_ves = 28 + random.randint(0, 10)
        elif temp_vozr == 11:
            temp_ves = 30 + random.randint(0, 11)
        elif temp_vozr == 12:
            temp_ves = 34 + random.randint(0, 7)
        elif temp_vozr == 13:
            temp_ves = 38 + random.randint(0, 15)
        elif temp_vozr == 14:
            temp_ves = 44 + random.randint(0, 13)
        elif temp_vozr == 15:
            temp_ves = 46 + random.randint(0, 23)
        elif temp_vozr == 16:
            temp_ves = 48 + random.randint(0, 27)
        elif temp_vozr == 17:
            temp_ves = 49 + random.randint(0, 30)
        else:
            temp_ves = 51 + random.randint(0, 48)
        fin_stroka.append("2.Вес пациента [кг]: " + str(temp_ves))

        if temp_vozr > 0 and temp_vozr <= 10:
            temp_sdi = round(temp_ves * (7 + random.randint(0, 2)) / 10, 0)
        else:
            temp_sdi = round(temp_ves * (10 + random.randint(0, 9)) / 10, 0)

        temp_staz = random.randint(0, 4)
        if temp_staz < 2:
            temp_sdi = round(temp_ves * (3 + random.randint(0, 2)) / 10, 0)
            #        bot.send_message(message.chat.id, "Стаж сахарного диабета меньше 2 лет.")
            fin_stroka.append("3.Стаж сахарного диабета меньше 2 лет.")

        else:
            fin_stroka.append("3.Стаж сахарного диабета больше 2 лет.")

        fin_stroka.append("4.Суточная доза инсулина [ЕД]: " + str(temp_sdi))
        temp_staz = random.randint(0, 4)
        if temp_staz < 2:
            temp_sdi = round(temp_sdi * 0.8)
            fin_stroka.append("5.Частые гипогликемии.")
        elif temp_staz > 1 and temp_staz < 4:
            temp_sdi = round(temp_sdi * 0.9)
            fin_stroka.append("5.Хорошие показатели глюкозы в крови, редкие гипогликемии.")
        else:
            fin_stroka.append("5.Высокие показатели глюкозы в крови.")

        # Определение БП, УК
        if temp_vozr < 7:
            users[call.from_user.id]['bp_et'] = round(temp_sdi * (30 + random.randint(0, 4)) / (100 * 24), 1)

        elif temp_vozr < 13 and temp_vozr > 6:
            users[call.from_user.id]['bp_et'] = round(temp_sdi * (35 + random.randint(0, 4)) / (100 * 24), 1)
        else:
            users[call.from_user.id]['bp_et'] = round(temp_sdi * (40 + random.randint(0, 9)) / (100 * 24), 1)

        users[call.from_user.id]['uk_et'] = round(temp_sdi * random.randint(12, 20) / (10 * temp_ves), 1)

        users[call.from_user.id]['phi_et'] = round(random.randint(100, 110) / temp_sdi, 1)

        bot.send_message(call.from_user.id, '\n'.join(fin_stroka))
        users[call.from_user.id]['about'] = fin_stroka

После выполнения данного кода, пользователю представляется описание пациента. На основании описания пользователь может определить примерные коэффициенты УК, ФЧИ и БП. Данное описание доступно на любой стадии выполнения задания при клике на кнопку «О пациенте».

Вариант описания

Вариант описания

Кнопка «Инфо», код которой представлен ниже, предназначена для вывода текущей информации о состоянии симулятора. Данная информация позволяет отслеживать изменение глюкозы, просматривать текущие настройки и значение гликированного гемоглобина за период симуляции.

Информация о состоянии симулятора

Информация о состоянии симулятора

    if call.data == "btn_info"  and chet == 0: 
        gg = round((users[call.from_user.id]['summ_gluk']*0.6302/users[call.from_user.id]['N_gluk'])+1.584, 1)
        fin_stroka = []
        fin_stroka.append("Время: " + str(users[call.from_user.id]['chas'])+":00")
        fin_stroka.append("                         ")
        fin_stroka.append("Глюкоза [мМ/л]: " + str(round(users[call.from_user.id]['gluk_tek'],1)))
        fin_stroka.append("Еда [ХЕ]: " + str(users[call.from_user.id]['kol_xe']))
        fin_stroka.append("Инсулин [ЕД]: " + str(users[call.from_user.id]['insulin']))
        fin_stroka.append("                         ")
        fin_stroka.append("Текущие настройки:")
        fin_stroka.append("БП [ЕД/ч]: " + str(users[call.from_user.id]['bp']))
        fin_stroka.append("УК [ЕД/ХЕ]: " + str(users[call.from_user.id]['uk']))
        fin_stroka.append("ФЧИ [мМ/л]: " + str(users[call.from_user.id]['phi']))
        fin_stroka.append("                         ")
        fin_stroka.append("Гликированный гемоглобин: " + str(gg))
        bot.send_message(call.message.chat.id,  '\n'.join(fin_stroka))

Кнопка «Еда» позволяет симулировать прием пищи. При этом требуется указание количества ХЕ.

    if users[message.from_user.id]['mode'] == 1:
        if is_number(message.text):
            users[message.from_user.id]['kol_xe'] = float(message.text)
            users[message.from_user.id]['mode'] = 0
            menu(message)  
        else:
            bot.send_message(message.chat.id, "Можно ввести только число")
            bot.send_message(message.chat.id, "Сколько ХЕ?")

Кнопка «Инсулин» запускает калькулятор болюса, позволяющий рассчитать количество инсулина на коррекцию и еду. Подробный расчет доступен пользователю. При этом расчет ведется в соответствии с установленными в симуляторе значениями УК, ФЧИ и БП.

Калькулятор болюса

Калькулятор болюса

    if call.data == "btn_insulin" and chet == 0:  
        if users[call.from_user.id]['uk'] != 0 and users[call.from_user.id]['bp'] != 0 and users[call.from_user.id]['phi'] != 0:
            fin_stroka = []
            fin_stroka.append("Помощник болюса:")
            eat = users[call.from_user.id]['kol_xe']*users[call.from_user.id]['uk']
            fin_stroka.append("Инсулин на еду [ЕД]: " + str(users[call.from_user.id]['kol_xe'])+" * "+str(users[call.from_user.id]['uk'])+" = "+str(round(eat, 1)))
            korr = (users[call.from_user.id]['gluk_tek']-7)/users[call.from_user.id]['phi']
            fin_stroka.append("Инсулин на коррекц. [ЕД]: (" + str(users[call.from_user.id]['gluk_tek'])+" - 7)/ "+str(users[call.from_user.id]['phi'])+" = "+str(round(korr, 1)))
            itog = eat+korr
            fin_stroka.append("Итого [ЕД]:" + str(round(eat, 1))+" + "+str(round(korr, 1))+" = "+ str(round(itog, 1)))
            bot.send_message(call.message.chat.id, '\n'.join(fin_stroka))

            bot.send_message(call.message.chat.id, "Введите количество инсулина[ЕД]")
            chet = 1  # Выбран режим работы
            bot.register_next_step_handler(call.message, btn_insulin)  # Вызов функции калькулятора болюса
        else : bot.send_message(call.message.chat.id, "Не введены УК, ФЧИ, БП.")

Кнопки УК, ФЧИ и БП предназначены для ввода соответствующих настроек симулятора.

Запуск шага симуляции осуществляется нажатием кнопки «Перемотка 2 часа». Соответствующий код представлен ниже.

    if call.data == "btn_peremotka" and chet == 0: 
        bot.send_message(call.message.chat.id, "Перемотка времени на 2 часа.")
        if users[call.from_user.id]['chas']<24:
            users[call.from_user.id]['chas'] +=2
        else:
            users[call.from_user.id]['chas'] = 0
        users[call.from_user.id]['summ_gluk'] += users[call.from_user.id]['gluk_tek']
        users[call.from_user.id]['N_gluk'] += 1
        users[call.from_user.id]['gluk_tek'] += (users[call.from_user.id]['bp_et']-users[call.from_user.id]['bp'])*2*users[call.from_user.id]['phi_et']
        users[call.from_user.id]['gluk_tek'] += ((users[call.from_user.id]['kol_xe']*users[call.from_user.id]['uk_et'])-users[call.from_user.id]['insulin'])*users[call.from_user.id]['phi_et']
        users[call.from_user.id]['kol_xe'] = 0
        users[call.from_user.id]['insulin'] = 0

После клика данной кнопки выполнится шаг симуляции и новое состояние симулятора будет доступно по клику на кнопку «Инфо».

!!! Данный бот предназначен исключительно для тестирования и определения актуальности разработки и не может использоваться для определения настроек помпы или количества инсулина без рекомендации врача!!!

На текущий момент данный бот доступен для тестирования

https://t.me/Sugarnorm_pomp_bot

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

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

© Habrahabr.ru