AAYMA
RU
Войти

ИИ-консультант ekt.kz

Консультант для покупателей ekt.kz: ищет товары с учётом опечаток и синонимов, показывает цены и остатки по складам, подбирает аналоги с отличиями…

Доведённый продукт
Команда «Qazyna» 20💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: Qazyna
Кейс HackAlem.ai: Торговля — Электрокомплект · ekt.kz
Стадия: Доведённый продукт

Задача кейса: AI-консультант по каталогу ekt.kz: товары, аналоги, цены, остатки, корзина

Суть

Консультант для покупателей ekt.kz: ищет товары с учётом опечаток и синонимов, показывает цены и остатки по складам, подбирает аналоги с отличиями, отвечает про условия покупки и ведёт корзину с явным подтверждением. Есть два интерфейса: Streamlit и встраиваемый JS-виджет на FastAPI.

Как устроено

ShopAgent определяет язык (рус/каз) и выбирает инструменты из TOOL_SCHEMAS: search_products, get_product, find_analogs, get_purchase_terms, propose_add_to_cart / confirm_add_to_cart, recommend_accessories, request_manager. Catalog работает по кэшу реального каталога ekt.kz (JSON api_details). Аналоги сверяются по току, полюсам и току утечки с разницей в цене. Корзина меняется только через Cart.confirm() в отдельном ходе клиента с проверкой остатка и минимальной партии. Вложения (спецификации, фото) разбираются локально или через модель OpenAI.

Ключевые решения

  • OpenAI function calling
  • поиск с учётом опечаток и синонимов
  • подбор аналогов по характеристикам
  • двухшаговое подтверждение корзины
  • распознавание вложений
  • эскалация менеджеру со сводкой

Особенности

Подтверждение покупки проверяется в коде, а не промптом. Текст вложения не может подтвердить покупку, так как берётся last_user_message до добавления контекста. В сводке для менеджера маскируются платёжные реквизиты. Таблица «Must have из ТЗ → реализация → как проверить» со ссылками на тесты.

Стек

Python · Streamlit · FastAPI · HTML/JavaScript widget

Модели

OpenAI (модель не указана)


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-c8f31fa0-qazyna.

README

README.md

⚡ ИИ-консультант ekt.kz

HackAlem AI · трек «Торговля» · партнёр — ТОО «Электрокомплект».

Консультант для покупателей электротехники: помогает найти товар, узнать характеристики и остатки по складам, сравнить аналоги и подготовить корзину. Проект решает задачу первичной консультации, с которой покупатель обычно обращается к менеджеру магазина.

В репозитории есть два интерфейса: Streamlit-демо с загрузкой спецификаций и встраиваемый HTML/JavaScript-виджет с сервером FastAPI. Они используют общие модули каталога, агента и корзины. Для показа жюри включён реальный сохранённый каталог ekt.kz; для ответов модели нужен собственный OPENAI_API_KEY.

Демо

Наличие, цена и характеристики автомата IEK ВА47-29 25А 1P.

Наличие, цена и характеристики автомата IEK ВА47-29 25А 1P.

Подтверждение добавления в корзину и ссылка в Streamlit.

Подтверждение добавления в корзину и ссылка в Streamlit.

Виджет на мобильном: наличие и характеристики товара.

Виджет на мобильном: наличие и характеристики товара.

Подтверждение корзины отдельным сообщением и ссылка в виджете.

Подтверждение корзины отдельным сообщением и ссылка в виджете.

Корзина по ссылке: 2 шт. автомата, итоговая сумма 1 616 ₸.

Корзина по ссылке: 2 шт. автомата, итоговая сумма 1 616 ₸.

Что реализовано

  • Поиск по артикулу, названию, бренду и характеристикам. Учитываются опечатки, синонимы «автомат» / «автоматический выключатель», «УЗО» / «устройство защитного отключения», записи ампер и обозначения полюсов.
  • Карточки с ценой, характеристиками, суммарным остатком и распределением по складам. Данные берутся из каталога.
  • Подбор кандидатов на замену товара с нулевым остатком: совпадающие характеристики, отличия и разница в цене.
  • Условия оплаты, доставки, возврата и покупки с сохранёнными ссылками на источники и предупреждениями о противоречиях.
  • Корзина через предложение и отдельное подтверждение клиента; проверяются минимальная партия и доступное количество.
  • Ссылка на страницу корзины. В HTTP-виджете также восстанавливается диалог после обновления страницы в той же вкладке.
  • Казахский язык, рекомендации сопутствующих товаров, сводка для менеджера и проверка вложений — подробнее в разделе «Опционально реализовано».

Это демонстрационный консультант с собственной корзиной. Оформление заказа, оплата и запись корзины в учётную систему партнёра не подключены.

Must have из ТЗ ekt.kz → как реализовано → как проверить

Все артикулы в таблице есть в сохранённом реальном кэше. Примеры цен и остатков относятся к этому снимку, а не к наличию на сайте в момент показа.

