У моего сына диабет 1 типа. Перед каждой едой нужно посчитать, сколько в тарелке углеводов, перевести их в хлебные единицы (ХЕ) и уже от этого считать инсулин. Дома для этого есть весы и таблицы. В школе, в гостях и в кафе нет ни того, ни другого: смотришь на тарелку макарон с котлетой и прикидываешь на глаз.
Готовые приложения для подсчёта ХЕ существуют, но самое нужное в них — фото и штрихкод — обычно платное, а западные приложения требуют иностранную карту и не знают российских продуктов. Поэтому я решил сделать своё: бесплатное, без регистрации и с дневником, который хранится только на телефоне.
Первую версию я выложил 20 октября. За 17 дней приложение открывали примерно на 11 800 устройствах, а хотя бы раз что-то посчитали около 3 000 человек; в обычный день это около 400 человек и 800 распознанных фото. Ниже рассказываю, как всё устроено, сколько стоит и где ИИ ошибается. Код я писал не один, а вместе с ИИ-ассистентом, поэтому часть решений — компромиссы в духе «быстро и работает», о них тоже расскажу.
Что умеет приложение
Главный сценарий — фото тарелки. Модель называет блюда, оценивает вес каждой порции и углеводы, а человек видит результат как черновик: вес можно поправить, и ХЕ сразу пересчитаются. Для продуктов в упаковке есть два других пути: навести камеру на штрихкод или сфотографировать таблицу «Пищевая ценность», из которой модель достанет углеводы на 100 г. Если ни то, ни другое не подходит, остаётся поиск по справочнику примерно из 1 200 продуктов и блюд. Его основа — таблицы Скурихина–Тутельяна с усвояемыми углеводами (я оцифровал 1 052 позиции из книги и вручную сверил выборку), сырые овощи взяты из USDA.
Всё записанное попадает в дневник по приёмам пищи. Хлебную единицу можно считать как 10 или 12 г углеводов, а можно перейти в режим «в граммах углеводов» — по отзывам, так сейчас считает большинство. Недавно по просьбе пользователей появилась запись замеров сахара и введённого инсулина: всё встаёт в дневник по времени рядом с едой, и его можно отправить врачу одним файлом.
Чего в приложении нет и не будет без врача и юриста — это расчёта дозы инсулина. С ним приложение становится медицинским изделием, а ошибка в дозе опасна, поэтому Хлебка считает только углеводы и ничего не советует.
Архитектура: всё на том, что уже было
У меня уже был хостинг интернет-магазина на WordPress, и первую версию я собрал прямо на нём. Фронтенд — одна страница PWA на HTML и ванильном JS без сборщика: она работает офлайн и ставится на экран «Домой». Бэкенд — PHP-код в плагине Code Snippets с эндпоинтами WP REST API /wp-json/xe/v1/*. Данные пользователя живут только в localStorage телефона: аккаунтов нет, на сервер уходят лишь фото для распознавания (они не хранятся) и анонимные счётчики.
Звучит несерьёзно, но для старта это сэкономило дни: домен, HTTPS, бэкапы и деплой уже были. Деплой — один Python-скрипт, который собирает страницу и обновляет сниппеты через REST API.
Плата за это пришла на десятый день. Хостинг начал ругаться на превышение CPU — 154 условных процессорных единицы при лимите 70 и 64 тысячи запросов в сутки. Причина была в том, что каждое открытие страницы запускало WordPress (0,8 секунды и 214 КБ HTML), а каждое событие статистики уходило отдельным запросом. Я вынес страницу и ассеты в статические файлы, которые веб-сервер отдаёт без PHP и с нормальными ответами 304, а события стал копить на клиенте и отправлять пачкой через sendBeacon — при сворачивании, раз в 20 секунд или каждые 20 событий. Открытие страницы больше не запускает PHP вообще. Если рост продолжится, следующий шаг — отдельный небольшой VPS в России, потому что данные пользователей должны оставаться в РФ.
Распознавание: Qwen 3.6 в Yandex AI Studio
Модель — qwen3.6-35b-a3b через OpenAI-совместимый API Yandex AI Studio; я выбирал из того, что доступно в российском облаке и принимает картинки. Одна грабля стоила вечера: у Qwen 3.6 по умолчанию включено «рассуждение», и оно съедает весь max_tokens, так что в ответе приходит пустой content. Лечится параметром reasoning_effort: "none", после чего ответ приходит за 0,5–2 секунды.
Промпт требует строгий JSON со списком блюд, весом каждого в граммах, углеводами на 100 г и уверенностью. Если на фото не еда, модель возвращает пустой список, и приложение просит переснять. Углеводы на 100 г модель берёт из подсказки со справочником типовых блюд, а вес оценивает сама.
Недавно я сравнил Qwen с DeepSeek v4.1 Flash, который в той же студии теперь тоже принимает картинки.
|
|
Qwen 3.6 35B |
DeepSeek v4.1 Flash |
|---|---|---|
|
Вход, ₽ за 1 000 токенов |
0,20 (из кэша 0,05) |
0,30 (из кэша 0,075) |
|
Выход, ₽ за 1 000 токенов |
0,30 |
0,50 |
|
Время ответа на фото |
~0,5 с |
~5,5 с |
Цены взяты из нашего счёта Yandex Cloud. Flash оказался в полтора раза дороже и на порядок медленнее, поэтому я остался на Qwen. Alice AI LLM на картинки отвечала ошибкой 500 и для этой задачи не подошла.
Сколько стоит одно распознавание
Одно фото — это около 1 000 токенов. С учётом кэша промпта и поиска штрихкодов в интернете выходит примерно 0,45 ₽ за распознавание, так что семья, которая фотографирует каждый приём пищи, обходится в 60–70 ₽ в месяц. Сейчас всё приложение стоит около 300–500 ₽ в день.
Экономят несколько вещей. Результат кэшируется по хэшу фото на 30 дней, поэтому повторная отправка того же снимка не тратит токены. Есть общая база продуктов: если кто-то один раз сфотографировал этикетку товара со штрихкодом, следующий человек получит углеводы бесплатно и мгновенно. Статичная часть промпта стоит в начале, чтобы чаще попадать в кэш, — около половины входных токенов идут по цене 0,05 ₽. Наконец, лимиты на 60 распознаваний в день с одного IP и общий потолок в сутки защищают счёт от ботов. Приложение бесплатное и без рекламы, расходы пока покрывают добровольные платежи пользователей через СБП.
Штрихкоды: самая неприятная часть
Со сканером пришлось повозиться: популярная библиотека на iPhone штрихкоды не читала, поэтому сейчас там свой поток с камеры через getUserMedia и полифил BarcodeDetector на ZXing (WASM). Если камера не справилась, можно сфотографировать штрихкод, и цифры под ним прочитает та же модель.
С базами всё сложнее, потому что открытой российской базы с пищевой ценностью нет. Open Food Facts работает прямо из браузера, но российских товаров с углеводами там порядка 17 тысяч. Дальше идёт своя общая база, которая наполняется из фото этикеток, затем поиск по интернету через Yandex Search API — модель вытаскивает углеводы, только если они явно написаны на найденной странице. Если не нашлось ничего, приложение просит сфотографировать таблицу на упаковке.
За первые две недели было 1 754 поиска по штрихкоду, и в 940 случаях продукт не нашёлся — это 54 %. Хвост очень длинный: из 762 ненайденных кодов 621 искали ровно один раз, так что краудсорсингом это не закрыть, нужен большой источник. Я спрашивал Национальный каталог («Честный знак»): их API отдаёт пищевую ценность только владельцу карточки товара, для стороннего приложения такого метода нет. Если вы знаете, у кого в России есть база «штрихкод → пищевая ценность» с адекватными условиями, напишите в комментариях.
Где ИИ ошибается: вес порции
После каждой оценки тарелки человек может поправить вес, и эти поправки анонимно копятся. За две недели их набралось 235, и вывод получился неожиданным. Углеводы на 100 г модель называет хорошо — медианная разница с поправкой равна нулю. А вот вес порции она завышает: люди уменьшали вес в 142 случаях и увеличивали в 62, а медиана отношения «вес пользователя / вес модели» — 0,75.
Для диабета это ровно та ошибка, которая опасна: завышенные углеводы означают лишний инсулин и риск гипогликемии. Поэтому оценка по фото всегда показывается как черновик с весом, который легко поправить, а частые поправки по типовым блюдам подмешиваются в промпт. На открытом наборе Nutrition5k средняя ошибка сейчас около 1 ХЕ на тарелку, но это американская столовая еда, и подгонять модель под неё дальше нельзя. Следующий шаг — свой набор домашних тарелок, сфотографированных и взвешенных. Ещё думаю, как калибровать вес по размеру тарелки, по приборам в кадре или по предмету известного размера рядом.
Android без Google Play
Приложение в RuStore — это TWA (Trusted Web Activity), обёртка над сайтом, собранная через PWABuilder. Плюс оказался неожиданно большим: любые изменения сайта сразу приходят всем, кто поставил приложение, без новой версии и модерации. Я пробовал перейти на Capacitor, чтобы встроить SDK аналитики установок, но нашёл ловушку ещё до публикации: у нативной сборки localStorage WebView живёт на другом origin, и при обновлении у людей пропал бы весь дневник. Поэтому остался на TWA. На iPhone Хлебка ставится как PWA через Safari («На экран Домой»), потому что подтвердить аккаунт разработчика Apple из России не получилось.
Что получилось и что дальше
За 17 дней приложение открывали примерно на 11 800 устройствах. Хотя бы раз что-то посчитали около 3 000 человек, за последнюю неделю — 2 240. На следующий день возвращаются около 15 % новых пользователей, в течение недели — около 10 %, и над этим ещё работать.
Две вещи я бы сказал себе в начале. Первая: ИИ на фото — это черновик, а не ответ, и самой ценной функцией оказалось не распознавание, а лёгкая поправка и сбор этих поправок. Вторая: скучная инфраструктура — это нормально. WordPress, статические файлы и один скрипт деплоя выдержали первые десять тысяч устройств, а узким местом оказались не технологии, а данные — штрихкоды и вес порций.
Приложение: хлебка.рф. Буду рад критике: что улучшить в распознавании, где взять базу штрихкодов и как вы бы калибровали вес порции по фото.
Автор: Hlebka-8


