О проекте
Команда: Memory Munchers
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Рабочий MVP
Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина
Суть
AI-консультант по каталогу ekt.kz: чат-помощник подбирает товары, показывает остатки, характеристики и сертификаты, предлагает аналоги, а позиции попадают в корзину только после подтверждения пользователем.
Как устроено
Бэкенд на ASP.NET Core (.NET 10) при старте импортирует CSV-каталог (около 12 853 товаров) и демо-фиды остатков и сертификатов в PostgreSQL с pg_trgm. Агент на OpenAI Responses API вызывает инструменты get_product_details, find_product_alternatives (ранжирование по типу товара, характеристикам, бренду, наличию и цене с текстовым обоснованием) и get_purchase_conditions. Агент только создаёт предложение, корзина меняется по нажатию «Подтвердить», при этом проверяются остаток, минимум и кратность. Покупатели изолированы анонимным подписанным токеном, есть rate limiting и удаление данных. Фронтенд на статическом HTML/JS встраивается в 1С-Битрикс.
Ключевые решения
- function calling
- pg_trgm fuzzy search
- alternative ranking with reasons
- confirm-before-cart
- rate limiting
- ASP.NET Data Protection tokens
Особенности
Корзина защищена: агент только предлагает, а подтверждение отклоняется, если цена или остаток изменились. Остатки и сертификаты загружаются отдельными CSV-фидами (формат описан для выгрузки из 1С). Описано встраивание чата в 1С-Битрикс без изменения движка. Приёмочные тесты покрывают каждый пункт Must have.
Стек
C# · ASP.NET Core (.NET 10) · Entity Framework Core · PostgreSQL · HTML/JS · xUnit
Модели
OpenAI Responses API
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-b6e61115-memory-munchers.
README
README.mdMemory Munchers
Репозиторий команды Memory Munchers для хакатона.
Приложение — каталог товаров с AI-помощником и корзиной:
- Бэкенд — ASP.NET Core (.NET 10) в
MemoryMunchers/MemoryMunchers, база данных PostgreSQL, AI-агент через OpenAI Responses API. - Фронтенд — статические HTML/JS-страницы без зависимостей в папке
frontend.
Локальный запуск
1. Установите необходимые программы
- .NET 10 SDK — проверьте командой
dotnet --version. - PostgreSQL (версия 14 или новее).
- Python 3 — только для раздачи статических файлов фронтенда (можно использовать любой другой статический сервер).
2. Установите и настройте PostgreSQL
Windows:
- Скачайте установщик с postgresql.org/download/windows и запустите его.
- Оставьте порт по умолчанию
5432. - Задайте пароль для пользователя
postgres— он понадобится для строки подключения. - Дождитесь окончания установки (Stack Builder можно пропустить).
Или через Docker:
docker run --name memory-munchers-db -e POSTGRES_PASSWORD=123 -p 5432:5432 -d postgres:17
Создавать базу данных вручную не нужно: при запуске API сам создаст базу memory_munchers и применит миграции. Пользователю БД нужны права на установку расширения pg_trgm (у пользователя postgres они есть).
3. Подключите приложение к PostgreSQL
Откройте MemoryMunchers/MemoryMunchers/appsettings.json и укажите свои данные в строке подключения:
"ConnectionStrings": {
"MemoryMunchers": "Host=localhost;Port=5432;Database=memory_munchers;Username=postgres;Password=ВАШ_ПАРОЛЬ"
}
Измените Password (и при необходимости Host, Port, Username) на значения, заданные при установке PostgreSQL.
Вместо правки файла можно задать переменную окружения:
$env:ConnectionStrings__MemoryMunchers = "Host=localhost;Port=5432;Database=memory_munchers;Username=postgres;Password=ВАШ_ПАРОЛЬ"
4. Добавьте API-ключ OpenAI
Ключ нужен для работы AI-помощника (каталог и корзина работают и без него).
- Создайте ключ на platform.openai.com/api-keys.
- Сохраните его в user-secrets. Это хранилище вне репозитория, и API подхватывает его в режиме Development:
dotnet user-secrets set "OpenAI:ApiKey" "sk-ваш-ключ" --project MemoryMunchers/MemoryMunchers
Либо задайте переменную окружения (она имеет приоритет над appsettings.json):
$env:OpenAI__ApiKey = "sk-ваш-ключ"
⚠️ Не вписывайте ключ в
appsettings.json: этот файл коммитится. Во фронтенд ключ тоже не добавляйте.
Если ключ не задан, запросы к агенту вернут HTTP 503 с кодом provider_not_configured.
5. Запустите API
Из корня репозитория:
dotnet run --project MemoryMunchers/MemoryMunchers --launch-profile http
API будет доступен по адресу http://localhost:5187. При старте автоматически применяются миграции базы данных.
6. Запустите фронтенд
В другом терминале, из корня репозитория:
python -m http.server 5500 --directory frontend
7. Откройте приложение
Откройте в браузере http://localhost:5500.
При старте API сам импортирует каталог из MemoryMunchers/MemoryMunchers/nursultan_ekt_catalog.csv (около 12 853 товаров), а затем демо-фиды остатков и сертификатов (см. ниже). Первый запуск может занять некоторое время.
Страницы:
| Адрес | Что открывается |
|---|---|
http://localhost:5500/ | Каталог товаров с чатом Помощник |
http://localhost:5500/basket.html | Корзина |
Фронтенд по умолчанию обращается к API по адресу http://localhost:5187. Изменить адрес можно в блоке Подключение к серверу на странице. Если фронтенд открыт с другого адреса (не localhost:5500), добавьте этот адрес в Cors:AllowedOrigins, иначе браузер заблокирует запросы.
Что умеет помощник
| Требование | Как реализовано |
|---|---|
| Наличие, характеристики, сертификаты | get_product_details возвращает остаток (availableQuantity, stockStatus), характеристики и сертификаты со ссылкой /api/certificates/{id} |
| Аналоги при отсутствии товара | find_product_alternatives исключает товары с нулевым остатком и ранжирует кандидатов по типу товара (словам из названия), совпадающим характеристикам, подкатегории, бренду, наличию и цене. Для каждого аналога возвращается текстовое обоснование reason, которое показывается в карточке. |
| Условия покупки | get_purchase_conditions: оплата, доставка, самовывоз, возврат и минимальный заказ из Shopping:PurchaseConditions (взяты с nursultan.ekt.kz), плюс минимум и кратность по конкретным товарам |
| Корзина только после подтверждения | Агент создаёт только предложение. Корзина меняется лишь по нажатию «Подтвердить добавление». Количество проверяется по остатку, минимуму, кратности и лимиту; если цена или остаток изменились, подтверждение отклоняется. |
| Ссылка на корзину | После подтверждения в чате появляется ссылка Shopping:BasketUrl; со страницы корзины можно перейти к оформлению (Shopping:CheckoutUrl) |
Безопасность и приватность
- Изоляция покупателей. Каждый браузер получает анонимный подписанный токен (
POST /api/shopper, ASP.NET Data Protection). Токен передаётся в заголовкеX-Shopper-Token. Корзина, диалоги и файлы видны только владельцу токена; без токена API отвечает 401. - Защита корзины от посторонних изменений. Cookie не используются, поэтому сторонний сайт не может отправить запрос от имени покупателя (CSRF). CORS разрешён только для адресов из
Cors:AllowedOrigins. Подтвердить чужое предложение нельзя: API ответит 404. - Ограничение частоты запросов (
RateLimits): сообщения в чат, загрузка файлов, операции с корзиной и выдача токенов. При превышении API отвечает 429. - Хранение данных. Вложения удаляются через
AttachmentLifetimeHours, диалоги — послеSessionRetentionDaysдней неактивности. Кнопка «Удалить мои данные» в чате (DELETE /api/shopper) сразу удаляет диалоги, файлы и корзину. OpenAI вызывается сstore: false, тексты сообщений в логи не пишутся. Агенту запрещено запрашивать персональные данные.
Данные магазина: остатки и сертификаты
Публичный каталог не содержит остатков и сертификатов, поэтому их загружают отдельными фидами (например, выгрузкой из 1С). Формат — CSV с разделителем ;:
| Фид | Колонки |
|---|---|
| Остатки | ID товара;Остаток[;Проверено UTC] |
| Сертификаты | ID товара;Номер;Тип;Выдан;Действует до;URL;Файл (файлы кладутся в папку certificates/ рядом с API) |
Загрузка реальных фидов (задайте Admin:ApiKey, по умолчанию эндпоинты выключены):
curl.exe -X POST -H "X-Admin-Key: <ключ>" -F "[email protected]" http://localhost:5187/api/admin/inventory
curl.exe -X POST -H "X-Admin-Key: <ключ>" -F "[email protected]" http://localhost:5187/api/admin/certificates
Демо-данные. При DemoData:Enabled = true API загружает demo_inventory.csv и demo_certificates.csv при старте, а остатки обновляет каждые 6 часов. Остатки сгенерированы: у позиций «Купить» от 5 до 184 шт., у каждой 9-й — 0. Позиции «Под заказ» без остатка. Сертификаты (у каждого 10-го товара) помечены «ДЕМО» и не являются реальными документами. Остатки старше InventoryMaxAgeMinutes считаются неизвестными. Для продакшена выключите DemoData:Enabled и загружайте реальные фиды.
Встраивание в сайт (1С-Битрикс)
Сайт nursultan.ekt.kz работает на 1С-Битрикс. Чат встраивается без изменений в движке: подключите в шаблоне (например, в footer.php) стили и скрипты, опубликованные вместе с API:
<link rel="stylesheet" href="https://assistant.example/chatbot.css">
<script src="https://assistant.example/shopping.js" data-api="https://api.assistant.example" data-basket-url="https://assistant.example/basket.html" defer></script>
<script src="https://assistant.example/chatbot.js" defer></script>
Затем добавьте адрес сайта в Cors:AllowedOrigins и пропишите Shopping:BasketUrl, Shopping:PublicApiUrl и Shopping:CheckoutUrl (сейчас это https://nursultan.ekt.kz/personal/cart/). Вёрстка адаптивная: на экранах до 520 px чат открывается на весь экран.
Автоматический перенос позиций в корзину Битрикс (
sale.basketitem.addчерез REST) требует доступа к API сайта и пока не подключён. До этого кнопка «Оформить заказ на сайте» открывает корзину сайта, а товары открываются по ссылкам из карточек.
Тесты
Приёмочные тесты по каждому пункту Must have, а также по изоляции покупателей, CORS и удалению данных лежат в MemoryMunchers/MemoryMunchers.Tests. Они запускают настоящий API на отдельной базе memory_munchers_tests; OpenAI при этом не вызывается, инструменты агента выполняются напрямую.
dotnet test MemoryMunchers/MemoryMunchers.Tests
Другую базу можно задать через $env:MM_TEST_CONNECTION = "Host=...;Database=...;Username=...;Password=...".
Частые проблемы
- Ошибка подключения к базе — проверьте, что PostgreSQL запущен, и что пароль/порт в строке подключения верные.
- Ошибка при установке
pg_trgm— используйте пользователя с правами суперпользователя или попросите администратора выполнитьCREATE EXTENSION pg_trgm;в базеmemory_munchers. - Помощник не отвечает (HTTP 503) — не задан
OpenAI:ApiKey. Добавьте ключ и перезапустите API. - HTTP 401
shopper_required— токен покупателя устарел (например, после смены ключей Data Protection). Обновите страницу: фронтенд получит новый токен сам. - Запросы блокируются CORS — добавьте адрес, с которого открыт фронтенд, в
Cors:AllowedOrigins. - HTTP 500 — смотрите логи API в терминале, где он запущен.
Ручное применение миграций (необязательно)
Миграции применяются при старте API, но их можно применить и вручную из корня репозитория:
dotnet tool restore
dotnet ef database update --project MemoryMunchers/MemoryMunchers
На сайте, агента можно найти тут:
Есть еще алтернативная версия решения на python в ветке alternative_version.
Авторы коммитов
История коммитов
- 2026-09-23 17:58Update README.mdYernazarB
- 2026-09-23 17:55Подготовлена альтернативная версия EKT: Docker, аудит HACKALEM и проверки корзиныZeroChance1
- 2026-09-23 17:44Update README.mdYernazarB
- 2026-09-23 17:33the latest refinementsernazarbis
- 2026-09-23 16:51removed the unnecessary chatbot pageernazarbis
- 2026-09-23 16:39updated readmeernazarbis
- 2026-09-23 16:26removed the exposed api keyernazarbis
- 2026-09-23 16:21fix the first chaternazarbis
Все коммиты (24)
- 2026-09-23 16:14integrate the chatbot with the producgtsernazarbis
- 2026-09-23 15:24translated to russianernazarbis
- 2026-09-23 15:10products as a main pageernazarbis
- 2026-09-23 15:05removed the testsernazarbis
- 2026-09-23 15:03products pageernazarbis
- 2026-09-23 14:52fetched test dataernazarbis
- 2026-09-23 14:32open api keyernazarbis
- 2026-09-23 14:25test agent session pageernazarbis
- 2026-09-23 14:07using gpt-6ernazarbis
- 2026-09-23 14:06agent's initial set upernazarbis
- 2026-09-23 12:53removed the unnecessary changesernazarbis
- 2026-09-23 12:51Add memory entry API and formernazarbis
- 2026-09-23 12:21updated read meernazarbis
- 2026-09-23 12:19added sample frontendernazarbis
- 2026-09-23 11:46Add Memory Munchers API projecternazarbis
- 2026-09-22 23:53Update READMEernazarbis
Структура репозитория (75 файлов)
.gitignore MemoryMunchers/MemoryMunchers.Tests/MemoryMunchers.Tests.csproj MemoryMunchers/MemoryMunchers.Tests/MustHaveTests.cs MemoryMunchers/MemoryMunchers.Tests/ShopFixture.cs MemoryMunchers/MemoryMunchers.slnx MemoryMunchers/MemoryMunchers/Agents/AgentCatalog.cs MemoryMunchers/MemoryMunchers/Agents/AgentContracts.cs MemoryMunchers/MemoryMunchers/Agents/AgentDefinition.cs MemoryMunchers/MemoryMunchers/Agents/AgentEventSink.cs MemoryMunchers/MemoryMunchers/Agents/AgentException.cs MemoryMunchers/MemoryMunchers/Agents/AgentExceptionHandler.cs MemoryMunchers/MemoryMunchers/Agents/AgentHistory.cs MemoryMunchers/MemoryMunchers/Agents/AgentRunner.cs MemoryMunchers/MemoryMunchers/Agents/AgentServiceCollectionExtensions.cs MemoryMunchers/MemoryMunchers/Agents/AgentSessionService.cs MemoryMunchers/MemoryMunchers/Agents/AgentToolRegistry.cs MemoryMunchers/MemoryMunchers/Agents/OpenAI/OpenAiOptions.cs MemoryMunchers/MemoryMunchers/Agents/OpenAI/OpenAiResponsesClient.cs MemoryMunchers/MemoryMunchers/Agents/Persistence/AgentRun.cs MemoryMunchers/MemoryMunchers/Agents/Persistence/AgentSession.cs MemoryMunchers/MemoryMunchers/Agents/Persistence/PostgresAgentSessionLock.cs MemoryMunchers/MemoryMunchers/Agents/Persistence/PostgresAgentSessionStore.cs MemoryMunchers/MemoryMunchers/Controllers/AdminFeedsController.cs MemoryMunchers/MemoryMunchers/Controllers/BasketController.cs MemoryMunchers/MemoryMunchers/Controllers/CertificatesController.cs MemoryMunchers/MemoryMunchers/Controllers/ProductChatController.cs MemoryMunchers/MemoryMunchers/Controllers/ProductsController.cs MemoryMunchers/MemoryMunchers/Controllers/ShopperController.cs MemoryMunchers/MemoryMunchers/MemoryMunchers.csproj MemoryMunchers/MemoryMunchers/MemoryMunchers.http MemoryMunchers/MemoryMunchers/Migrations/20260923074135_init.Designer.cs MemoryMunchers/MemoryMunchers/Migrations/20260923074135_init.cs MemoryMunchers/MemoryMunchers/Migrations/20260923085413_AddAgentSessions.Designer.cs MemoryMunchers/MemoryMunchers/Migrations/20260923085413_AddAgentSessions.cs MemoryMunchers/MemoryMunchers/Migrations/20260923095627_AddProducts.Designer.cs MemoryMunchers/MemoryMunchers/Migrations/20260923095627_AddProducts.cs MemoryMunchers/MemoryMunchers/Migrations/20260923100630_RemoveWeatherForecasts.Designer.cs MemoryMunchers/MemoryMunchers/Migrations/20260923100630_RemoveWeatherForecasts.cs MemoryMunchers/MemoryMunchers/Migrations/20260923105301_AddProductShopping.Designer.cs MemoryMunchers/MemoryMunchers/Migrations/20260923105301_AddProductShopping.cs MemoryMunchers/MemoryMunchers/Migrations/20260923121641_AddProductCertificates.Designer.cs MemoryMunchers/MemoryMunchers/Migrations/20260923121641_AddProductCertificates.cs MemoryMunchers/MemoryMunchers/Migrations/MemoryMunchersDbContextModelSnapshot.cs MemoryMunchers/MemoryMunchers/Persistence/MemoryMunchersDbContext.cs MemoryMunchers/MemoryMunchers/Products/MerchantFeedImporter.cs MemoryMunchers/MemoryMunchers/Products/Product.cs MemoryMunchers/MemoryMunchers/Products/ProductCatalogReader.cs MemoryMunchers/MemoryMunchers/Products/ProductCatalogService.cs MemoryMunchers/MemoryMunchers/Program.cs MemoryMunchers/MemoryMunchers/Properties/launchSettings.json MemoryMunchers/MemoryMunchers/Shopping/AttachmentService.cs MemoryMunchers/MemoryMunchers/Shopping/BasketService.cs MemoryMunchers/MemoryMunchers/Shopping/ProductChatService.cs MemoryMunchers/MemoryMunchers/Shopping/ProductConsultant.cs MemoryMunchers/MemoryMunchers/Shopping/ProductLookup.cs MemoryMunchers/MemoryMunchers/Shopping/ShopperContext.cs MemoryMunchers/MemoryMunchers/Shopping/ShoppingModels.cs MemoryMunchers/MemoryMunchers/appsettings.Development.json MemoryMunchers/MemoryMunchers/appsettings.json MemoryMunchers/MemoryMunchers/demo_certificates.csv MemoryMunchers/MemoryMunchers/demo_inventory.csv MemoryMunchers/MemoryMunchers/nursultan_ekt_catalog.csv README.md dotnet-tools.json frontend/basket.css frontend/basket.html frontend/basket.js frontend/chatbot.css frontend/chatbot.js frontend/index.html frontend/products.css frontend/products.html frontend/products.js frontend/shopping.js frontend/styles.css
Ветки (2)
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.