Must have из ТЗ ekt.kzКак реализованоКак проверить
1. Наличие, характеристики, сертификатыsearch_products и get_product возвращают карточку из каталога. Если документа сертификата нет, агент сообщает об этом и предлагает обратиться к менеджеру, не придумывая ссылку.Спросить «Покажи цену, наличие и характеристики 010500008_», затем «Покажи сертификат на 010500008_». В кэше: 25 А, 1 полюс, характеристика C; сертификата нет. Автопроверки: test_demo_real.py, test_catalog_api.py.
2. Аналоги при нулевом остатке с обоснованиемfind_analogs возвращает доступные кандидаты с matching_specs, differences, price_diff_kzt. Для аппаратов защиты проверяются ток и полюса, для УЗО/дифавтоматов — также ток утечки.Спросить «Есть ли 11006DEK? Если нет, покажи аналоги и отличия». Остаток исходного товара — 0. Проверить объяснение совпадений и отличий, включая характеристику B у оригинала и возможную C у кандидатов. Тесты: test_live_regressions.py.
3. Условия покупкиget_purchase_terms читает purchase_terms.json: условия, source, дату проверки, предупреждения.Спросить «Как оплатить заказ, какие условия доставки в Алматы и минимальная партия? Укажи источник». Ответ должен отметить расхождение порогов доставки 30 000 / 15 000 ₸ и не придумывать общий минимум заказа. Тесты: test_demo_real.py.
4. Корзина только после явного подтверждения с учётом остатковpropose_add_to_cart создаёт предложение; confirm_add_to_cart вызывает Cart.confirm(). Подтверждение проверяется кодом, в отдельном ходе после предложения. Минимум проверяется при предложении, остаток — также при подтверждении с учётом уже добавленного количества.Попросить «Предложи добавить 2 товара 010500008_». До отдельного «Да, добавь» корзина пуста. На «Нет, не добавляй» она не меняется. Запрос 100 000 единиц этого артикула превышает остаток снимка и должен быть отклонён. Тесты: test_must_have.py, test_server.py.
5. Ссылка на корзинуStreamlit: /?cart=<id>. FastAPI: /cart/<id>. Страница читает состав корзины из памяти соответствующего сервера.После подтверждения открыть ссылку и увидеть 2 товара 010500008_, сумма по снимку — 1 616 ₸. После следующего добавления обновить страницу. Тесты: test_demo_real.py, test_server.py.

Как работает решение

  1. Входные данные. Покупатель пишет вопрос или прикладывает спецификацию в Streamlit. Для текстовых документов содержимое извлекается локально; фотография распознаётся моделью через OpenAI API.
  2. Диалог и поиск. ShopAgent определяет язык ответа. Модель выбирает инструменты из TOOL_SCHEMAS, например поиск, карточку товара или условия покупки. Артикулы из вложения проверяются по каталогу, результаты передаются агенту как контекст.
  3. Проверка данных. Catalog ищет в загруженной выборке. В режиме API полная карточка при необходимости запрашивается отдельно. Пустой поиск не означает, что товара нет на всём сайте.
  4. Результат консультации. Клиент получает сведения о товаре, кандидатов на замену с отличиями и условия покупки. При отсутствии сертификата агент сообщает, что документа нет в базе.
  5. Предложение покупки. Агент показывает товар, количество и сумму, затем спрашивает о добавлении. На этом шаге корзина не меняется.
  6. Подтверждение. Отдельное сообщение «Да, добавь», «иә», «қосыңыз» или нажатие кнопки проходит проверки Cart.confirm(). После успешного добавления выдаётся ссылка на корзину.
  7. Помощь менеджера. По кнопке или запросу в чате создаётся сводка: запрос клиента, рассмотренные товары, подтверждённая корзина и неподтверждённые предложения. Автоматической отправки менеджеру нет.

Требования партнёра

ТребованиеРеализация и границы
Нет изменения корзины без подтвержденияДобавление из инструментов агента и HTTP-интерфейса проходит через Cart.confirm(). Предложение само по себе не меняет корзину.
Нет выдуманных цен и наличияИнструменты возвращают значения из каталога; промпт запрещает дополнять их догадками. Если поле или товар отсутствует, это сообщается клиенту. Свободные формулировки модели требуют проверки при демонстрации.
Не запрашиваем платёжные данныеВ чате и передаче менеджеру не предусмотрен сбор номера карты, CVV/CVC или PIN. В сводке маскируются распознанные реквизиты и исключаются просьбы их прислать. Платёжного интерфейса нет.
ПриватностьСекреты задаются в .env, который исключён из Git; в .env.example только плейсхолдеры. Загруженные документы не сохраняются приложением на диск. История диалога и корзины находятся в памяти сервера. Текст диалога и контекст обрабатываются внешним OpenAI API; полная анонимизация всей истории не реализована.
Подтверждение проверяется в коде; текст вложения не может подтвердить покупкуПроверяются отдельный ход клиента, явное согласие и отрицания. last_user_message берётся из сообщения клиента до добавления контекста вложения. Это проверяет test_attachments.py.
Объяснимость аналоговВыдаются совпадения, различия и разница цены. Подбор по части характеристик не является гарантией полной взаимозаменяемости; различия типа B/C требуют уточнения.
Виджет для встраивания в сайтstatic/widget.js создаёт кнопку чата и iframe с static/widget.html. Серверная часть — server.py. Пример встраивания приведён ниже.
Десктоп и мобильная версияHTML-виджет содержит viewport, адаптивную ширину и высоту относительно экрана, перенос длинного текста и прокрутку. Для жюри предусмотрена ручная проверка на ширине 320 px. Это веб-интерфейс, отдельного мобильного приложения нет.

В демо нет авторизации владельца сессии или корзины: доступ определяется идентификатором в запросе/ссылке. Поэтому текущую реализацию нельзя считать готовым защищённым сервисом для персональных данных реальных клиентов.

Опционально реализовано

