AAYMA
RU
Войти

ИИ-помощник по каталогу ekt.kz

Чат-консультант по каталогу ekt.kz: поиск позиций по названию/артикулу/ID, объяснение аналогов, подбор по условиям покупателя, сравнение товаров…

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

О проекте

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

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

Суть

Чат-консультант по каталогу ekt.kz: поиск позиций по названию/артикулу/ID, объяснение аналогов, подбор по условиям покупателя, сравнение товаров, список покупок с бюджетом и добавление в демо-корзину после подтверждения. Есть встраиваемый виджет для сайта.

Как устроено

FastAPI-бэкенд ходит в ekt.kz Products API (Basic Auth, пагинация, кеш страниц 60 с, повторное чтение карточки и остатка перед записью в корзину). LLM через OpenAI Responses API со Structured Outputs (схемы AIReply, ShoppingRequirements, валидация Pydantic) только классифицирует запрос и выбирает ID товаров; текст с фактами собирает бэкенд из проверенных карточек. Поиск по требованиям ранжирует кандидатов и помечает совпадающие, противоречащие и неизвестные характеристики. История сессии и корзина хранятся в SQLite, без ключей работает явно помеченный offline/demo режим.

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

  • OpenAI Structured Outputs (responses.parse)
  • Pydantic-валидация ответов модели
  • сверка ID из ответа модели с результатами бэкенда
  • ранжирование по артикулу и названию
  • кеширование страниц каталога
  • iframe-виджет embed.js

Особенности

LLM не пишет ответ покупателю: модель только выбирает ID и условия, а текст с фактами собирает бэкенд из данных API, поэтому модель не может придумать цену или остаток. Есть явный demo mode на шести вымышленных карточках, которые покрывают крайние случаи (нет в наличии, конфликт характеристик, неизвестное значение); при ошибке настоящего каталога система не переключается на них молча.

Стек

Python · FastAPI · HTTPX · Pydantic · Uvicorn · SQLite · HTML/CSS/JS

Модели

OpenAI Responses API


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

README

README.md

ИИ-помощник по каталогу ekt.kz

Покупателю электротехнических товаров часто нужен быстрый ответ о характеристиках, цене и наличии. Этот прототип помогает найти позицию в каталоге ekt.kz, показывает только полученные из API сведения, объясняет проверяемое сходство аналога и после отдельного подтверждения добавляет товар в демонстрационную корзину. Чат и страница корзины адаптируются к телефону и компьютеру. Виджет обращается только к backend; ключи API браузеру не передаются.

Архитектура

Браузер: HTML/CSS/JS → FastAPI → Catalog adapter → ekt.kz Products API
                              ├→ OpenAI Python SDK / Responses API → Pydantic → выбор ID и условий
                              ├→ backend: проверенные факты и таблица → ответ
                              └→ SQLite: история сессии и demo cart adapter

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

Запуск

Нужны Python 3.11 или новее и pip. Frontend — статические HTML/CSS/JS: Node.js и отдельная сборка не требуются. Docker Compose не используется.

Основные зафиксированные зависимости: FastAPI 0.115.12, HTTPX 0.28.1, Pydantic Settings 2.8.1, Uvicorn 0.34.0 и официальный OpenAI Python SDK 3.19.0. requirements.lock.txt фиксирует также транзитивные зависимости.

В PowerShell из корня репозитория:

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.lock.txt
Copy-Item .env.example .env
.\.venv\Scripts\python.exe -m uvicorn backend.main:app --host 127.0.0.1 --port 8000

Если команда python отсутствует, установите Python 3.11+ и добавьте его в PATH либо замените первую команду на py -3 -m venv .venv. В Linux/macOS используйте python3 -m venv .venv, затем .venv/bin/python вместо .\.venv\Scripts\python.exe. Запускайте команды из корня проекта: оттуда читается локальный .env.

Откройте http://127.0.0.1:8000. Документация backend доступна по адресу http://127.0.0.1:8000/docs. Для запуска без ключей оставьте все секретные значения в .env пустыми: статус покажет demo и offline, а /api/products вернёт шесть вымышленных карточек. Не используйте этот режим как подтверждение работы OpenAI или каталога ekt.kz.

