О проекте
Команда: хюмандар
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Рабочий MVP
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
Каталог и чат-консультант для ekt.kz: поиск по артикулу и характеристикам, подбор аналогов по правилам категории, предупреждения о противоречиях, импорт спецификаций и локальная корзина с отдельным подтверждением.
Как устроено
React-фронтенд обращается к FastAPI. LLM-агент (OpenAI Responses, gpt-4.1-mini) вызывает инструменты поиска и получения карточек, данные берутся из снимка каталога или живого API ekt.kz с Basic Auth. Аналоги проверяются правилами категории: совпадения, различия, недостающие данные. XLSX, DOCX и PDF разбираются на сервере в редактируемый черновик, JPEG и PNG распознаёт модель. Добавление в корзину идёт через предложение и отдельное подтверждение с проверкой цены и остатка; сессии, история и корзина хранятся в SQLite, есть CSRF-защита.
Ключевые решения
- function calling
- rule-based analog matching
- contradiction detection
- document parsing (openpyxl/python-docx/pypdf)
- image recognition
- CSRF
Особенности
Доступный к продаже остаток отделён от общего quantity: пока ID складов не подтверждены, доступность считается неизвестной. Есть демо-режим с синтетическими товарами без ключа. При этом в репозитории всего 5 коммитов, по истории процесс разработки не восстановить.
Стек
Python · FastAPI · Pydantic · SQLite · httpx · TypeScript · React 19 · Vite 6 · pytest
Модели
GPT-4.1-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-14d000d9-team.
README
README.md1. Название проекта
EKT Assistant — ИИ-ассистент для интернет-магазина электротехники ekt.kz.
Прототип для HackAlem AI: каталог, чат-консультант, обработка списков товаров и демонстрационная корзина.
2. Краткое описание
Покупателям электротехники нужно находить товары по артикулам и характеристикам, сравнивать варианты и собирать список покупок. Данные могут содержать противоречия, а наличие на складе не всегда означает доступность для продажи.
EKT Assistant помогает частным покупателям, монтажникам и специалистам по закупкам искать позиции обычным текстом или загружать спецификацию. Ассистент показывает сведения каталога, предупреждает о неизвестных и противоречивых характеристиках и предлагает подтвердить выбранные позиции.
3. Что реализовано
- Каталог с поиском, ценами в тенге, описаниями и остатками по складам.
- Плавающий чат с ИИ: поиск по названию и артикулу, уточнение запроса, просмотр характеристик и подбор кандидатов на замену.
- Проверка аналогов по правилам категории с указанием совпадений, различий и недостающих данных.
- Выявление противоречий: например, у товара 027228 в источниках указаны значения тока 160 и 250 А.
- Загрузка XLSX, DOCX и PDF с текстом; интеграция распознавания JPEG/PNG через модель с поддержкой изображений.
- Редактируемый черновик распознанных позиций и количеств. Загрузка файла сама по себе не меняет корзину.
- Локальная корзина: предложение → отдельное подтверждение → добавление. Повторное подтверждение не дублирует позицию.
- Серверные сессии, CSRF-проверка, проверка цены и доступного остатка при подтверждении.
- Явный демо-режим без ключа модели и три синтетических товара для воспроизводимого показа.
4. Как работает решение
- Пользователь открывает каталог и чат, вводит запрос, выбирает товар или загружает список позиций.
- Сервер обрабатывает запрос; для файлов извлекает названия и количества в черновик для проверки.
- ИИ вызывает инструменты поиска и получения карточек. Сведения о товарах берутся из каталога.
- Интерфейс показывает ответ, карточки, остатки и предупреждения. При неоднозначном запросе пользователь уточняет выбор.
- Пользователь выбирает товар и количество. Сервер формирует предложение добавления.
- После отдельного подтверждения позиция появляется в локальной корзине
/cart. Реальный заказ на ekt.kz не отправляется.
5. Технологии
| Компонент | Технологии |
|---|---|
| Интерфейс | TypeScript, React 19, Vite 6, CSS, lucide-react |
| Сервер | Python, FastAPI, Uvicorn, Pydantic |
| ИИ | OpenAI Responses API, Python SDK openai, модель по умолчанию gpt-4.1-mini, вызов инструментов |
| Каталог | API ekt.kz, HTTP Basic Auth, httpx, локальные JSON-снимки |
| Хранение | SQLite: сессии, история, предложения и демонстрационная корзина |
| Файлы | openpyxl, python-docx, pypdf, Pillow |
| Настройки и проверки | python-dotenv, pytest, TypeScript, тесты контрактов на Node.js |
Версии Python-зависимостей закреплены в requirements.txt, зависимости интерфейса — в frontend/package.json и frontend/package-lock.json.
6. Архитектура проекта
Браузер: React-каталог, чат, черновик, корзина
│ HTTP /api
▼
FastAPI
┌───────────┼─────────────┐
▼ ▼ ▼
ИИ-агент Каталог Обработка файлов
│ JSON/API текст / модель
▼ │
OpenAI Responses ▼
ekt.kz
FastAPI → проверка предложения и подтверждения → SQLite
frontend/— интерфейс;src/services/backendApi.tsсвязывает его с сервером;dist/содержит готовую сборку.backend/— HTTP API, нормализация каталога, обработка файлов и локальная корзина. Точка входа объединённого приложения —backend/server.py; отдельный ранний бэкенд команды сохранён вbackend/app/.agent/— ИИ-агент, инструменты и правила подбора аналогов.data/— исходные данные, снимок каталога и синтетические товары.tests/,frontend/tests/— серверные тесты и проверки интерфейсных контрактов.docs/— дополнительные контракты и отчёты разработки.var/— создаваемая при запуске база SQLite; не включается в Git.import_catalog.py— импорт каталога;start.ps1— запуск приложения.
FastAPI раздаёт API и собранный интерфейс с одного адреса. Добавление проходит через /api/proposals и /api/proposals/{id}/confirm. Ключи внешних сервисов находятся только на сервере.
7. Установка и запуск
Нужны Python 3.11+ и интернет для установки зависимостей. Для сборки и разработки интерфейса нужны Node.js 22.12+ и npm. Если frontend/dist/ присутствует, для обычного запуска сборка не требуется. Для ответов ИИ нужен доступ к OpenAI API; без него работает демо-режим.
Команды ниже выполняются в PowerShell из корня проекта.
Шаг 1. Создать настройки, не перезаписывая существующий .env:
if (-not (Test-Path .env)) { Copy-Item .env.example .env }
В корневом .env задать:
AGENT_MODE=auto
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4.1-mini
CATALOG_MODE=snapshot
EKT_CURRENCY=KZT
EKT_API_USER=
EKT_API_PASSWORD=
EKT_SELLABLE_STORE_IDS=
COOKIE_SECURE=0
Для ИИ заполнить OPENAI_API_KEY своим ключом. Для показа без модели задать AGENT_MODE=demo. Файл .env исключён из Git; ключи не размещаются в frontend или переменных VITE_*.
Шаг 2. Запустить приложение:
.\start.ps1
Скрипт создаёт .venv, устанавливает Python-зависимости, при отсутствии сборки собирает интерфейс и запускает сервер.
Альтернатива — ручной запуск:
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
# Следующие четыре команды нужны, если нет frontend/dist или интерфейс изменён:
Push-Location frontend
npm.cmd ci
npm.cmd run build
Pop-Location
.\.venv\Scripts\python.exe -m uvicorn backend.server:app --host 127.0.0.1 --port 8765
Шаг 3. Открыть приложение:
- Каталог и чат: http://127.0.0.1:8765/
- Локальная корзина: http://127.0.0.1:8765/cart
- Состояние подключений: http://127.0.0.1:8765/api/status
Остановка сервера — Ctrl+C. Если порт занят, сначала остановить предыдущий экземпляр.
Для разработки интерфейса запустить backend, затем в другом терминале:
cd frontend
npm.cmd ci
npm.cmd run dev
Открыть адрес, который напечатает Vite. Запросы /api проксируются на порт 8765. После изменений для обычного запуска снова выполнить npm.cmd run build из frontend. Если ограниченное окружение блокирует загрузчик конфигурации, использовать npm.cmd run build -- --configLoader runner.
8. Как проверить решение
Для проверки жюри достаточно режима CATALOG_MODE=snapshot. Основной сценарий не требует доступа к API магазина; для диалога с моделью нужен ключ OpenAI. Без ключа доступны демонстрационные сценарии.
- Открыть главную страницу и найти
027228. Ожидается карточка Legrand с ценой 64 920 ₸. - Открыть чат и написать: «Покажи 027228». Ожидаются сведения о товаре и предупреждение о расхождении 160/250 А; совместимость не должна подтверждаться без уточнения.
- Написать: «Найди DEMO-B16», затем попросить добавить 2 штуки. Ожидается предложение с товаром и количеством.
- Нажать отдельную кнопку подтверждения и открыть
/cart. В новой сессии ожидается 2 шт. DEMO-B16. Для повторного показа с пустой корзиной открыть приложение в приватном окне; «Новый диалог» корзину не очищает. - Дополнительно загрузить XLSX с колонками
АртикулиКоличество, строкойDEMO-B16и числом2. Ожидается редактируемый черновик; автоматического добавления в корзину нет. - При настроенном ключе загрузить JPEG/PNG с читаемым списком товаров. Проверить названия и количества вручную: качество распознавания реальных фото ещё требует отдельной оценки.
В снимке реальный товар не добавляется в корзину: актуальный доступный остаток неизвестен. Это ожидаемое поведение; для проверки подтверждения предусмотрен DEMO-B16.
Автоматические проверки:
.\.venv\Scripts\python.exe -m pytest -q
Push-Location frontend
npm.cmd ci
npm.cmd test
npm.cmd run build
Pop-Location
9. Данные и интеграции
В поставку входят сохранённые карточки 40 реальных товаров и 3 синтетических демо-товара. Полный каталог не импортирован.
API ekt.kz использует Basic Auth:
GET https://ekt.kz/api/products— список товаров.GET https://ekt.kz/api/products?page=2— следующая страница.GET https://ekt.kz/api/products/detail?id=515291— подробная карточка.
Сервер поддерживает импорт страниц и обновление карточек. CATALOG_MODE=live включает обращения за свежими карточками; нужны EKT_API_USER и EKT_API_PASSWORD. Переключение режима само по себе не загружает весь каталог: поиск работает по импортированной выборке.
Для отдельного импорта первых двух страниц после настройки доступа:
.\.venv\Scripts\python.exe import_catalog.py --pages 2 --force
После импорта перезапустить сервер. Число страниц задаётся параметром --pages; два — ограничение примера, а не полный каталог.
Для расчёта доступного к продаже остатка отдельно задаются подтверждённые магазином ID в EKT_SELLABLE_STORE_IDS. Пока список пуст, доступность для продажи считается неизвестной. Общий остаток quantity не заменяет это подтверждение.
В исходных карточках валюта отсутствует. По настройке проекта EKT_CURRENCY=KZT такие цены обозначаются в тенге без пересчёта суммы; источник валюты отмечается как project_config. Синтетические товары используют условную единицу DEMO.
OpenAI Responses API используется для диалога и распознавания изображений. При включённом ИИ запросы пользователя, необходимые сведения каталога и загруженные для распознавания фото передаются этому сервису. Документы XLSX/DOCX/PDF сначала разбираются на сервере. Изображения товаров загружаются с ekt.kz.
10. Ограничения
- Локальная корзина не связана с настоящими заказами ekt.kz. Оплата, резервирование, доставка и авторизация покупателей магазина не реализованы.
- Каталог ограничен импортированными данными. Снимок не гарантирует актуальность цен и остатков; полный импорт и периодическая синхронизация требуют настройки.
- Подтверждённый список складов для продажи и правила магазина не предоставлены. Название склада само по себе не является разрешением на продажу.
- Некоторые характеристики противоречат друг другу; сертификаты и условия показываются только при наличии источника. Подбор аналогов не гарантирует электротехническую совместимость.
- До 3 вложений за отправку в интерфейсе, до 5 МБ на файл. Изображения — до 12 млн пикселей. Извлечение ограничено 50 позициями на файл; большие документы следует делить.
- Сканированный PDF без текстового слоя напрямую не распознаётся: страницы нужно загрузить как JPEG/PNG. Для фото нужен ключ модели; точность OCR на реальных материалах отдельно не оценена.
- Работа без ключа модели ограничена демонстрационной логикой. Ответы ИИ и распознанные позиции требуют проверки пользователем.
- Встраивание в настоящий ekt.kz и публичное развёртывание не выполнены. Текущая политика сервера запрещает внешнее iframe-встраивание. Для размещения нужны согласованные настройки HTTPS, origin и cookies.
- Нагрузочное тестирование и подготовка к промышленной эксплуатации не выполнены. Локальный запуск подходит для демонстрации на одном компьютере.
Авторы коммитов
История коммитов
- 2026-09-23 17:48feat: finalDamir
- 2026-09-23 17:47feat: final addDamir
- 2026-09-23 17:29feat: add backendbizbenbilimgmail.com
- 2026-09-23 16:11front commitRuslankyzy-Aldina
- 2026-09-23 11:05checkDamir
Структура репозитория (96 файлов)
.DS_Store .env.example .gitignore README.md agent/__init__.py agent/analogs.py agent/service.py backend/.env.example backend/.gitignore backend/Makefile backend/README.md backend/VERIFICATION.md backend/__init__.py backend/app/__init__.py backend/app/api/__init__.py backend/app/api/health.py backend/app/api/products.py backend/app/clients/__init__.py backend/app/clients/ekt_client.py backend/app/config.py backend/app/dependencies.py backend/app/exceptions.py backend/app/fixtures/product_515291.json backend/app/main.py backend/app/schemas/__init__.py backend/app/schemas/product.py backend/app/services/__init__.py backend/app/services/normalization.py backend/app/services/product_service.py backend/attachments.py backend/cart.py backend/catalog.py backend/normalize.py backend/package-test-results.txt backend/pytest.ini backend/requirements.txt backend/server.py backend/smoke-results.json backend/test-results.txt backend/tests/conftest.py backend/tests/test_api.py backend/tests/test_config.py backend/tests/test_ekt_client.py backend/tests/test_normalization.py data/catalog-cache.json data/demo.json data/live-detail.json data/live-page1.json data/page1.json data/page2.json docs/CONTRACT.md docs/INTEGRATION.md docs/VERIFICATION.md docs/benchmark.json docs/live-benchmark.json frontend/.env.example frontend/.gitignore frontend/README.md frontend/index.html frontend/package-lock.json frontend/package.json frontend/public/embed.js frontend/src/app/App.tsx frontend/src/components/CartDialog.tsx frontend/src/components/ProductCard.tsx frontend/src/components/ProposalPanel.tsx frontend/src/components/UploadReview.tsx frontend/src/components/chat/ChatWidget.tsx frontend/src/components/chat/MessageComposer.tsx frontend/src/components/chat/MessageList.tsx frontend/src/components/s frontend/src/data/.gitkeep frontend/src/data/catalog-page-1.json frontend/src/data/catalog-page-2.json frontend/src/data/product-515291.json frontend/src/hooks/useChat.ts frontend/src/main.tsx frontend/src/pages/CartPage.tsx frontend/src/pages/ChatPage.tsx frontend/src/services/backendApi.ts frontend/src/services/catalog.ts frontend/src/services/chatApi.ts frontend/src/services/comparison.ts frontend/src/styles/global.css frontend/src/styles/widget.css frontend/src/types/chat.ts frontend/tests/contracts.mjs frontend/tsconfig.json frontend/vite.config.ts import_catalog.py pytest.ini requirements.txt start.ps1 tests/benchmark.py tests/test_frontend_integration.py tests/test_system.py
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.