ВозможностьЧто доступно
Казахский языкАвтоопределение языка диалога, сохранение языка при коротких ответах и артикулах. В Streamlit есть выбор «Қазақша», переведённые кнопки и сообщения об ошибках модели. «Иә» и «қосыңыз» проходят обычные проверки корзины. Подписи HTML-виджета и часть HTTP-сообщений пока на русском.
Сопутствующие товарыrecommend_accessories: к автомату ищутся DIN-рейки и боксы, к кабелю — гофра. Предлагаются только найденные в каталоге позиции с остатком не ниже минимальной партии. При отсутствии товара не предлагаются даже категории вместо него. В текущем кэше подходящих дополнений нет; совместимость найденных в будущем позиций требует проверки.
Эскалация на менеджераКнопка «Позвать менеджера» есть в Streamlit и HTML-виджете. request_manager готовит сводку без дополнительного вызова модели. В Streamlit её можно скачать в TXT/UTF-8. Передача по контактам сайта — ручная; CRM и уведомления менеджеру не подключены.
ВложенияВ Streamlit: Excel .xlsx, Word .docx, текстовый PDF, фото .jpg, .jpeg, .png. Поддерживаются проверка найденных позиций и поиск аналогов при нулевом остатке. Лимиты: 10 МБ на файл, 50 строк позиций и 40 000 символов извлечённого текста. В HTTP-виджете загрузки файлов нет.

Технологии

Зависимости перечислены в requirements.txt; отдельного фронтенд-сборщика не требуется.

КомпонентТехнология и назначение
Основной языкPython 3.11+
Демонстрационный интерфейсStreamlit
HTTP-серверFastAPI, Uvicorn; модели запросов и валидация — Pydantic
ВиджетHTML, CSS, JavaScript; iframe и Shadow DOM в загрузчике
AI-агентOpenAI Python SDK, Chat Completions с вызовами инструментов (function calling)
МодельВ коде и шаблоне окружения по умолчанию настроена gpt-5-mini; меняется через OPENAI_MODEL. Для фото используется OPENAI_VISION_MODEL, если задана, иначе OPENAI_MODEL
Каталог партнёраHTTPS API ekt.kz, библиотека requests, Basic Auth для доступа к API
Конфигурацияpython-dotenv, файл .env
Документыopenpyxl для XLSX, python-docx для DOCX, pypdf для текстового PDF; распознавание фото — OpenAI API
ПоискНормализация, словарь синонимов, difflib для опечаток и фильтры характеристик
ХранениеJSON-файлы каталога/условий; сессии и корзины в памяти процесса. База данных и векторный индекс не используются
Тестыpytest, FastAPI TestClient / httpx, Streamlit AppTest, моки внешних вызовов

Архитектура проекта

flowchart TD
    U[Покупатель] --> S[Streamlit: app.py]
    U --> W[HTML/JS-виджет: static/]
    W --> F[FastAPI: server.py]
    S --> A[ShopAgent: agent/agent.py]
    F --> A
    S --> X[Чтение вложений: agent/attachments.py]
    X --> A
    A <--> O[OpenAI API]
    X -->|Фото| O
    A --> T[Toolbox: agent/tools.py]
    T --> C[Catalog: agent/catalog.py]
    C --> J[JSON-кэш или API ekt.kz]
    T --> B[Cart: agent/cart.py]
    T --> P[Условия: data/purchase_terms.json]
    T --> H[Сводка: agent/handoff.py]
  • ShopAgent ведёт историю и выполняет до восьми раундов ответа/инструментов; в последнем раунде новые вызовы инструментов запрещены. При ошибке модели формируется ответ по доступным полным карточкам кэша.
  • Toolbox описывает доступные модели операции и преобразует их результаты в данные для ответа.
  • Catalog загружает и нормализует товары, выполняет поиск и подбор аналогов/дополнений.
  • Cart хранит подтверждённые позиции и отдельный список предложений. CartStore используется Streamlit; FastAPI хранит сессии и корзины в собственных реестрах, с блокировкой параллельных запросов одной сессии.
  • agent/language.py определяет язык; agent/handoff.py формирует сводку и маскирует платёжные данные в её контексте.
  • scripts/fetch_catalog.py сохраняет полные карточки выбранных страниц API в кэш.
  • tests/ содержит проверки логики, реальных сохранённых карточек, вложений, Streamlit и HTTP-интерфейса.

Streamlit и FastAPI, запущенные отдельными процессами, не делят историю и корзины. Ссылку на корзину нужно открывать у того сервера, где был создан диалог.

Установка и запуск

Перед запуском

Нужны Git и Python 3.11 или новее. Установка пакетов и работа с OpenAI требуют доступа к интернету. Для основной демонстрации достаточно своего OPENAI_API_KEY: реальный кэш уже хранится в репозитории, логин и пароль ekt.kz для режима cache не нужны.

Если .env уже существует, сохраните его и пропустите команду копирования шаблона. Настоящие ключи и учётные данные записывайте только в .env.

Windows — PowerShell

Установите Python 3.11 или новее с python.org/downloads. При установке отметьте «Add python.exe to PATH», затем откройте новое окно PowerShell.

Проверьте доступность Python:

python --version

Если команда не найдена, попробуйте:

py --version

Продолжайте только если одна из команд показывает Python 3.11+. Для создания окружения используйте ту команду, которая сработала.

git clone https://github.com/BAITC-Hacks/hack-c8f31fa0-qazyna.git
cd hack-c8f31fa0-qazyna

Создайте окружение одним из вариантов:

python -m venv .venv

Если при проверке сработала только py, вместо предыдущей команды выполните:

py -m venv .venv

После успешного создания .venv все Python-команды выполняются через её интерпретатор; активировать окружение отдельно не требуется:

.\.venv\Scripts\python.exe --version
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
Copy-Item .env.example .env
notepad .env

В редакторе замените YOUR_OPENAI_API_KEY своим ключом и оставьте CATALOG_SOURCE=cache. Затем:

.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe -m streamlit run app.py

Для HTML-виджета запустите во втором терминале из каталога проекта:

.\.venv\Scripts\python.exe -m uvicorn server:app --host 127.0.0.1 --port 8000 --workers 1