Для пробного встраивания в страницу того же сайта добавьте перед </body> тег <script defer src="http://127.0.0.1:8000/static/embed.js"></script>. Он открывает компактный чат в iframe по /widget; основная страница прототипа остаётся доступна по /. Для размещения на другом домене нужен публичный HTTPS-адрес backend и проверка CSP, разрешений iframe и хранения сессии в браузере владельца сайта. Это пример встраивания прототипа, а не изменение production-сайта ekt.kz.

Настройка каталога

Добавьте учётные данные в локальный .env:

ПеременнаяНазначениеЗначение по умолчанию
APP_ENVРежим приложенияdevelopment
EKT_API_BASE_URLАдрес API каталогаhttps://ekt.kz/api
EKT_API_USERNAMEЛогин Basic Authпусто
EKT_API_PASSWORDПароль Basic Authпусто
EKT_API_TIMEOUT_SECONDSТайм-аут запроса10
OPENAI_API_KEYКлюч OpenAI API, используется только backendпусто
OPENAI_MODELID доступной проекту модели OpenAI Responses APIпусто
OPENAI_TIMEOUT_SECONDSТайм-аут запроса к OpenAI30

Файл .env исключён из Git. Пример содержит только пустые значения; секреты нельзя добавлять в исходный код, клиент или логи. Для live-каталога внесите в него выданные владельцем ekt.kz EKT_API_USERNAME и EKT_API_PASSWORD. Эти переменные используются только в Basic Auth запросах backend. Для облачного режима создайте API key в панели OpenAI, укажите его как OPENAI_API_KEY и отдельно задайте OPENAI_MODEL — ID модели, доступной вашему API-проекту и поддерживающей Structured Outputs. Доступность модели, биллинг и лимиты проекта проверьте до презентации; live вызовы могут быть платными.

В live-режиме backend обращается к GET /products, к последующим страницам добавляет параметр page, а карточку загружает из GET /products/detail?id={id}. В проверенном live-ответе список содержал 20 товаров и поля article, id, name, offers, price, url; детальная карточка дополнительно содержала description, properties, quantity, stores. Категория может находиться в properties.KATEGORIYA. Отсутствующие значения не придумываются. Страницы списка кешируются на 60 секунд; перед записью в demo-корзину детальная карточка и остаток читаются заново.

Если доступ не настроен, backend явно включает demo mode с шестью вымышленными карточками: DEMO-OUT (остаток 0), DEMO-ALT (сопоставимый кабель, 6 шт.), DEMO-IN (автомат 16 А, 8 шт.), DEMO-CONFLICT (автомат 20 А), DEMO-UNKNOWN (автомат без значения тока) и DEMO-PARTIAL (характеристики и цена отсутствуют). У пяти ценовых demo-карточек валюта явно указана как KZT; для DEMO-PARTIAL цены и валюты нет. В demo mode можно пройти подтверждение и запись в локальную демо-корзину; остаток повторно проверяется по неизменяемому demo-набору. Эти данные не представляют реальные остатки или цены ekt.kz. При ошибке настроенного каталога UI показывает ошибку и не переключается незаметно на вымышленные товары.

Чат и OpenAI API

Backend ищет совпадения по словам, ID и артикулу среди первых трёх страниц каталога и при необходимости получает подробные карточки найденных позиций. Числовой ID можно запросить напрямую. В live AI режиме вопрос пользователя, до восьми последних реплик этой сессии и только нужные поля найденных товаров отправляются OpenAI API. Для обработки используется официальный Python SDK и Responses API с store: false. Системные инструкции лежат отдельно в backend/prompt.py; ответ запрашивается как Structured Output по схеме AIReply и дополнительно проверяется через Pydantic. ID товаров и аналогов сверяются с результатами backend. Модель классифицирует запрос и выбирает ID; показанный покупателю текст с фактами о товарах составляет backend из проверенных карточек. Свободный текст модели не отображается, поскольку произвольное утверждение в нём нельзя надёжно сверить с API. Ключ и модель задаются через OPENAI_API_KEY и OPENAI_MODEL; оба параметра нужны для live AI режима. Подходящий ID модели должен быть доступен вашему API-проекту.

Документация API: Responses API, Structured Outputs. Список доступных моделей можно получить через OpenAI API или посмотреть в настройках своего проекта.

Если ключ или модель не заданы, чат явно показывает Offline demo — OpenAI API is not configured: ответ составляется из фактически найденных значений, без облачной модели. Это отдельная техническая репетиция, не работа OpenAI. Ошибка авторизации, лимита, тайм-аута, отказ модели или невалидного формата отображается как ошибка с предложением повтора; скрытого перехода в offline режим нет. Чат восстанавливает историю после перезагрузки страницы; кнопка сброса удаляет историю и неподтверждённое добавление, сохраняя уже добавленную demo-корзину.

