EKT AI
Ассистент каталога ekt.kz на Go: поиск товаров, объяснение назначения, проверенные цены и остатки из EKT API, аналоги с объяснением совпавших…
О проекте
Команда: donerka house
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Доведённый продукт
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
Ассистент каталога ekt.kz на Go: поиск товаров, объяснение назначения, проверенные цены и остатки из EKT API, аналоги с объяснением совпавших характеристик, условия покупки, сертификаты, аккаунты и корзина с явным подтверждением.
Как устроено
При старте загружается локальный снимок из 40 товаров, затем в фоне синхронизируется до 1200 товаров из официального EKT API (Basic Auth) и публичных региональных страниц. Факты о цене и наличии формирует сервер с отметкой времени проверки. OpenAI gpt-4o-mini консультирует только по назначению и характеристикам и не имеет инструмента корзины, а защитный фильтр заменяет утверждения модели о цене и наличии серверными фактами. Корзина: серверное предложение со сводкой, подтверждение одноразовым токеном (10 минут, под блокировкой), повторная проверка цены и остатка, CSRF и проверка origin. Email и телефоны маскируются, реквизиты карт отфильтровываются.
Ключевые решения
- server-side fact guardrails
- one-time confirmation tokens
- incremental catalog sync
- CSRF/origin checks
- PII masking
- retry on 5xx
- attribute-based analog matching
Особенности
Глубоко проработана безопасность корзины: одноразовые токены, привязанные к снимку корзины, защита от параллельных дублей, запрет прямого POST /api/cart. Guardrail перезаписывает ответы LLM о цене и наличии серверными данными. Аналог объясняется совпавшими характеристиками и не выдаётся за подтверждённую совместимость.
Стек
Go · HTML/CSS/JavaScript · Docker · Docker Compose · OpenAI API
Модели
gpt-4o-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-400d70df-donerka-house.
README
README.mdEKT AI — ассистент для каталога ekt.kz
Прототип на Go, HTML/CSS/JavaScript и OpenAI. Находит товары EKT, объясняет назначение, показывает проверенные цены и остатки и помогает собрать локальную корзину с явным подтверждением клиента.
Запуск
Нужны Docker Desktop и Docker Compose.
git clone https://github.com/BAITC-Hacks/hack-400d70df-donerka-house.git
cd hack-400d70df-donerka-house
cp .env.example .env
# Заполните .env своими серверными ключами и выданными EKT credentials
docker compose up --build -d
docker compose ps
curl http://localhost:8080/health
Откройте localhost:8080. Без ключа OpenAI работают серверные сценарии корзины и ответы по данным товаров. Без доступа к EKT доступны локальные карточки, но добавление блокируется, если актуальные цена и остаток не проверены.
Для запуска без Docker: Go 1.21+, переменные окружения из таблицы ниже, затем go run .. Сам Go-процесс не читает файл .env; Docker Compose подставляет его автоматически.
| Переменная | Назначение |
|---|---|
OPENAI_API_KEY | Ключ для консультаций OpenAI, модель gpt-4o-mini |
EKT_API_BASE_URL | Официальный API, по умолчанию https://ekt.kz/api |
EKT_API_USERNAME, EKT_API_PASSWORD | Выданные EKT логин и пароль Basic Auth |
EKT_CATALOG_URL | Региональная публичная страница; по умолчанию https://nursultan.ekt.kz |
ACCOUNT_STORE_PATH | Файл аккаунтов; по умолчанию data/accounts.json |
PUBLIC_ORIGIN | Внешний origin за reverse proxy, например https://shop.example.kz; пустой для прямого localhost |
PORT | HTTP-порт, по умолчанию 8080 |
Ключи не передаются браузеру и не включаются в Git или Docker-образ. Basic Auth EKT авторизует каталог, а не покупателя. OpenAI-ключ не заменяет credentials EKT.
Каталог и достоверность
При старте загружаются 40 записей из data/products.json и data/products2.json; detail.json — пример детализации. В фоне сервер читает до 1200 уникальных товаров официального API и публикует готовый набор одним обновлением. Обновление страницы не добавляет позиции; запросы AI не увеличивают публичный каталог. До окончания синхронизации или при её ошибке остаётся локальный снимок.
Используются GET /api/products?page=N и GET /api/products/detail?id=... на сервере EKT, а также публичные карточки регионального сайта. Публичный каталог — снимок: его цены помечены как требующие уточнения. Чат отмечает время проверки фактов; неподтверждённые цена и наличие не подаются как актуальные.
Перед предложением добавления и повторно при подтверждении сервер запрашивает данные EKT. Неизвестная цена, неизвестный/нулевой остаток, ошибка API или превышение доступного количества блокируют добавление. Изменение цены требует нового подтверждения. Нулевое значение из EKT заменяет старое, а не сохраняет прежнюю цену или остаток. Общий остаток API явно отделён от регионального; карточки могут содержать разбивку по складам.
Фактические ответы о цене и наличии формирует сервер. Модель консультирует по назначению и характеристикам и не имеет инструмента изменения корзины. Защитная проверка заменяет ответы модели с утверждениями о цене, наличии или действиях корзины серверными фактами. Это не является гарантией отсутствия любых ошибок в свободном техническом объяснении.
Корзина: явное подтверждение
- Напишите
Добавь 2 шт 200300285_или выберите товар кнопкой «В корзину». - Сервер показывает артикул, количество, цену за единицу и сумму.
- Отправьте
да, добавьили нажмите «Подтверждаю добавление».
До шага 3 корзина не меняется. Простое «да» не подтверждает покупку. «Отмена» снимает текущий выбор. Несколько позиций можно указать через точку с запятой: Добавь 1 шт ARTICLE1; 2 шт ARTICLE2 (до четырёх строк).
Подтверждение связано с серверным выбором, действует 10 минут и потребляется один раз под блокировкой. Повторные и параллельные запросы не дублируют добавление. Текст модели не восстанавливает разрешение на изменение корзины. Устаревшая кнопка подтверждения не применяется к новому выбору.
Для удаления или очистки сначала создаётся серверное предложение, затем пользователь подтверждает диалог. Его токен действует 5 минут, связан с владельцем и снимком корзины. Если корзина изменилась, нужно новое подтверждение. Прямое добавление через POST /api/cart и удаление без токена запрещены.
Гостевая корзина переносится в аккаунт только при отмеченном согласии в форме входа. Вход и чтение корзины сами по себе не объединяют товары.
Заказы и платежи не выполняются. Этот прототип изменяет только локальную корзину помощника. Нет endpoint создания заказа, списания денег или формы ввода платёжных реквизитов.
9. Ограничения и реализованные меры
| Требование | Реализация |
|---|---|
| Не изменять корзину без явного подтверждения | Серверное предложение, точная сводка, отдельное подтверждение добавления/удаления/очистки, одноразовые токены и сроки действия |
| Не оформлять заказ без подтверждения | Оформление заказа отсутствует; добавление явно сообщает, что заказ не оформлен |
| Не сообщать недостоверные цену и наличие | Проверка источника EKT, отметка времени, блокировка непроверенного добавления, повторное подтверждение изменившейся цены |
| Не запрашивать/хранить платёжные данные | Нет платёжной формы; запрет в инструкции модели; фильтры входа в браузере и на сервере до истории и внешних запросов, проверка ответа модели |
| Приватность | Минимальный контекст, маскирование распознаваемых email/телефона, очистка истории, ограниченное время хранения, private API без браузерного кэширования |
| Защита корзины и аккаунта | Зарегистрированные случайные сессии, HttpOnly/SameSite cookies, Secure на HTTPS, CSRF-токен и проверка origin для всех изменяющих запросов |
| Объяснимость аналогов | В карточке перечислены совпавшие свойства или слова названия; сходство по названию не объявляется технической совместимостью |
| Совместимость с платформой | Отдельный сервис с JSON API, серверный EKT Basic Auth, относительные URL фронтенда, размещение на одном origin через reverse proxy |
| Десктоп и мобильный | Адаптивные каталог/чат/вход/корзина, видимая мобильная корзина, прокрутка в ограниченной высоте, кнопки подтверждения и удаления |
Объяснение аналога строится из данных: например, «совпадают характеристики: Полюсов=3, Ток=80 A». Наличие само по себе не делает товар аналогом. Перед технической заменой нужно проверить все необходимые параметры по документации производителя; алгоритм не сертифицирует совместимость.
Приватность и хранение
- История: последние 12 сообщений, только в памяти. Через 30 минут бездействия она удаляется плановой очисткой (раз в минуту). «Очистить» и выход из аккаунта удаляют соответствующую историю.
- Сессии: случайные серверные идентификаторы, срок 24 часа. Произвольная гостевая cookie, включая идентификатор аккаунта, не даёт доступ к чужой корзине.
- Корзины: в памяти сервера. Гостевые корзины очищаются по окончании сессии; аккаунтные — при перезапуске или подтверждённой очистке пользователем. Перезапуск сбрасывает все корзины и сессии.
- Аккаунты: имя, email, соль и хеш пароля в
data/accounts.json, доступ к файлу 0600. Этот файл исключён из Git и Docker build context. В Docker он сохраняется в локальном volume./data:/app/data. Удаление аккаунта пока выполняет администратор. - Приложение не пишет сообщения чата и тела запросов в логи. На reverse proxy также нельзя включать запись тел запросов или секретных заголовков.
- Для ответа OpenAI передаются очищенный вопрос, короткая история и контекст товаров; данные аккаунта и credentials EKT не включаются. Запрос принудительно содержит
store:false. По стандартным правилам OpenAI журналы предотвращения злоупотреблений могут сохраняться до 30 дней; локальная очистка не удаляет их. См. официальную документацию по данным OpenAI API. - Фильтры распознают длинные номера карт, типичные IBAN и подписанные CVV/PIN/SMS-коды; скрытые или необычно записанные реквизиты могут не распознаться. Это не универсальная DLP-система и не заявление о PCI DSS-сертификации. Пользовательская памятка: приватность.
HTTP API
Все изменяющие запросы требуют cookie сессии, X-CSRF-Token, Content-Type: application/json и допустимый origin. Чужой origin получает 403. Для первого запроса получите токен через GET /api/session.
| Метод | Путь | Действие |
|---|---|---|
| GET | /api/session | Создать сессию и вернуть csrf_token |
| GET | /api/catalog | Опубликованный каталог |
| POST | /api/chat | message, опционально confirmation_token от кнопки; поиск/подтверждение |
| DELETE | /api/chat | Удалить историю и ожидающий выбор |
| GET | /api/cart | Корзина текущей сессии/аккаунта |
| POST | /api/cart | 409: прямое добавление запрещено |
| POST | /api/cart/confirmation | action: remove/clear, для remove — article; получить сводку и токен |
| DELETE | /api/cart | confirmation_token; применить подтверждённое удаление |
| GET | /api/auth | Состояние аккаунта |
| POST | /api/auth | action: login/register, email, password, name; merge_cart: true только с согласием |
| DELETE | /api/auth | Выход и очистка истории аккаунта |
| GET | /health | Статус и количество опубликованных товаров |
Пример для локальной проверки (нужен jq):
csrf=$(curl -fsS -c /tmp/ekt-cookies.txt http://localhost:8080/api/session | jq -r .csrf_token)
curl -fsS -b /tmp/ekt-cookies.txt http://localhost:8080/api/chat \
-H "X-CSRF-Token: $csrf" -H 'Content-Type: application/json' \
-d '{"message":"Добавь 1 шт 200300285_"}'
# Прочитайте полученную сводку. Только если согласны:
curl -fsS -b /tmp/ekt-cookies.txt http://localhost:8080/api/chat \
-H "X-CSRF-Token: $csrf" -H 'Content-Type: application/json' \
-d '{"message":"да, добавь"}'
Интеграция с настоящим ekt.kz
Проверенная интеграция в этом проекте — чтение товаров/деталей и публичных страниц EKT. Локальный аккаунт не равен кабинету EKT; локальная корзина не синхронизируется с серверной корзиной ekt.kz.
Для production владелец платформы должен предоставить customer-auth/cart/order API и контракт идентификации покупателя. При подключении этих API необходимо сохранить серверные подтверждения, идемпотентность, проверку владельца и повторную проверку цены. Не пересылайте сервисный пароль каталога покупателям.
Сервис рассчитан на один экземпляр. Для нескольких экземпляров нужны общее хранилище сессий/корзин/подтверждений, транзакции и лимиты запросов на reverse proxy. Размещайте UI и API на одном origin, установите PUBLIC_ORIGIN и HTTPS. Сквозная совместимость с производственной платформой EKT требует проверки владельцем сайта; здесь она не заявляется как завершённая.
Проверка и структура
go test -race ./...
go vet ./...
node --check static/chat.js
docker compose up --build -d
Регрессионные тесты проверяют запрет неподтверждённых действий, подмену cookie, CSRF, одноразовость и срок подтверждения, параллельный повтор, изменение цены, сбой EKT, нулевой/неизвестный остаток, блокировку платёжных данных и обоснование аналогов.
Для ручной проверки откройте сайт на десктопе и узком мобильном экране: выберите товар, отклоните/подтвердите добавление, повторите подтверждение, отмените удаление, затем подтвердите его. Убедитесь, что отмена сохраняет корзину и кнопка корзины доступна на мобильном.
Основные файлы: main.go — сервер; handlers/chat.go и quotes.go — диалог и проверка цен; security.go — CSRF и подтверждение удаления; privacy.go — фильтры данных; conversation.go — ограниченная история и одноразовый выбор; ekt_api.go/live_catalog.go — источники EKT; static/ — адаптивный интерфейс.
Авторы коммитов
История коммитов
- 2026-09-23 17:57Enforce confirmed cart actions, verified EKT facts and privacy safeguardsDonerka House Bot
- 2026-09-23 17:39feat: publish 1200 product catalog snapshotDonerka House Bot
- 2026-09-23 17:37fix: publish catalog count after syncDonerka House Bot
- 2026-09-23 17:33fix: guard recovered purchase confirmationsDonerka House Bot
- 2026-09-23 17:32fix: recover confirmed assistant selectionsDonerka House Bot
- 2026-09-23 17:24fix: align product detail certificate modelDonerka House Bot
- 2026-09-23 17:22Implement Must Have #7 flowsibyrkhanov06-ux
- 2026-09-23 17:21chore: remove CI workflow that cannot start on organization runnersibyrkhanov06-ux
Все коммиты (100)
- 2026-09-23 17:19test: preserve normalized EKT article lookup in confirmed cart flowibyrkhanov06-ux
- 2026-09-23 17:15fix: rebuild Must Have chat flow cleanly on latest mainibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for static/index.htmlibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for static/chat.jsibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for models/types.goibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for handlers/live_catalog_test.goibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for handlers/live_catalog.goibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for handlers/ekt_api_test.goibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for handlers/ekt_api.goibyrkhanov06-ux
- 2026-09-23 17:11chore: carry Must Have changes for handlers/conversation.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/live_catalog_test.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/live_catalog.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/ekt_api_test.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/ekt_api.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/conversation.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/chat.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/cart_test.goibyrkhanov06-ux
- 2026-09-23 17:10chore: carry Must Have changes for handlers/cart.goibyrkhanov06-ux
- 2026-09-23 17:09chore: carry Must Have changes for handlers/auth_test.goibyrkhanov06-ux
- 2026-09-23 17:09chore: carry Must Have changes for README.mdibyrkhanov06-ux
- 2026-09-23 17:09chore: carry Must Have changes for .github/workflows/go-test.ymlibyrkhanov06-ux
- 2026-09-23 17:09fix: normalize EKT article referencesDonerka House Bot
- 2026-09-23 17:08ci: run tests before enforcing formattingibyrkhanov06-ux
- 2026-09-23 17:08ci: run Go tests for Must Have flowsibyrkhanov06-ux
- 2026-09-23 17:07docs: document Must Have flows and confirmed cart behavioribyrkhanov06-ux
- 2026-09-23 17:07test: preserve account-cart test with confirmed-only cart APIibyrkhanov06-ux
- 2026-09-23 17:07test: add Must Have coverage in handlers/ekt_api_test.goibyrkhanov06-ux
- 2026-09-23 17:07test: add Must Have coverage in handlers/live_catalog_test.goibyrkhanov06-ux
- 2026-09-23 17:06test: add Must Have coverage in handlers/cart_test.goibyrkhanov06-ux
- 2026-09-23 17:06feat: point cart button to current session cartibyrkhanov06-ux
- 2026-09-23 17:06feat: show analogs certificates and current-cart link in chat UIibyrkhanov06-ux
- 2026-09-23 17:06feat: add confirmed cart analog certificate and purchase-term chat flowsibyrkhanov06-ux
- 2026-09-23 17:05feat: enforce confirmed cart flow and stock limitsibyrkhanov06-ux
- 2026-09-23 17:05feat: propagate certificates from EKT API detailsibyrkhanov06-ux
- 2026-09-23 17:05feat: parse certificate links from live EKT pagesibyrkhanov06-ux
- 2026-09-23 17:05feat: track pending cart confirmationsibyrkhanov06-ux
- 2026-09-23 17:04feat: extend models for certificates analogs and cart linksibyrkhanov06-ux
- 2026-09-23 17:02ci: run Go tests for must-have flowsibyrkhanov06-ux
- 2026-09-23 17:02refactor: remove legacy immediate cart mutation helpersibyrkhanov06-ux
- 2026-09-23 17:01docs: describe must-have flows and confirmed cart behavioribyrkhanov06-ux
- 2026-09-23 17:01test: enforce confirmed-only cart mutations and stock limitsibyrkhanov06-ux
- 2026-09-23 17:00fix: prevent direct cart adds without chat confirmationibyrkhanov06-ux
- 2026-09-23 17:00fix: require explicit add confirmation instead of bare yesibyrkhanov06-ux
- 2026-09-23 16:59test: cover analog suggestions for unavailable productsibyrkhanov06-ux
- 2026-09-23 16:59test: verify certificate propagation from authenticated EKT APIibyrkhanov06-ux
- 2026-09-23 16:59test: verify certificate parsing from live EKT pageibyrkhanov06-ux
- 2026-09-23 16:59fix: treat zero-stock catalog items as unavailable for analog suggestionsibyrkhanov06-ux
- 2026-09-23 16:59fix: propagate EKT API certificates into product detailsibyrkhanov06-ux
- 2026-09-23 16:57feat: add local accounts with persistent user cartsDonerka House Bot
- 2026-09-23 16:55fix: rebuild chat handler with safe confirmation and analog flowsibyrkhanov06-ux
- 2026-09-23 16:54fix: enforce either regional or total EKT stock limitibyrkhanov06-ux
- 2026-09-23 16:54fix: merge API stock details into refreshed catalog productsibyrkhanov06-ux
- 2026-09-23 16:53test: cover confirmation stock limits cart link and purchase termsibyrkhanov06-ux
- 2026-09-23 16:53feat: make cart panel link point to current session cartibyrkhanov06-ux
- 2026-09-23 16:53feat: show analogs certificates and current-cart link in chatibyrkhanov06-ux
- 2026-09-23 16:52feat: require cart confirmation and add analog/purchase-term flowsibyrkhanov06-ux
- 2026-09-23 16:50fix: expose certificates on product API modelsibyrkhanov06-ux
- 2026-09-23 16:49feat: enforce cart quantities against live stockibyrkhanov06-ux
- 2026-09-23 16:49feat: parse certificate links from live EKT product pagesibyrkhanov06-ux
- 2026-09-23 16:49feat: refresh catalog products with live stock and certificatesibyrkhanov06-ux
- 2026-09-23 16:49feat: track pending cart confirmations per sessionibyrkhanov06-ux
- 2026-09-23 16:48feat: extend product and chat models for must-have flowsibyrkhanov06-ux
- 2026-09-23 16:43fix: synchronize EKT catalog incrementallyDonerka House Bot
- 2026-09-23 16:42feat: integrate authenticated EKT catalog APIDonerka House Bot
- 2026-09-23 15:53fix: add explicit purchases without confirmationDonerka House Bot
- 2026-09-23 15:50feat: add live EKT stock availability to assistantDonerka House Bot
- 2026-09-23 15:43feat: enrich assistant with live EKT product contextDonerka House Bot
- 2026-09-23 15:43docs: document remote detail loading and demo certificatesibyrkhanov06-ux
- 2026-09-23 15:43fix: revalidate pending cart priceibyrkhanov06-ux
- 2026-09-23 15:43fix: fall back to catalog price when detail price is absentibyrkhanov06-ux
- 2026-09-23 15:42feat: load remote product details and certificate placeholdersibyrkhanov06-ux
- 2026-09-23 15:41fix: remove unused main importibyrkhanov06-ux
- 2026-09-23 15:40docs: describe assistant, cart, and data APIsibyrkhanov06-ux
- 2026-09-23 15:39feat: add cart link to chat widgetibyrkhanov06-ux
- 2026-09-23 15:39feat: persist chat sessions and expose cart linkibyrkhanov06-ux
- 2026-09-23 15:39feat: wire product details, terms, sessions, and cart routesibyrkhanov06-ux
- 2026-09-23 15:38feat: add session history, analogs, terms, and confirmed cart flowibyrkhanov06-ux
- 2026-09-23 15:34feat: expose product details and certificatesibyrkhanov06-ux
- 2026-09-23 15:34feat: add session cart API and cart pageibyrkhanov06-ux
- 2026-09-23 15:32feat: add certificate links metadataibyrkhanov06-ux
- 2026-09-23 15:32feat: add structured purchase termsibyrkhanov06-ux
- 2026-09-23 15:32feat: add catalog details and cart modelsibyrkhanov06-ux
- 2026-09-23 15:29feat: add validated AI cart API and session basketDonerka House Bot
- 2026-09-23 14:34feat: AI can add items to cart via OpenAI function callingDonerka House Bot
- 2026-09-23 14:18fix: retry OpenAI 3x on 5xx errors, show friendly fallback with productsDonerka House Bot
- 2026-09-23 14:15feat: show product cards with photo and link in chatDonerka House Bot
- 2026-09-23 14:11Add Go CI workflowibyrkhanov06-ux
- 2026-09-23 14:11Harden AI assistant endpoint: update static/chat.jsibyrkhanov06-ux
- 2026-09-23 14:10Harden AI assistant endpoint: update handlers/chat.goibyrkhanov06-ux
- 2026-09-23 14:07feat: add docker-compose.yml for easy local devDonerka House Bot
- 2026-09-23 14:03feat: rebrand to ekt.kz electrical equipment AI assistantDonerka House Bot
- 2026-09-23 13:57feat: add AI assistant chatbot to Donerka House websiteDonerka House Bot
Структура репозитория (33 файлов)
.dockerignore .env.example .gitignore Dockerfile README.md data/detail.json data/products.json data/products2.json docker-compose.yml go.mod go.sum handlers/auth.go handlers/auth_test.go handlers/cart.go handlers/cart_test.go handlers/chat.go handlers/conversation.go handlers/ekt_api.go handlers/ekt_api_test.go handlers/live_catalog.go handlers/live_catalog_integration_test.go handlers/live_catalog_test.go handlers/menu.go handlers/privacy.go handlers/quotes.go handlers/restrictions_test.go handlers/security.go main.go models/types.go static/chat.js static/index.html static/privacy.html static/style.css
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.