Если команда не найдена

  • Не работает python — проверьте py --version; если он показывает 3.11+, создайте окружение командой py -m venv .venv.
  • Не работают обе команды или версия ниже 3.11 — установите Python 3.11+ по ссылке выше с «Add python.exe to PATH», откройте новый PowerShell и повторите проверку.
  • Не найден .\.venv\Scripts\python.exe — убедитесь, что терминал открыт в папке hack-c8f31fa0-qazyna и создание .venv завершилось без ошибки. Не переходите к установке зависимостей и запуску, пока этот интерпретатор не доступен.

macOS — Terminal

git clone https://github.com/BAITC-Hacks/hack-c8f31fa0-qazyna.git
cd hack-c8f31fa0-qazyna
python3 --version
python3 -m venv .venv
.venv/bin/python -m pip install -r requirements.txt
cp .env.example .env
open -e .env

Убедитесь, что python3 --version показывает 3.11 или новее. В .env замените YOUR_OPENAI_API_KEY своим ключом и оставьте CATALOG_SOURCE=cache. Затем:

.venv/bin/python -m pytest -q
.venv/bin/python -m streamlit run app.py

Для HTML-виджета запустите во втором терминале из каталога проекта:

.venv/bin/python -m uvicorn server:app --host 127.0.0.1 --port 8000 --workers 1

Открыть: Streamlit — localhost:8501 или демо HTML-виджета — 127.0.0.1:8000. Остановка сервера — Ctrl+C.

Консольный режим также доступен: Windows — .\.venv\Scripts\python.exe -m agent.agent, macOS — .venv/bin/python -m agent.agent. Пустая строка завершает диалог.

Настройки .env

ПеременнаяНазначение
OPENAI_API_KEYСобственный ключ OpenAI; замените плейсхолдер. Нужен для запуска консультанта
OPENAI_MODELМодель диалога; по умолчанию gpt-5-mini
OPENAI_VISION_MODELНеобязательная модель для фото; иначе используется OPENAI_MODEL
CATALOG_SOURCEcache — реальный кэш, api — API партнёра, sample — синтетические тестовые данные. По умолчанию cache
EKT_API_BASEБазовый адрес API; по умолчанию https://ekt.kz/api
EKT_API_USER, EKT_API_PASSWORDУчётные данные партнёра для режима api и обновления кэша. В режиме cache не используются
CART_BASE_URLАдрес Streamlit для ссылок на корзину; по умолчанию http://localhost:8501/. FastAPI формирует собственные ссылки /cart/<id>

Встраивание виджета

После запуска FastAPI подключите загрузчик на тестовой HTML-странице:

<script src="http://127.0.0.1:8000/widget.js" async></script>

Для публикации замените адрес на HTTPS-адрес своего сервера. Если сайт использует CSP, адрес нужно разрешить в script-src и frame-src. Чат работает в iframe сервера, поэтому запросы виджета к его API имеют тот же origin; CORS для всех сайтов в проекте не открыт.

Основные маршруты FastAPI:

Метод и путьНазначение
POST /chatНовое сообщение: message, необязательный session_id; кнопка подтверждения также передаёт proposal_id. Ответ содержит answer, history, pending, cart, cart_url, session_id
GET /session/{session_id}Восстановление состояния существующей сессии
GET /cart/{cart_id}Страница корзины; обновите её после нового добавления
GET /Демо-страница с виджетом
GET /widget.js, GET /widget.htmlЗагрузчик и интерфейс виджета

Идентификатор сессии виджет хранит в sessionStorage. Неизвестная сессия возвращает 404, неверное сообщение — 422; повторное или чужое предложение при подтверждении кнопкой — 409.

Как проверить решение — сценарий для жюри

Используйте CATALOG_SOURCE=cache, новый чат и неизменённый кэш из репозитория. Ниже — ожидаемые данные сохранённого снимка. Формулировки и время ответа модели могут отличаться.

  1. Найти товар. «Есть ли автомат IEK ВА47-29 25А 1P, артикул 010500008_?» В карточке — 808 ₸, суммарный остаток 93 849, 1 полюс, 25 А, C, 4,5 кА.
  2. Сравнить аналоги. «Есть ли 11006DEK? Если нет, покажи аналоги и отличия». Исходный остаток — 0; возможные кандидаты: 010800130_, 010700135_, 010400568_. Проверить обоснование и предупреждение о различиях B/C.
  3. Проверить сертификат. «Покажи сертификат на 010500008_». Ожидается сообщение об отсутствии документа в базе и предложение обратиться к менеджеру, без придуманного PDF.
  4. Узнать условия. «Как оплатить заказ и сколько стоит доставка по Алматы? Укажи источник». Ответ должен содержать ссылку из сохранённых условий и предупреждение о расхождении 30 000 / 15 000 ₸.
  5. Проверить защиту корзины. «Предложи добавить 2 товара 010500008_». Убедиться, что до подтверждения корзина пуста. Ответить «Нет, не добавляй» — состав не меняется. Затем новым предложением и отдельным «Да, добавь» подтвердить покупку. Открыть ссылку: 2 товара, сумма 1 616 ₸ по снимку.
  6. Проверить казахский. В новом диалоге спросить «010500008_ бар ма?». Запросить предложение добавить товар и подтвердить отдельным «иә» или «қосыңыз».
  7. Проверить менеджера. Нажать «Позвать менеджера». Появится сводка с рассмотренными товарами и корзиной. В Streamlit скачать TXT. Интерфейс сообщает, что автоматическая отправка не подключена.
  8. Проверить вложение в Streamlit. Создать XLSX с колонками «Артикул», «Наименование» и двумя строками из таблицы ниже. Нажать «Проверить спецификацию»: должны быть проверены обе позиции, для нулевого остатка — получены кандидаты на замену.
АртикулНаименование
010500008_ВА47-29 (1ф) 25А IEK (12/144)
11006DEK11006 BA 101 1P 16А х-ка B DEKraft