Расширение: распознавание условий покупателя

Первый дополнительный спринт добавил отдельную форму «Подбор по условиям» на главной странице и во встраиваемом виджете. Покупатель описывает задачу; backend отправляет текущее сообщение, до восьми недавних реплик этой сессии и короткий список известных характеристик в OpenAI Responses API. Отдельный prompt находится в backend/requirements_prompt.py; строгая схема ShoppingRequirements и дополнительные проверки — в backend/requirements.py. Результат включает тип запроса, товарные слова, артикул, обязательные/желательные параметры, количество, бюджет, явно указанную валюту и не более одного проверяемого уточняющего вопроса. Неподтверждённый артикул, значение, отрицание, количество или валюта отклоняются. Названия параметров ограничены характеристиками, уже наблюдавшимися в карточках API и маркированном demo-наборе.

Поля показываются до поиска и доступны для исправления. Сохранённый черновик привязан к текущему session ID в SQLite; сброс диалога удаляет его. Обычный чат по точному артикулу и безопасная demo cart продолжают работать отдельно. Без OpenAI key форма использует ограниченные локальные правила и явно помечается Offline demo; ошибка облачной модели не заменяется таким ответом незаметно. Формат Structured Outputs реализован через responses.parse и Pydantic согласно официальной документации OpenAI.

Второй спринт подключил кнопку «Найти товары» к сохранённым условиям. Backend просматривает до пяти страниц GET /api/products?page=N, сохраняет ограниченный индекс на 60 секунд и повторно использует кэш страниц и проверенных детальных карточек. Кнопка «Обновить каталог» принудительно перечитывает страницы и карточки. Поиск ранжирует артикул и название, затем проверяет доступные нормализованные характеристики из detail?id=... для первых 12 кандидатов. Финальный список содержит не более пяти позиций, причём ID должны совпасть в списке и подробной карточке. Совпадающие, противоречащие и неизвестные характеристики отмечаются отдельно: кандидат с противоречием остаётся видимым для сравнения, но не называется подходящим.

Ответ различает found, not_found и incomplete и отдельно возвращает coverage_complete. Даже при найденных позициях неполный охват страниц, ограничение детальных карточек или ошибка API показываются явно. Если первая страница недоступна, результат также обозначается как неполный, без перехода к вымышленным товарам. В demo mode поиск выполняется только по шести явно вымышленным карточкам. Read-only проверка live-каталога по слову «автомат» вернула пять проверенных ID после просмотра пяти страниц и корректно пометила охват как неполный.

Третий спринт добавил выбор двух–четырёх найденных товаров и таблицу сравнения. Таблица показывает цену с валютой, если она есть в карточке, наличие или точный остаток, а также нужные характеристики. Для каждого указанного параметра backend вычисляет совпадает, противоречит или нет данных по фактическому значению детальной карточки. Пустое поле не считается совпадением. В заголовках таблицы есть ссылки на карточки: внешний адрес допускается только на HTTPS-домен ekt.kz, иначе используется локальный API карточки. Сравнить произвольный ID нельзя: backend повторно сверяет выбранные ID с текущими результатами поиска.

Для короткого пояснения backend передаёт OpenAI проверенную матрицу и готовые предложения. Модель через Structured Outputs выбирает только ID предложений и товаров; backend отклоняет чужой ID и выводит лишь собственные проверенные формулировки. Если OpenAI не настроен, объяснение явно помечено как локальное. При ошибке настроенной модели скрытого перехода в offline режим нет. Кандидат на замену показывается только среди выбранных найденных товаров при подтверждённом остатке и совпадении всех указанных обязательных характеристик; пометка не обещает полной технической совместимости.

Четвёртый спринт использует demo cart как список закупки. В карточке найденного товара покупатель задаёт количество, видит точные товар и количество и отдельной кнопкой подтверждает добавление. Backend допускает только ID из текущего поиска, повторно читает карточку и проверяет точный положительный остаток перед подготовкой и ещё раз перед записью. Повторное подтверждение того же ID и количества не создаёт дубль; смена количества перечитывает карточку и проверяет остаток. Удаление выполняется по отдельной кнопке в списке. При неизвестном остатке добавление блокируется с объяснением.

