О проекте
Команда: Avengers
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Прототип
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
AI-консультант для покупателей ekt.kz: чат с агентом, поиск по названию и артикулу, карточки с характеристиками и остатками, серверная демо-корзина и встраиваемый виджет.
Как устроено
React-фронт отправляет сообщение и историю в POST /api/chat; агент на OpenAI Responses API (gpt-5-mini) вызывает инструмент search_products, который ищет по каталогу EKT (HTTP Basic Auth, кеш 60 с, ранжирование по числу совпавших слов). Карточки подгружаются отдельно через endpoint деталей; корзина в памяти процесса проверяет остаток перед добавлением. Отдельный виджет в Shadow DOM ищет по каталогу без AI.
Ключевые решения
- function calling
- ранжирование по совпадению слов
- кеш каталога
- Shadow DOM виджет
Особенности
Встраиваемый чат-виджет с изоляцией стилей через Shadow DOM, который можно вставить на страницу магазина. README честно описывает ограничения: общая корзина на процесс, AI не подключён к виджету.
Стек
Python · FastAPI · React · Vite · JavaScript · unittest
Модели
gpt-5-mini (OpenAI)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-3b719372-avengers.
README
README.mdEKT AI — AI-консультант по электротехническим товарам
Хакатон-прототип помощника для покупателей ekt.kz: консультация на естественном языке, поиск товаров по названию или артикулу, просмотр характеристик и добавление выбранных позиций в демонстрационную корзину.
Проект помогает покупателю сформулировать требования к электротехническому товару и найти варианты в подключённом каталоге. В репозитории есть веб-интерфейс, HTTP API, AI-агент и отдельно собираемый виджет для встраивания на страницу.
Статус: прототип. Серверная корзина общая для всех пользователей одного процесса; оформление заказа не реализовано. AI подключён в основном чате, но не в плавающем виджете.
Репозиторий: BAITC-Hacks/hack-3b719372-avengers.
Описание проверено 23 сентября 2026 года по исходникам архива hack-3b719372-avengers-main.zip, совпадающим с кодом коммита 08ea0d3 без учёта переводов строк. Значения секретов из .env не использовались в документе.
Что реализовано
| Возможность | Реализация и границы |
|---|---|
| AI-консультация | Основной чат отправляет сообщение и историю на /api/chat. Агент использует OpenAI Responses API и модель gpt-5-mini. |
| Поиск для AI | Модели доступен инструмент search_products, вызывающий поиск backend по каталогу. |
| Поиск в интерфейсе | Отдельная форма поиска по названию или артикулу; карточки дополняются данными из endpoint деталей товара. |
| Карточки товаров | Название, артикул, цена в ₸, наличие, изображение при наличии URL, доступные характеристики, складские остатки и ссылка на товар. |
| Фильтрация | В основной странице — фильтр «Только в наличии» и сортировка полученных результатов по цене. |
| Корзина | Добавление после подтверждения, проверка остатка на backend, просмотр количества и суммы. API также поддерживает изменение количества, удаление и очистку. |
| Встраиваемый виджет | Поиск по каталогу, карточки, подтверждение количества перед добавлением, просмотр серверной корзины. Стили изолированы через Shadow DOM. |
| Обработка ошибок | Тайм-ауты запросов, сообщения о недоступности сервисов, повтор поиска/отправки через интерфейс. |
| Демо без backend | Основная страница умеет искать по трём встроенным тестовым товарам и хранить локальную корзину в браузере. Ограничение демочата описано ниже. |
Системный промпт предписывает агенту отвечать на языке покупателя, уточнять параметры, не выдумывать товары, цены и наличие и показывать не более трёх вариантов. Это инструкции модели, а не программная гарантия корректности ответа.
Основания: основная страница, виджет, агент, промпт.
Как работает решение
- Покупатель открывает основную страницу и пишет, например: «Найди автомат на 16 А».
- Frontend передаёт текст и историю диалога в
POST /api/chat. - Backend вызывает AI-агента. При вызове моделью
search_productsагент получает товары через модуль поиска backend. - Backend запрашивает страницы каталога EKT с HTTP Basic Auth. Поиск сопоставляет слова запроса с названием и артикулом и ранжирует товары по числу совпадений.
- Агент передаёт результат поиска модели и получает текстовый ответ. Backend возвращает
answerи обновлённуюhistory. - Для просмотра карточек покупатель использует отдельную форму поиска либо плавающий виджет. Frontend дополнительно запрашивает детали найденных товаров.
- После нажатия «В корзину» и подтверждения backend проверяет количество по данным каталога и обновляет свою демо-корзину.
Текст AI и карточки — разные потоки: ответ /api/chat сам по себе не заполняет панель карточек. Плавающий виджет обращается к поиску напрямую и не вызывает AI.
Технологии
| Слой | Используемые технологии |
|---|---|
| Frontend | JavaScript, React, React DOM, Vite, CSS, lucide-react, браузерный Fetch API |
| Backend | Python, FastAPI, Pydantic, Uvicorn, Requests, python-dotenv |
| AI | Python SDK openai, Responses API, модель gpt-5-mini, function calling |
| Данные | Внешний HTTP API каталога EKT; кеш каталога и серверная корзина в памяти процесса |
| Проверки | unittest, unittest.mock, сборки Vite |
В frontend/package-lock.json зафиксированы React/React DOM 19.3.0, Vite 8.3.0, @vitejs/plugin-react 6.1.1 и lucide-react 1.47.0. В package.json зависимости указаны как latest, поэтому для воспроизводимой установки используется npm ci.
Python-зависимости не закреплены по версиям. В backend/requirements.txt перечислены fastapi, uvicorn, requests, python-dotenv; ai/requirements.txt пуст. Пакет openai, импортируемый приложением, необходимо установить отдельно.
Основания: package.json, package-lock.json, backend/requirements.txt.
Архитектура
Основная страница React
├─ AI-чат → POST /api/chat → ai.agent → OpenAI Responses API
│ └─ search_products → backend.products
├─ Поиск → GET /api/search ────────────────────────────┘
├─ Карточки → GET /api/products/{id} → backend.ekt_api → API EKT
└─ Корзина → /api/cart... → backend.cart → память процесса
Плавающий виджет React / Shadow DOM
└─ Поиск, детали и корзина → те же HTTP endpoints backend
backend.products → кеш на 60 секунд → backend.ekt_api → API EKT
ai/
agent.py # OpenAI-клиент, инструмент поиска, консольный чат
prompts.py # Инструкции консультанта
tools.py # Связь AI с поиском backend
requirements.txt # Пока пуст
backend/
main.py # FastAPI, маршруты, обработка ошибок
ekt_api.py # Запросы к внешнему каталогу
products.py # Поиск, ранжирование, кеш
cart.py # Общая корзина в памяти
models.py # Пока пуст
test_reliability.py # Тесты кеша и ошибок чата
requirements.txt
frontend/
src/main.jsx # Основная страница
src/api.js # Запросы AI-чата
src/catalog.js # Поиск и загрузка деталей
src/widget/ # Виджет, карточки, корзина, выбор вложений
vite.widget.config.js # Отдельная сборка widget.js
package.json
package-lock.json
AI — модуль того же Python-приложения, а не отдельный HTTP-сервис. База данных, векторное хранилище и очередь задач в прикладном коде не подключены.
Установка и запуск
1. Подготовить окружение
Нужны Git для клонирования, Python, Node.js и npm, а для полноценной демонстрации — доступ к OpenAI и API каталога EKT.
- Для повторения исходного окружения можно использовать Python 3.12: включённое в репозиторий окружение было создано на 3.12.3. Формальный диапазон поддерживаемых версий Python проект не задаёт.
- Для frontend используйте Node.js 22.12 или новее. В lock-файле Vite и его React-плагин требуют
^20.19.0 || >=22.12.0. - Не используйте включённый в архив
backend/venv: он содержит пути к компьютеру автора. Создайте новое окружение.
Ниже команды для Windows PowerShell. Если команда py -3.12 сообщает No suitable Python runtime found, сначала установите Python 3.12; наличие .venv не устанавливает отсутствующий интерпретатор. Доступные версии показывает py --list.
git clone https://github.com/BAITC-Hacks/hack-3b719372-avengers.git
cd hack-3b719372-avengers
py -3.12 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r backend/requirements.txt
.\.venv\Scripts\python.exe -m pip install openai
При работе с ZIP распакуйте его и откройте терминал в папке с ai, backend и frontend; вместо клонирования выполните команды начиная с создания .venv. Активация окружения не нужна: команды используют его интерпретатор напрямую.
2. Настроить доступ к сервисам
Локально создайте или отредактируйте ai/.env:
OPENAI_API_KEY=YOUR_OPENAI_API_KEY
Локально создайте или отредактируйте backend/.env:
EKT_API_URL=https://your-catalog-api.example/base
EKT_API_USERNAME=YOUR_EKT_USERNAME
EKT_API_PASSWORD=YOUR_EKT_PASSWORD
Это заполнители, не рабочие учётные данные. Адрес базового API и доступ выдаёт владелец интеграции. EKT_API_URL укажите без завершающего /: код добавляет /products и /products/detail самостоятельно. Для OpenAI нужен ключ с доступом к используемой модели и доступной квотой.
| Переменная | Где используется |
|---|---|
OPENAI_API_KEY | OpenAI SDK; ai/agent.py загружает ai/.env |
EKT_API_URL | Базовый URL каталога; backend/ekt_api.py |
EKT_API_USERNAME | Имя пользователя для HTTP Basic Auth |
EKT_API_PASSWORD | Пароль для HTTP Basic Auth |
VITE_API_URL | Адрес backend для frontend (локальный или публичный), задаётся при запуске/сборке Vite |
Секреты должны оставаться на стороне backend. Не помещайте ключ OpenAI или пароль EKT в переменные VITE_*, HTML или исходники frontend. В поставке уже присутствуют .env; не переносите их значения в README и не публикуйте свои ключи. Если находящиеся в Git значения действующие, их следует заменить у провайдера. frontend/.gitignore не защищает файлы в соседних ai/ и backend/ и содержит маркеры конфликта слияния.
3. Запустить backend
Из корня проекта:
.\.venv\Scripts\python.exe -m uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
- Проверка процесса: http://127.0.0.1:8000/health.
- Интерактивная документация FastAPI: http://127.0.0.1:8000/docs.
OpenAI-клиент создаётся при импорте приложения, поэтому без OPENAI_API_KEY запуск может завершиться ошибкой ещё до обращения к чату. Успешный /health подтверждает работу приложения, но не проверяет доступность EKT или OpenAI.
4. Запустить frontend
Во втором терминале, из корня проекта:
cd frontend
npm ci
$env:VITE_API_URL = "http://127.0.0.1:8000"
npm run dev -- --host 127.0.0.1 --port 5173
Откройте адрес, напечатанный Vite; при свободном порте это http://127.0.0.1:5173. Оставьте оба терминала работающими: закрытие процесса backend или frontend остановит соответствующую часть приложения.
Вместо переменной терминала можно создать frontend/.env.local с VITE_API_URL=http://127.0.0.1:8000. После изменения настройки перезапустите Vite. Если адрес пуст, основная страница переходит в деморежим, а виджет не выполняет реальный поиск.
5. Собрать frontend и виджет
В каталоге frontend, с настроенным VITE_API_URL:
npm run build
npm run build:widget
npm run preview -- --host 127.0.0.1 --port 4173
Основная сборка попадает в frontend/dist, отдельный виджет — в frontend/dist-widget/widget.js. preview предназначен для локальной проверки основной сборки; backend запускается отдельно.
Пример подключения виджета после размещения widget.js на своей странице:
<script
src="/widget.js"
data-ekt-widget
data-api-base="http://127.0.0.1:8000"
></script>
Это пример локальной интеграции. Адрес backend для отдельного виджета задаётся во время загрузки через data-api-base. Основная страница уже монтирует виджет сама.
Основания: настройка API, frontend API, точка входа виджета, конфигурация сборки.
Как проверить решение жюри
Сценарий с подключёнными сервисами
- Запустите backend и frontend по инструкции выше.
- Проверьте
/health: ожидается{"status":"healthy"}. - В отдельной форме каталога найдите товар по известному артикулу из доступного каталога. Если артикула нет, попробуйте короткий запрос «автомат». Конкретные результаты зависят от данных API и охваченных поиском страниц.
- Откройте «Характеристики и склады» у результата. Проверьте отображение цены, наличия и доступных параметров. Отсутствующие сведения не должны восприниматься как подтверждённые.
- Выберите доступный товар с указанной ценой, нажмите «В корзину», подтвердите добавление и откройте корзину. Должны появиться позиция, количество и сумма. Реальный заказ при этом не создаётся.
- В основном AI-чате отправьте «Найди автомат на 16 А», затем уточните запрос. Ожидается текстовый ответ от модели; точное содержание заранее не фиксируется.
- Откройте плавающий «Помощник EKT» и выполните поиск по артикулу. Это проверка отдельного поискового виджета, а не ещё одного AI-чата.
Без доступа к внешним сервисам можно проверить только демопоиск основной страницы: уберите VITE_API_URL из окружения и .env.local, перезапустите Vite и найдите Schneider. Результат берётся из встроенных тестовых данных. Демо-корзина хранится в localStorage; её цены и наличие не являются данными EKT.
Проверка HTTP API
Invoke-RestMethod "http://127.0.0.1:8000/health"
$query = [uri]::EscapeDataString("автомат")
Invoke-RestMethod "http://127.0.0.1:8000/api/search?q=$query"
$payload = @{ message = "Найди автомат на 16 А"; history = @() } | ConvertTo-Json -Depth 10
Invoke-RestMethod -Method Post -Uri "http://127.0.0.1:8000/api/chat" -ContentType "application/json; charset=utf-8" -Body ([System.Text.Encoding]::UTF8.GetBytes($payload))
Для следующего сообщения передайте массив history из предыдущего ответа. Endpoint чата возвращает answer и history, а не массив карточек товаров.
Автоматические проверки
Из корня проекта, после установки Python-зависимостей:
$env:OPENAI_API_KEY = "test-placeholder"
.\.venv\Scripts\python.exe -m unittest backend.test_reliability -v
Remove-Item Env:OPENAI_API_KEY
Запускайте этот блок в отдельном тестовом терминале. Временное значение нужно только для создания OpenAI-клиента при импорте; тесты подменяют сетевые зависимости и не требуют настоящего ключа. Удаление переменной позволяет при следующем запуске прочитать ключ из ai/.env.
В файле три тестовых метода: совместное использование кеша при параллельном поиске и ранжирование, обновление кеша после истечения срока и ошибки, безопасные HTTP-ошибки чата. Это не полная проверка приложения: тесты не проверяют реальную сеть, качество ответов модели или браузерный сценарий. В package.json нет команды test; доступны команды сборки.
При подготовке этого README выполнено статическое изучение исходников и сравнение архива с GitHub. Установка зависимостей, сборки, тесты и сквозной запуск с реальными ключами в рамках подготовки документа не выполнялись; приведённые команды не являются отчётом об успешном прогоне.
Основание: backend/test_reliability.py.
HTTP API
| Метод | Путь | Назначение |
|---|---|---|
| GET | / | Статус backend и сообщение |
| GET | /health | Статус процесса |
| GET | /api/products?page=1 | Страница внешнего каталога |
| GET | /api/products/{product_id} | Детали товара |
| GET | /api/search?q=... | Поиск; ответ содержит query, count, products |
| POST | /api/chat | JSON с message и history; ответ с answer и history |
| GET | /api/cart | Корзина: items, total, items_count |
| POST | /api/cart/add?product_id=...&quantity=1 | Добавить товар |
| PATCH | /api/cart/{product_id}?quantity=... | Изменить количество; 0 удаляет позицию |
| DELETE | /api/cart/{product_id} | Удалить позицию |
| DELETE | /api/cart | Очистить общую корзину |
Параметры добавления и изменения количества передаются в query string, а не JSON. Изменения корзины затрагивают общую демо-корзину текущего процесса.
Для чата предусмотрены ответы 504 при тайм-ауте, 503 при лимите/квоте OpenAI, 502 при ошибке внешней зависимости и 500 при неожиданной ошибке. Это поведение маршрута, не результат проверки доступности конкретных сервисов.
Основание: backend/main.py.
Данные и интеграции
- Каталог EKT: backend обращается к
${EKT_API_URL}/products?page=...и${EKT_API_URL}/products/detail?id=...с HTTP Basic Auth. Подключённый адрес определяется локальной настройкой; доменekt.kzсам по себе не является подтверждённым адресом этого API. - OpenAI: агент отправляет историю диалога, а при поиске — также найденные записи каталога, в Responses API. Модель указана в коде как
gpt-5-mini. - История: frontend хранит её в состоянии React и передаёт с каждым запросом. Постоянное серверное хранилище диалогов не реализовано.
- Кеш: поисковый каталог хранится в памяти на 60 секунд. Обновление страниц выполняется пулом до пяти потоков с блокировкой одновременного обновления.
- Тестовые данные: три товара в
frontend/src/main.jsxиспользуются только в демопоиске.TEST_PRODUCTSвai/tools.pyне используется текущей функцией поиска и не служит резервным каталогом при ошибке API.
Основания: поиск и кеш, AI-инструмент, загрузка деталей на frontend.
Ограничения текущей версии
- Корзина не персональная и не постоянная. Она хранится в глобальном словаре Python, общая для запросов одного процесса и теряется при перезапуске. Несколько процессов будут иметь разные корзины. Авторизация пользователей и сессионное разделение не реализованы.
- Нет оформления заказа. Backend не отправляет корзину в магазин; платёжные, заказные и доставочные endpoints отсутствуют.
- AI не управляет корзиной. Единственный инструмент агента —
search_products. Отдельного инструмента получения деталей товара у модели также нет. Упоминание подтверждения корзины в промпте не добавляет эту возможность. - Поиск ограничен. По умолчанию загружаются первые 10 страниц; возвращается максимум 20 результатов. Это совпадение слов по подстрокам названия и артикула, без семантического поиска, морфологии и проверки технической совместимости. Пустой результат не доказывает отсутствие товара во всём каталоге.
- AI-ответ и карточки не синхронизированы автоматически. Карточки формируются отдельным поиском; виджет не подключён к
/api/chat. - Редактирование серверной корзины ограничено в UI. Основная страница отключает изменение количества и удаление при подключённом backend, хотя соответствующие API-маршруты есть. Виджет позволяет выбрать количество при добавлении и просмотреть корзину.
- Вложения не отправляются. Виджет проверяет расширение и размер до 10 МБ для JPEG, PDF, Excel и Word, показывает предпросмотр JPEG, но загрузка и обработка файлов отсутствуют. Выбранное вложение блокирует отправку текста до удаления.
- Демочат содержит несогласованность полей. Демоответ создаётся с полем
message, а вывод читаетanswer, поэтому без backend ответ может отображаться пустым. Демо следует показывать через поиск тестовых товаров, не как работающую AI-консультацию. - Нет полной изоляции и защиты публичного сервиса. CORS разрешает все origins, собственная авторизация и ограничение частоты запросов отсутствуют. Перед публичным запуском это требует доработки. Ошибки маршрутов каталога включают строку исключения внешнего запроса.
- Окружение требует подготовки. Python-зависимости не закреплены,
openaiотсутствует в requirements, в поставке есть виртуальное окружение и.env, аfrontend/.gitignoreсодержит маркеры конфликта. Установка в чистое окружение обязательна для корректной проверки переносимости. - Нет подтверждённых метрик качества. В исходниках нет результатов оценки точности рекомендаций, нагрузочных измерений или доказательства работы всей цепочки на реальных сервисах. История диалога не ограничивается по длине на backend.
Основания: корзина, вложения, а также исходники frontend, агента и API, указанные выше.
Развёрнутая версия и локальная демонстрация
Подтверждённая публичная ссылка на работающую версию проекта в проверенных исходниках не найдена. Для демонстрации используйте локальный запуск. ekt.kz — целевой магазин, а не подтверждённый deployment этого прототипа.
Для запуска на своём компьютере хостинг не нужен: frontend и backend запускаются локально по инструкции выше. Для реального каталога и AI-консультации необходимы интернет и настроенные доступы к EKT и OpenAI.
В общей «Инструкции для участников HackAlem AI» (стр. 1–2) ссылка на развёрнутую версию запрашивается «если она есть». Общая инструкция требует разместить итоговый код в выданном команде GitHub-репозитории, подготовить README и сдать решение через платформу; обязательный публичный хостинг в ней не указан. Дополнительные требования конкретного кейса EKT необходимо сверить с его заданием.
Авторы коммитов
История коммитов
- 2026-09-23 17:40Update README.mddias23nuly
- 2026-09-23 17:34Update README.mdagadil
- 2026-09-23 17:31Delete ai/.envalikhanov0
- 2026-09-23 17:31Delete backend/.envalikhanov0
- 2026-09-23 17:30Merge branch 'main' of https://github.com/BAITC-Hacks/hack-3b719372-avengersYerbol Alikhan
- 2026-09-23 17:29Added readme, deleted filesYerbol Alikhan
- 2026-09-23 17:24Delete ai/.envalikhanov0
- 2026-09-23 17:23Delete backend/.envalikhanov0
Все коммиты (23)
- 2026-09-23 17:20Add files via uploaddias23nuly
- 2026-09-23 17:04Integrate backend AI and frontendYerbol Alikhan
- 2026-09-23 16:54Fix product image overflow in catalog and cartAgadil
- 2026-09-23 16:32last buildYerbol Alikhan
- 2026-09-23 16:18Add embeddable chat widget, product details and server cartAgadil
- 2026-09-23 15:56little changesYerbol Alikhan
- 2026-09-23 15:56Merge remote-tracking branch 'origin/ai-agent'Yerbol Alikhan
- 2026-09-23 15:49added endpointsYerbol Alikhan
- 2026-09-23 14:58Merge main into ai-agentnurlybekuly
- 2026-09-23 14:52backend main filesYerbol Alikhan
- 2026-09-23 14:37Add AI product search toolnurlybekuly
- 2026-09-23 14:34Add frontend storefront, AI chat and cartAgadil
- 2026-09-23 14:31lcYerbol Alikhan
- 2026-09-23 14:25Add initial AI agentnurlybekuly
- 2026-09-23 13:58basic architecture, first filesYerbol Alikhan
Структура репозитория (33 файлов)
README.md ai/__init__.py ai/agent.py ai/prompts.py ai/requirements.txt ai/tools.py backend/__init__.py backend/cart.py backend/ekt_api.py backend/main.py backend/models.py backend/products.py backend/requirements.txt backend/test_reliability.py frontend/.env.example frontend/.gitignore frontend/WIDGET.md frontend/index.html frontend/package-lock.json frontend/package.json frontend/src/api.js frontend/src/catalog.js frontend/src/improvements.css frontend/src/main.jsx frontend/src/store.css frontend/src/styles.css frontend/src/widget/ChatWidget.jsx frontend/src/widget/ProductDetails.jsx frontend/src/widget/attachment.js frontend/src/widget/cart.js frontend/src/widget/entry.jsx frontend/src/widget/widget.css frontend/vite.widget.config.js
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.