Для проверки мобильного интерфейса откройте демо HTML-виджета в браузере на ширине 320 px: должны оставаться доступны ввод, подтверждение и ссылка на корзину. Отдельно проверьте обычную ширину десктопа. Подробный сценарий показа с таймингом — DEMO.md.

Автотесты запускаются командами из раздела установки. Они используют сохранённые данные и моки внешних API; действующие ключи и обращения к OpenAI/ekt.kz для тестов не нужны. Синтетический каталог применяется в части модульных тестов, реальный кэш — в демонстрационных проверках. Тесты не подтверждают актуальность остатков на сайте и качество каждого свободного ответа модели.

Данные и интеграции

Каталог ekt.kz

  • data/catalog_cache.json — 470 полных реальных карточек. По catalog_coverage.json сохранённый список API содержит 15 037 товаров. Это выборка, а не весь каталог.
  • CATALOG_SOURCE=cache — режим по умолчанию. Если файл отсутствует, пуст или повреждён, запуск завершается ошибкой; синтетические товары автоматически не подставляются.
  • CATALOG_SOURCE=api выбирает API даже при наличии кэша. GET /products?page=N загружает список, GET /products/detail?id=... — полную карточку. При недоступности API допускается только сохранённый реальный кэш; без него возвращается ошибка.
  • count в ответе списка означает размер текущей страницы. Загрузчик учитывает пагинацию и прекращает повторяющиеся страницы. По умолчанию читается до пяти страниц; это не загрузка всех 15 037 товаров.
  • data/catalog_sample.json — синтетические товары для явно выбранного режима sample и тестов. Для жюри этот режим не используйте. USE_LIVE_API больше не управляет выбором источника.
  • Примеры контрактов: api_sample_list.json, api_sample_detail.json. Диагностика: CATALOG_DIAGNOSTICS.md. Исходные сохранённые ответы находятся также в data/api_probe/ и data/api_details/.

Нормализация сохраняет артикул, цену, склады, минимальную партию, бренд и доступные характеристики. quantity используется только при отсутствии складских данных, чтобы не считать остаток дважды. Единица измерения и документы сертификатов в изученном API не обнаружены и не придумываются.

Для обновления кэша заполните EKT_API_USER и EKT_API_PASSWORD в .env и выполните:

# Windows PowerShell
.\.venv\Scripts\python.exe scripts/fetch_catalog.py --pages 5
# macOS
.venv/bin/python scripts/fetch_catalog.py --pages 5

Скрипт заменяет текущий кэш первыми указанными страницами с полными карточками. Перед обновлением сохраните копию файла: такой запуск может сузить подготовленную выборку из 470 товаров. После обновления перезапустите приложение и заново проверьте артикулы сценария.

Условия покупки и сертификаты

data/purchase_terms.json содержит сохранённое изложение страниц партнёра с датой проверки 23.09.2026, полями source, sources, warnings и перечнем вопросов для менеджера. Условия не скачиваются заново на каждый вопрос. Ссылки в данных: оплата и доставка, возврат, оформление заказа.

data/certificate_audit.json фиксирует отсутствие файлов и ссылок на сертификаты в проверенных 470 карточках и примере detail. Текстовое упоминание сертификата в описании не считается документом. Это не доказывает, что сертификатов нет у поставщика или во всех непроверенных ответах API.

Обработка данных внешними сервисами

OpenAI API получает сообщения и контекст, необходимые для ответа, включая результаты проверки спецификации; при распознавании фотографии передаётся само изображение. XLSX, DOCX и текстовый PDF разбираются локально. В репозитории нет собственной обученной модели, базы эмбеддингов или интеграции с CRM.

Ограничения

  • Сертификатов нет в изученных ответах API партнёра. На реальных данных можно показать честный ответ об отсутствии документа, но нельзя продемонстрировать выдачу настоящего сертификата из этой выборки. Ссылки /certificates/demo/ из синтетических тестовых данных не являются подтверждением сертификатов реальных товаров.
  • Кэш — 470 из 15 037 товаров. Поиск и аналоги ограничены загруженной выборкой. Цены и остатки — снимок; автоматического обновления по расписанию нет. Проверки корзины используют загруженные остатки и не резервируют товар в API партнёра.
  • Расхождение порога доставки — 30 000 / 15 000 ₸. В сохранённых результатах проверки основной раздел сайта и всплывающий блок расходятся. Бесплатную доставку по нижнему порогу нельзя обещать без менеджера; условия ровно на пороге также требуют уточнения.
  • Неполные и противоречивые характеристики. Например, в названии товара 515291 указано 160 А, а свойство API содержит 250 А. Исходные значения сохраняются; подбор кандидата не гарантирует полной технической совместимости.
  • Сессии в памяти. История и корзины теряются при перезапуске. FastAPI нужно запускать одним worker; распределённого хранилища, авторизации, ограничения частоты запросов и производственной настройки HTTPS в проекте нет.
  • Нужен собственный OPENAI_API_KEY. Ключ не поставляется с проектом. Кэш позволяет обойтись без доступа к API ekt.kz, но ответы модели и распознавание фото требуют OpenAI. Тесты работают с моками.
  • Приватность ограничена возможностями прототипа. Не сохраняются исходные загруженные файлы, но текст диалога находится в памяти и передаётся модели. Маскирование реквизитов в сводке не равно анонимизации всей переписки.
  • Менеджер подключается вручную. Создаётся сводка, а не уведомление, CRM-заявка или соединение с оператором. В текущем кэше нет подходящих сопутствующих товаров, поэтому рекомендаций для них не будет.
  • Вложения — только в Streamlit. Старые форматы .xls/.doc не поддерживаются. Сканированный PDF без текстового слоя не распознаётся автоматически; для распознавания предусмотрены JPG/PNG. HTML-виджет пока имеет русские подписи интерфейса.
  • Оформление заказа не реализовано. Корзина демонстрационная: нет оплаты, заказа в учётной системе или общей резервации остатков между покупателями.