Для каждой позиции список показывает цену единицы из последней сохранённой карточки и произведение на количество. Общий итог считается через Decimal лишь когда у всех позиций есть числовая цена и явно указанная единая валюта. Иначе показываются только известные части по валютам и причины неполноты; валюту live-каталога backend не угадывает. Бюджет сравнивается с итогом только при той же явно указанной валюте. Более дешёвый кандидат предлагается только из найденных позиций с подтверждённой ценой в валюте бюджета, доступным остатком на нужное количество и совпадением всех указанных обязательных характеристик. Это вариант для проверки, а не гарантия совместимости. Расчёт по сохранённым ценам не является окончательной стоимостью заказа.

Схема нового подбора и границы проверки

Форма «Подбор по условиям» отправляет текст в POST /api/requirements/extract. При настроенной модели prompt из backend/requirements_prompt.py требует вернуть только явно названные артикул, товарные слова, характеристики, количество, бюджет и одну проверяемую уточняющую фразу. Ответ OpenAI имеет строгую схему ShoppingRequirements; backend дополнительно сверяет значения с исходным сообщением и допустимыми названиями характеристик. Пользователь исправляет черновик и сохраняет его до поиска. Без ключа работает отдельно помеченный локальный разбор; ошибка настроенной модели возвращает ошибку, не выдавая локальный ответ за OpenAI.

CatalogClient собирает ограниченный индекс из GET /api/products?page=N (не более пяти страниц), кеширует страницы, индекс и детальные карточки на 60 секунд, затем перечитывает detail?id=... для первых 12 кандидатов. ID в списке и деталях должны совпасть. Поиск возвращает до пяти позиций и признак полноты охвата. Нажатие «Обновить каталог» вызывает поиск с refresh:true и обходит кэш; то же можно сделать через POST /api/requirements/search с телом {"session_id":"...","refresh":true}. Лимит страниц или карточек, ошибка и тайм-аут показываются как неполный охват; отсутствие в просмотренной части не доказывает отсутствие товара во всём каталоге.

Backend строит таблицу сравнения по сохранённым условиям: совпадает, противоречит, нет данных. Пустое значение никогда не считается совпадением. Prompt сравнения в backend/comparison.py получает только проверенную матрицу и готовые предложения, а возвращает ID выбранных предложений и товаров через строгую схему ComparisonChoice. Backend отклоняет посторонние ID и не выводит новое числовое утверждение модели. Для live-сравнения матрица и названия товаров отправляются в OpenAI API при настроенном ключе; это внешний запрос. Без ключа показывается локальное объяснение с пометкой offline.

Перед добавлением UI показывает товар и количество, а отдельное нажатие «Подтвердить добавление» записывает позицию только в SQLite demo cart. Backend снова читает остаток; неизвестный, нулевой или недостаточный остаток блокирует действие. Повторное подтверждение не увеличивает количество. Итог по сохранённым ценам считается лишь при известной цене и единой явной валюте. Сравнение с бюджетом выполняется только в той же валюте. Это не заказ и не запись в корзину ekt.kz: у прототипа нет официального write API.

Пошаговый сценарий показа

