AAYMA
RU
Войти

Memory Munchers

AI-консультант по каталогу ekt.kz: чат-помощник подбирает товары, показывает остатки, характеристики и сертификаты, предлагает аналоги, а позиции…

Рабочий MVP
Команда «Memory Munchers» 3💬 0 комментариевс 22 сентября 2026 г.

О проекте

Команда: 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.md

Memory 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:

  1. Скачайте установщик с postgresql.org/download/windows и запустите его.
  2. Оставьте порт по умолчанию 5432.
  3. Задайте пароль для пользователя postgres — он понадобится для строки подключения.
  4. Дождитесь окончания установки (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-помощника (каталог и корзина работают и без него).

  1. Создайте ключ на platform.openai.com/api-keys.
  2. Сохраните его в 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.

Звёзды
⭐ 0
Форки
0
Язык
C#
Последний push
в прошлом месяце
Коммиты
24
Авторы
3
Файлы
75
Ветки
2

Авторы коммитов

ernazarbis 21YernazarB 2ZeroChance1 1

История коммитов

  • 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 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.