Deployed-версия

Подтверждённая ссылка на публично развёрнутый консультант в репозитории не указана. Для проверки используйте локальные адреса: Streamlit и HTML-виджет. Наличие интеграционного виджета не означает, что он уже установлен на сайте партнёра.

Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
17
Авторы
3
Файлы
544
Ветки
1

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

zere90 9aemkls 4aziza.ikhsanova 4

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

  • 2026-09-23 17:37update READMEzere90
  • 2026-09-23 17:34Final toucheszere90
  • 2026-09-23 17:25READMEzere90
  • 2026-09-23 17:18FINAL READMEaemkls
  • 2026-09-23 17:02final changeszere90
  • 2026-09-23 16:51readme changeaziza.ikhsanova
  • 2026-09-23 16:43Виджетzere90
  • 2026-09-23 16:25Optional Finalaemkls
Все коммиты (17)
  • 2026-09-23 16:19Optionalaemkls
  • 2026-09-23 16:05вложения app.pyaziza.ikhsanova
  • 2026-09-23 16:00windows обновлениеaziza.ikhsanova
  • 2026-09-23 15:55Каталог оригzere90
  • 2026-09-23 15:52Fetch → Pull → Summary Реальный каталог: кэш 470 товаров, исправлен поискzere90
  • 2026-09-23 15:25Улучшенный поискaemkls
  • 2026-09-23 15:17Кеш каталогаaziza.ikhsanova
  • 2026-09-23 14:44Подключен живой API ekt.kzzere90
  • 2026-09-23 14:30Скелет ИИ-консультанта ekt.kzzere90