Для воспроизводимого показа очистите значения EKT_API_USERNAME, EKT_API_PASSWORD, OPENAI_API_KEY и OPENAI_MODEL в локальном .env, запустите сервер и откройте главную страницу. Над каталогом должны быть надписи Демо-каталог и Offline demo; все DEMO-* позиции вымышлены.

  1. В форме «Подбор по условиям» введите Нужен автомат и нажмите «Разобрать условия». Появится вопрос о номинальном токе. Нажмите «+ Условие», выберите номинальный ток, впишите 16 А; задайте количество 2, бюджет 5000, валюту KZT, затем нажмите «Найти товары». Исправления сохраняются перед поиском.
  2. В результатах выберите DEMO-IN, DEMO-CONFLICT и DEMO-UNKNOWN, затем «Сравнить выбранные товары». В одной таблице видны совпадает для 16 А, противоречит для 20 А и нет данных для отсутствующего тока. Таблица прокручивается внутри блока на телефоне. Ссылки demo-карточек ведут на локальный API, не на ekt.kz.
  3. Для показа замены спросите в чате DEMO-OUT: ответ предложит только DEMO-ALT и назовёт совпадающие характеристики. Вернитесь к форме и разберите Нужен кабель. На вопрос о сечении добавьте условие сечение = 2,5 мм², затем нажмите «Найти товары» и «Сравнить выбранные товары». У DEMO-OUT остаток 0; DEMO-ALT имеет подтверждённое совпадение по указанному полю. Это не гарантия полной совместимости.
  4. У DEMO-ALT установите 2 шт. и нажмите «Добавить в demo cart». До отдельного «Подтвердить добавление» список не меняется. Подтвердите и откройте «Демо-корзину»: сумма 2500 KZT. Вернитесь к форме, смените товарные слова на автомат, характеристику на номинальный ток = 16 А, найдите DEMO-IN и тем же двухшаговым действием добавьте 2 шт. Список покажет 4280 KZT и сравнение с лимитом 5000 KZT. Попытка поставить 9 шт. DEMO-IN блокируется, так как доступно 8.
  5. Для live-показа задайте credentials каталога в .env и перезапустите сервер. Статус должен стать live; результаты и ссылки будут основаны на текущих ответах ekt.kz. Ассортимент, остаток и полнота поиска могут отличаться. Если отдельно настроены OPENAI_API_KEY и OPENAI_MODEL, распознавание и объяснение сравнения идут через OpenAI; интерфейс отмечает источник. Перед показом проверьте фактические товар и цену: live API может не указать валюту, тогда общий итог честно останется неполным.

API прототипа

  • GET /api/status — состояние live/demo подключения.
  • POST /api/requirements/extract — структурированное извлечение условий из сообщения без запуска поиска.
  • GET/PUT /api/requirements/{session_id} — загрузка и сохранение исправленного черновика условий с проверкой названий характеристик.
  • POST /api/requirements/search с JSON {"session_id":"...","refresh":false} — поиск по сохранённым условиям; refresh:true принудительно обновляет кэш.
  • POST /api/requirements/compare с JSON {"session_id":"...","product_ids":["id1","id2"]} — матрица по двум–четырём найденным товарам и короткое проверяемое объяснение.
  • GET /widget и /static/embed.js — компактный встраиваемый чат и загрузчик iframe.
  • GET /api/products?page=1 — страница каталога.
  • GET /api/products/{product_id} — карточка товара.
  • POST /api/chat с JSON {"message":"...","session_id":"..."} — поиск по каталогу, ответы помощника и безопасный сценарий подтверждения корзины.
  • GET /api/cart/{session_id} — состояние демонстрационной корзины текущей сессии.
  • POST /api/cart/prepare, POST /api/cart/confirm, POST /api/cart/cancel — раздельная подготовка, явное подтверждение и отмена добавления найденной позиции.
  • PATCH/DELETE /api/cart/{session_id}/items/{product_id} — явное изменение количества и удаление позиции.
  • GET /api/cart/{session_id}/budget-options — более дешёвые проверяемые варианты из текущего поиска.
  • GET /api/session/{session_id} — последние реплики и статус ожидающего подтверждения.
  • DELETE /api/session/{session_id} — новый диалог в той же браузерной сессии.

Аналоги и демонстрационная корзина

Если у найденной live-позиции остаток равен нулю, backend загружает детальные карточки похожих по названию кандидатов и сравнивает реальные характеристики. Вариант отображается только при подтверждённом наличии и хотя бы одной совпадающей характеристике; совпадение одной лишь категории недостаточно. Объяснение называет совпадающие поля, отличающиеся значения, поля без данных и доступный остаток, а также прямо говорит, что полная совместимость не подтверждена. Служебные маркетинговые поля не используются для технического сравнения. Кандидаты передаются OpenAI для выбора релевантных ID, но видимые факты формирует backend. Без сравнимых полей система сообщает, что данных недостаточно. В offline/demo режиме тот же поиск работает только по явно вымышленному набору.

Покупатель может запросить добавление товара. Backend уточнит количество, затем покажет конкретные товар и количество и попросит отдельное однозначное подтверждение. Только после него backend повторно загружает live-карточку и остаток либо перечитывает запись demo-набора, проверяет положительное количество и доступный остаток с учётом уже выбранной позиции. Сессия хранит демонстрационную корзину в SQLite; ссылка «Демо-корзина» ведёт на /cart. Повторный ответ на уже обработанное подтверждение не создаёт дубликат.

Доступны только read endpoints каталога. Корзина ekt.kz не меняется: для реального добавления потребуется подтверждённый официальный write API/SDK или согласованная ссылка перехода.

