О проекте
Команда: 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.

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

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

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

Корзина по ссылке: 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. |
Как работает решение
- Входные данные. Покупатель пишет вопрос или прикладывает спецификацию в Streamlit. Для текстовых документов содержимое извлекается локально; фотография распознаётся моделью через OpenAI API.
- Диалог и поиск.
ShopAgentопределяет язык ответа. Модель выбирает инструменты изTOOL_SCHEMAS, например поиск, карточку товара или условия покупки. Артикулы из вложения проверяются по каталогу, результаты передаются агенту как контекст. - Проверка данных.
Catalogищет в загруженной выборке. В режиме API полная карточка при необходимости запрашивается отдельно. Пустой поиск не означает, что товара нет на всём сайте. - Результат консультации. Клиент получает сведения о товаре, кандидатов на замену с отличиями и условия покупки. При отсутствии сертификата агент сообщает, что документа нет в базе.
- Предложение покупки. Агент показывает товар, количество и сумму, затем спрашивает о добавлении. На этом шаге корзина не меняется.
- Подтверждение. Отдельное сообщение «Да, добавь», «иә», «қосыңыз» или нажатие кнопки проходит проверки
Cart.confirm(). После успешного добавления выдаётся ссылка на корзину. - Помощь менеджера. По кнопке или запросу в чате создаётся сводка: запрос клиента, рассмотренные товары, подтверждённая корзина и неподтверждённые предложения. Автоматической отправки менеджеру нет.
Требования партнёра
| Требование | Реализация и границы |
|---|---|
| Нет изменения корзины без подтверждения | Добавление из инструментов агента и 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_SOURCE | cache — реальный кэш, 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, новый чат и неизменённый кэш из репозитория. Ниже — ожидаемые данные сохранённого снимка. Формулировки и время ответа модели могут отличаться.
- Найти товар. «Есть ли автомат IEK ВА47-29 25А 1P, артикул 010500008_?» В карточке — 808 ₸, суммарный остаток 93 849, 1 полюс, 25 А, C, 4,5 кА.
- Сравнить аналоги. «Есть ли 11006DEK? Если нет, покажи аналоги и отличия». Исходный остаток — 0; возможные кандидаты:
010800130_,010700135_,010400568_. Проверить обоснование и предупреждение о различиях B/C. - Проверить сертификат. «Покажи сертификат на 010500008_». Ожидается сообщение об отсутствии документа в базе и предложение обратиться к менеджеру, без придуманного PDF.
- Узнать условия. «Как оплатить заказ и сколько стоит доставка по Алматы? Укажи источник». Ответ должен содержать ссылку из сохранённых условий и предупреждение о расхождении 30 000 / 15 000 ₸.
- Проверить защиту корзины. «Предложи добавить 2 товара 010500008_». Убедиться, что до подтверждения корзина пуста. Ответить «Нет, не добавляй» — состав не меняется. Затем новым предложением и отдельным «Да, добавь» подтвердить покупку. Открыть ссылку: 2 товара, сумма 1 616 ₸ по снимку.
- Проверить казахский. В новом диалоге спросить «010500008_ бар ма?». Запросить предложение добавить товар и подтвердить отдельным «иә» или «қосыңыз».
- Проверить менеджера. Нажать «Позвать менеджера». Появится сводка с рассмотренными товарами и корзиной. В Streamlit скачать TXT. Интерфейс сообщает, что автоматическая отправка не подключена.
- Проверить вложение в Streamlit. Создать XLSX с колонками «Артикул», «Наименование» и двумя строками из таблицы ниже. Нажать «Проверить спецификацию»: должны быть проверены обе позиции, для нулевого остатка — получены кандидаты на замену.
| Артикул | Наименование |
|---|---|
010500008_ | ВА47-29 (1ф) 25А IEK (12/144) |
11006DEK | 11006 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-виджет. Наличие интеграционного виджета не означает, что он уже установлен на сайте партнёра.
Авторы коммитов
История коммитов
- 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 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.