Структура репозитория (544 файлов)
.DS_Store
.env.example
.gitignore
AGENTS.md
CATALOG_DIAGNOSTICS.md
DEMO.md
PROMPTS.md
README.md
agent/.DS_Store
agent/__init__.py
agent/agent.py
agent/attachments.py
agent/cart.py
agent/catalog.py
agent/handoff.py
agent/language.py
agent/tools.py
app.py
data/.DS_Store
data/agent_smoke_results.json
data/api_details/17999.json
data/api_details/18000.json
data/api_details/18002.json
data/api_details/18041.json
data/api_details/18092.json
data/api_details/18106.json
data/api_details/18112.json
data/api_details/18143.json
data/api_details/18145.json
data/api_details/18148.json
data/api_details/18157.json
data/api_details/18158.json
data/api_details/18159.json
data/api_details/18160.json
data/api_details/18161.json
data/api_details/18238.json
data/api_details/18301.json
data/api_details/18370.json
data/api_details/18383.json
data/api_details/18384.json
data/api_details/18387.json
data/api_details/18412.json
data/api_details/18426.json
data/api_details/18465.json
data/api_details/18563.json
data/api_details/18945.json
data/api_details/18987.json
data/api_details/19048.json
data/api_details/19071.json
data/api_details/19080.json
data/api_details/19086.json
data/api_details/19099.json
data/api_details/19163.json
data/api_details/19166.json
data/api_details/19358.json
data/api_details/19404.json
data/api_details/19418.json
data/api_details/19420.json
data/api_details/19452.json
data/api_details/19455.json
data/api_details/19459.json
data/api_details/19480.json
data/api_details/19481.json
data/api_details/19483.json
data/api_details/19491.json
data/api_details/19498.json
data/api_details/19543.json
data/api_details/19563.json
data/api_details/19716.json
data/api_details/19954.json
data/api_details/19988.json
data/api_details/20048.json
data/api_details/20057.json
data/api_details/20088.json
data/api_details/20120.json
data/api_details/20173.json
data/api_details/20177.json
data/api_details/20178.json
data/api_details/20182.json
data/api_details/20191.json
data/api_details/20275.json
data/api_details/20347.json
data/api_details/20443.json
data/api_details/20448.json
data/api_details/20451.json
data/api_details/20482.json
data/api_details/20490.json
data/api_details/20492.json
data/api_details/20496.json
data/api_details/20504.json
data/api_details/20505.json
data/api_details/20509.json
data/api_details/20516.json
data/api_details/20518.json
data/api_details/20559.json
data/api_details/20573.json
data/api_details/20626.json
data/api_details/20627.json
data/api_details/21003.json
data/api_details/21045.json
data/api_details/21049.json
data/api_details/21116.json
data/api_details/21120.json
data/api_details/21162.json
data/api_details/21163.json
data/api_details/21164.json
data/api_details/21165.json
data/api_details/21182.json
data/api_details/21185.json
data/api_details/21190.json
data/api_details/21191.json
data/api_details/21192.json
data/api_details/21210.json
data/api_details/21274.json
data/api_details/21341.json
data/api_details/21408.json
data/api_details/21409.json
data/api_details/21450.json
data/api_details/21455.json
data/api_details/21484.json
data/api_details/21536.json
data/api_details/21588.json
data/api_details/21702.json
data/api_details/21988.json
data/api_details/22033.json
data/api_details/22039.json
data/api_details/22100.json
data/api_details/22163.json
data/api_details/22169.json
data/api_details/22170.json
data/api_details/22183.json
data/api_details/22267.json
data/api_details/22299.json
data/api_details/22306.json
data/api_details/22309.json
data/api_details/22417.json
data/api_details/22428.json
data/api_details/22453.json
data/api_details/22459.json
data/api_details/22462.json
data/api_details/22463.json
data/api_details/22483.json
data/api_details/22485.json
data/api_details/22491.json
data/api_details/22494.json
data/api_details/22998.json
data/api_details/23063.json
data/api_details/23081.json
data/api_details/23095.json
data/api_details/23104.json
data/api_details/23116.json
data/api_details/23158.json
data/api_details/23159.json
data/api_details/23160.json
data/api_details/23162.json
data/api_details/23180.json
data/api_details/23181.json
data/api_details/23276.json
data/api_details/23326.json
data/api_details/23397.json
data/api_details/23404.json
data/api_details/23424.json
data/api_details/23444.json
data/api_details/23471.json
data/api_details/23475.json
data/api_details/23733.json
data/api_details/23923.json
data/api_details/23952.json
data/api_details/24003.json
data/api_details/24007.json
data/api_details/24053.json
data/api_details/24082.json
data/api_details/24091.json
data/api_details/24146.json
data/api_details/24149.json
data/api_details/24160.json
data/api_details/24163.json
data/api_details/24164.json
data/api_details/24165.json
data/api_details/24166.json
data/api_details/24167.json
data/api_details/24198.json
data/api_details/24303.json
data/api_details/24353.json
data/api_details/24420.json
data/api_details/24423.json
data/api_details/24424.json
data/api_details/24425.json
data/api_details/24459.json
data/api_details/24466.json
data/api_details/24467.json
data/api_details/24468.json
data/api_details/24476.json
data/api_details/24480.json
data/api_details/24482.json
data/api_details/24504.json
data/api_details/24505.json
data/api_details/24509.json
data/api_details/24786.json
data/api_details/24985.json
data/api_details/24996.json
data/api_details/25010.json
data/api_details/25026.json
data/api_details/25051.json
data/api_details/25139.json
data/api_details/25168.json
data/api_details/25397.json
data/api_details/25428.json
data/api_details/25491.json
data/api_details/25496.json
data/api_details/25504.json
data/api_details/25740.json
data/api_details/28190.json
data/api_details/29415.json
data/api_details/29425.json
data/api_details/29426.json
data/api_details/29433.json
data/api_details/29444.json
data/api_details/29445.json
data/api_details/29447.json
data/api_details/29652.json
data/api_details/29671.json
data/api_details/30032.json
data/api_details/30094.json
data/api_details/30248.json
data/api_details/30528.json
data/api_details/30553.json
data/api_details/31038.json
data/api_details/31212.json
data/api_details/31224.json
data/api_details/31333.json
data/api_details/31337.json
data/api_details/31386.json
data/api_details/31500.json
data/api_details/31734.json
data/api_details/31770.json
data/api_details/31774.json
data/api_details/31777.json
data/api_details/31780.json
data/api_details/31783.json
data/api_details/31912.json
data/api_details/31993.json
data/api_details/32083.json
data/api_details/32233.json
data/api_details/32260.json
data/api_details/32262.json
data/api_details/32263.json
data/api_details/32295.json
data/api_details/32361.json
data/api_details/32475.json
data/api_details/32514.json
data/api_details/32527.json
data/api_details/32539.json
data/api_details/32648.json
data/api_details/33303.json
data/api_details/33314.json
data/api_details/33315.json
data/api_details/33419.json
data/api_details/33611.json
data/api_details/33632.json
data/api_details/33700.json
data/api_details/33701.json
data/api_details/33702.json
data/api_details/33703.json
data/api_details/33704.json
data/api_details/33705.json
data/api_details/33706.json
data/api_details/33707.json
data/api_details/33708.json
data/api_details/33709.json
data/api_details/33710.json
data/api_details/33711.json
data/api_details/33712.json
data/api_details/33713.json
data/api_details/33714.json
data/api_details/33715.json
data/api_details/33716.json
data/api_details/33717.json
data/api_details/33718.json
data/api_details/33719.json
data/api_details/33724.json
data/api_details/33727.json
data/api_details/33729.json
data/api_details/33731.json
data/api_details/33733.json
data/api_details/33734.json
data/api_details/33735.json
data/api_details/33737.json
data/api_details/33784.json
data/api_details/33789.json
data/api_details/33791.json
data/api_details/33814.json
data/api_details/33816.json
data/api_details/34414.json
data/api_details/34758.json
data/api_details/34891.json
data/api_details/35009.json
data/api_details/35010.json
data/api_details/35563.json
data/api_details/35568.json
data/api_details/35572.json
data/api_details/35573.json
data/api_details/35574.json
data/api_details/35581.json
data/api_details/35585.json
data/api_details/35587.json
data/api_details/35588.json
data/api_details/35589.json
data/api_details/35596.json
data/api_details/35597.json
data/api_details/35598.json
data/api_details/35599.json
data/api_details/35600.json
data/api_details/35601.json
data/api_details/35604.json
data/api_details/35608.json
data/api_details/35609.json
data/api_details/35610.json
data/api_details/35818.json
data/api_details/35819.json
data/api_details/35869.json
data/api_details/36242.json
data/api_details/36406.json
data/api_details/36413.json
data/api_details/36419.json
data/api_details/36730.json
data/api_details/36881.json
data/api_details/37125.json
data/api_details/37126.json
data/api_details/37173.json
data/api_details/37284.json
data/api_details/37568.json
data/api_details/38089.json
data/api_details/38314.json
data/api_details/38319.json
data/api_details/38742.json
data/api_details/39147.json
data/api_details/40906.json
data/api_details/40912.json
data/api_details/41102.json
data/api_details/41765.json
data/api_details/41839.json
data/api_details/43603.json
data/api_details/43676.json
data/api_details/43799.json
data/api_details/43802.json
data/api_details/44198.json
data/api_details/44199.json
data/api_details/44255.json
data/api_details/44356.json
data/api_details/44358.json
data/api_details/44365.json
data/api_details/44367.json
data/api_details/44374.json
data/api_details/44376.json
data/api_details/44679.json
data/api_details/44799.json
data/api_details/44822.json
data/api_details/45277.json
data/api_details/45334.json
data/api_details/45340.json
data/api_details/45357.json
data/api_details/45567.json
data/api_details/47333.json
data/api_details/47337.json
data/api_details/47351.json
data/api_details/47788.json
data/api_details/48150.json
data/api_details/49524.json
data/api_details/49552.json
data/api_details/49953.json
data/api_details/49956.json
data/api_details/49989.json
data/api_details/50230.json
data/api_details/50518.json
data/api_details/507738.json
data/api_details/507805.json
data/api_details/509031.json
data/api_details/509481.json
data/api_details/509483.json
data/api_details/509485.json
data/api_details/509487.json
data/api_details/509489.json
data/api_details/509518.json
data/api_details/51147.json
data/api_details/515042.json
data/api_details/515218.json
data/api_details/515227.json
data/api_details/515236.json
data/api_details/515245.json
data/api_details/515252.json
data/api_details/515260.json
data/api_details/515271.json
data/api_details/515273.json
data/api_details/515275.json
data/api_details/515277.json
data/api_details/515278.json
data/api_details/515279.json
data/api_details/515280.json
data/api_details/515281.json
data/api_details/515282.json
data/api_details/515283.json
data/api_details/515284.json
data/api_details/515285.json
data/api_details/515286.json
data/api_details/515287.json
data/api_details/515288.json
data/api_details/515289.json
data/api_details/515290.json
data/api_details/515291.json
data/api_details/515292.json
data/api_details/515293.json
data/api_details/515294.json
data/api_details/515296.json
data/api_details/515298.json
data/api_details/515306.json
data/api_details/515421.json
data/api_details/515479.json
data/api_details/515582.json
data/api_details/518851.json
data/api_details/518985.json
data/api_details/519532.json
data/api_details/519540.json
data/api_details/519586.json
data/api_details/519618.json
data/api_details/519759.json
data/api_details/519793.json
data/api_details/519822.json
data/api_details/519965.json
data/api_details/520700.json
data/api_details/520710.json
data/api_details/520712.json
data/api_details/520716.json
data/api_details/520718.json
data/api_details/520719.json
data/api_details/520721.json
data/api_details/520722.json
data/api_details/520732.json
data/api_details/521832.json
data/api_details/524722.json
data/api_details/524799.json
data/api_details/524874.json
data/api_details/526356.json
data/api_details/526423.json
data/api_details/526425.json
data/api_details/526427.json
data/api_details/526429.json
data/api_details/526431.json
data/api_details/526433.json
data/api_details/526435.json
data/api_details/526437.json
data/api_details/526439.json
data/api_details/526441.json
data/api_details/526443.json
data/api_details/526445.json
data/api_details/526447.json
data/api_details/526599.json
data/api_details/526616.json
data/api_details/528362.json
data/api_details/52858.json
data/api_details/529614.json
data/api_details/531521.json
data/api_details/532818.json
data/api_details/54184.json
data/api_details/54185.json
data/api_details/54188.json
data/api_details/54310.json
data/api_details/54316.json
data/api_details/54323.json
data/api_details/54338.json
data/api_details/54339.json
data/api_details/54340.json
data/api_details/54341.json
data/api_details/54342.json
data/api_details/54345.json
data/api_details/54351.json
data/api_details/54571.json
data/api_details/54690.json
data/api_details/54774.json
data/api_details/54794.json
data/api_details/54921.json
data/api_details/55675.json
data/api_details/56050.json
data/api_details/56138.json
data/api_details/58050.json
data/api_details/58368.json
data/api_details/58378.json
data/api_details/58379.json
data/api_details/58380.json
data/api_details/58412.json
data/api_probe/page_100_20.json
data/api_probe/page_10_1000.json
data/api_probe/page_11_1000.json
data/api_probe/page_12_1000.json
data/api_probe/page_13_1000.json
data/api_probe/page_14_1000.json
data/api_probe/page_15_1000.json
data/api_probe/page_16_1000.json
data/api_probe/page_17_1000.json
data/api_probe/page_18_1000.json
data/api_probe/page_19_1000.json
data/api_probe/page_1_1000.json
data/api_probe/page_20_1000.json
data/api_probe/page_2_1000.json
data/api_probe/page_2_20.json
data/api_probe/page_3_1000.json
data/api_probe/page_4_1000.json
data/api_probe/page_5_1000.json
data/api_probe/page_6_1000.json
data/api_probe/page_7_1000.json
data/api_probe/page_8_1000.json
data/api_probe/page_9_1000.json
data/api_probe/results.json
data/api_sample_detail.json
data/api_sample_list.json
data/catalog_cache.json
data/catalog_coverage.json
data/catalog_sample.json
data/certificate_audit.json
data/purchase_terms.json
docs/.DS_Store
docs/screenshots/.gitkeep
docs/screenshots/Снимок экрана — 2026-09-23 в 17.31.51.png
docs/screenshots/Снимок экрана — 2026-09-23 в 17.32.06.png
docs/screenshots/Снимок экрана — 2026-09-23 в 17.32.30.png
docs/screenshots/Снимок экрана — 2026-09-23 в 17.32.43.png
docs/screenshots/Снимок экрана — 2026-09-23 в 17.33.56.png
requirements.txt
scripts/fetch_catalog.py
server.py
static/demo.html
static/widget.html
static/widget.js
tests/fixtures/catalog_live.json
tests/test_app_manager.py
tests/test_attachments.py
tests/test_catalog_api.py
tests/test_catalog_cache.py
tests/test_catalog_search.py
tests/test_consultant_features.py
tests/test_demo_real.py
tests/test_live_regressions.py
tests/test_must_have.py
tests/test_server.py

Обсуждение 0 комментариев

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

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