После установки выполните тесты без сети и платных запросов:

.\.venv\Scripts\python.exe -m unittest discover -s tests -v
.\.venv\Scripts\python.exe -m pip check

Для проверки внешних сервисов выполните два скрипта. Первый проверяет только live-каталог, поиск и backend-таблицу, без вызова OpenAI. Второй проверяет одну read-only карточку каталога и отдельно делает потенциально платный вызов OpenAI только с вымышленным текстом Нужен кабель 2 шт; карточка каталога в OpenAI не отправляется. Скрипты выводят только статусы, ID и количества, без ключей и содержимого карточек:

.\.venv\Scripts\python.exe -m scripts.catalog_decision_smoke
.\.venv\Scripts\python.exe -m scripts.live_smoke

После отдельного разрешения на передачу live-карточек можно выполнить один платный сквозной тест сравнения. Он отправит в OpenAI проверенную матрицу двух товаров (ID, названия, цена, наличие, номинальный ток), но не Basic Auth и не API-ключ в prompt. Отдельный тест корзины использует live-каталог и временную локальную demo cart без OpenAI и без записи на ekt.kz:

.\.venv\Scripts\python.exe -m scripts.live_comparison_smoke
.\.venv\Scripts\python.exe -m scripts.live_cart_smoke

Для быстрой проверки прежнего чата без credentials спросите DEMO-OUT. Ответ покажет DEMO-ALT и совпадающие характеристики. Напишите Добавь DEMO-ALT 2 шт: до отдельного ответа Подтверждаю страница /cart остаётся пустой. После подтверждения откройте «Демо-корзину». Проверьте, что Добавь DEMO-IN 9 шт отклоняется при остатке 8, а DEMO-PARTIAL не получает вымышленных характеристик. Перезагрузка страницы сохраняет историю и корзину в той же браузерной сессии.

Для live-проверки укажите каталог и OpenAI в .env. На 23 сентября 2026 года read-only карточка 515291 и артикул 200300285_ были доступны. В чате запрос 515291 вызвал OpenAI Responses API и вернул проверенную структуру; Добавь в корзину 200300285_ 1 шт создал только ожидающее подтверждение, а после Подтверждаю demo cart содержала 1 шт. Остатки и ассортимент могут измениться, поэтому перед выступлением проверьте товар заново.

Фактический результат базового MVP: новая виртуальная среда установлена из lock-файла, импорт и HTTP-запуск успешны; 27 unit/integration tests пройдены; pip check ошибок не нашёл; JS-файлы прошли node --check. На раннем этапе live smoke test дал 20 позиций на первой странице и структурированный ответ OpenAI с одним проверенным ID. На предыдущем этапе в браузере проверены ширины 390 и 1280 px без горизонтального переполнения.

Для первого спринта расширения тот же тестовый запуск прошёл с 33 тестами, включая неполный запрос, сохранение исправлений, отрицание «не 16 А», ошибку модели и сохранность прежнего сценария. В браузере проверены ввод, уточняющий вопрос, редактирование и восстановление черновика. Живой OpenAI вызов для запроса «Нужен автомат на 16 А, 2 шт, до 5000 тг» вернул валидные количество 2, бюджет 5000, валюту и требование по току. Отдельный неполный запрос не создал количество из слова «несколько»; backend сформировал уточняющий вопрос о доступной для проверки характеристике. Для второго спринта добавлены проверки пагинации, повторного запроса с кэшем, лимита страниц, частичного сбоя и API поиска по сохранённому черновику. В третьем спринте добавлены тесты трёх статусов сравнения, пустого поля, проверенного URL, кандидата на замену и ошибочного ID модели. В четвёртом — расчёт двух позиций, неполный итог, смешанные валюты, превышение остатка, смена количества, более дешёвый вариант и двойное подтверждение.

