О проекте
Команда: BlueLens
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Рабочий MVP
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
Чат-консультант для ekt.kz: ищет товары по артикулу, названию и бренду, показывает цены, остатки по городам и аналоги, добавляет в корзину после подтверждения и разбирает загруженные PDF/DOCX/XLSX/изображения.
Как устроено
В DEMO_MODE загружается локальный каталог из 40 позиций, собранный из выгрузок кейса (catalog.json); сессии и корзина хранятся в SQLite. Свободные запросы обрабатывает gpt-4o-mini через function calling: поиск, карточка товара, остатки, аналоги и корзина вынесены в backend tools. Демо-фразы обрабатывает локальный сценарный обработчик без ключа. Поиск использует нормализацию и простой fuzzy matching. Перед добавлением в корзину backend заново проверяет остаток и отклоняет неподтверждённые запросы. Отдельный скрипт синхронизирует каталог с API ekt.kz по Basic Auth.
Ключевые решения
- function calling
- fuzzy matching
- двухшаговое подтверждение корзины
- мультимодальное распознавание изображений
- сессионный контекст
Особенности
Бот не выдумывает данные: неизвестные остатки явно помечаются как неизвестные, а запрос сверх остатка отклоняется с предложением доступного количества. Контекст сессии позволяет ссылаться на «второй» товар из выдачи. Код продублирован в папке Hackalemai-main после перезаливки.
Стек
Python · FastAPI · SQLite · Next.js · Tailwind · Docker
Модели
gpt-4o-mini
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-5c17db41-bluelens.
EKT — ИИ-помощник по каталогу
Локальный MVP для демонстрации чата интернет-магазина электротехники ekt.kz. По умолчанию приложение работает в DEMO_MODE=true: берет 40 позиций из загруженных материалов кейса, использует SQLite для сессий и корзины и не обращается к API магазина.
Возможности MVP
- Поиск по артикулу, названию и бренду с нормализацией текста и простым fuzzy matching.
- Карточки товаров с ценой и известными характеристиками.
- Остаток по городу только для товаров, где он есть в исходных деталях. Для товара
027228каталог содержит общий остаток 23 шт. и остаток Алматы 5 шт.; неизвестные поля не заполняются вымышленными значениями. - Подбор близких позиций той же серии и сравнение характеристик.
- Контекст сессии хранится в SQLite. Можно спросить про «второй» товар в найденном списке.
- Корзина с двухшаговым подтверждением в чате и окном подтверждения в интерфейсе. Перед записью backend заново проверяет товар, остаток и количество; неподтверждённые запросы, неизвестный остаток и превышение остатка отклоняются.
- Загрузка PDF, DOCX, XLSX и PNG/JPG. Документы разбираются локально; для распознавания изображения нужен
OPENAI_API_KEY. - OpenAI chat completions с function calling для свободных запросов (при наличии ключа). Поиск, данные товара, остатки, аналоги и корзина доступны модели как backend tools. Для предусмотренных демо-фраз работает локальный сценарный обработчик и ключ не требуется.
- Отдельный скрипт синхронизации каталога с ekt.kz Basic Auth. В обычном демо-запуске внешнее API не вызывается.
Структура
backend/app/main.py FastAPI API, инструменты каталога, SQLite, upload, чат
backend/app/system_prompt.txt системные правила AI-консультанта
backend/tests/ интеграционные и доменные smoke-тесты
data/catalog.json нормализованный локальный каталог для DEMO_MODE
frontend/app/ Next.js интерфейс чата и корзины
scripts/prepare_catalog.mjs импорт исходных JSON-выгрузок проекта
scripts/sync_catalog.py опциональная синхронизация с API магазина
product_list.txt загруженная выгрузка каталога, страница 1
page_2_product.txt загруженная выгрузка каталога, страница 2
detail_inf.txt загруженная карточка товара 027228
Требования
- Node.js 20 или новее и npm.
- Python 3.10–3.13.
В Windows PowerShell используйте py -3.13 или py -3.12, если соответствующая версия установлена. Команды ниже показаны для py -3.13.
Установка и запуск
Откройте два терминала из папки проекта.
- Создайте локальную конфигурацию и подготовьте каталог:
if (!(Test-Path .env)) { Copy-Item .env.example .env }
node scripts/prepare_catalog.mjs
- Установите и запустите backend:
py -3.13 -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r backend\requirements.txt
python -m uvicorn backend.app.main:app --reload --host 127.0.0.1 --port 8000
- Во втором терминале установите и запустите frontend:
cd frontend
Copy-Item .env.local.example .env.local
npm install
npm run dev
Откройте http://localhost:3000. API и интерактивная документация доступны по http://localhost:8000/api/health и http://localhost:8000/docs.
Если PowerShell запрещает активацию виртуального окружения, можно не активировать его и запускать \.venv\Scripts\python.exe -m pip ... / \.venv\Scripts\python.exe -m uvicorn ....
Docker
После создания .env:
docker compose up --build
Настройка переменных
В проекте уже создан локальный .env, который исключён из Git. Откройте его и вставьте ключ после OPENAI_API_KEY=. После изменения перезапустите backend (или docker compose up --build). Проверка http://localhost:8000/api/health должна вернуть "ai_enabled": true; сам ключ API наружу не передаётся и не возвращается.
| Переменная | Назначение |
|---|---|
DEMO_MODE=true | Локальный каталог из файлов кейса; не вызывает ekt.kz API |
OPENAI_API_KEY | Необязательный OpenAI tool calling и multimodal распознавание изображений |
OPENAI_MODEL=gpt-4o-mini | Модель диалога с function calling |
EKT_API_USERNAME, EKT_API_PASSWORD | Basic Auth для явной синхронизации каталога |
EKT_API_BASE_URL=https://ekt.kz/api | Базовый URL API магазина |
DATABASE_PATH | Файл SQLite для сессий и корзины |
FRONTEND_ORIGIN | Origin для CORS backend |
Локальная сборка и основные сценарии работают без OpenAI API key. Без ключа image upload сообщает, что визуальное распознавание отключено; файл остаётся принятым, а поиск в локальном каталоге доступен по тексту.
Синхронизация каталога ekt.kz
Демо по умолчанию не делает сетевых запросов. Для опционального импорта задайте EKT_API_USERNAME и EKT_API_PASSWORD в .env, затем запустите:
python scripts/sync_catalog.py
Скрипт проходит GET /products, страницы ?page=N, затем запрашивает GET /products/detail?id={id}. Он использует Basic Auth, timeout и три попытки; учётные данные не записываются в каталог. После синхронизации backend читает сохранённый data/catalog.json, а не обращается к API на каждое сообщение. Перед production-использованием нужно проверить фактический контракт пагинации API и нормализацию характеристик.
Проверки
python -m unittest backend.tests.test_assistant -v
cd frontend
npm run build
API curl-примеры:
curl "http://localhost:8000/api/products/search?q=027228"
curl "http://localhost:8000/api/products/027228/stock?city=Алматы"
curl "http://localhost:8000/api/products/515291/analogs"
curl "http://localhost:8000/api/cart?session_id=demo-session"
Демо-последовательность
Найди Legrand— список локальных позиций.Есть ли 027228?— цена и общий остаток из detail-файла.Есть ли 027228 в Алматы?— городской остаток из списка складов.Покажи характеристики— данные сохранённого выбранного товара.Покажи аналоги— близкие позиции серии DRX250 MT с отличиями параметров.Мне нужно 3 штуки— запрос подтверждения, корзина пока без изменений.Да, добавь— повторная проверка остатка и запись в корзину.Добавь 100 штук— backend отклоняет превышение и предлагает остаток, не изменяя корзину.
На карточке товара действие также открывает подтверждение перед запросом POST /api/cart/add.
Ограничения демо и production
- Демо-файлы содержат две страницы (40 позиций) и одну полную детальную запись. Цена и остатки для остальных позиций есть не везде, поэтому UI явно показывает неизвестный остаток.
- Поиск по характеристикам использует поля, извлечённые из названий и одной детальной карточки; для точного аналога нужны полные API details.
- SQLite предназначена для локальной демонстрации. Корзина разделена по постоянному случайному ID посетителя в браузере; это удобство демо, но не способ аутентификации. Перед публичным использованием привяжите корзину к серверной сессии в защищённой cookie или аккаунту, добавьте rate limiting и серверный аудит. В демо остаток проверяется отдельно в корзине каждого посетителя; резервирование общего складского остатка не подключено.
- Реальная корзина сайта не подключена: текущая корзина — локальная демонстрационная таблица SQLite.
- Перед production-синхронизацией следует проверить формат ekt API и поля остатков, а также настроить HTTPS, CORS и ротацию секретов.
Авторы коммитов
История коммитов
- 2026-09-23 17:13Add files via uploadInt665
- 2026-09-23 17:11Delete docker-compose.ymlInt665
- 2026-09-23 17:11Delete detail_inf.txtInt665
- 2026-09-23 17:11Delete README.mdInt665
- 2026-09-23 17:11Delete scripts directoryInt665
- 2026-09-23 17:10Delete frontend directoryInt665
- 2026-09-23 17:10Delete backend directoryInt665
- 2026-09-23 17:10Delete data directoryInt665
Все коммиты (17)
- 2026-09-23 16:24Remove generated cache and demo databasebissrx
- 2026-09-23 16:22Merge remote-tracking branch 'submission/main'bissrx
- 2026-09-23 16:22Restrict assistant answers to verified EKT databissrx
- 2026-09-23 15:09Isolate demo carts by visitor sessionbissrx
- 2026-09-23 15:08Update README.mdRikomiko1
- 2026-09-23 15:05Add files via uploadbissrx
- 2026-09-23 14:54Build ekt.kz AI assistant demo MVPbissrx
- 2026-09-23 14:50Rename repository from BlueLens to NightsWatchInt665
- 2026-09-23 14:48Update README.mdInt665
Структура репозитория (37 файлов)
.env.example .gitignore HackAlem_AI_ИИ_ассистент_для_чата_на_сайте_ekt_kz.pdf Hackalemai-main/HackAlem_AI_ИИ_ассистент_для_чата_на_сайте_ekt_kz.pdf Hackalemai-main/README.md Hackalemai-main/backend/Dockerfile Hackalemai-main/backend/__init__.py Hackalemai-main/backend/app/__init__.py Hackalemai-main/backend/app/main.py Hackalemai-main/backend/app/system_prompt.txt Hackalemai-main/backend/data/ekt_assistant.sqlite3 Hackalemai-main/backend/requirements.txt Hackalemai-main/backend/tests/__init__.py Hackalemai-main/backend/tests/test_assistant.py Hackalemai-main/data/case_description.txt Hackalemai-main/data/catalog.json Hackalemai-main/detail_inf.txt Hackalemai-main/docker-compose.yml Hackalemai-main/frontend/Dockerfile Hackalemai-main/frontend/app/cart/page.tsx Hackalemai-main/frontend/app/extras.css Hackalemai-main/frontend/app/globals.css Hackalemai-main/frontend/app/layout.tsx Hackalemai-main/frontend/app/page.tsx Hackalemai-main/frontend/lib/session.ts Hackalemai-main/frontend/next.config.mjs Hackalemai-main/frontend/package-lock.json Hackalemai-main/frontend/package.json Hackalemai-main/frontend/postcss.config.mjs Hackalemai-main/frontend/tailwind.config.ts Hackalemai-main/frontend/tsconfig.json Hackalemai-main/page_2_product.txt Hackalemai-main/product_list.txt Hackalemai-main/scripts/prepare_catalog.mjs Hackalemai-main/scripts/sync_catalog.py page_2_product.txt product_list.txt
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.