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