Проверка пятого спринта 23 сентября 2026 года: полный набор из 59 unit/integration тестов прошёл; проверены сквозной demo-путь от уточнения до списка из двух товаров, три статуса сравнения, тайм-аут страницы каталога, отказ OpenAI, двойное подтверждение и предел остатка. pip check и node --check для всех четырёх JS-файлов прошли; отдельная сборка статического frontend не нужна. Read-only live-каталог вернул 20 товаров на первой странице и детальную карточку с тем же ID; поиск просмотрел 5 страниц и 12 деталей, вернул ID 25397, 515279, 515280, 515278, 515282, пометил охват неполным и построил сравнение двух ID. Отдельный настоящий запрос OpenAI Responses API на вымышленном тексте прошёл строгую проверку схемы. В браузере на ширинах 390 и 320 px выполнены поиск, сравнение и подтверждение demo cart; горизонтального переполнения страницы нет, таблица прокручивается внутри себя. На этой первоначальной проверке live-чтение каталога и облачный вызов на синтетических данных выполнялись отдельно.

Финальная доработка: таблица включает цену и наличие, варианты замены показывают различия и пропущенные поля, а свободный текст OpenAI не выводится как доказанный факт. Положительный целый остаток теперь требуется строго: булево или дробное значение не превращается в количество штук. 64 теста прошли, включая целый маршрут live-mode с подменёнными каталогом и OpenAI. После явного разрешения пользователя один настоящий OpenAI-вызов сравнил проверенную матрицу live-карточек 25397 и 515279; структурированное объяснение прошло backend-валидацию. Отдельный live-запуск добавил ID 515279 только после подтверждения в временную локальную demo cart; вызовов OpenAI в этом запуске не было. Оба live-поиска пометили охват каталога как неполный. Настоящая корзина ekt.kz не изменялась.

Текущий объём

Обычный чат пока ограничен первыми тремя страницами API: товар вне них может быть найден только по точному числовому ID. Новый подбор по условиям просматривает до пяти страниц и сообщает о неполном охвате. Подбор аналогов опирается на совпадающие поля, которые вернул API; совместимость не гарантируется и при неполных характеристиках не выводится. Свободную формулировку модели о товаре нельзя доказать по произвольной карточке, поэтому она не показывается покупателю: backend выводит только свои формулировки из проверенных полей. Перед покупкой характеристики всё равно следует сверить с карточкой. Клиентский ID сессии не заменяет авторизацию пользователя; прототип не предназначен для личных данных или платежей. Корзина является демонстрационной и не записывает заказ в ekt.kz. Для реальной корзины потребуется подтверждённый официальный write API/SDK или согласованный URL handoff.

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

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

Codex 12

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

  • 2026-09-23 17:21test: verify live catalog decisions and demo cartCodex
  • 2026-09-23 17:15fix: ground catalog decisions and complete comparison evidenceCodex
  • 2026-09-23 16:59docs: finalize catalog decision assistant demoCodex
  • 2026-09-23 16:48feat: build budget aware shopping listCodex
  • 2026-09-23 16:28feat: compare catalog products with evidenceCodex
  • 2026-09-23 16:16feat: search paginated catalog by requirementsCodex
  • 2026-09-23 16:07feat: extract shopping requirementsCodex
  • 2026-09-23 15:40docs: finalize reproducible ekt assistant demoCodex
Все коммиты (12)
  • 2026-09-23 15:16feat: complete assistant workflow and session handlingCodex
  • 2026-09-23 14:47feat: add alternatives and confirmed demo cartCodex
  • 2026-09-23 14:21feat: add grounded product chatCodex
  • 2026-09-23 14:04feat: bootstrap ekt assistant and catalog clientCodex
Структура репозитория (46 файлов)
.env.example
.gitignore
README.md
backend/__init__.py
backend/ai.py
backend/cart.py
backend/catalog.py
backend/chat.py
backend/comparison.py
backend/config.py
backend/demo_data.py
backend/main.py
backend/prompt.py
backend/requirement_search.py
backend/requirements.py
backend/requirements_prompt.py
backend/session.py
backend/shopping_list.py
frontend/app.js
frontend/cart.css
frontend/cart.html
frontend/cart.js
frontend/embed-preview.html
frontend/embed.js
frontend/index.html
frontend/requirements.css
frontend/requirements.js
frontend/styles.css
frontend/ux.css
frontend/widget.css
frontend/widget.html
requirements.lock.txt
requirements.txt
scripts/__init__.py
scripts/catalog_decision_smoke.py
scripts/live_cart_smoke.py
scripts/live_comparison_smoke.py
scripts/live_smoke.py
tests/test_cart_workflow.py
tests/test_comparison.py
tests/test_live_decision_chain.py
tests/test_part4.py
tests/test_part5.py
tests/test_requirement_search.py
tests/test_requirements.py
tests/test_shopping_list.py

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

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

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