О проекте
Команда: Creepers
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Рабочий MVP
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
Чат-консультант по каталогу ekt.kz: поиск, наличие, характеристики, сравнение товаров, аналоги, анализ спецификаций из Excel и корзина с явным подтверждением; ответы на русском и казахском.
Как устроено
FastAPI-бэкенд ходит в API EKT (/products, /products/detail) с кешем и нормализацией; детерминированный классификатор намерений обрабатывает основные сценарии, а нераспознанные запросы опционально уходят в OpenAI gpt-4o-mini через Structured Outputs, возвращая только намерение чтения. Цены и остатки берутся только из каталога; корзина работает по схеме prepare → pending → confirm с повторной проверкой остатка. Next.js-фронт показывает чат, каталог, сравнение и корзину; есть автономный демо-режим на 24 синтетических товарах.
Ключевые решения
- классификатор намерений
- OpenAI Structured Outputs
- Responses API с изображениями (распознавание маркировки)
- подбор аналогов
- двухшаговое подтверждение корзины
- session lock + TTL
Особенности
LLM не может подтвердить корзину или выдумать цену: модель только маршрутизирует запрос, а факты приходят из каталога. Есть анализ спецификации из XLSX с расчётом дефицита и защита от двойного добавления.
Стек
Python · FastAPI · Next.js · React · TypeScript · pytest
Модели
gpt-4o-mini (OpenAI)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-3b4a7b41-creepers.
README
README.mdEKT Copilot — Creepers / HackAlem AI 2026
Рабочее пространство закупщика для кейса ТОО «Электрокомплект». Один диалог объединяет поиск товара, проверку характеристик и наличия, подбор объяснимых альтернатив и подготовку корзины после явного подтверждения.
Что готово
- Чат с контекстом: поиск, наличие, характеристики, сертификаты и уточнения «а есть на 40А?». Основные ответы доступны на русском и казахском; интерфейс — на русском.
- Каталог с поиском, просмотром страниц, карточками товаров и маркировкой источника:
ekt_catalogилиdemo_catalog. - Сравнение двух товаров по фактическим параметрам. Неизвестные значения отображаются как «Нет данных».
- Аналоги с объяснением совпадений и отличий; текущие остатки проверяются перед показом.
- Анализ спецификации: запросы и количества → найденные позиции → доступное количество и дефицит → выбор кандидатов/замен → отдельное подтверждение каждой позиции.
- Корзина со ссылкой и выгрузкой списка. Подготовка не меняет её; подтверждение повторно проверяет остаток.
- Семь быстрых действий, индикаторы выполнения, повтор безопасных запросов и отдельный автономный режим с 24 учебными товарами.
- Опциональные OpenAI-маршрутизация свободного запроса и распознавание маркировки на фото. Цены, наличие и характеристики модель не придумывает.
Это хакатонный MVP с работающим frontend и backend. Заказ на стороне ekt.kz не создаётся.
Запуск за несколько минут
Требования: Python 3.12+, Node.js 22, npm. Команды выполняются из корня репозитория в PowerShell.
git clone https://github.com/BAITC-Hacks/hack-3b4a7b41-creepers.git
cd hack-3b4a7b41-creepers
py -3.12 -m venv Backend/.venv
Backend/.venv/Scripts/python.exe -m pip install -r Backend/requirements.txt
cd Frontend
npm ci
cd ..
./start.ps1
- Реальный каталог: http://localhost:3000
- Автономное демо для жюри: http://localhost:3000/?mode=demo — без аккаунтов и ключей.
- API: http://127.0.0.1:8000/docs
- Логи запуска:
.local/. Скрипт не останавливает уже работающие процессы.
Альтернатива: два терминала, cd Backend → .venv/Scripts/python.exe -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --no-access-log; cd Frontend → npm run dev. Для демонстрации используйте один backend worker. Корзины хранятся в памяти и сбрасываются при перезапуске.
Данные и ключи
Для реального каталога создайте Backend/.env из Backend/.env.example, если файла ещё нет, и локально заполните EKT_API_PASSWORD. Логин — apiuser, URL — https://ekt.kz/api. Уже существующий .env не перезаписывайте. Пароли и ключи нельзя добавлять в Git или браузерный код.
API EKT доступен только backend. /products используется для ограниченного поиска по страницам, /products/detail?id=… — для актуальных характеристик и остатка. Неизвестные цена, валюта, остаток и сертификаты остаются неизвестными. Конфликтующие параметры явно показываются. Изображения и ссылки на товар берутся из EKT. Кэш поиска — 60 секунд, детальные данные обновляются перед добавлением. По умолчанию поиск просматривает до 20 страниц (до 400 позиций при 20 товарах на странице), ограничен 8 секундами и возвращает до 20 совпадений. Это не полный каталог. В разделе «Каталог» доступен просмотр первых 50 страниц без поискового запроса.
Учебный режим использует 24 отдельные синтетические позиции 900001–900024 и отдельные сессии: автоматы, кабель, розетка, щиты, УЗО, освещение и монтажные принадлежности. Он включается только явно, никогда автоматически после ошибки EKT. Названия брендов используются для демонстрации поиска; учебные цены и остатки не являются предложением EKT. Учебный сертификат не является документом соответствия.
Оплата и доставка описаны по официальному FAQ EKT, проверенному 23.09.2026. Неуказанная единая минимальная партия не выдумывается. Тарифы и окончательные условия подтверждает менеджер.
Нужен ли AI-ключ?
Для основного демо, каталога и корзины — нет. Для дополнительного понимания свободных запросов на русском/казахском и распознавания маркировки на фото добавьте локально в Backend/.env:
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o-mini
Заполните значение ключа именно в Backend/.env, не в .env.example, и перезапустите backend. Это отдельный ключ OpenAI API; пароль EKT его не заменяет. Без ключа включены детерминированные сценарии, включая основные ответы RU/KZ. При ошибке модели они остаются доступны. Модель используется для нераспознанных запросов, а не для генерации цен и наличия. Это консультант по каталогу; произвольный общий диалог и полная казахская локализация интерфейса пока не реализованы.
В реальном режиме индикатор AI MODE означает, что ключ настроен. DEMO MODE означает работу без модели; источник товаров отдельно обозначен в карточках и баннере. Автономный режим никогда не вызывает OpenAI. Для диагностики откройте http://127.0.0.1:8000/api/status: language_model_configured должен быть true. Этот флаг проверяет наличие настройки, а не доступность внешнего сервиса. Ошибки подключения и лимиты OpenAI не отключают базовые сценарии.
Модель возвращает только проверяемое намерение чтения через Structured Outputs. Она не может подтвердить корзину. Факты извлекаются сервисами из каталога. Нераспознанный текстовый запрос передаётся OpenAI только при настроенном ключе; store:false. Фото отправляется только при включённом пользователем флажке «Распознать фото через OpenAI», в реальном режиме. Использован Responses API с изображениями. Реальный вызов модели требует вашего действующего ключа; без него интеграция проверяется подменённым HTTP-ответом.
Что проверить в интерфейсе
- Откройте
/?mode=demoи нажмите «Проверить наличие»: товар900001, 24 единицы, характеристики и учебный документ. - Укажите 2 единицы → «В корзину». Корзина остаётся пустой до «Да, добавь 2».
- Нажмите подтверждение → откройте корзину → скачайте список. Перезагрузка страницы сохраняет корзину, пока живёт серверная сессия.
- Нажмите «Найти замену» или отправьте
товар 900003: нулевой остаток, аналоги с объяснением совпадений. Автомат на 40А не предлагается как замена 25А. - Подготовьте ещё одно добавление → «Отмена» → отправьте
да, добавь: отменённое действие не выполняется. - Запросите
добавь 100 штук: превышение остатка блокируется на сервере. - Откройте раздел оплаты и доставки; задайте те же вопросы в чате.
- Отправьте «Сравни товары 900001 и 900002» — появится таблица характеристик и различий.
- Нажмите «Проанализируй Excel»: в учебном режиме доступен пример из трёх позиций. Или загрузите XLSX с колонками «Наименование» и «Количество». Проверьте дефицит, выберите неоднозначные совпадения и подтвердите каждую подготовленную позицию отдельно.
- Отправьте «Маған 25А автомат керек» — основной ответ будет на казахском. Учебное фото показывает явно обозначенных демонстрационных кандидатов, без заявления о распознавании изображения.
- Переключитесь на реальный каталог:
товар 515282. Данные приходят из EKT, синтетическая корзина изолирована.
Вложения
Принимаются XLSX, DOCX, PDF, JPEG/PNG и старые XLS/DOC, до 10 МБ. XLSX/DOCX и текстовые PDF читаются в памяти: до 6000 символов, 5 листов, 10 страниц. ZIP ограничен суммарным распакованным размером 20 МБ и 1000 элементами. Формулы и макросы не исполняются. Файлы не сохраняются на диск. Импорт не добавляет товары автоматически.
Табличные строки с названием и целым количеством анализируются автоматически: максимум 8 позиций, до 3 параллельных проверок, до 8 секунд на строку. Если найдено несколько кандидатов, пользователь выбирает нужный товар. Неизвестный остаток не засчитывается как доступный. Повторяющиеся позиции учитывают общий остаток и уже собранную корзину. Отчёт и результаты фото живут в памяти до часа. Перед добавлением пользователь проверяет результат и отдельно подтверждает каждую позицию.
Пример учебной спецификации:
| Наименование | Количество |
|---|---|
| Автомат Schneider 25А | 10 |
| Розетка DEMO | 30 |
| Кабель ВВГ | 100 |
Для пустой учебной корзины: 3 позиции, 140 запрошенных единиц, 100 доступных, дефицит 40. Это сумма единиц строк, не масса, стоимость или метры всего заказа.
Фото до 4 МБ: опциональное AI-распознавание видимой маркировки после включения флажка и подключения ключа. Модель может ошибаться. Старые XLS/DOC, сканы PDF, зашифрованные и нераспознанные документы пока требуют ручного ввода или конвертации в поддерживаемый текстовый формат. PDF-парсер ещё не изолирован отдельным процессом: публичная обработка произвольных документов требует дополнительного усиления.
Архитектура
Next.js / React (чат, каталог, корзина, вложения)
└─ same-origin /backend proxy
└─ FastAPI
├─ классификатор → optional OpenAI → read-only catalog tools
├─ EKT client → нормализация → поиск / аналоги / свежие остатки
├─ спецификация → procurement report → выбор → prepare каждой позиции
├─ контекст сессии → сравнение товаров / ответы RU-KZ
├─ prepare → pending → explicit confirm → cart
├─ session lock + TTL → изоляция и защита от двойного добавления
└─ /demo/api → автономный каталог и отдельное хранилище сессий
Случайный UUID сессии хранится в браузере отдельно для каждого режима. Ссылка на корзину — bearer-ссылка: знающий её получает доступ к сессии. Она не является авторизованным аккаунтом. TTL — 1 час бездействия, подготовленное добавление — 5 минут. Сессии ограничены по количеству. Платёжные данные не собираются.
Граница MVP: это локальная корзина прототипа. Заказ в ekt.kz не создаётся, товар не резервируется. Настоящий checkout требует согласованного с EKT API, авторизации и серверной интеграции. До публичного SaaS нужны tenant isolation, авторизация, серверное хранилище, rate limits, квоты AI, аудит, изоляция обработчиков файлов, HTTPS и тестирование под нагрузкой. Производственных клиентов, выручки и доказанного процента экономии времени пока нет.
Проверки
cd Backend
.venv/Scripts/python.exe -m pytest -q
.venv/Scripts/python.exe scripts/check_workspace.py
cd ../Frontend
npm run lint
npx tsc --noEmit
npm run build
check_workspace.py требует запущенные frontend/backend и проверяет HTTP-цепочку через Next.js proxy: поиск, контекст, сравнение, XLSX-отчёт, отдельные подтверждения, ссылку на корзину, отмену, превышение остатка, RU/KZ и честный сценарий фото. Это API/HTTP-проверка, не автоматизация кликов браузера. Основные тесты backend не требуют сети или ключей. Для реального EKT отдельно доступен Backend/scripts/inspect_ekt.py.
Если не отвечает
- Страница не открывается: запустите
./start.ps1, проверьте.local/backend.err.logи наличие frontend-зависимостей. - Backend недоступен: проверьте
http://127.0.0.1:8000/health. После изменения.envостановите и заново запустите backend;start.ps1оставляет существующий сервер работать. - Нет AI MODE: проверьте
OPENAI_API_KEYвBackend/.env, перезапустите backend и обновите страницу. Секреты не должны находиться в.env.exampleили переменныхNEXT_PUBLIC_*. - Поиск пустой: уточните артикул/ID. Поиск ограничен частью каталога; пустой результат не доказывает отсутствие товара во всём EKT.
- Нет доступа к EKT: проверьте локальные Basic Auth реквизиты или откройте явно обозначенное автономное демо.
Материалы для защиты
Критерии, сценарий демонстрации и SaaS-план. Подробности backend-контракта.
Сторонние компоненты: Next.js, React, Tailwind CSS, TypeScript, FastAPI, Uvicorn, HTTPX, Pydantic, pypdf, pytest; версии зафиксированы в package-lock.json и requirements.txt. Макет и интерфейс написаны в репозитории; изображения реальных товаров принадлежат их источникам. Опциональный внешний сервис — OpenAI API. Разработка выполнялась с помощью Codex; исходники и настоящая история Git доступны для проверки.
Авторы коммитов
История коммитов
- 2026-09-23 17:25feat(backend): add contextual assistant and procurement analysisNURIKZIX
- 2026-09-23 17:25feat(frontend): add procurement reports comparison and catalog browsingNURIKZIX
- 2026-09-23 17:25docs: complete setup API configuration and hackathon demo guideNURIKZIX
- 2026-09-23 16:26feat(frontend): build EKT procurement workspace and working cartNURIKZIX
- 2026-09-23 16:26feat(backend): add isolated demo, document extraction and optional AI routingNURIKZIX
- 2026-09-23 15:33test: merge frontend into integration branchNURIKZIX
- 2026-09-23 15:22feat(backend): integrate verified EKT catalog responsesNURIKZIX
- 2026-09-23 15:08test(backend): finalize core workflow and validationNURIKZIX
Все коммиты (12)
- 2026-09-23 14:57feat(cart): implement confirmation and stock validationNURIKZIX
- 2026-09-23 14:54feat(agent): implement catalog assistant workflowNURIKZIX
- 2026-09-23 14:51feat(backend): implement catalog and product servicesNURIKZIX
- 2026-09-23 14:50feat(backend): initialize backend and ekt api clientNURIKZIX
Структура репозитория (109 файлов)
.gitignore Backend/.env.example Backend/.gitignore Backend/README.md Backend/app/__init__.py Backend/app/agents/__init__.py Backend/app/agents/assistant.py Backend/app/agents/intent.py Backend/app/agents/language.py Backend/app/agents/localization.py Backend/app/agents/tools.py Backend/app/api/__init__.py Backend/app/api/cart.py Backend/app/api/chat.py Backend/app/api/health.py Backend/app/api/products.py Backend/app/clients/__init__.py Backend/app/clients/demo_catalog.py Backend/app/clients/ekt_client.py Backend/app/config.py Backend/app/core/__init__.py Backend/app/core/errors.py Backend/app/core/logging.py Backend/app/main.py Backend/app/schemas/__init__.py Backend/app/schemas/attachment.py Backend/app/schemas/cart.py Backend/app/schemas/chat.py Backend/app/schemas/procurement.py Backend/app/schemas/product.py Backend/app/services/__init__.py Backend/app/services/alternative_service.py Backend/app/services/attachment_service.py Backend/app/services/cart_service.py Backend/app/services/conditions_service.py Backend/app/services/procurement_service.py Backend/app/services/product_service.py Backend/app/services/session_service.py Backend/app/services/stock_service.py Backend/app/services/vision_service.py Backend/pytest.ini Backend/requirements.txt Backend/scripts/check_workspace.py Backend/scripts/demo.py Backend/scripts/inspect_ekt.py Backend/scripts/smoke.py Backend/tests/__init__.py Backend/tests/conftest.py Backend/tests/fixtures/ekt_verified.json Backend/tests/test_alternatives.py Backend/tests/test_attachments.py Backend/tests/test_cart.py Backend/tests/test_chat.py Backend/tests/test_ekt_client.py Backend/tests/test_ekt_verified.py Backend/tests/test_final_demo.py Backend/tests/test_health.py Backend/tests/test_products.py Backend/tests/test_sessions.py Backend/tests/test_workspace.py Frontend/.env.example Frontend/.gitignore Frontend/README.md Frontend/app/cart/[session_id]/page.tsx Frontend/app/demo-polish.css Frontend/app/favicon.ico Frontend/app/globals.css Frontend/app/layout.tsx Frontend/app/page.tsx Frontend/app/workspace.css Frontend/components/AlternativeCard.tsx Frontend/components/CartCard.tsx Frontend/components/CatalogProduct.tsx Frontend/components/ChatInput.tsx Frontend/components/ChatMessage.tsx Frontend/components/ChatWindow.tsx Frontend/components/ConfirmationCard.tsx Frontend/components/EktWorkspace.tsx Frontend/components/ErrorMessage.tsx Frontend/components/Header.tsx Frontend/components/Icon.tsx Frontend/components/LoadingIndicator.tsx Frontend/components/ProcurementSummary.tsx Frontend/components/ProductCard.tsx Frontend/components/ProductComparison.tsx Frontend/components/ProductDetails.tsx Frontend/components/ProductList.tsx Frontend/components/PurchaseCart.tsx Frontend/components/WelcomeScreen.tsx Frontend/eslint.config.mjs Frontend/lib/api.ts Frontend/lib/workspace-api.ts Frontend/next.config.ts Frontend/package-lock.json Frontend/package.json Frontend/postcss.config.mjs Frontend/public/demo-certificate.html Frontend/public/file.svg Frontend/public/globe.svg Frontend/public/next.svg Frontend/public/vercel.svg Frontend/public/window.svg Frontend/tsconfig.json Frontend/types/cart.ts Frontend/types/chat.ts Frontend/types/product.ts README.md docs/DEMO.md start.ps1
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.